添加注册登录功能
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -274,8 +274,8 @@ def int_within_variance(expected, received, variance):
|
||||
)
|
||||
|
||||
|
||||
def eq_regex(a, b, msg=None):
|
||||
assert re.match(b, a), msg or "%r !~ %r" % (a, b)
|
||||
def eq_regex(a, b, msg=None, flags=0):
|
||||
assert re.match(b, a, flags), msg or "%r !~ %r" % (a, b)
|
||||
|
||||
|
||||
def eq_(a, b, msg=None):
|
||||
@@ -513,6 +513,7 @@ class AssertsCompiledSQL:
|
||||
use_default_dialect=False,
|
||||
allow_dialect_select=False,
|
||||
supports_default_values=True,
|
||||
supports_native_boolean=False,
|
||||
supports_default_metavalue=True,
|
||||
literal_binds=False,
|
||||
render_postcompile=False,
|
||||
@@ -527,6 +528,7 @@ class AssertsCompiledSQL:
|
||||
dialect = default.DefaultDialect()
|
||||
dialect.supports_default_values = supports_default_values
|
||||
dialect.supports_default_metavalue = supports_default_metavalue
|
||||
dialect.supports_native_boolean = supports_native_boolean
|
||||
elif allow_dialect_select:
|
||||
dialect = None
|
||||
else:
|
||||
|
||||
@@ -392,8 +392,8 @@ def open(): # noqa
|
||||
return skip_if(BooleanPredicate(False, "mark as execute"))
|
||||
|
||||
|
||||
def closed():
|
||||
return skip_if(BooleanPredicate(True, "marked as skip"))
|
||||
def closed(reason="marked as skip"):
|
||||
return skip_if(BooleanPredicate(True, reason))
|
||||
|
||||
|
||||
def fails(reason=None):
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -14,6 +14,7 @@ from .. import assertions
|
||||
from .. import config
|
||||
from ..assertions import eq_
|
||||
from ..util import drop_all_tables_from_metadata
|
||||
from ..util import picklers
|
||||
from ... import Column
|
||||
from ... import func
|
||||
from ... import Integer
|
||||
@@ -194,6 +195,10 @@ class TestBase:
|
||||
|
||||
return go
|
||||
|
||||
@config.fixture(params=picklers())
|
||||
def picklers(self, request):
|
||||
yield request.param
|
||||
|
||||
@config.fixture()
|
||||
def metadata(self, request):
|
||||
"""Provide bound MetaData for a single test, dropping afterwards."""
|
||||
|
||||
@@ -143,7 +143,9 @@ class MypyTest(TestBase):
|
||||
from sqlalchemy.ext.mypy.util import mypy_14
|
||||
|
||||
expected_messages = []
|
||||
expected_re = re.compile(r"\s*# EXPECTED(_MYPY)?(_RE)?(_TYPE)?: (.+)")
|
||||
expected_re = re.compile(
|
||||
r"\s*# EXPECTED(_MYPY)?(_RE)?(_ROW)?(_TYPE)?: (.+)"
|
||||
)
|
||||
py_ver_re = re.compile(r"^#\s*PYTHON_VERSION\s?>=\s?(\d+\.\d+)")
|
||||
with open(path) as file_:
|
||||
current_assert_messages = []
|
||||
@@ -161,9 +163,24 @@ class MypyTest(TestBase):
|
||||
if m:
|
||||
is_mypy = bool(m.group(1))
|
||||
is_re = bool(m.group(2))
|
||||
is_type = bool(m.group(3))
|
||||
is_row = bool(m.group(3))
|
||||
is_type = bool(m.group(4))
|
||||
|
||||
expected_msg = re.sub(r"# noqa[:]? ?.*", "", m.group(5))
|
||||
if is_row:
|
||||
expected_msg = re.sub(
|
||||
r"Row\[([^\]]+)\]",
|
||||
lambda m: f"tuple[{m.group(1)}, fallback=s"
|
||||
f"qlalchemy.engine.row.{m.group(0)}]",
|
||||
expected_msg,
|
||||
)
|
||||
# For some reason it does not use or syntax (|)
|
||||
expected_msg = re.sub(
|
||||
r"Optional\[(.*)\]",
|
||||
lambda m: f"Union[{m.group(1)}, None]",
|
||||
expected_msg,
|
||||
)
|
||||
|
||||
expected_msg = re.sub(r"# noqa[:]? ?.*", "", m.group(4))
|
||||
if is_type:
|
||||
if not is_re:
|
||||
# the goal here is that we can cut-and-paste
|
||||
@@ -243,7 +260,9 @@ class MypyTest(TestBase):
|
||||
|
||||
return expected_messages
|
||||
|
||||
def _check_output(self, path, expected_messages, stdout, stderr, exitcode):
|
||||
def _check_output(
|
||||
self, path, expected_messages, stdout: str, stderr, exitcode
|
||||
):
|
||||
not_located = []
|
||||
filename = os.path.basename(path)
|
||||
if expected_messages:
|
||||
@@ -263,7 +282,8 @@ class MypyTest(TestBase):
|
||||
):
|
||||
while raw_lines:
|
||||
ol = raw_lines.pop(0)
|
||||
if not re.match(r".+\.py:\d+: note: +def \[.*", ol):
|
||||
if not re.match(r".+\.py:\d+: note: +def .*", ol):
|
||||
raw_lines.insert(0, ol)
|
||||
break
|
||||
elif re.match(
|
||||
r".+\.py:\d+: note: .*(?:perhaps|suggestion)", e, re.I
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -270,7 +270,6 @@ def pytest_collection_modifyitems(session, config, items):
|
||||
for test_class in test_classes:
|
||||
# transfer legacy __backend__ and __sparse_backend__ symbols
|
||||
# to be markers
|
||||
add_markers = set()
|
||||
if getattr(test_class.cls, "__backend__", False) or getattr(
|
||||
test_class.cls, "__only_on__", False
|
||||
):
|
||||
|
||||
@@ -19,6 +19,7 @@ to provide specific inclusion/exclusions.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import platform
|
||||
|
||||
from . import asyncio as _test_asyncio
|
||||
@@ -314,6 +315,13 @@ class SuiteRequirements(Requirements):
|
||||
|
||||
return exclusions.closed()
|
||||
|
||||
@property
|
||||
def ctes_with_values(self):
|
||||
"""target database supports CTES that ride on top of a VALUES
|
||||
clause."""
|
||||
|
||||
return exclusions.closed()
|
||||
|
||||
@property
|
||||
def ctes_on_dml(self):
|
||||
"""target database supports CTES which consist of INSERT, UPDATE
|
||||
@@ -657,6 +665,12 @@ class SuiteRequirements(Requirements):
|
||||
|
||||
return exclusions.closed()
|
||||
|
||||
@property
|
||||
def temp_table_comment_reflection(self):
|
||||
"""indicates if database supports comments on temp tables and
|
||||
the dialect can reflect them"""
|
||||
return exclusions.closed()
|
||||
|
||||
@property
|
||||
def comment_reflection(self):
|
||||
"""Indicates if the database support table comment reflection"""
|
||||
@@ -822,6 +836,11 @@ class SuiteRequirements(Requirements):
|
||||
|
||||
return exclusions.open()
|
||||
|
||||
@property
|
||||
def nvarchar_types(self):
|
||||
"""target database supports NVARCHAR and NCHAR as an actual datatype"""
|
||||
return exclusions.closed()
|
||||
|
||||
@property
|
||||
def unicode_data_no_special_types(self):
|
||||
"""Target database/dialect can receive / deliver / compare data with
|
||||
@@ -1014,6 +1033,13 @@ class SuiteRequirements(Requirements):
|
||||
"""target dialect supports 'AUTOCOMMIT' as an isolation_level"""
|
||||
return exclusions.closed()
|
||||
|
||||
@property
|
||||
def skip_autocommit_rollback(self):
|
||||
"""target dialect supports the detect_autocommit_setting() method and
|
||||
uses the default implementation of do_rollback()"""
|
||||
|
||||
return exclusions.closed()
|
||||
|
||||
@property
|
||||
def isolation_level(self):
|
||||
"""target dialect supports general isolation level settings.
|
||||
@@ -1168,6 +1194,19 @@ class SuiteRequirements(Requirements):
|
||||
"""
|
||||
return self.precision_numerics_many_significant_digits
|
||||
|
||||
@property
|
||||
def server_defaults(self):
|
||||
"""Target backend supports server side defaults for columns"""
|
||||
|
||||
return exclusions.closed()
|
||||
|
||||
@property
|
||||
def expression_server_defaults(self):
|
||||
"""Target backend supports server side defaults with SQL expressions
|
||||
for columns"""
|
||||
|
||||
return exclusions.closed()
|
||||
|
||||
@property
|
||||
def implicit_decimal_binds(self):
|
||||
"""target backend will return a selected Decimal as a Decimal, not
|
||||
@@ -1485,6 +1524,10 @@ class SuiteRequirements(Requirements):
|
||||
|
||||
return config.add_to_marker.timing_intensive
|
||||
|
||||
@property
|
||||
def posix(self):
|
||||
return exclusions.skip_if(lambda: os.name != "posix")
|
||||
|
||||
@property
|
||||
def memory_intensive(self):
|
||||
from . import config
|
||||
@@ -1526,6 +1569,27 @@ class SuiteRequirements(Requirements):
|
||||
|
||||
return exclusions.skip_if(check)
|
||||
|
||||
@property
|
||||
def up_to_date_typealias_type(self):
|
||||
# this checks a particular quirk found in typing_extensions <=4.12.0
|
||||
# using older python versions like 3.10 or 3.9, we use TypeAliasType
|
||||
# from typing_extensions which does not provide for sufficient
|
||||
# introspection prior to 4.13.0
|
||||
def check(config):
|
||||
import typing
|
||||
import typing_extensions
|
||||
|
||||
TypeAliasType = getattr(
|
||||
typing, "TypeAliasType", typing_extensions.TypeAliasType
|
||||
)
|
||||
TV = typing.TypeVar("TV")
|
||||
TA_generic = TypeAliasType( # type: ignore
|
||||
"TA_generic", typing.List[TV], type_params=(TV,)
|
||||
)
|
||||
return hasattr(TA_generic[int], "__value__")
|
||||
|
||||
return exclusions.only_if(check)
|
||||
|
||||
@property
|
||||
def python38(self):
|
||||
return exclusions.only_if(
|
||||
@@ -1556,6 +1620,26 @@ class SuiteRequirements(Requirements):
|
||||
lambda: util.py312, "Python 3.12 or above required"
|
||||
)
|
||||
|
||||
@property
|
||||
def fail_python314b1(self):
|
||||
return exclusions.fails_if(
|
||||
lambda: util.compat.py314b1, "Fails as of python 3.14.0b1"
|
||||
)
|
||||
|
||||
@property
|
||||
def not_python314(self):
|
||||
"""This requirement is interim to assist with backporting of
|
||||
issue #12405.
|
||||
|
||||
SQLAlchemy 2.0 still includes the ``await_fallback()`` method that
|
||||
makes use of ``asyncio.get_event_loop_policy()``. This is removed
|
||||
in SQLAlchemy 2.1.
|
||||
|
||||
"""
|
||||
return exclusions.skip_if(
|
||||
lambda: util.py314, "Python 3.14 or above not supported"
|
||||
)
|
||||
|
||||
@property
|
||||
def cpython(self):
|
||||
return exclusions.only_if(
|
||||
@@ -1826,3 +1910,9 @@ class SuiteRequirements(Requirements):
|
||||
def supports_bitwise_shift(self):
|
||||
"""Target database supports bitwise left or right shift"""
|
||||
return exclusions.closed()
|
||||
|
||||
@property
|
||||
def like_escapes(self):
|
||||
"""Target backend supports custom ESCAPE characters
|
||||
with LIKE comparisons"""
|
||||
return exclusions.open()
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -10,11 +10,13 @@ from .. import fixtures
|
||||
from ..assertions import eq_
|
||||
from ..schema import Column
|
||||
from ..schema import Table
|
||||
from ... import column
|
||||
from ... import ForeignKey
|
||||
from ... import Integer
|
||||
from ... import select
|
||||
from ... import String
|
||||
from ... import testing
|
||||
from ... import values
|
||||
|
||||
|
||||
class CTETest(fixtures.TablesTest):
|
||||
@@ -209,3 +211,27 @@ class CTETest(fixtures.TablesTest):
|
||||
).fetchall(),
|
||||
[(1, "d1", None), (5, "d5", 3)],
|
||||
)
|
||||
|
||||
@testing.variation("values_named", [True, False])
|
||||
@testing.variation("cte_named", [True, False])
|
||||
@testing.variation("literal_binds", [True, False])
|
||||
@testing.requires.ctes_with_values
|
||||
def test_values_named_via_cte(
|
||||
self, connection, values_named, cte_named, literal_binds
|
||||
):
|
||||
|
||||
cte1 = (
|
||||
values(
|
||||
column("col1", String),
|
||||
column("col2", Integer),
|
||||
literal_binds=bool(literal_binds),
|
||||
name="some name" if values_named else None,
|
||||
)
|
||||
.data([("a", 2), ("b", 3)])
|
||||
.cte("cte1" if cte_named else None)
|
||||
)
|
||||
|
||||
stmt = select(cte1)
|
||||
|
||||
rows = connection.execute(stmt).all()
|
||||
eq_(rows, [("a", 2), ("b", 3)])
|
||||
|
||||
@@ -17,6 +17,7 @@ from .. import eq_
|
||||
from .. import fixtures
|
||||
from .. import is_not_none
|
||||
from .. import is_true
|
||||
from .. import mock
|
||||
from .. import ne_
|
||||
from .. import provide_metadata
|
||||
from ..assertions import expect_raises
|
||||
@@ -293,7 +294,11 @@ class AutocommitIsolationTest(fixtures.TablesTest):
|
||||
test_needs_acid=True,
|
||||
)
|
||||
|
||||
def _test_conn_autocommits(self, conn, autocommit):
|
||||
def _test_conn_autocommits(self, conn, autocommit, ensure_table=False):
|
||||
if ensure_table:
|
||||
self.tables.some_table.create(conn, checkfirst=True)
|
||||
conn.commit()
|
||||
|
||||
trans = conn.begin()
|
||||
conn.execute(
|
||||
self.tables.some_table.insert(), {"id": 1, "data": "some data"}
|
||||
@@ -336,6 +341,37 @@ class AutocommitIsolationTest(fixtures.TablesTest):
|
||||
)
|
||||
self._test_conn_autocommits(conn, False)
|
||||
|
||||
@testing.requires.skip_autocommit_rollback
|
||||
@testing.variation("autocommit_setting", ["false", "engine", "option"])
|
||||
@testing.variation("block_rollback", [True, False])
|
||||
def test_autocommit_block(
|
||||
self, testing_engine, autocommit_setting, block_rollback
|
||||
):
|
||||
kw = {}
|
||||
if bool(block_rollback):
|
||||
kw["skip_autocommit_rollback"] = True
|
||||
if autocommit_setting.engine:
|
||||
kw["isolation_level"] = "AUTOCOMMIT"
|
||||
|
||||
engine = testing_engine(options=kw)
|
||||
|
||||
conn = engine.connect()
|
||||
if autocommit_setting.option:
|
||||
conn.execution_options(isolation_level="AUTOCOMMIT")
|
||||
self._test_conn_autocommits(
|
||||
conn,
|
||||
autocommit_setting.engine or autocommit_setting.option,
|
||||
ensure_table=True,
|
||||
)
|
||||
with mock.patch.object(
|
||||
conn.connection, "rollback", wraps=conn.connection.rollback
|
||||
) as check_rollback:
|
||||
conn.close()
|
||||
if autocommit_setting.false or not block_rollback:
|
||||
eq_(check_rollback.mock_calls, [mock.call()])
|
||||
else:
|
||||
eq_(check_rollback.mock_calls, [])
|
||||
|
||||
@testing.requires.independent_readonly_connections
|
||||
@testing.variation("use_dialect_setting", [True, False])
|
||||
def test_dialect_autocommit_is_restored(
|
||||
@@ -537,7 +573,7 @@ class DifficultParametersTest(fixtures.TestBase):
|
||||
t.c[name].in_(["some name", "some other_name"])
|
||||
)
|
||||
|
||||
row = connection.execute(stmt).first()
|
||||
connection.execute(stmt).first()
|
||||
|
||||
@testing.fixture
|
||||
def multirow_fixture(self, metadata, connection):
|
||||
@@ -621,7 +657,7 @@ class ReturningGuardsTest(fixtures.TablesTest):
|
||||
f"current server capabilities does not support "
|
||||
f".*RETURNING when executemany is used",
|
||||
):
|
||||
result = connection.execute(
|
||||
connection.execute(
|
||||
stmt,
|
||||
[
|
||||
{id_param_name: 1, "data": "d1"},
|
||||
|
||||
@@ -14,6 +14,7 @@ import sqlalchemy as sa
|
||||
from .. import config
|
||||
from .. import engines
|
||||
from .. import eq_
|
||||
from .. import eq_regex
|
||||
from .. import expect_raises
|
||||
from .. import expect_raises_message
|
||||
from .. import expect_warnings
|
||||
@@ -23,6 +24,8 @@ from ..provision import get_temp_table_name
|
||||
from ..provision import temp_table_keyword_args
|
||||
from ..schema import Column
|
||||
from ..schema import Table
|
||||
from ... import Boolean
|
||||
from ... import DateTime
|
||||
from ... import event
|
||||
from ... import ForeignKey
|
||||
from ... import func
|
||||
@@ -220,6 +223,7 @@ class HasTableTest(OneConnectionTablesTest):
|
||||
|
||||
class HasIndexTest(fixtures.TablesTest):
|
||||
__backend__ = True
|
||||
__requires__ = ("index_reflection",)
|
||||
|
||||
@classmethod
|
||||
def define_tables(cls, metadata):
|
||||
@@ -294,25 +298,36 @@ class HasIndexTest(fixtures.TablesTest):
|
||||
)
|
||||
|
||||
|
||||
class BizarroCharacterFKResolutionTest(fixtures.TestBase):
|
||||
"""tests for #10275"""
|
||||
class BizarroCharacterTest(fixtures.TestBase):
|
||||
|
||||
__backend__ = True
|
||||
|
||||
@testing.combinations(
|
||||
("id",), ("(3)",), ("col%p",), ("[brack]",), argnames="columnname"
|
||||
)
|
||||
def column_names():
|
||||
return testing.combinations(
|
||||
("plainname",),
|
||||
("(3)",),
|
||||
("col%p",),
|
||||
("[brack]",),
|
||||
argnames="columnname",
|
||||
)
|
||||
|
||||
def table_names():
|
||||
return testing.combinations(
|
||||
("plain",),
|
||||
("(2)",),
|
||||
("per % cent",),
|
||||
("[brackets]",),
|
||||
argnames="tablename",
|
||||
)
|
||||
|
||||
@testing.variation("use_composite", [True, False])
|
||||
@testing.combinations(
|
||||
("plain",),
|
||||
("(2)",),
|
||||
("per % cent",),
|
||||
("[brackets]",),
|
||||
argnames="tablename",
|
||||
)
|
||||
@column_names()
|
||||
@table_names()
|
||||
@testing.requires.foreign_key_constraint_reflection
|
||||
def test_fk_ref(
|
||||
self, connection, metadata, use_composite, tablename, columnname
|
||||
):
|
||||
"""tests for #10275"""
|
||||
tt = Table(
|
||||
tablename,
|
||||
metadata,
|
||||
@@ -352,6 +367,77 @@ class BizarroCharacterFKResolutionTest(fixtures.TestBase):
|
||||
if use_composite:
|
||||
assert o2.c.ref2.references(t1.c[1])
|
||||
|
||||
@column_names()
|
||||
@table_names()
|
||||
@testing.requires.identity_columns
|
||||
def test_reflect_identity(
|
||||
self, tablename, columnname, connection, metadata
|
||||
):
|
||||
Table(
|
||||
tablename,
|
||||
metadata,
|
||||
Column(columnname, Integer, Identity(), primary_key=True),
|
||||
)
|
||||
metadata.create_all(connection)
|
||||
insp = inspect(connection)
|
||||
|
||||
eq_(insp.get_columns(tablename)[0]["identity"]["start"], 1)
|
||||
|
||||
@column_names()
|
||||
@table_names()
|
||||
@testing.requires.comment_reflection
|
||||
def test_reflect_comments(
|
||||
self, tablename, columnname, connection, metadata
|
||||
):
|
||||
Table(
|
||||
tablename,
|
||||
metadata,
|
||||
Column("id", Integer, primary_key=True),
|
||||
Column(columnname, Integer, comment="some comment"),
|
||||
)
|
||||
metadata.create_all(connection)
|
||||
insp = inspect(connection)
|
||||
|
||||
eq_(insp.get_columns(tablename)[1]["comment"], "some comment")
|
||||
|
||||
|
||||
class TempTableElementsTest(fixtures.TestBase):
|
||||
|
||||
__backend__ = True
|
||||
|
||||
__requires__ = ("temp_table_reflection",)
|
||||
|
||||
@testing.fixture
|
||||
def tablename(self):
|
||||
return get_temp_table_name(
|
||||
config, config.db, f"ident_tmp_{config.ident}"
|
||||
)
|
||||
|
||||
@testing.requires.identity_columns
|
||||
def test_reflect_identity(self, tablename, connection, metadata):
|
||||
Table(
|
||||
tablename,
|
||||
metadata,
|
||||
Column("id", Integer, Identity(), primary_key=True),
|
||||
)
|
||||
metadata.create_all(connection)
|
||||
insp = inspect(connection)
|
||||
|
||||
eq_(insp.get_columns(tablename)[0]["identity"]["start"], 1)
|
||||
|
||||
@testing.requires.temp_table_comment_reflection
|
||||
def test_reflect_comments(self, tablename, connection, metadata):
|
||||
Table(
|
||||
tablename,
|
||||
metadata,
|
||||
Column("id", Integer, primary_key=True),
|
||||
Column("foobar", Integer, comment="some comment"),
|
||||
)
|
||||
metadata.create_all(connection)
|
||||
insp = inspect(connection)
|
||||
|
||||
eq_(insp.get_columns(tablename)[1]["comment"], "some comment")
|
||||
|
||||
|
||||
class QuotedNameArgumentTest(fixtures.TablesTest):
|
||||
run_create_tables = "once"
|
||||
@@ -455,7 +541,7 @@ class QuotedNameArgumentTest(fixtures.TablesTest):
|
||||
is_true(isinstance(res, dict))
|
||||
else:
|
||||
with expect_raises(NotImplementedError):
|
||||
res = insp.get_table_options(name)
|
||||
insp.get_table_options(name)
|
||||
|
||||
@quote_fixtures
|
||||
@testing.requires.view_column_reflection
|
||||
@@ -474,11 +560,13 @@ class QuotedNameArgumentTest(fixtures.TablesTest):
|
||||
assert insp.get_pk_constraint(name)
|
||||
|
||||
@quote_fixtures
|
||||
@testing.requires.foreign_key_constraint_reflection
|
||||
def test_get_foreign_keys(self, name):
|
||||
insp = inspect(config.db)
|
||||
assert insp.get_foreign_keys(name)
|
||||
|
||||
@quote_fixtures
|
||||
@testing.requires.index_reflection
|
||||
def test_get_indexes(self, name):
|
||||
insp = inspect(config.db)
|
||||
assert insp.get_indexes(name)
|
||||
@@ -1947,6 +2035,8 @@ class ComponentReflectionTest(ComparesTables, OneConnectionTablesTest):
|
||||
if dupe:
|
||||
names_that_duplicate_index.add(dupe)
|
||||
eq_(refl.pop("comment", None), None)
|
||||
# ignore dialect_options
|
||||
refl.pop("dialect_options", None)
|
||||
eq_(orig, refl)
|
||||
|
||||
reflected_metadata = MetaData()
|
||||
@@ -2038,7 +2128,7 @@ class ComponentReflectionTest(ComparesTables, OneConnectionTablesTest):
|
||||
is_true(isinstance(res, dict))
|
||||
else:
|
||||
with expect_raises(NotImplementedError):
|
||||
res = insp.get_table_options("users", schema=schema)
|
||||
insp.get_table_options("users", schema=schema)
|
||||
|
||||
@testing.combinations((True, testing.requires.schemas), False)
|
||||
def test_multi_get_table_options(self, use_schema):
|
||||
@@ -2054,7 +2144,7 @@ class ComponentReflectionTest(ComparesTables, OneConnectionTablesTest):
|
||||
eq_(res, exp)
|
||||
else:
|
||||
with expect_raises(NotImplementedError):
|
||||
res = insp.get_multi_table_options()
|
||||
insp.get_multi_table_options()
|
||||
|
||||
@testing.fixture
|
||||
def get_multi_exp(self, connection):
|
||||
@@ -2762,12 +2852,25 @@ class ComponentReflectionTestExtra(ComparesIndexes, fixtures.TestBase):
|
||||
eq_(typ.scale, 5)
|
||||
|
||||
@testing.requires.table_reflection
|
||||
def test_varchar_reflection(self, connection, metadata):
|
||||
typ = self._type_round_trip(
|
||||
connection, metadata, sql_types.String(52)
|
||||
)[0]
|
||||
assert isinstance(typ, sql_types.String)
|
||||
@testing.combinations(
|
||||
sql_types.String,
|
||||
sql_types.VARCHAR,
|
||||
sql_types.CHAR,
|
||||
(sql_types.NVARCHAR, testing.requires.nvarchar_types),
|
||||
(sql_types.NCHAR, testing.requires.nvarchar_types),
|
||||
argnames="type_",
|
||||
)
|
||||
def test_string_length_reflection(self, connection, metadata, type_):
|
||||
typ = self._type_round_trip(connection, metadata, type_(52))[0]
|
||||
if issubclass(type_, sql_types.VARCHAR):
|
||||
assert isinstance(typ, sql_types.VARCHAR)
|
||||
elif issubclass(type_, sql_types.CHAR):
|
||||
assert isinstance(typ, sql_types.CHAR)
|
||||
else:
|
||||
assert isinstance(typ, sql_types.String)
|
||||
|
||||
eq_(typ.length, 52)
|
||||
assert isinstance(typ.length, int)
|
||||
|
||||
@testing.requires.table_reflection
|
||||
def test_nullable_reflection(self, connection, metadata):
|
||||
@@ -2879,6 +2982,47 @@ class ComponentReflectionTestExtra(ComparesIndexes, fixtures.TestBase):
|
||||
eq_(opts, expected)
|
||||
# eq_(dict((k, opts[k]) for k in opts if opts[k]), expected)
|
||||
|
||||
@testing.combinations(
|
||||
(Integer, sa.text("10"), r"'?10'?"),
|
||||
(Integer, "10", r"'?10'?"),
|
||||
(Boolean, sa.true(), r"1|true"),
|
||||
(
|
||||
Integer,
|
||||
sa.text("3 + 5"),
|
||||
r"3\+5",
|
||||
testing.requires.expression_server_defaults,
|
||||
),
|
||||
(
|
||||
Integer,
|
||||
sa.text("(3 * 5)"),
|
||||
r"3\*5",
|
||||
testing.requires.expression_server_defaults,
|
||||
),
|
||||
(DateTime, func.now(), r"current_timestamp|now|getdate"),
|
||||
(
|
||||
Integer,
|
||||
sa.literal_column("3") + sa.literal_column("5"),
|
||||
r"3\+5",
|
||||
testing.requires.expression_server_defaults,
|
||||
),
|
||||
argnames="datatype, default, expected_reg",
|
||||
)
|
||||
@testing.requires.server_defaults
|
||||
def test_server_defaults(
|
||||
self, metadata, connection, datatype, default, expected_reg
|
||||
):
|
||||
t = Table(
|
||||
"t",
|
||||
metadata,
|
||||
Column("id", Integer, primary_key=True),
|
||||
Column("thecol", datatype, server_default=default),
|
||||
)
|
||||
t.create(connection)
|
||||
|
||||
reflected = inspect(connection).get_columns("t")[1]["default"]
|
||||
reflected_sanitized = re.sub(r"[\(\) \']", "", reflected)
|
||||
eq_regex(reflected_sanitized, expected_reg, flags=re.IGNORECASE)
|
||||
|
||||
|
||||
class NormalizedNameTest(fixtures.TablesTest):
|
||||
__requires__ = ("denormalized_names",)
|
||||
@@ -3215,11 +3359,12 @@ __all__ = (
|
||||
"ComponentReflectionTestExtra",
|
||||
"TableNoColumnsTest",
|
||||
"QuotedNameArgumentTest",
|
||||
"BizarroCharacterFKResolutionTest",
|
||||
"BizarroCharacterTest",
|
||||
"HasTableTest",
|
||||
"HasIndexTest",
|
||||
"NormalizedNameTest",
|
||||
"ComputedReflectionTest",
|
||||
"IdentityReflectionTest",
|
||||
"CompositeKeyReflectionTest",
|
||||
"TempTableElementsTest",
|
||||
)
|
||||
|
||||
@@ -268,6 +268,8 @@ class ServerSideCursorsTest(
|
||||
return isinstance(cursor, sscursor)
|
||||
elif self.engine.dialect.driver == "mariadbconnector":
|
||||
return not cursor.buffered
|
||||
elif self.engine.dialect.driver == "mysqlconnector":
|
||||
return "buffered" not in type(cursor).__name__.lower()
|
||||
elif self.engine.dialect.driver in ("asyncpg", "aiosqlite"):
|
||||
return cursor.server_side
|
||||
elif self.engine.dialect.driver == "pg8000":
|
||||
|
||||
@@ -1541,6 +1541,7 @@ class LikeFunctionsTest(fixtures.TablesTest):
|
||||
col = self.tables.some_table.c.data
|
||||
self._test(col.startswith("ab%c"), {1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
|
||||
|
||||
@testing.requires.like_escapes
|
||||
def test_startswith_autoescape(self):
|
||||
col = self.tables.some_table.c.data
|
||||
self._test(col.startswith("ab%c", autoescape=True), {3})
|
||||
@@ -1552,10 +1553,12 @@ class LikeFunctionsTest(fixtures.TablesTest):
|
||||
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
|
||||
)
|
||||
|
||||
@testing.requires.like_escapes
|
||||
def test_startswith_escape(self):
|
||||
col = self.tables.some_table.c.data
|
||||
self._test(col.startswith("ab##c", escape="#"), {7})
|
||||
|
||||
@testing.requires.like_escapes
|
||||
def test_startswith_autoescape_escape(self):
|
||||
col = self.tables.some_table.c.data
|
||||
self._test(col.startswith("ab%c", autoescape=True, escape="#"), {3})
|
||||
@@ -1571,14 +1574,17 @@ class LikeFunctionsTest(fixtures.TablesTest):
|
||||
col.endswith(literal_column("'e%fg'")), {1, 2, 3, 4, 5, 6, 7, 8, 9}
|
||||
)
|
||||
|
||||
@testing.requires.like_escapes
|
||||
def test_endswith_autoescape(self):
|
||||
col = self.tables.some_table.c.data
|
||||
self._test(col.endswith("e%fg", autoescape=True), {6})
|
||||
|
||||
@testing.requires.like_escapes
|
||||
def test_endswith_escape(self):
|
||||
col = self.tables.some_table.c.data
|
||||
self._test(col.endswith("e##fg", escape="#"), {9})
|
||||
|
||||
@testing.requires.like_escapes
|
||||
def test_endswith_autoescape_escape(self):
|
||||
col = self.tables.some_table.c.data
|
||||
self._test(col.endswith("e%fg", autoescape=True, escape="#"), {6})
|
||||
@@ -1588,14 +1594,17 @@ class LikeFunctionsTest(fixtures.TablesTest):
|
||||
col = self.tables.some_table.c.data
|
||||
self._test(col.contains("b%cde"), {1, 2, 3, 4, 5, 6, 7, 8, 9})
|
||||
|
||||
@testing.requires.like_escapes
|
||||
def test_contains_autoescape(self):
|
||||
col = self.tables.some_table.c.data
|
||||
self._test(col.contains("b%cde", autoescape=True), {3})
|
||||
|
||||
@testing.requires.like_escapes
|
||||
def test_contains_escape(self):
|
||||
col = self.tables.some_table.c.data
|
||||
self._test(col.contains("b##cde", escape="#"), {7})
|
||||
|
||||
@testing.requires.like_escapes
|
||||
def test_contains_autoescape_escape(self):
|
||||
col = self.tables.some_table.c.data
|
||||
self._test(col.contains("b%cd", autoescape=True, escape="#"), {3})
|
||||
@@ -1771,7 +1780,7 @@ class IdentityAutoincrementTest(fixtures.TablesTest):
|
||||
)
|
||||
|
||||
def test_autoincrement_with_identity(self, connection):
|
||||
res = connection.execute(self.tables.tbl.insert(), {"desc": "row"})
|
||||
connection.execute(self.tables.tbl.insert(), {"desc": "row"})
|
||||
res = connection.execute(self.tables.tbl.select()).first()
|
||||
eq_(res, (1, "row"))
|
||||
|
||||
|
||||
@@ -299,6 +299,7 @@ class ArrayTest(_LiteralRoundTripFixture, fixtures.TablesTest):
|
||||
|
||||
class BinaryTest(_LiteralRoundTripFixture, fixtures.TablesTest):
|
||||
__backend__ = True
|
||||
__requires__ = ("binary_literals",)
|
||||
|
||||
@classmethod
|
||||
def define_tables(cls, metadata):
|
||||
@@ -1483,6 +1484,7 @@ class JSONTest(_LiteralRoundTripFixture, fixtures.TablesTest):
|
||||
|
||||
return datatype, compare_value, p_s
|
||||
|
||||
@testing.requires.legacy_unconditional_json_extract
|
||||
@_index_fixtures(False)
|
||||
def test_index_typed_access(self, datatype, value):
|
||||
data_table = self.tables.data_table
|
||||
@@ -1504,6 +1506,7 @@ class JSONTest(_LiteralRoundTripFixture, fixtures.TablesTest):
|
||||
eq_(roundtrip, compare_value)
|
||||
is_(type(roundtrip), type(compare_value))
|
||||
|
||||
@testing.requires.legacy_unconditional_json_extract
|
||||
@_index_fixtures(True)
|
||||
def test_index_typed_comparison(self, datatype, value):
|
||||
data_table = self.tables.data_table
|
||||
@@ -1528,6 +1531,7 @@ class JSONTest(_LiteralRoundTripFixture, fixtures.TablesTest):
|
||||
# make sure we get a row even if value is None
|
||||
eq_(row, (compare_value,))
|
||||
|
||||
@testing.requires.legacy_unconditional_json_extract
|
||||
@_index_fixtures(True)
|
||||
def test_path_typed_comparison(self, datatype, value):
|
||||
data_table = self.tables.data_table
|
||||
|
||||
@@ -10,10 +10,12 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections import deque
|
||||
from collections import namedtuple
|
||||
import contextlib
|
||||
import decimal
|
||||
import gc
|
||||
from itertools import chain
|
||||
import pickle
|
||||
import random
|
||||
import sys
|
||||
from sys import getsizeof
|
||||
@@ -55,15 +57,10 @@ else:
|
||||
|
||||
|
||||
def picklers():
|
||||
picklers = set()
|
||||
import pickle
|
||||
nt = namedtuple("picklers", ["loads", "dumps"])
|
||||
|
||||
picklers.add(pickle)
|
||||
|
||||
# yes, this thing needs this much testing
|
||||
for pickle_ in picklers:
|
||||
for protocol in range(-2, pickle.HIGHEST_PROTOCOL + 1):
|
||||
yield pickle_.loads, lambda d: pickle_.dumps(d, protocol)
|
||||
for protocol in range(-2, pickle.HIGHEST_PROTOCOL + 1):
|
||||
yield nt(pickle.loads, lambda d: pickle.dumps(d, protocol))
|
||||
|
||||
|
||||
def random_choices(population, k=1):
|
||||
|
||||
Reference in New Issue
Block a user