From adac78424490159148cb1b5bb30e1b98816044d8 Mon Sep 17 00:00:00 2001 From: rtmigo Date: Thu, 27 May 2021 09:16:02 +0300 Subject: [PATCH 1/5] refa --- tests/test_arg_parser.py | 52 +++++++++++++++++------------------ tests/test_get_project_dir.py | 4 +-- tests/test_main.py | 2 +- vien/_cmdexe_escape_args.py | 2 +- vien/_main.py | 8 +++--- vien/_parsed_args.py | 10 +++---- 6 files changed, 39 insertions(+), 39 deletions(-) diff --git a/tests/test_arg_parser.py b/tests/test_arg_parser.py index d91918b..d1db7aa 100644 --- a/tests/test_arg_parser.py +++ b/tests/test_arg_parser.py @@ -9,7 +9,7 @@ from tests.common import is_posix from vien._main import get_project_dir -from vien._parsed_args import Parsed, Commands, items_after +from vien._parsed_args import ParsedArgs, Commands, _iter_after def windows_too(args: List[str]) -> List[str]: @@ -20,21 +20,21 @@ def windows_too(args: List[str]) -> List[str]: implemented for Windows. """ if is_windows: - return [Parsed.PARAM_WINDOWS_ALL_ARGS] + args + return [ParsedArgs.PARAM_WINDOWS_ALL_ARGS] + args else: return args class TestItemsAfter(unittest.TestCase): def test_items_after(self): - self.assertEqual(list(items_after(['A', 'B', 'C'], 'A')), + self.assertEqual(list(_iter_after(['A', 'B', 'C'], 'A')), ['B', 'C']) - self.assertEqual(list(items_after(['A', 'B', 'C'], 'B')), + self.assertEqual(list(_iter_after(['A', 'B', 'C'], 'B')), ['C']) - self.assertEqual(list(items_after(['A', 'B', 'C'], 'C')), + self.assertEqual(list(_iter_after(['A', 'B', 'C'], 'C')), []) with self.assertRaises(LookupError): - list(items_after(['A', 'B', 'C'], 'X')) + list(_iter_after(['A', 'B', 'C'], 'X')) class TestWindowsAllArgs(unittest.TestCase): @@ -43,106 +43,106 @@ def test_windowsallargs_fails_on_posix(self): # is the PARAM_WINDOWS_ALL_ARGS is set, we must run windows. # Otherwise, AssertionError is thrown with self.assertRaises(AssertionError): - Parsed([Parsed.PARAM_WINDOWS_ALL_ARGS, 'shell']) + ParsedArgs([ParsedArgs.PARAM_WINDOWS_ALL_ARGS, 'shell']) class TestProjectDir(unittest.TestCase): def test_run_short_left(self): - pd = Parsed(windows_too('-p a/b/c run python3 myfile.py'.split())) + pd = ParsedArgs(windows_too('-p a/b/c run python3 myfile.py'.split())) self.assertEqual(pd.project_dir_arg, 'a/b/c') def test_run_long_left(self): - pd = Parsed( + pd = ParsedArgs( windows_too('--project-dir a/b/c run python3 myfile.py'.split())) self.assertEqual(pd.project_dir_arg, 'a/b/c') def test_call_short_right(self): - pd = Parsed('call -p a/b/c myfile.py'.split()) + pd = ParsedArgs('call -p a/b/c myfile.py'.split()) self.assertEqual(pd.project_dir_arg, 'a/b/c') def test_call_long_right(self): - pd = Parsed('call --project-dir a/b/c myfile.py'.split()) + pd = ParsedArgs('call --project-dir a/b/c myfile.py'.split()) self.assertEqual(pd.project_dir_arg, 'a/b/c') def test_call_short_left(self): - pd = Parsed('-p a/b/c call myfile.py'.split()) + pd = ParsedArgs('-p a/b/c call myfile.py'.split()) self.assertEqual(pd.project_dir_arg, 'a/b/c') def test_call_long_left(self): - pd = Parsed('--project-dir a/b/c call myfile.py'.split()) + pd = ParsedArgs('--project-dir a/b/c call myfile.py'.split()) self.assertEqual(pd.project_dir_arg, 'a/b/c') def test_call_short_both(self): - pd = Parsed('-p a/b/c call -p d/e/f myfile.py'.split()) + pd = ParsedArgs('-p a/b/c call -p d/e/f myfile.py'.split()) self.assertEqual(pd.project_dir_arg, 'd/e/f') class TestParseCall(unittest.TestCase): def test_outdated_p(self): - pd = Parsed('-p a/b/c call -p d/e/f myfile.py arg1 arg2'.split()) + pd = ParsedArgs('-p a/b/c call -p d/e/f myfile.py arg1 arg2'.split()) self.assertEqual(pd.args_to_python, ['myfile.py', 'arg1', 'arg2']) def test_p(self): - pd = Parsed('-p a/b/c call -d myfile.py a b c'.split()) + pd = ParsedArgs('-p a/b/c call -d myfile.py a b c'.split()) self.assertEqual(pd.args_to_python, ['-d', 'myfile.py', 'a', 'b', 'c']) def test_unrecoginzed(self): """Unrecognized arguments that are NOT after the 'call' word.""" with self.assertRaises(SystemExit) as ce: - Parsed('-labuda call myfile.py a b c'.split()) + ParsedArgs('-labuda call myfile.py a b c'.split()) self.assertEqual(ce.exception.code, 2) class TestParseShell(unittest.TestCase): def test_no_args(self): - pd = Parsed(windows_too('shell'.split())) + pd = ParsedArgs(windows_too('shell'.split())) self.assertEqual(pd.command, Commands.shell) self.assertEqual(pd.shell_delay, None) self.assertEqual(pd.shell_input, None) def test_input(self): - pd = Parsed(windows_too(['shell', '--input', 'cd / && ls'])) + pd = ParsedArgs(windows_too(['shell', '--input', 'cd / && ls'])) self.assertEqual(pd.shell_input, 'cd / && ls') def test_delay(self): - pd = Parsed(windows_too('shell --delay 1.2'.split())) + pd = ParsedArgs(windows_too('shell --delay 1.2'.split())) self.assertEqual(pd.shell_delay, 1.2) def test_labuda(self): with self.assertRaises(SystemExit) as ce: - pd = Parsed(windows_too('shell --labuda'.split())) + pd = ParsedArgs(windows_too('shell --labuda'.split())) self.assertEqual(ce.exception.code, 2) class TestParseRun(unittest.TestCase): def test(self): - pd = Parsed(windows_too(['run', 'python3', '-OO', 'file.py'])) + pd = ParsedArgs(windows_too(['run', 'python3', '-OO', 'file.py'])) self.assertEqual(pd.command, Commands.run) self.assertEqual(pd.run_args, ['python3', '-OO', 'file.py']) class TestParseCreate(unittest.TestCase): def test_with_arg(self): - pd = Parsed(['create', 'python3']) + pd = ParsedArgs(['create', 'python3']) self.assertEqual(pd.command, Commands.create) self.assertEqual(pd.python_executable, "python3") def test_without_arg(self): - pd = Parsed(['create']) + pd = ParsedArgs(['create']) self.assertEqual(pd.command, Commands.create) self.assertEqual(pd.python_executable, None) class TestParseRecreate(unittest.TestCase): def test_with_arg(self): - pd = Parsed(['recreate', 'python3']) + pd = ParsedArgs(['recreate', 'python3']) self.assertEqual(pd.command, Commands.recreate) self.assertEqual(pd.python_executable, "python3") def test_without_arg(self): - pd = Parsed(['recreate']) + pd = ParsedArgs(['recreate']) self.assertEqual(pd.command, Commands.recreate) self.assertEqual(pd.python_executable, None) diff --git a/tests/test_get_project_dir.py b/tests/test_get_project_dir.py index 10bd42f..678e1de 100644 --- a/tests/test_get_project_dir.py +++ b/tests/test_get_project_dir.py @@ -9,7 +9,7 @@ from tests.test_arg_parser import windows_too from vien._main import get_project_dir from vien._exceptions import PyFileArgNotFoundExit -from vien._parsed_args import Parsed +from vien._parsed_args import ParsedArgs def fix_paths(s: str): @@ -25,7 +25,7 @@ def setUp(self) -> None: def _gpd(self, cmd: str) -> Path: cmd = fix_paths(cmd) - result = get_project_dir(Parsed(windows_too(cmd.split()))) + result = get_project_dir(ParsedArgs(windows_too(cmd.split()))) self.assertTrue(result.is_absolute()) return result diff --git a/tests/test_main.py b/tests/test_main.py index f075900..a090a19 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -16,7 +16,7 @@ from typing import List, Optional from tests.test_arg_parser import windows_too -from vien._parsed_args import Parsed +from vien._parsed_args import ParsedArgs from vien._common import is_windows diff --git a/vien/_cmdexe_escape_args.py b/vien/_cmdexe_escape_args.py index 8cef589..6ddae0f 100644 --- a/vien/_cmdexe_escape_args.py +++ b/vien/_cmdexe_escape_args.py @@ -1,4 +1,4 @@ -# Code taken from https://stackoverflow.com/a/29215357 +# taken from https://stackoverflow.com/a/29215357 # SPDX-FileCopyrightText: Holger Just # SPDX-License-Identifier: CC BY-SA 3.0 diff --git a/vien/_main.py b/vien/_main.py index aa16dec..aeb5216 100755 --- a/vien/_main.py +++ b/vien/_main.py @@ -14,7 +14,7 @@ from vien import is_posix from vien._common import need_posix, is_windows, need_windows -from vien._parsed_args import Commands, Parsed +from vien._parsed_args import Commands, ParsedArgs from vien._bash_runner import run_as_bash_script from vien._call_funcs import relative_fn_to_module_name, relative_inner_path from vien._parsed_call import ParsedCall, list_left_partition @@ -388,7 +388,7 @@ def replace_arg(args: List[str], old: str, new: List[str]) -> List[str]: return result -def main_call(parsed: Parsed, dirs: Dirs): +def main_call(parsed: ParsedArgs, dirs: Dirs): dirs.venv_must_exist() parsed_call = ParsedCall(parsed.args) @@ -431,7 +431,7 @@ def normalize_path(reference: Path, path: Path) -> Path: return Path(os.path.normpath(reference / path)) -def get_project_dir(parsed: Parsed) -> Path: +def get_project_dir(parsed: ParsedArgs) -> Path: if parsed.project_dir_arg is not None: if parsed.command == Commands.call: # for the 'call' the reference dir is the parent or .py file @@ -453,7 +453,7 @@ def get_project_dir(parsed: Parsed) -> Path: def main_entry_point(args: Optional[List[str]] = None): - parsed = Parsed(args) + parsed = ParsedArgs(args) dirs = Dirs(project_dir=get_project_dir(parsed)) diff --git a/vien/_parsed_args.py b/vien/_parsed_args.py index 2217e90..6cbb115 100644 --- a/vien/_parsed_args.py +++ b/vien/_parsed_args.py @@ -34,7 +34,7 @@ def usage_doc(): return f"{above_first_line}\n{doc}\n" -def items_after(items: Iterable[str], x: str) -> Iterable[str]: +def _iter_after(items: Iterable[str], x: str) -> Iterable[str]: found = False for arg in items: if found: @@ -45,7 +45,7 @@ def items_after(items: Iterable[str], x: str) -> Iterable[str]: raise LookupError -def remove_leading_p(args: List[str]) -> List[str]: +def _remove_leading_p(args: List[str]) -> List[str]: # fixing a problem that is outdated since 2021-05 if len(args) < 2: return args @@ -64,7 +64,7 @@ class Commands(Enum): path = "path" -class Parsed: +class ParsedArgs: PARAM_WINDOWS_ALL_ARGS = "--vien-secret-windows-all-args" def __init__(self, args: Optional[List[str]]): @@ -161,7 +161,7 @@ def __init__(self, args: Optional[List[str]]): self._ns, unknown = parser.parse_known_args(self.args) if self.command == Commands.call: - self.args_to_python = list(items_after(args, 'call')) + self.args_to_python = list(_iter_after(args, 'call')) # if some of the unknown args are NOT after the 'call', # then we're failed to interpret the command. Parsing @@ -173,7 +173,7 @@ def __init__(self, args: Optional[List[str]]): raise AssertionError("Not expected to run this line") # todo Remove later. [call -p] is outdated since 2021-05 - self.args_to_python = remove_leading_p(self.args_to_python) + self.args_to_python = _remove_leading_p(self.args_to_python) else: # if some args were not recognized, parsing everything stricter if unknown: From da6472c275d8497d2f82307f3b166e66cc43aef6 Mon Sep 17 00:00:00 2001 From: rtmigo Date: Thu, 27 May 2021 09:20:31 +0300 Subject: [PATCH 2/5] docs --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e6ed86b..5b0f227 100644 --- a/README.md +++ b/README.md @@ -239,7 +239,7 @@ $ vien call -m /abc/myProject/pkg/sub/module.py ``` - `module.py` must be located somewhere inside the `/abc/myProject` -- parent subdirectories such as `pkg` an `sub` must be importable, i.e. must contain +- parent subdirectories such as `pkg` and `sub` must be importable, i.e. must contain `__init__.py` - the project directory will be inserted into `$PYTHONPATH` making the module visible From d4f2413c1279c5a95a47c40d6812da558eea770d Mon Sep 17 00:00:00 2001 From: rtmigo Date: Thu, 27 May 2021 09:26:58 +0300 Subject: [PATCH 3/5] refa --- vien/_parsed_call.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/vien/_parsed_call.py b/vien/_parsed_call.py index ab8eb78..f5b5f70 100644 --- a/vien/_parsed_call.py +++ b/vien/_parsed_call.py @@ -26,7 +26,7 @@ def list_left_partition(items: Iterable[str], split: str) \ class ParsedCall: - # todo cache to avoid parsing twice? + # todo make a part of ParsedArgs __slots__ = ['args', 'file', 'file_idx'] def __init__(self, args: List[str]): @@ -58,10 +58,3 @@ def before_filename(self) -> Optional[str]: if val == "call": return None return val - -# def call_pyfile(args: List[str]) -> Optional[str]: -# # todo remove? -# for arg in items_after(args, "call"): -# if arg.lower().endswith(".py"): -# return arg -# return None From 7de1d5d2fb4e49adea1cf511168390e272ed8d7e Mon Sep 17 00:00:00 2001 From: rtmigo Date: Fri, 28 May 2021 02:10:47 +0300 Subject: [PATCH 4/5] publish --- README.md | 38 +++++++++++++++++++++++++++----------- tests/test_arg_parser.py | 6 ++++++ tests/test_call_parser.py | 4 ++-- vien/_constants.py | 2 +- vien/_main.py | 24 +++++++++++++----------- vien/_parsed_args.py | 24 ++++++++++++++++++------ vien/_parsed_call.py | 17 ++++++++++------- 7 files changed, 77 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 5b0f227..e269190 100644 --- a/README.md +++ b/README.md @@ -117,20 +117,28 @@ $ vien call main.py # "create" command -`vien create` сreates a virtual environment that will correspond the current -working directory. The **working directory** in this case is assumed to be -your **project directory**. Subsequent calls to other `vien` commands in the -same directory will use the same virtual environment. +`vien create` сreates a virtual environment that will correspond the +**project directory**. Subsequent calls to `vien` +with the same project directory will use the same virtual environment. ``` bash -$ cd /path/to/myProject +$ cd /abc/myProject $ vien create ``` -By default `vien` will use the Python interpreter that running `vien` itself as -the interpreter for the virtual environment. +By default, the current **working directory** is assumed to be the +**project directory**. This can be changed using the `-p` parameter. + +``` bash +$ vien -p /abc/myProject create +``` + + +The `-p` parameter works with all commands, not just `create`. + +### "create": choose the Python version -If you have more than one Python version, you can provide an argument to point +If you have more than one Python installed, you can provide an argument to point to the proper interpreter. ``` bash @@ -144,6 +152,12 @@ be executed in the shell as `python3.8`, you can try $ vien create python3.8 ``` +When `create` is called with no argument, `vien` will use the Python +interpreter that is running `vien` itself. For example, if you used Python 3.9 +to `pip install vien`, then it is the Python 3.9 runs `vien`, and this +Python 3.9 will be used in the virtual environment. + + # "shell" command `vien shell` starts interactive bash session in the virtual environment. @@ -361,9 +375,11 @@ vien -p /abc/myProject run python3 /abc/myProject/main.py If `--project-dir` is specified as a **relative path**, its interpretation depends -on the command. For the `call` command, this is considered a path relative to -the parent directory of the `.py` file being run. For other commands, this is -a path relative to the current working directory. +on the command. +- For the `call` command, this is a path relative to +the parent directory of the `.py` file being run +- For other commands, this is +a path relative to the current working directory # Virtual environments location diff --git a/tests/test_arg_parser.py b/tests/test_arg_parser.py index d1db7aa..13bfd7c 100644 --- a/tests/test_arg_parser.py +++ b/tests/test_arg_parser.py @@ -94,6 +94,12 @@ def test_unrecoginzed(self): ParsedArgs('-labuda call myfile.py a b c'.split()) self.assertEqual(ce.exception.code, 2) + def test_call_field(self): + pd = ParsedArgs('-p a/b/c call -m myfile.py arg1 arg2'.split()) + self.assertIsNotNone(pd.call) + self.assertEqual(pd.call.filename, "myfile.py") + self.assertEqual(pd.call.before_filename, "-m") + class TestParseShell(unittest.TestCase): def test_no_args(self): diff --git a/tests/test_call_parser.py b/tests/test_call_parser.py index 0006930..36f3a6f 100644 --- a/tests/test_call_parser.py +++ b/tests/test_call_parser.py @@ -12,11 +12,11 @@ class TestNew(unittest.TestCase): def test_file_after_call(self): psr = ParsedCall("vien -p zzz call -d FiLe.Py arg1".split()) - self.assertEqual(psr.file, "FiLe.Py") + self.assertEqual(psr.filename, "FiLe.Py") def test_file_before_and_after_call(self): psr = ParsedCall("vien -p wrong.py call -d right.py arg1".split()) - self.assertEqual(psr.file, "right.py") + self.assertEqual(psr.filename, "right.py") def test_file_not_found(self): with self.assertRaises(PyFileArgNotFoundExit): diff --git a/vien/_constants.py b/vien/_constants.py index ca62375..65443fa 100644 --- a/vien/_constants.py +++ b/vien/_constants.py @@ -1,3 +1,3 @@ -__version__ = "8.0.2" +__version__ = "8.0.3" __copyright__ = "(c) 2020-2021 Artëm IG " __license__ = "BSD-3-Clause" diff --git a/vien/_main.py b/vien/_main.py index aeb5216..a0ffe68 100755 --- a/vien/_main.py +++ b/vien/_main.py @@ -391,22 +391,24 @@ def replace_arg(args: List[str], old: str, new: List[str]) -> List[str]: def main_call(parsed: ParsedArgs, dirs: Dirs): dirs.venv_must_exist() - parsed_call = ParsedCall(parsed.args) - assert parsed_call.file is not None + #parsed_call = ParsedCall(parsed.args) + #assert parsed_call.file is not None - if not os.path.exists(parsed_call.file): - raise PyFileNotFoundExit(Path(parsed_call.file)) + assert parsed.call is not None - if parsed_call.before_filename == "-m": + if not os.path.exists(parsed.call.filename): + raise PyFileNotFoundExit(Path(parsed.call.filename)) + + if parsed.call.before_filename == "-m": # todo unit test # /abc/project/package/module.py -> package/module.py - relative = relative_inner_path(parsed_call.file, dirs.project_dir) + relative = relative_inner_path(parsed.call.filename, dirs.project_dir) # package/module.py -> package.module module_name = relative_fn_to_module_name(relative) # replacing the filename in args with the module name. # It is already prefixed with -m - args = parsed_call.args.copy() - args[parsed_call.file_idx] = module_name + args = parsed.call.args.copy() + args[parsed.call.filename_idx] = module_name # args to python are those after 'call' word _, args_to_python = list_left_partition(args, 'call') assert '-m' in args_to_python @@ -435,10 +437,10 @@ def get_project_dir(parsed: ParsedArgs) -> Path: if parsed.project_dir_arg is not None: if parsed.command == Commands.call: # for the 'call' the reference dir is the parent or .py file - pyfile = ParsedCall(parsed.args).file - if pyfile is None: + assert parsed.call is not None + if parsed.call.filename is None: raise PyFileArgNotFoundExit - reference_dir = Path(pyfile).parent.absolute() + reference_dir = Path(parsed.call.filename).parent.absolute() else: # for other commands the reference dir is cwd reference_dir = Path(".").absolute() diff --git a/vien/_parsed_args.py b/vien/_parsed_args.py index 6cbb115..d754ce7 100644 --- a/vien/_parsed_args.py +++ b/vien/_parsed_args.py @@ -11,7 +11,8 @@ from vien import is_posix import vien -#from vien.call_parser import items_after +# from vien.call_parser import items_after +from vien._parsed_call import ParsedCall def version_message() -> str: @@ -70,6 +71,8 @@ class ParsedArgs: def __init__(self, args: Optional[List[str]]): super().__init__() + self._call: Optional[ParsedCall] = None + if args is None: args = sys.argv[1:] @@ -160,12 +163,11 @@ def __init__(self, args: Optional[List[str]]): unknown: List[str] self._ns, unknown = parser.parse_known_args(self.args) - if self.command == Commands.call: + if self._ns.command == 'call': self.args_to_python = list(_iter_after(args, 'call')) # if some of the unknown args are NOT after the 'call', - # then we're failed to interpret the command. Parsing - # it stricter + # then we're failed to interpret the command bad_unrecognized = [unk for unk in unknown if unk not in self.args_to_python] if bad_unrecognized: @@ -174,14 +176,24 @@ def __init__(self, args: Optional[List[str]]): # todo Remove later. [call -p] is outdated since 2021-05 self.args_to_python = _remove_leading_p(self.args_to_python) + self._call = ParsedCall(args) else: # if some args were not recognized, parsing everything stricter if unknown: self._ns = parser.parse_args(self.args) + self.command = Commands(self._ns.command) + + # @property + # def command(self) -> Commands: + # return Commands(self._ns.command) + @property - def command(self) -> Commands: - return Commands(self._ns.command) + def call(self) -> ParsedCall: + if self.command != Commands.call: + raise RuntimeError("The current command is not 'call'") + assert self._call is not None + return self._call @property def project_dir_arg(self) -> Optional[str]: diff --git a/vien/_parsed_call.py b/vien/_parsed_call.py index f5b5f70..6e8d5c7 100644 --- a/vien/_parsed_call.py +++ b/vien/_parsed_call.py @@ -26,8 +26,7 @@ def list_left_partition(items: Iterable[str], split: str) \ class ParsedCall: - # todo make a part of ParsedArgs - __slots__ = ['args', 'file', 'file_idx'] + __slots__ = ['args', 'filename', 'filename_idx'] def __init__(self, args: List[str]): @@ -41,9 +40,9 @@ def __init__(self, args: List[str]): call_found = True continue - if arg.lower().endswith(".py"): - self.file = arg - self.file_idx = idx + if len(arg) > 3 and arg[-3:].lower() == ".py": + self.filename = arg + self.filename_idx = idx file_found = True break @@ -52,9 +51,13 @@ def __init__(self, args: List[str]): @property def before_filename(self) -> Optional[str]: - if self.file_idx <= 0: + """Returns the argument before the filename, but after the 'call'. + For command 'vien call -m file.py' it is '-m'. + For command 'vien call file.py' it is None. + """ + if self.filename_idx <= 0: return None - val = self.args[self.file_idx - 1] + val = self.args[self.filename_idx - 1] if val == "call": return None return val From a4b558a9d328e02a45ac2a3152acb68cbd903986 Mon Sep 17 00:00:00 2001 From: rtmigo Date: Fri, 28 May 2021 02:29:02 +0300 Subject: [PATCH 5/5] publish --- README.md | 14 +++++++++++--- vien/_constants.py | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e269190..f16bafb 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,9 @@ $ vien create ``` By default, the current **working directory** is assumed to be the -**project directory**. This can be changed using the `-p` parameter. +**project directory**. + +Alternatively you can use `-p` parameter. ``` bash $ vien -p /abc/myProject create @@ -136,6 +138,12 @@ $ vien -p /abc/myProject create The `-p` parameter works with all commands, not just `create`. +``` bash +$ cd /other/working/dir +$ vien -p /abc/myProject create +$ vien -p /abc/myProject shell +``` + ### "create": choose the Python version If you have more than one Python installed, you can provide an argument to point @@ -255,8 +263,8 @@ $ vien call -m /abc/myProject/pkg/sub/module.py - `module.py` must be located somewhere inside the `/abc/myProject` - parent subdirectories such as `pkg` and `sub` must be importable, i.e. must contain `__init__.py` -- the project directory will be inserted into `$PYTHONPATH` making the module - visible +- the project directory will be inserted into `$PYTHONPATH`, making + `pkg.sub.module` resolvable from `/abc/myProject` to a file The project directory can be specified not only by the working directory, but also by the `-p` parameter. diff --git a/vien/_constants.py b/vien/_constants.py index 65443fa..7ce2cf8 100644 --- a/vien/_constants.py +++ b/vien/_constants.py @@ -1,3 +1,4 @@ __version__ = "8.0.3" __copyright__ = "(c) 2020-2021 Artëm IG " __license__ = "BSD-3-Clause" +