from . import context
from . import op
-__version__ = "1.16.6"
+__version__ = "1.17.0"
from ..runtime.migration import StampStep
try:
- if compat.py39:
- from zoneinfo import ZoneInfo
- from zoneinfo import ZoneInfoNotFoundError
- else:
- from backports.zoneinfo import ZoneInfo # type: ignore[import-not-found,no-redef] # noqa: E501
- from backports.zoneinfo import ZoneInfoNotFoundError # type: ignore[no-redef] # noqa: E501
+ from zoneinfo import ZoneInfo
+ from zoneinfo import ZoneInfoNotFoundError
except ImportError:
ZoneInfo = None # type: ignore[assignment, misc]
import sys
from typing import Any
from typing import Callable
-from typing import Dict
-from typing import List
-from typing import Optional
from typing import TYPE_CHECKING
-from typing import Union
from .. import util
from ..util import compat
def _invoke(
name: str,
- revision_path: Union[str, os.PathLike[str]],
+ revision_path: str | os.PathLike[str],
options: PostWriteHookConfig,
) -> Any:
"""Invokes the formatter registered for the given name.
def _run_hooks(
- path: Union[str, os.PathLike[str]], hooks: list[PostWriteHookConfig]
+ path: str | os.PathLike[str], hooks: list[PostWriteHookConfig]
) -> None:
"""Invoke hooks for a generated revision."""
_invoke(type_, path, hook)
-def _parse_cmdline_options(cmdline_options_str: str, path: str) -> List[str]:
+def _parse_cmdline_options(cmdline_options_str: str, path: str) -> list[str]:
"""Parse options from a string into a list.
Also substitutes the revision script token with the actual filename of
def _run_hook(
- path: str, options: dict, ignore_output: bool, command: List[str]
+ path: str, options: dict, ignore_output: bool, command: list[str]
) -> None:
- cwd: Optional[str] = options.get("cwd", None)
+ cwd: str | None = options.get("cwd", None)
cmdline_options_str = options.get("options", "")
cmdline_options_list = _parse_cmdline_options(cmdline_options_str, path)
- kw: Dict[str, Any] = {}
+ kw: dict[str, Any] = {}
if ignore_output:
kw["stdout"] = kw["stderr"] = subprocess.DEVNULL
# timezone to use when rendering the date within the migration file
# as well as the filename.
-# If specified, requires the python>=3.9 or backports.zoneinfo library and tzdata library.
-# Any required deps can installed by adding `alembic[tz]` to the pip requirements
+# If specified, requires the tzdata library which can be installed by adding
+# `alembic[tz]` to the pip requirements.
# string value is passed to ZoneInfo()
# leave blank for localtime
# timezone =
# timezone to use when rendering the date within the migration file
# as well as the filename.
-# If specified, requires the python>=3.9 or backports.zoneinfo library and tzdata library.
-# Any required deps can installed by adding `alembic[tz]` to the pip requirements
+# If specified, requires the tzdata library which can be installed by adding
+# `alembic[tz]` to the pip requirements.
# string value is passed to ZoneInfo()
# leave blank for localtime
# timezone =
# timezone to use when rendering the date within the migration file
# as well as the filename.
-# If specified, requires the python>=3.9 or backports.zoneinfo library and tzdata library.
-# Any required deps can installed by adding `alembic[tz]` to the pip requirements
+# If specified, requires the tzdata library which can be installed by adding
+# `alembic[tz]` to the pip requirements.
# string value is passed to ZoneInfo()
# leave blank for localtime
# timezone =
# timezone to use when rendering the date within the migration file
# as well as the filename.
-# If specified, requires the python>=3.9 or backports.zoneinfo library and tzdata library.
-# Any required deps can installed by adding `alembic[tz]` to the pip requirements
+# If specified, requires the tzdata library which can be installed by adding
+# `alembic[tz]` to the pip requirements.
# string value is passed to ZoneInfo()
# leave blank for localtime
# timezone =
# timezone to use when rendering the date within the migration file
# as well as the filename.
-# If specified, requires the python>=3.9 or backports.zoneinfo library and tzdata library.
-# Any required deps can installed by adding `alembic[tz]` to the pip requirements
+# If specified, requires the tzdata library which can be installed by adding
+# `alembic[tz]` to the pip requirements.
# string value is passed to ZoneInfo()
# leave blank for localtime
# timezone =
import shutil
from typing import Any
from typing import Dict
+from typing import Generator
+from typing import Literal
+from typing import overload
from sqlalchemy import Column
from sqlalchemy import create_mock_engine
shutil.rmtree(file_path)
@contextmanager
- def pushd(self, dirname):
+ def pushd(self, dirname) -> Generator[None, None, None]:
current_dir = os.getcwd()
try:
os.chdir(dirname)
_engs: Dict[Any, Any] = {}
+@overload
@contextmanager
-def capture_context_buffer(**kw):
+def capture_context_buffer(
+ bytes_io: Literal[True], **kw: Any
+) -> Generator[io.BytesIO, None, None]: ...
+
+
+@overload
+@contextmanager
+def capture_context_buffer(
+ **kw: Any,
+) -> Generator[io.StringIO, None, None]: ...
+
+
+@contextmanager
+def capture_context_buffer(
+ **kw: Any,
+) -> Generator[io.StringIO | io.BytesIO, None, None]:
if kw.pop("bytes_io", False):
buf = io.BytesIO()
else:
@contextmanager
-def capture_engine_context_buffer(**kw):
+def capture_engine_context_buffer(
+ **kw: Any,
+) -> Generator[io.StringIO, None, None]:
from .env import _sqlite_file_db
from sqlalchemy import event
from __future__ import annotations
from configparser import ConfigParser
+from importlib import metadata
+from importlib.metadata import EntryPoint
import io
import os
from pathlib import Path
import typing
from typing import Any
from typing import Iterator
-from typing import List
-from typing import Optional
from typing import Sequence
-from typing import Union
if True:
# zimports hack for too-long names
py313 = sys.version_info >= (3, 13)
py312 = sys.version_info >= (3, 12)
py311 = sys.version_info >= (3, 11)
-py310 = sys.version_info >= (3, 10)
-py39 = sys.version_info >= (3, 9)
# produce a wrapper that allows encoded text to stream
pass
-if py39:
- from importlib import resources as _resources
-
- importlib_resources = _resources
- from importlib import metadata as _metadata
-
- importlib_metadata = _metadata
- from importlib.metadata import EntryPoint as EntryPoint
-else:
- import importlib_resources # type:ignore # noqa
- import importlib_metadata # type:ignore # noqa
- from importlib_metadata import EntryPoint # type:ignore # noqa
-
if py311:
import tomllib as tomllib
else:
def importlib_metadata_get(group: str) -> Sequence[EntryPoint]:
- ep = importlib_metadata.entry_points()
- if hasattr(ep, "select"):
- return ep.select(group=group)
- else:
- return ep.get(group, ()) # type: ignore
+ """provide a facade for metadata.entry_points().
+
+ This is no longer a "compat" function as of Python 3.10, however
+ the function is widely referenced in the test suite and elsewhere so is
+ still in this module for compatibility reasons.
+
+ """
+ return metadata.entry_points().select(group=group)
def formatannotation_fwdref(
- annotation: Any, base_module: Optional[Any] = None
+ annotation: Any, base_module: Any | None = None
) -> str:
"""vendored from python 3.7"""
# copied over _formatannotation from sqlalchemy 2.0
def read_config_parser(
file_config: ConfigParser,
- file_argument: Sequence[Union[str, os.PathLike[str]]],
-) -> List[str]:
- if py310:
- return file_config.read(file_argument, encoding="locale")
- else:
- return file_config.read(file_argument)
+ file_argument: list[str | os.PathLike[str]],
+) -> list[str]:
+ return file_config.read(file_argument, encoding="locale")
import atexit
from contextlib import ExitStack
import importlib
+from importlib import resources
import importlib.machinery
import importlib.util
import os
from mako import exceptions
from mako.template import Template
-from . import compat
from .exc import CommandError
file_manager = ExitStack()
atexit.register(file_manager.close)
- ref = compat.importlib_resources.files(tokens[0])
+ ref = resources.files(tokens[0])
for tok in tokens[1:]:
ref = ref / tok
fname_or_resource = file_manager.enter_context( # type: ignore[assignment] # noqa: E501
- compat.importlib_resources.as_file(ref)
+ resources.as_file(ref)
)
return pathlib.Path(fname_or_resource)
==========
.. changelog::
- :version: 1.16.6
+ :version: 1.17.0
:include_notes_from: unreleased
.. changelog::
--- /dev/null
+.. change::
+ :tags: change, general
+
+ The minimum Python version is now 3.10, as Python 3.9 is EOL.
from __future__ import annotations
+from glob import glob
import os
+import shutil
import sys
from typing import Optional
from typing import Sequence
)
PYTHON_VERSIONS = [
- "3.8",
- "3.9",
"3.10",
"3.11",
"3.12",
if sqlalchemy == "sqla14":
return python_version < parse_version("3.14")
elif sqlalchemy == "sqlamain":
- return python_version > parse_version("3.9")
+ return python_version >= parse_version("3.10")
else:
return True
if database in ["oracle", "mssql"]:
session.run("python", "reap_dbs.py", "db_idents.txt")
+ # Clean up scratch directories
+ for scratch_dir in glob("scratch*"):
+ if os.path.isdir(scratch_dir):
+ shutil.rmtree(scratch_dir)
+
@nox.session(name="pep484")
def mypy_check(session: nox.Session) -> None:
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: Implementation :: PyPy",
"Topic :: Database :: Front-Ends",
]
-requires-python = ">=3.9"
+requires-python = ">=3.10"
dependencies = [
"SQLAlchemy>=1.4.0",
"Mako",
[tool.black]
line-length = 79
-target-version = ['py39']
+target-version = ['py310']
[tool.pytest.ini_options]
addopts = "--tb native -v -r sfxX -p no:warnings -p no:logging --maxfail=100"