diff --git a/.gitignore b/.gitignore index 45a067a..74c1245 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,5 @@ Session.vim *~ /pipreqs/*.bak + +.venv \ No newline at end of file diff --git a/README.rst b/README.rst index 45dce6a..60358c5 100644 --- a/README.rst +++ b/README.rst @@ -47,6 +47,7 @@ Usage Options: --use-local Use ONLY local package info instead of querying PyPI + --only-venv Use ONLY venv packages instead local system --pypi-server Use custom PyPi server --proxy Use Proxy, parameter will be passed to requests library. You can also just set the environments parameter in your terminal: diff --git a/pipreqs/__main__.py b/pipreqs/__main__.py new file mode 100644 index 0000000..bd8961a --- /dev/null +++ b/pipreqs/__main__.py @@ -0,0 +1,4 @@ +from pipreqs import pipreqs + +if __name__ == "__main__": + pipreqs.main() diff --git a/pipreqs/pipreqs.py b/pipreqs/pipreqs.py index dceda96..0a05aa6 100644 --- a/pipreqs/pipreqs.py +++ b/pipreqs/pipreqs.py @@ -12,6 +12,7 @@ Arguments: Options: --use-local Use ONLY local package info instead of querying PyPI. + --only-venv Use ONLY venv packages instead local system. --pypi-server Use custom PyPi server. --proxy Use Proxy, parameter will be passed to requests library. You can also just set the environments @@ -49,6 +50,7 @@ from docopt import docopt import requests from yarg import json2package from yarg.exceptions import HTTPError +from typing import Optional from pipreqs import __version__ @@ -260,10 +262,29 @@ def get_imports_info(imports, pypi_server="https://pypi.python.org/pypi/", proxy return result -def get_locally_installed_packages(encoding="utf-8"): +def get_locally_installed_packages(use_venv_packages: bool, encoding="utf-8"): packages = [] ignore = ["tests", "_tests", "egg", "EGG", "info"] - for path in sys.path: + + venv_path = os.environ.get("VIRTUAL_ENV") + paths_to_search = [] + if use_venv_packages and venv_path: + lib_path = os.path.join(venv_path, "lib") + if os.path.isdir(lib_path): + for entry in os.listdir(lib_path): + site_packages = os.path.join(lib_path, entry, "site-packages") + if os.path.isdir(site_packages): + paths_to_search.append(site_packages) + break + else: + if use_venv_packages and not venv_path: + logging.warning( + "You specified to use only the virtual environment packages, " + "but no virtual environment is currently active." + ) + paths_to_search = sys.path + + for path in paths_to_search: for root, dirs, files in os.walk(path): for item in files: if "top_level" in item: @@ -301,8 +322,8 @@ def get_locally_installed_packages(encoding="utf-8"): return packages -def get_import_local(imports, encoding="utf-8"): - local = get_locally_installed_packages() +def get_import_local(imports, use_venv_packages: Optional[bool] = False, encoding="utf-8"): + local = get_locally_installed_packages(use_venv_packages=use_venv_packages) result = [] for item in imports: # search through local packages @@ -551,7 +572,9 @@ def init(args): if args["--use-local"]: logging.debug("Getting package information ONLY from local installation.") - imports = get_import_local(candidates, encoding=encoding) + print(candidates) + imports = get_import_local(candidates, args["--only-venv"], encoding=encoding) + print(imports) else: logging.debug("Getting packages information from Local/PyPI") local = get_import_local(candidates, encoding=encoding) diff --git a/tests/_data_ignore/requirements.txt b/tests/_data_ignore/requirements.txt new file mode 100644 index 0000000..dd5edfd --- /dev/null +++ b/tests/_data_ignore/requirements.txt @@ -0,0 +1,13 @@ +asposestorage==1.0.2 +beautifulsoup4==4.13.3 +boto==2.49.0 +docopt==0.6.2 +Flask==3.1.0 +ipython==8.12.3 +nose==1.3.7 +peewee==3.17.9 +pyflakes==3.1.0 +pyflakes==3.3.2 +Requests==2.32.3 +SQLAlchemy==2.0.40 +ujson==5.10.0 diff --git a/tests/_data_notebook/requirements.txt b/tests/_data_notebook/requirements.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/_data_notebook/requirements.txt @@ -0,0 +1 @@ + diff --git a/tests/test_pipreqs.py b/tests/test_pipreqs.py index 5e046e0..7eeaee5 100644 --- a/tests/test_pipreqs.py +++ b/tests/test_pipreqs.py @@ -156,6 +156,22 @@ class TestPipreqs(unittest.TestCase): for item in imports_with_info: self.assertTrue(item["name"].lower() in self.local) + @patch("pipreqs.pipreqs.get_locally_installed_packages") + def test_get_import_local_only_from_venv(self, mock_get_local_packages): + mock_get_local_packages.return_value = [ + {"name": "requests", "version": "2.31.0", "exports": ["requests"]}, + {"name": "docopt", "version": "0.6.2", "exports": ["docopt"]}, + ] + + imports = {"requests": "2.31.0", "docopt": "0.6.2", "flask": "3.0.2"} + + result = pipreqs.get_import_local(imports, use_venv_packages=True) + + self.assertEqual(result, [ + {"name": "requests", "version": "2.31.0", "exports": ["requests"]}, + {"name": "docopt", "version": "0.6.2", "exports": ["docopt"]}, + ]) + def test_init(self): """ Test that all modules we will test upon are in requirements file @@ -194,6 +210,7 @@ class TestPipreqs(unittest.TestCase): "--savepath": None, "--print": False, "--use-local": True, + "--only-venv": False, "--force": True, "--proxy": None, "--pypi-server": None,