--- /dev/null
+.. change::
+ :tags: installation
+
+ Compatibility improvements to work fully with Python 3.12
Column(
"changed",
DateTime,
- default=datetime.datetime.utcnow,
+ default=lambda: datetime.datetime.now(datetime.timezone.utc),
info=version_meta,
)
)
typedef intargfunc ssizeargfunc;
#endif
+#if PY_VERSION_HEX > 0x030c0000
+# define PY_RAISE_SLICE_FOR_MAPPING PyExc_KeyError
+#else
+# define PY_RAISE_SLICE_FOR_MAPPING PyExc_TypeError
+#endif
+
#if PY_MAJOR_VERSION < 3
// new typedef in Python 3
if (record == NULL) {
if (PySlice_Check(key)) {
- PyErr_Format(PyExc_TypeError, "can't use slices for mapping access");
+ PyErr_Format(PY_RAISE_SLICE_FOR_MAPPING, "can't use slices for mapping access");
return NULL;
}
record = PyObject_CallMethod(self->parent, "_key_fallback",
try:
rec = self._keymap[key]
except KeyError as ke:
- rec = self._parent._key_fallback(key, ke)
+ if isinstance(key, slice):
+ return tuple(self._data[key])
+ else:
+ rec = self._parent._key_fallback(key, ke)
except TypeError:
if isinstance(key, slice):
return tuple(self._data[key])
"""
impl = DateTime
- epoch = dt.datetime.utcfromtimestamp(0)
+ if compat.py2k:
+ epoch = dt.datetime.utcfromtimestamp(0)
+ else:
+ epoch = dt.datetime.fromtimestamp(0, dt.timezone.utc).replace(
+ tzinfo=None
+ )
cache_ok = True
def __init__(self, native=True, second_precision=None, day_precision=None):
warnings.filterwarnings(
"error", category=DeprecationWarning, module=origin
)
+ warnings.filterwarnings(
+ "ignore",
+ category=DeprecationWarning,
+ message=r".*The default (?:date)?(?:time)?(?:stamp)? "
+ r"(adapter|converter) is deprecated",
+ )
# ignore things that are deprecated *as of* 2.0 :)
warnings.filterwarnings(
from sqlalchemy.testing import fixtures
from sqlalchemy.testing import is_false
from sqlalchemy.testing import is_true
+from sqlalchemy.testing.assertions import expect_raises
from sqlalchemy.testing.util import picklers
+from sqlalchemy.util import compat
class ResultTupleTest(fixtures.TestBase):
def test_slices_arent_in_mappings(self):
keyed_tuple = self._fixture([1, 2], ["a", "b"])
- assert_raises(TypeError, lambda: keyed_tuple._mapping[0:2])
+ if compat.py312:
+ with expect_raises(KeyError):
+ keyed_tuple._mapping[0:2]
+ else:
+ with expect_raises(TypeError):
+ keyed_tuple._mapping[0:2]
def test_integers_arent_in_mappings(self):
keyed_tuple = self._fixture([1, 2], ["a", "b"])
assert canary.call_args_list[0][0][0] is dbapi_con
assert canary.call_args_list[0][0][2] is exc
- @testing.combinations((True,), (False,), argnames="is_asyncio")
- @testing.combinations((True,), (False,), argnames="has_terminate")
+ @testing.variation("is_asyncio", [(True, testing.requires.asyncio), False])
+ @testing.variation("has_terminate", [True, False])
@testing.requires.python3
def test_checkin_event_gc(self, is_asyncio, has_terminate):
p, canary = self._checkin_event_fixture(
exc_cls=TimeoutThing if exc_type.base_exception else Exception,
)
- @testing.combinations((True, testing.requires.python3), (False,))
+ @testing.variation(
+ "detach_gced",
+ [("detached_gc", testing.requires.asyncio), "normal_gc"],
+ )
+ @testing.emits_warning("The garbage collector")
+ @testing.requires.python3
def test_userspace_disconnectionerror_weakref_finalizer(self, detach_gced):
dbapi, pool = self._queuepool_dbapi_fixture(
pool_size=1, max_overflow=2, _is_asyncio=detach_gced
class InvalidateDuringResultTest(fixtures.TestBase):
__backend__ = True
+ # test locks SQLite file databases due to unconsumed results
+ __requires__ = ("ad_hoc_engines",)
+
def setup_test(self):
self.engine = engines.reconnecting_engine()
self.meta = MetaData()
self.meta.drop_all(conn)
self.engine.dispose()
- @testing.crashes(
- "oracle",
- "cx_oracle 6 doesn't allow a close like this due to open cursors",
- )
- @testing.fails_if(
- [
- "+mysqlconnector",
- "+mysqldb",
- "+cymysql",
- "+pymysql",
- "+pg8000",
- "+asyncpg",
- "+aiosqlite",
- "+aiomysql",
- "+asyncmy",
- ],
- "Buffers the result set and doesn't check for connection close",
- )
def test_invalidate_on_results(self):
conn = self.engine.connect()
- result = conn.exec_driver_sql("select * from sometable")
+ result = conn.exec_driver_sql(
+ "select * from sometable",
+ )
for x in range(20):
result.fetchone()
+
+ real_cursor = result.cursor
self.engine.test_shutdown()
+
+ def produce_side_effect():
+ # will fail because connection was closed, with an exception
+ # that should trigger disconnect routines
+ real_cursor.execute("select * from sometable")
+
+ result.cursor = Mock(
+ fetchone=mock.Mock(side_effect=produce_side_effect)
+ )
try:
_assert_invalidated(result.fetchone)
assert conn.invalidated
sqlite_file: .[aiosqlite]
sqlite_file: .[sqlcipher]; python_version >= '3' and python_version < '3.10'
postgresql: .[postgresql]
- postgresql: .[postgresql_asyncpg]; python_version >= '3'
+ py3{,7,8,9,10,11}-postgresql: .[postgresql_asyncpg]; python_version >= '3'
postgresql: .[postgresql_pg8000]; python_version >= '3'
mysql: .[mysql]
mssql: .[mssql]
+ py312: greenlet>=3.0.0a1
+
dbapimain-sqlite: git+https://github.com/omnilib/aiosqlite.git#egg=aiosqlite
dbapimain-sqlite: git+https://github.com/coleifer/sqlcipher3.git#egg=sqlcipher3
PYTEST_COLOR={tty:--color=yes}
+ # pytest 'rewrite' is hitting lots of deprecation warnings under py312 and
+ # i can't find any way to ignore those warnings, so this turns it off
+ py312: PYTEST_ARGS=--assert plain
+
MEMUSAGE=--nomemory
BASECOMMAND=python -m pytest {env:PYTEST_COLOR} --rootdir {toxinidir} --log-info=sqlalchemy.testing
WORKERS={env:TOX_WORKERS:-n4 --max-worker-restart=5}
+
+
nocext: DISABLE_SQLALCHEMY_CEXT=1
cext: REQUIRE_SQLALCHEMY_CEXT=1
cov: COVERAGE={[testenv]cov_args}
postgresql: POSTGRESQL={env:TOX_POSTGRESQL:--db postgresql}
py2{,7}-postgresql: POSTGRESQL={env:TOX_POSTGRESQL_PY2K:{env:TOX_POSTGRESQL:--db postgresql}}
py3{,5,6,7,8,9,10,11}-postgresql: EXTRA_PG_DRIVERS={env:EXTRA_PG_DRIVERS:--dbdriver psycopg2 --dbdriver asyncpg --dbdriver pg8000}
+ py312-postgresql: EXTRA_PG_DRIVERS={env:EXTRA_PG_DRIVERS:--dbdriver psycopg2 --dbdriver pg8000}
mysql: MYSQL={env:TOX_MYSQL:--db mysql}
py2{,7}-mysql: MYSQL={env:TOX_MYSQL_PY2K:{env:TOX_MYSQL:--db mysql}}