summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2021-08-23 16:24:26 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2021-08-23 16:45:06 -0400
commite80d1d2299f69e1f4a4e91af70d1244a32c39c65 (patch)
treeaa503c84e9bafc450fe6bada08ce64825c49aa91
parent7fd48061bbf893002b2d7a624b313b09ee0a9700 (diff)
downloadalembic-e80d1d2299f69e1f4a4e91af70d1244a32c39c65.tar.gz
remove dependency on pkg_resources
The dependency on ``pkg_resources`` which is part of ``setuptools`` has been removed, so there is no longer any runtime dependency on ``setuptools``. The functionality has been replaced with ``importlib.metadata`` and ``importlib.resources`` which are both part of Python std.lib, or via pypy dependency ``importlib-metadata`` for Python version < 3.8 and ``importlib-resources`` for Python version < 3.7. Change-Id: I7802fe72ff644f52ae2edde53bc8e16f016b7c45 Fixes: #885
-rw-r--r--alembic/script/write_hooks.py17
-rw-r--r--alembic/util/compat.py22
-rw-r--r--alembic/util/pyfiles.py18
-rw-r--r--docs/build/unreleased/885.rst10
-rw-r--r--setup.cfg2
-rw-r--r--tests/test_post_write.py16
6 files changed, 71 insertions, 14 deletions
diff --git a/alembic/script/write_hooks.py b/alembic/script/write_hooks.py
index 8990148..7c8acab 100644
--- a/alembic/script/write_hooks.py
+++ b/alembic/script/write_hooks.py
@@ -114,7 +114,6 @@ def _parse_cmdline_options(cmdline_options_str: str, path: str) -> List[str]:
@register("console_scripts")
def console_scripts(path, options, ignore_output=False):
- import pkg_resources
try:
entrypoint_name = options["entrypoint"]
@@ -123,8 +122,14 @@ def console_scripts(path, options, ignore_output=False):
"Key %s.entrypoint is required for post write hook %r"
% (options["_hook_name"], options["_hook_name"])
) from ke
- iter_ = pkg_resources.iter_entry_points("console_scripts", entrypoint_name)
- impl = next(iter_)
+ for entry in compat.importlib_metadata_get("console_scripts"):
+ if entry.name == entrypoint_name:
+ impl = entry
+ break
+ else:
+ raise util.CommandError(
+ f"Could not find entrypoint console_scripts.{entrypoint_name}"
+ )
cwd = options.get("cwd", None)
cmdline_options_str = options.get("options", "")
cmdline_options_list = _parse_cmdline_options(cmdline_options_str, path)
@@ -132,14 +137,14 @@ def console_scripts(path, options, ignore_output=False):
kw = {}
if ignore_output:
kw["stdout"] = kw["stderr"] = subprocess.DEVNULL
+
subprocess.run(
[
sys.executable,
"-c",
- "import %s; %s()"
- % (impl.module_name, ".".join((impl.module_name,) + impl.attrs)),
+ "import %s; %s.%s()" % (impl.module, impl.module, impl.attr),
]
+ cmdline_options_list,
cwd=cwd,
- **kw
+ **kw,
)
diff --git a/alembic/util/compat.py b/alembic/util/compat.py
index dae98f4..f83901f 100644
--- a/alembic/util/compat.py
+++ b/alembic/util/compat.py
@@ -8,7 +8,8 @@ from sqlalchemy.util.compat import inspect_formatargspec # noqa
is_posix = os.name == "posix"
py39 = sys.version_info >= (3, 9)
-
+py38 = sys.version_info >= (3, 8)
+py37 = sys.version_info >= (3, 7)
string_types = (str,)
binary_type = bytes
@@ -21,3 +22,22 @@ text_type = str
class EncodedIO(io.TextIOWrapper):
def close(self) -> None:
pass
+
+
+if py37:
+ from importlib import resources as importlib_resources
+else:
+ import importlib_resources # noqa
+
+if py38:
+ from importlib import metadata as importlib_metadata
+else:
+ import importlib_metadata # noqa
+
+
+def importlib_metadata_get(group):
+ ep = importlib_metadata.entry_points()
+ if hasattr(ep, "select"):
+ return ep.select(group=group)
+ else:
+ return ep.get(group, ())
diff --git a/alembic/util/pyfiles.py b/alembic/util/pyfiles.py
index 7eb582e..3da32c3 100644
--- a/alembic/util/pyfiles.py
+++ b/alembic/util/pyfiles.py
@@ -1,3 +1,5 @@
+import atexit
+from contextlib import ExitStack
import importlib
import importlib.machinery
import importlib.util
@@ -9,6 +11,7 @@ from typing import Optional
from mako import exceptions
from mako.template import Template
+from . import compat
from .exc import CommandError
@@ -44,9 +47,20 @@ def coerce_resource_to_filename(fname: str) -> str:
"""
if not os.path.isabs(fname) and ":" in fname:
- import pkg_resources
- fname = pkg_resources.resource_filename(*fname.split(":"))
+ tokens = fname.split(":")
+
+ # from https://importlib-resources.readthedocs.io/en/latest/migration.html#pkg-resources-resource-filename # noqa E501
+
+ file_manager = ExitStack()
+ atexit.register(file_manager.close)
+
+ ref = compat.importlib_resources.files(tokens[0])
+ for tok in tokens[1:]:
+ ref = ref / tok
+ fname = file_manager.enter_context(
+ compat.importlib_resources.as_file(ref)
+ )
return fname
diff --git a/docs/build/unreleased/885.rst b/docs/build/unreleased/885.rst
new file mode 100644
index 0000000..cf010a3
--- /dev/null
+++ b/docs/build/unreleased/885.rst
@@ -0,0 +1,10 @@
+.. change::
+ :tags: bug, general
+ :tickets: 885
+
+ The dependency on ``pkg_resources`` which is part of ``setuptools`` has
+ been removed, so there is no longer any runtime dependency on
+ ``setuptools``. The functionality has been replaced with
+ ``importlib.metadata`` and ``importlib.resources`` which are both part of
+ Python std.lib, or via pypy dependency ``importlib-metadata`` for Python
+ version < 3.8 and ``importlib-resources`` for Python version < 3.7.
diff --git a/setup.cfg b/setup.cfg
index d2df66c..fab504d 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -42,6 +42,8 @@ python_requires = >=3.6
install_requires =
SQLAlchemy>=1.3.0
Mako
+ importlib-metadata;python_version<"3.8"
+ importlib-resources;python_version<"3.7"
[options.extras_require]
tz =
diff --git a/tests/test_post_write.py b/tests/test_post_write.py
index 18c1d82..82a9174 100644
--- a/tests/test_post_write.py
+++ b/tests/test_post_write.py
@@ -133,17 +133,23 @@ class RunHookTest(TestBase):
self, input_config, expected_additional_arguments_fn, cwd=None
):
self.cfg = _no_sql_testing_config(directives=input_config)
- impl = mock.Mock(attrs=("foo", "bar"), module_name="black_module")
- entrypoints = mock.Mock(return_value=iter([impl]))
+
+ class MocksCantName:
+ name = "black"
+ attr = "bar"
+ module = "black_module.foo"
+
+ importlib_metadata_get = mock.Mock(return_value=iter([MocksCantName]))
with mock.patch(
- "pkg_resources.iter_entry_points", entrypoints
+ "alembic.util.compat.importlib_metadata_get",
+ importlib_metadata_get,
), mock.patch(
"alembic.script.write_hooks.subprocess"
) as mock_subprocess:
rev = command.revision(self.cfg, message="x")
- eq_(entrypoints.mock_calls, [mock.call("console_scripts", "black")])
+ eq_(importlib_metadata_get.mock_calls, [mock.call("console_scripts")])
eq_(
mock_subprocess.mock_calls,
[
@@ -151,7 +157,7 @@ class RunHookTest(TestBase):
[
sys.executable,
"-c",
- "import black_module; black_module.foo.bar()",
+ "import black_module.foo; black_module.foo.bar()",
]
+ expected_additional_arguments_fn(rev.path),
cwd=cwd,