Skip to content

Commit

Permalink
publish
Browse files Browse the repository at this point in the history
  • Loading branch information
rtmigo committed May 20, 2021
1 parent ef590dd commit 5c5ca08
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 64 deletions.
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
neatest
37 changes: 15 additions & 22 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,26 @@
from importlib.machinery import SourceFileLoader
from pathlib import Path

from setuptools import setup, find_packages
from setuptools import setup

constants = SourceFileLoader('constants', 'vien/constants.py').load_module()

# def readDocText():
# """Reads README.md and returns the text after first empty line.
# It helps to skip the header with badges intended only for GitHub.
# """
# doctext = (Path(__file__).parent / 'README.md').read_text()
#
# # skipping until first empty line
# lines = [l.strip() for l in doctext.splitlines()]
# first_empty_line_index = lines.index("")
# lines = lines[first_empty_line_index + 1:]
#
# return "\n".join(lines)
def load_module_dict(filename: str) -> dict:
import importlib.util as ilu
filename = Path(__file__).parent / filename
spec = ilu.spec_from_file_location('', filename)
module = ilu.module_from_spec(spec)
spec.loader.exec_module(module)
return module.__dict__


name = "vien"
constants = load_module_dict(f'{name}/constants.py')

readme = (Path(__file__).parent / 'README.md').read_text()
readme = "# " + readme.partition("\n#")[-1]

setup(
name="vien",
version=constants.__version__,
name=name,
version=constants['__version__'],

author="Artëm IG",
author_email="ortemeo@gmail.com",
Expand All @@ -37,7 +34,7 @@
long_description=readme,
long_description_content_type='text/markdown',

license=constants.__license__,
license=constants['__license__'],

entry_points={
'console_scripts': [
Expand All @@ -47,11 +44,7 @@
keywords="virtual-environment venv virtualenv python command-line shell "
"terminal bash run create delete execute".split(),

# https://pypi.org/classifiers/
classifiers=[

# "Development Status :: 2 - Pre-Alpha",
# "Development Status :: 3 - Alpha",
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
'License :: OSI Approved :: BSD License',
Expand Down
56 changes: 31 additions & 25 deletions test_unit.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,35 @@
#!/usr/bin/env python3

import unittest
from pathlib import Path


def suite():
"""Can be imported into `setup.py` as `test_suite="test_unit.suite"`."""

parent_dir = Path(__file__).parent
init_py, = parent_dir.glob("*/__init__.py")

return unittest.TestLoader().discover(
top_level_dir=str(parent_dir),
start_dir=str(init_py.parent),
pattern="*.py")


def run_tests():
"""Discovers and runs unit tests for the module."""

result = unittest.TextTestRunner(buffer=True).run(suite())

if result.failures or result.errors:
exit(1)

import neatest

if __name__ == "__main__":
run_tests()
neatest.run()

#
# import unittest
# from pathlib import Path
#
#
# def suite():
# """Can be imported into `setup.py` as `test_suite="test_unit.suite"`."""
#
# parent_dir = Path(__file__).parent
# init_py, = parent_dir.glob("*/__init__.py")
#
# return unittest.TestLoader().discover(
# top_level_dir=str(parent_dir),
# start_dir=str(init_py.parent),
# pattern="*.py")
#
#
# def run_tests():
# """Discovers and runs unit tests for the module."""

# result = unittest.TextTestRunner(buffer=True).run(suite())
#
# if result.failures or result.errors:
# exit(1)
#
#
# if __name__ == "__main__":
# run_tests()
Empty file added tests/__init__.py
Empty file.
24 changes: 24 additions & 0 deletions vien/main_test.py → tests/main_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,30 @@ def test_shell_fails_if_not_exist(self):
with self.assertRaises(VenvDoesNotExistError) as cm:
main_entry_point(["shell"])

# TODO test 'shell' exit codes too?

def test_run_exit_code_0(self):
"""Test that main_entry_point returns the same exit code,
as the called command"""
with self.assertRaises(SystemExit) as ce:
main_entry_point(["run", "python3", "-c", "exit(0)"])
self.assertEqual(ce.exception.code, 0)

def test_run_exit_code_1(self):
"""Test that main_entry_point returns the same exit code,
as the called command"""
with self.assertRaises(SystemExit) as ce:
main_entry_point(["run", "python3", "-c", "exit(1)"])
self.assertEqual(ce.exception.code, 1)

def test_run_exit_code_2(self):
"""Test that main_entry_point returns the same exit code,
as the called command"""
with self.assertRaises(SystemExit) as ce:
main_entry_point(["run", "python3", "-c", "exit(2)"])
self.assertEqual(ce.exception.code, 2)



def test_run(self):
main_entry_point(["create"])
Expand Down
2 changes: 1 addition & 1 deletion vien/constants.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
__version__ = "0.3.5"
__version__ = "0.3.6"
__copyright__ = "(c) 2020-2021 Artëm IG <github.com/rtmigo>"
__license__ = "BSD-3-Clause"
33 changes: 17 additions & 16 deletions vien/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class VenvExistsError(VienError):

class VenvDoesNotExistError(VienError):
def __init__(self, path: Path):
super().__init__(f"Virtualenv {path} does not exist.")
super().__init__(f"Virtual environment {path} does not exist.")


class FailedToCreateVenvError(VienError):
Expand Down Expand Up @@ -142,13 +142,7 @@ def test_if_not_n(self):
self.assertGreater(len(p), len("/.vien"))


# def run(args: List[str]):
# if verbose:
# print(f"Running {args}")
# subprocess.run(args, shell=True)
#

def runseq(commands: List[str]):
def run_bash_sequence(commands: List[str]) -> int:
bash_lines = [
"#!/bin/bash"
"set -e", # fail on first error
Expand All @@ -160,7 +154,9 @@ def runseq(commands: List[str]):
# Otherwise the command is executed in /bin/sh, ignoring the hashbang,
# but SH fails to execute commands like 'source'

subprocess.call("\n".join(bash_lines), shell=True, executable='/bin/bash')
return subprocess.call("\n".join(bash_lines),
shell=True,
executable='/bin/bash')


def quote(arg: str) -> str:
Expand Down Expand Up @@ -258,7 +254,8 @@ def guess_bash_ps1():
return r"\h:\W \u\$" # default for MacOS up to Catalina

# hope for the best in other systems
return subprocess.check_output(['/bin/bash', '-i', '-c', 'echo $PS1']).decode().rstrip()
return subprocess.check_output(
['/bin/bash', '-i', '-c', 'echo $PS1']).decode().rstrip()


def main_shell(venv_dir: Path, venv_name: str, input: str, input_delay: float):
Expand All @@ -283,8 +280,9 @@ def main_shell(venv_dir: Path, venv_name: str, input: str, input_delay: float):

if bashrc_file.exists():
# Ubuntu
commands.append(f"exec bash --rcfile <(cat {json.dumps(str(bashrc_file))} "
f"&& echo 'PS1={json.dumps(new_ps1)}')")
commands.append(
f"exec bash --rcfile <(cat {json.dumps(str(bashrc_file))} "
f"&& echo 'PS1={json.dumps(new_ps1)}')")
else:
# MacOS
commands.append(f"PS1={json.dumps(new_ps1)} exec bash")
Expand All @@ -299,7 +297,8 @@ def main_shell(venv_dir: Path, venv_name: str, input: str, input_delay: float):
# It seems it closes immediately after the subprocess.Popen closes the stdin.
# So it will not wait for "exit". But it serves the task well

run_as_bash_script("\n".join(commands), input=input.encode() if input else None,
run_as_bash_script("\n".join(commands),
input=input.encode() if input else None,
input_delay=input_delay)


Expand All @@ -310,7 +309,7 @@ def main_run(venv_dir: Path, otherargs):
" ".join(quote(a) for a in otherargs)
]

exit(runseq(commands))
exit(run_bash_sequence(commands))


def main_entry_point(args: Optional[List[str]] = None):
Expand All @@ -333,9 +332,11 @@ def main_entry_point(args: Optional[List[str]] = None):
shell_parser = subparsers.add_parser('shell',
help="dive into Bash sub-shell using the virtualenv")
shell_parser.add_argument("--input", type=str, default=None)
shell_parser.add_argument("--delay", type=float, default=None, help=argparse.SUPPRESS)
shell_parser.add_argument("--delay", type=float, default=None,
help=argparse.SUPPRESS)

parser_run = subparsers.add_parser('run', help="run a command inside the virtualenv")
parser_run = subparsers.add_parser('run',
help="run a command inside the virtualenv")
parser_run.add_argument('otherargs', nargs=argparse.REMAINDER)

subparsers.add_parser('path',
Expand Down

0 comments on commit 5c5ca08

Please sign in to comment.