mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 22:50:18 +00:00
added callables to [scripts] in Pipfile
Can now add a callable like {call = "package.module:func('arg')"}
This commit is contained in:
+28
-1
@@ -1,23 +1,47 @@
|
||||
import itertools
|
||||
import re
|
||||
import shlex
|
||||
import tomlkit
|
||||
|
||||
|
||||
class ScriptEmptyError(ValueError):
|
||||
pass
|
||||
|
||||
|
||||
class ScriptParseError(ValueError):
|
||||
pass
|
||||
|
||||
|
||||
def _quote_if_contains(value, pattern):
|
||||
if next(iter(re.finditer(pattern, value)), None):
|
||||
return '"{0}"'.format(re.sub(r'(\\*)"', r'\1\1\\"', value))
|
||||
return value
|
||||
|
||||
|
||||
def _parse_toml_inline_table(value: tomlkit.items.InlineTable) -> str:
|
||||
"""parses the [scripts] in pipfile and converts: `{call = "package.module:func('arg')"}` into an executable command
|
||||
"""
|
||||
keys_list = list(value.keys())
|
||||
if len(keys_list) > 1:
|
||||
raise ScriptParseError("More than 1 key in toml script line")
|
||||
cmd_key = keys_list[0]
|
||||
if cmd_key not in Script.script_types:
|
||||
raise ScriptParseError(f"Not an accepted script callabale, options are: {Script.script_types}")
|
||||
if cmd_key == "call":
|
||||
module, _, func = str(value["call"]).partition(":")
|
||||
if not module or not func:
|
||||
raise ScriptParseError("Callable must be like: <pathed.module>:<func>")
|
||||
if re.search(r"\(.*?\)", func) is None:
|
||||
func += "()"
|
||||
return f"python -c \"import {module} as _m; _m.{func}\""
|
||||
|
||||
|
||||
class Script(object):
|
||||
"""Parse a script line (in Pipfile's [scripts] section).
|
||||
|
||||
This always works in POSIX mode, even on Windows.
|
||||
"""
|
||||
script_types = ["call"]
|
||||
|
||||
def __init__(self, command, args=None):
|
||||
self._parts = [command]
|
||||
@@ -26,7 +50,10 @@ class Script(object):
|
||||
|
||||
@classmethod
|
||||
def parse(cls, value):
|
||||
if isinstance(value, str):
|
||||
if isinstance(value, tomlkit.items.InlineTable):
|
||||
cmd_string = _parse_toml_inline_table(value)
|
||||
value = shlex.split(cmd_string)
|
||||
elif isinstance(value, str):
|
||||
value = shlex.split(value)
|
||||
if not value:
|
||||
raise ScriptEmptyError(value)
|
||||
|
||||
@@ -4,6 +4,7 @@ import pytest
|
||||
|
||||
from pipenv.project import Project
|
||||
from pipenv.utils.shell import subprocess_run, temp_environ
|
||||
from pipenv.utils.shell import mkdir_p
|
||||
|
||||
|
||||
@pytest.mark.run
|
||||
@@ -63,6 +64,36 @@ multicommand = "bash -c \"cd docs && make html\""
|
||||
assert c.stdout.strip() == "WORLD"
|
||||
|
||||
|
||||
@pytest.mark.run
|
||||
def test_scripts_with_package_functions(pipenv_instance_pypi):
|
||||
with pipenv_instance_pypi(chdir=True) as p:
|
||||
p.pipenv('install')
|
||||
pkg_path = os.path.join(p.path, "pkg")
|
||||
mkdir_p(pkg_path)
|
||||
file_path = os.path.join(pkg_path, "mod.py")
|
||||
with open(file_path, "w+") as f:
|
||||
f.write("""
|
||||
def test_func():
|
||||
print("success")
|
||||
|
||||
def arg_func(s, i):
|
||||
print(f"{s.upper()}. Easy as {i}")
|
||||
""")
|
||||
|
||||
with open(p.pipfile_path, 'w') as f:
|
||||
f.write(r"""
|
||||
[scripts]
|
||||
pkgfunc = {call = "pkg.mod:test_func"}
|
||||
argfunc = {call = "pkg.mod:arg_func('abc', 123)"}
|
||||
""")
|
||||
|
||||
c = p.pipenv('run pkgfunc')
|
||||
assert c.stdout.strip() == "success"
|
||||
|
||||
c = p.pipenv('run argfunc')
|
||||
assert c.stdout.strip() == "ABC. Easy as 123"
|
||||
|
||||
|
||||
@pytest.mark.run
|
||||
@pytest.mark.skip_windows
|
||||
def test_run_with_usr_env_shebang(pipenv_instance_pypi):
|
||||
|
||||
Reference in New Issue
Block a user