From 4eae4794a0548710099ae22ce5b9fcfd2a8845b7 Mon Sep 17 00:00:00 2001 From: Jake Teo Date: Thu, 25 Mar 2021 17:37:00 +0800 Subject: [PATCH] New Option for Dynamic Versioning (#1) * added new option for dynamic versioning * added quotes for dynamic options Co-authored-by: Siyang --- AUTHORS.rst | 3 ++- README.rst | 2 +- pipreqs/pipreqs.py | 34 +++++++++++++++++++++--- tests/test_pipreqs.py | 61 ++++++++++++++++++++++++++++++++++++------- 4 files changed, 85 insertions(+), 15 deletions(-) mode change 100755 => 100644 pipreqs/pipreqs.py mode change 100755 => 100644 tests/test_pipreqs.py diff --git a/AUTHORS.rst b/AUTHORS.rst index eaa038a..2f31bac 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -10,4 +10,5 @@ Development Lead Contributors ------------ -None yet. Why not be the first? +* Jake Teo +* Jerome Chan diff --git a/README.rst b/README.rst index 139fa7d..93b1735 100644 --- a/README.rst +++ b/README.rst @@ -49,7 +49,7 @@ Usage --force Overwrite existing requirements.txt --diff Compare modules in requirements.txt to project imports. --clean Clean up requirements.txt by removing modules that are not imported in project. - --no-pin Omit version of output packages. + --dynamic Enables dynamic version updates by 'minor', 'micro' or 'all' schemes. Example ------- diff --git a/pipreqs/pipreqs.py b/pipreqs/pipreqs.py old mode 100755 new mode 100644 index 57147e2..069c28a --- a/pipreqs/pipreqs.py +++ b/pipreqs/pipreqs.py @@ -31,7 +31,8 @@ Options: imports. --clean Clean up requirements.txt by removing modules that are not imported in project. - --no-pin Omit version of output packages. + --dynamic Enables dynamic version updates by 'minor', + 'micro' or 'all' schemes. """ from __future__ import print_function, absolute_import from contextlib import contextmanager @@ -392,6 +393,28 @@ def clean(file_, imports): logging.info("Successfully cleaned up requirements in " + file_) +def dynamic_versioning(scheme, imports): + """Enables dynamic versioning by minor, micro or all scheme.""" + if scheme == "all": + imports = [{"name": item["name"], "version": ""} for item in imports] + else: + for item in imports: + version = item["version"] + arr = version.split(".") + length = len(arr) + if length != 1: + if scheme == "minor": + arr = arr[0] + + elif scheme == "micro" and length >= 2: + arr = arr[:2] + arr = ".".join(arr) + + arr = arr + ".*" + item["version"] = arr + return imports + + def init(args): encoding = args.get('--encoding') extra_ignore_dirs = args.get('--ignore') @@ -450,8 +473,13 @@ def init(args): "use --force to overwrite it") return - if args.get('--no-pin'): - imports = [{'name': item["name"], 'version': ''} for item in imports] + if args["--dynamic"]: + scheme = args.get("--dynamic") + if scheme in ["minor", "micro", "all"]: + imports = dynamic_versioning(scheme, imports) + else: + raise ValueError("Invalid argument for dynamic scheme, " + "use 'minor', 'micro' or 'all' instead") if args["--print"]: output_requirements(imports) diff --git a/tests/test_pipreqs.py b/tests/test_pipreqs.py old mode 100755 new mode 100644 index dcd75c5..b150c9a --- a/tests/test_pipreqs.py +++ b/tests/test_pipreqs.py @@ -93,7 +93,7 @@ class TestPipreqs(unittest.TestCase): """ pipreqs.init({'': self.project, '--savepath': None, '--print': False, '--use-local': None, '--force': True, '--proxy':None, '--pypi-server':None, - '--diff': None, '--clean': None}) + '--diff': None, '--clean': None, '--dynamic': None}) assert os.path.exists(self.requirements_path) == 1 with open(self.requirements_path, "r") as f: data = f.read().lower() @@ -106,7 +106,7 @@ class TestPipreqs(unittest.TestCase): """ pipreqs.init({'': self.project, '--savepath': None, '--print': False, '--use-local': True, '--force': True, '--proxy':None, '--pypi-server':None, - '--diff': None, '--clean': None}) + '--diff': None, '--clean': None, '--dynamic': None}) assert os.path.exists(self.requirements_path) == 1 with open(self.requirements_path, "r") as f: data = f.readlines() @@ -120,7 +120,7 @@ class TestPipreqs(unittest.TestCase): """ pipreqs.init({'': self.project, '--savepath': self.alt_requirement_path, '--use-local': None, '--proxy':None, '--pypi-server':None, '--print': False, - "--diff": None, "--clean": None}) + "--diff": None, "--clean": None, '--dynamic': None}) assert os.path.exists(self.alt_requirement_path) == 1 with open(self.alt_requirement_path, "r") as f: data = f.read().lower() @@ -137,7 +137,7 @@ class TestPipreqs(unittest.TestCase): f.write("should_not_be_overwritten") pipreqs.init({'': self.project, '--savepath': None, '--use-local': None, '--force': None, '--proxy':None, '--pypi-server':None, '--print': False, - "--diff": None, "--clean": None}) + "--diff": None, "--clean": None, '--dynamic': None}) assert os.path.exists(self.requirements_path) == 1 with open(self.requirements_path, "r") as f: data = f.read().lower() @@ -173,7 +173,8 @@ class TestPipreqs(unittest.TestCase): '--pypi-server':None, '--ignore':'.ignored_dir,.ignore_second', '--diff': None, - '--clean': None + '--clean': None, + '--dynamic': None } ) with open(os.path.join(self.project_with_ignore_directory, "requirements.txt"), "r") as f: @@ -181,9 +182,9 @@ class TestPipreqs(unittest.TestCase): for item in ['click', 'getpass']: self.assertFalse(item.lower() in data) - def test_omit_version(self): + def test_dynamic_version_all_scheme(self): """ - Test --no-pin parameter + Test --dynamic=all """ pipreqs.init( {'': self.project_with_ignore_directory, '--savepath': None, '--print': False, @@ -192,13 +193,53 @@ class TestPipreqs(unittest.TestCase): '--pypi-server': None, '--diff': None, '--clean': None, - '--no-pin': True + '--dynamic': 'all' } ) with open(os.path.join(self.project_with_ignore_directory, "requirements.txt"), "r") as f: data = f.read().lower() - for item in ['beautifulsoup4==4.8.1', 'boto==2.49.0']: - self.assertFalse(item.lower() in data) + for item in ['beautifulsoup4', 'boto']: + self.assertTrue(item.lower() in data) + + def test_dynamic_version_micro_scheme(self): + """ + Test --dynamic=micro + """ + pipreqs.init( + {'': self.project_with_ignore_directory, '--savepath': None, '--print': False, + '--use-local': None, '--force': True, + '--proxy': None, + '--pypi-server': None, + '--diff': None, + '--clean': None, + '--dynamic': 'micro' + } + ) + with open(os.path.join(self.project_with_ignore_directory, "requirements.txt"), "r") as f: + data = f.readlines() + for item in data: + asterisk = item.strip().split(".")[2] + self.assertEqual(asterisk, "*",) + + def test_dynamic_version_minor_scheme(self): + """ + Test --dynamic=minor + """ + pipreqs.init( + {'': self.project_with_ignore_directory, '--savepath': None, '--print': False, + '--use-local': None, '--force': True, + '--proxy': None, + '--pypi-server': None, + '--diff': None, + '--clean': None, + '--dynamic': 'minor' + } + ) + with open(os.path.join(self.project_with_ignore_directory, "requirements.txt"), "r") as f: + data = f.readlines() + for item in data: + asterisk = item.strip().split(".")[1] + self.assertEqual(asterisk, "*",) def tearDown(self): """