summaryrefslogtreecommitdiff
path: root/alembic/util
diff options
context:
space:
mode:
authorCaselIT <cfederico87@gmail.com>2021-06-15 22:32:05 +0200
committerCaselIT <cfederico87@gmail.com>2021-06-15 23:38:07 +0200
commit7756b35e23ec11b64a1ac37afcb41dda3ca29913 (patch)
treea2c46870a195f22c7489bface5a890cf90acff5c /alembic/util
parentc0f0a3238fe1ec8029d66ad6ac518b60c78c36ed (diff)
downloadalembic-7756b35e23ec11b64a1ac37afcb41dda3ca29913.tar.gz
Revendor editor and make dateutil optional
Re-implemented the ``python-editor`` dependency as a small internal function to avoid the need for external dependencies. The implementation is based on the original version in 7b91b325ff43a0e9235e0f15b57391fa92352626. Make the ``python-dateutil`` library an optional dependency. This library is only required if the ``timezone`` option is used in the Alembic configuration. An extra require named ``tz`` is available with ``pip install alembic[tz]`` to install it. Fixes: #674 Fixes: #856 Change-Id: I07f17b2fea01e3a3d677ce95333fe3e8d8d438fd
Diffstat (limited to 'alembic/util')
-rw-r--r--alembic/util/__init__.py2
-rw-r--r--alembic/util/editor.py71
-rw-r--r--alembic/util/pyfiles.py12
3 files changed, 72 insertions, 13 deletions
diff --git a/alembic/util/__init__.py b/alembic/util/__init__.py
index cfdab49..2a3d8a8 100644
--- a/alembic/util/__init__.py
+++ b/alembic/util/__init__.py
@@ -1,4 +1,5 @@
from .compat import raise_ # noqa
+from .editor import open_in_editor # noqa
from .exc import CommandError
from .langhelpers import _with_legacy_names # noqa
from .langhelpers import asbool # noqa
@@ -19,7 +20,6 @@ from .messaging import status # noqa
from .messaging import warn # noqa
from .messaging import write_outstream # noqa
from .pyfiles import coerce_resource_to_filename # noqa
-from .pyfiles import edit # noqa
from .pyfiles import load_python_file # noqa
from .pyfiles import pyc_file_from_path # noqa
from .pyfiles import template_to_file # noqa
diff --git a/alembic/util/editor.py b/alembic/util/editor.py
new file mode 100644
index 0000000..c27f0f3
--- /dev/null
+++ b/alembic/util/editor.py
@@ -0,0 +1,71 @@
+import os
+from os.path import exists
+from os.path import join
+from os.path import splitext
+from subprocess import check_call
+
+from .compat import is_posix
+from .exc import CommandError
+
+
+def open_in_editor(filename, environ=None):
+ """
+ Opens the given file in a text editor. If the environment variable
+ ``EDITOR`` is set, this is taken as preference.
+
+ Otherwise, a list of commonly installed editors is tried.
+
+ If no editor matches, an :py:exc:`OSError` is raised.
+
+ :param filename: The filename to open. Will be passed verbatim to the
+ editor command.
+ :param environ: An optional drop-in replacement for ``os.environ``. Used
+ mainly for testing.
+ """
+
+ try:
+ editor = _find_editor(environ)
+ check_call([editor, filename])
+ except Exception as exc:
+ raise CommandError("Error executing editor (%s)" % (exc,)) from exc
+
+
+def _find_editor(environ=None):
+ candidates = _default_editors()
+ for i, var in enumerate(("EDITOR", "VISUAL")):
+ if var in environ:
+ user_choice = environ[var]
+ if exists(user_choice):
+ return user_choice
+ if os.sep not in user_choice:
+ candidates.insert(i, user_choice)
+
+ for candidate in candidates:
+ path = _find_executable(candidate, environ)
+ if path is not None:
+ return path
+ raise OSError(
+ "No suitable editor found. Please set the "
+ '"EDITOR" or "VISUAL" environment variables'
+ )
+
+
+def _find_executable(candidate, environ):
+ # Assuming this is on the PATH, we need to determine it's absolute
+ # location. Otherwise, ``check_call`` will fail
+ if not is_posix and splitext(candidate)[1] != ".exe":
+ candidate += ".exe"
+ for path in environ.get("PATH", "").split(os.pathsep):
+ value = join(path, candidate)
+ if exists(value):
+ return value
+ return None
+
+
+def _default_editors():
+ # Look for an editor. Prefer the user's choice by env-var, fall back to
+ # most commonly installed editor (nano/vim)
+ if is_posix:
+ return ["sensible-editor", "editor", "nano", "vim", "code"]
+ else:
+ return ["code.exe", "notepad++.exe", "notepad.exe"]
diff --git a/alembic/util/pyfiles.py b/alembic/util/pyfiles.py
index 8dfb9db..1bc5be3 100644
--- a/alembic/util/pyfiles.py
+++ b/alembic/util/pyfiles.py
@@ -10,7 +10,6 @@ from .compat import has_pep3147
from .compat import load_module_py
from .compat import load_module_pyc
from .compat import py3k
-from .compat import raise_
from .exc import CommandError
@@ -75,17 +74,6 @@ def pyc_file_from_path(path):
return None
-def edit(path):
- """Given a source path, run the EDITOR for it"""
-
- import editor
-
- try:
- editor.edit(path)
- except Exception as exc:
- raise_(CommandError("Error executing editor (%s)" % (exc,)), from_=exc)
-
-
def load_python_file(dir_, filename):
"""Load a file from the given path as a Python module."""