From 62ae7b45ad4b4a1cd587edf8d864c69ab19dc06d Mon Sep 17 00:00:00 2001 From: c-w-m Date: Thu, 12 Jan 2023 08:48:58 -0700 Subject: [PATCH 1/7] fix SSLError --- pipreqs/pipreqs.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pipreqs/pipreqs.py b/pipreqs/pipreqs.py index 24eeeb7..df6cbff 100644 --- a/pipreqs/pipreqs.py +++ b/pipreqs/pipreqs.py @@ -18,6 +18,8 @@ Options: parameter in your terminal: $ export HTTP_PROXY="http://10.10.1.10:3128" $ export HTTPS_PROXY="https://10.10.1.10:1080" + --verify Use verify to provide a CA_BUNDLE file or directory + with certificates of trusted CAs --debug Print debug information --ignore ... Ignore extra directories, each separated by a comma --no-follow-links Do not follow symbolic links in the project @@ -171,13 +173,13 @@ def output_requirements(imports, symbol): def get_imports_info( - imports, pypi_server="https://pypi.python.org/pypi/", proxy=None): + imports, pypi_server="https://pypi.python.org/pypi/", proxy=None, verify=None): result = [] for item in imports: try: response = requests.get( - "{0}{1}/json".format(pypi_server, item), proxies=proxy) + "{0}{1}/json".format(pypi_server, item), proxies=proxy, verify=verify) if response.status_code == 200: if hasattr(response.content, 'decode'): data = json2package(response.content.decode()) @@ -419,6 +421,7 @@ def init(args): candidates = get_pkg_names(candidates) logging.debug("Found imports: " + ", ".join(candidates)) pypi_server = "https://pypi.python.org/pypi/" + verify = None proxy = None if args["--pypi-server"]: pypi_server = args["--pypi-server"] @@ -426,6 +429,9 @@ def init(args): if args["--proxy"]: proxy = {'http': args["--proxy"], 'https': args["--proxy"]} + if args["--verify"]: + verify = args["--verify"] + if args["--use-local"]: logging.debug( "Getting package information ONLY from local installation.") @@ -438,6 +444,7 @@ def init(args): if x.lower() not in [z['name'].lower() for z in local]] imports = local + get_imports_info(difference, proxy=proxy, + verify=verify, pypi_server=pypi_server) # sort imports based on lowercase name of package, similar to `pip freeze`. imports = sorted(imports, key=lambda x: x['name'].lower()) From e0830d44a5b0ea37b9850b3fb4c13c13a8608f50 Mon Sep 17 00:00:00 2001 From: c-w-m Date: Thu, 12 Jan 2023 09:31:26 -0700 Subject: [PATCH 2/7] black install --- requirements-dev.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 requirements-dev.txt diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..e87d699 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,3 @@ +black +flake8 +tox From ffc2c11d991cdb2175406e25d4123dd1a650e332 Mon Sep 17 00:00:00 2001 From: c-w-m Date: Thu, 12 Jan 2023 09:50:00 -0700 Subject: [PATCH 3/7] black auto format and sort imports --- pipreqs/pipreqs.py | 188 +++++++++++-------- tests/_data/test.py | 70 ++++--- tests/_data_clean/test.py | 70 ++++--- tests/_data_ignore/.ignore_second/ignored.py | 2 +- tests/_data_ignore/test.py | 65 +++---- tests/test_pipreqs.py | 11 +- 6 files changed, 214 insertions(+), 192 deletions(-) diff --git a/pipreqs/pipreqs.py b/pipreqs/pipreqs.py index df6cbff..7b1f7e5 100644 --- a/pipreqs/pipreqs.py +++ b/pipreqs/pipreqs.py @@ -38,28 +38,29 @@ Options: | e.g. Flask>=1.1.2 | e.g. Flask """ -from contextlib import contextmanager -import os -import sys -import re -import logging import ast +import logging +import os +import re +import sys import traceback -from docopt import docopt +from contextlib import contextmanager + import requests +from docopt import docopt from yarg import json2package from yarg.exceptions import HTTPError from pipreqs import __version__ REGEXP = [ - re.compile(r'^import (.+)$'), - re.compile(r'^from ((?!\.+).*?) import (?:.*)$') + re.compile(r"^import (.+)$"), + re.compile(r"^from ((?!\.+).*?) import (?:.*)$"), ] @contextmanager -def _open(filename=None, mode='r'): +def _open(filename=None, mode="r"): """Open a file or ``sys.stdout`` depending on the provided filename. Args: @@ -72,13 +73,13 @@ def _open(filename=None, mode='r'): A file handle. """ - if not filename or filename == '-': - if not mode or 'r' in mode: + if not filename or filename == "-": + if not mode or "r" in mode: file = sys.stdin - elif 'w' in mode: + elif "w" in mode: file = sys.stdout else: - raise ValueError('Invalid mode for file: {}'.format(mode)) + raise ValueError("Invalid mode for file: {}".format(mode)) else: file = open(filename, mode) @@ -90,7 +91,8 @@ def _open(filename=None, mode='r'): def get_all_imports( - path, encoding=None, extra_ignore_dirs=None, follow_links=True): + path, encoding=None, extra_ignore_dirs=None, follow_links=True +): imports = set() raw_imports = set() candidates = [] @@ -139,11 +141,11 @@ def get_all_imports( # Cleanup: We only want to first part of the import. # Ex: from django.conf --> django.conf. But we only want django # as an import. - cleaned_name, _, _ = name.partition('.') + cleaned_name, _, _ = name.partition(".") imports.add(cleaned_name) packages = imports - (set(candidates) & imports) - logging.debug('Found packages: {0}'.format(packages)) + logging.debug("Found packages: {0}".format(packages)) with open(join("stdlib"), "r") as f: data = {x.strip() for x in f} @@ -157,42 +159,59 @@ def filter_line(line): def generate_requirements_file(path, imports, symbol): with _open(path, "w") as out_file: - logging.debug('Writing {num} requirements: {imports} to {file}'.format( - num=len(imports), - file=path, - imports=", ".join([x['name'] for x in imports]) - )) - fmt = '{name}' + symbol + '{version}' - out_file.write('\n'.join( - fmt.format(**item) if item['version'] else '{name}'.format(**item) - for item in imports) + '\n') + logging.debug( + "Writing {num} requirements: {imports} to {file}".format( + num=len(imports), + file=path, + imports=", ".join([x["name"] for x in imports]), + ) + ) + fmt = "{name}" + symbol + "{version}" + out_file.write( + "\n".join( + fmt.format(**item) + if item["version"] + else "{name}".format(**item) + for item in imports + ) + + "\n" + ) def output_requirements(imports, symbol): - generate_requirements_file('-', imports, symbol) + generate_requirements_file("-", imports, symbol) def get_imports_info( - imports, pypi_server="https://pypi.python.org/pypi/", proxy=None, verify=None): + imports, + pypi_server="https://pypi.python.org/pypi/", + proxy=None, + verify=None, +): result = [] for item in imports: try: response = requests.get( - "{0}{1}/json".format(pypi_server, item), proxies=proxy, verify=verify) + "{0}{1}/json".format(pypi_server, item), + proxies=proxy, + verify=verify, + ) if response.status_code == 200: - if hasattr(response.content, 'decode'): + if hasattr(response.content, "decode"): data = json2package(response.content.decode()) else: data = json2package(response.content) elif response.status_code >= 300: - raise HTTPError(status_code=response.status_code, - reason=response.reason) + raise HTTPError( + status_code=response.status_code, reason=response.reason + ) except HTTPError: logging.debug( - 'Package %s does not exist or network problems', item) + "Package %s does not exist or network problems", item + ) continue - result.append({'name': item, 'version': data.latest_release_id}) + result.append({"name": item, "version": data.latest_release_id}) return result @@ -212,16 +231,20 @@ def get_locally_installed_packages(encoding=None): # TODO: What errors do we intend to suppress here? continue for i_item in package_import: - if ((i_item not in ignore) and - (package[0] not in ignore)): + if (i_item not in ignore) and ( + package[0] not in ignore + ): version = None if len(package) > 1: - version = package[1].replace( - ".dist", "").replace(".egg", "") + version = ( + package[1] + .replace(".dist", "") + .replace(".egg", "") + ) packages[i_item] = { - 'version': version, - 'name': package[0] + "version": version, + "name": package[0], } return packages @@ -234,12 +257,7 @@ def get_import_local(imports, encoding=None): result.append(local[item.lower()]) # removing duplicates of package/version - result_unique = [ - dict(t) - for t in set([ - tuple(d.items()) for d in result - ]) - ] + result_unique = [dict(t) for t in set([tuple(d.items()) for d in result])] return result_unique @@ -270,7 +288,7 @@ def get_name_without_alias(name): match = REGEXP[0].match(name.strip()) if match: name = match.groups(0)[0] - return name.partition(' as ')[0].partition('.')[0].strip() + return name.partition(" as ")[0].partition(".")[0].strip() def join(f): @@ -356,7 +374,8 @@ def diff(file_, imports): logging.info( "The following modules are in {} but do not seem to be imported: " - "{}".format(file_, ", ".join(x for x in modules_not_imported))) + "{}".format(file_, ", ".join(x for x in modules_not_imported)) + ) def clean(file_, imports): @@ -404,20 +423,22 @@ def dynamic_versioning(scheme, imports): def init(args): - encoding = args.get('--encoding') - extra_ignore_dirs = args.get('--ignore') - follow_links = not args.get('--no-follow-links') - input_path = args[''] + encoding = args.get("--encoding") + extra_ignore_dirs = args.get("--ignore") + follow_links = not args.get("--no-follow-links") + input_path = args[""] if input_path is None: input_path = os.path.abspath(os.curdir) if extra_ignore_dirs: - extra_ignore_dirs = extra_ignore_dirs.split(',') + extra_ignore_dirs = extra_ignore_dirs.split(",") - candidates = get_all_imports(input_path, - encoding=encoding, - extra_ignore_dirs=extra_ignore_dirs, - follow_links=follow_links) + candidates = get_all_imports( + input_path, + encoding=encoding, + extra_ignore_dirs=extra_ignore_dirs, + follow_links=follow_links, + ) candidates = get_pkg_names(candidates) logging.debug("Found imports: " + ", ".join(candidates)) pypi_server = "https://pypi.python.org/pypi/" @@ -427,30 +448,36 @@ def init(args): pypi_server = args["--pypi-server"] if args["--proxy"]: - proxy = {'http': args["--proxy"], 'https': args["--proxy"]} + proxy = {"http": args["--proxy"], "https": args["--proxy"]} if args["--verify"]: verify = args["--verify"] if args["--use-local"]: logging.debug( - "Getting package information ONLY from local installation.") + "Getting package information ONLY from local installation." + ) imports = get_import_local(candidates, encoding=encoding) else: logging.debug("Getting packages information from Local/PyPI") local = get_import_local(candidates, encoding=encoding) # Get packages that were not found locally - difference = [x for x in candidates - if x.lower() not in [z['name'].lower() for z in local]] - imports = local + get_imports_info(difference, - proxy=proxy, - verify=verify, - pypi_server=pypi_server) + difference = [ + x + for x in candidates + if x.lower() not in [z["name"].lower() for z in local] + ] + imports = local + get_imports_info( + difference, proxy=proxy, verify=verify, pypi_server=pypi_server + ) # sort imports based on lowercase name of package, similar to `pip freeze`. - imports = sorted(imports, key=lambda x: x['name'].lower()) + imports = sorted(imports, key=lambda x: x["name"].lower()) - path = (args["--savepath"] if args["--savepath"] else - os.path.join(input_path, "requirements.txt")) + path = ( + args["--savepath"] + if args["--savepath"] + else os.path.join(input_path, "requirements.txt") + ) if args["--diff"]: diff(args["--diff"], imports) @@ -460,12 +487,15 @@ def init(args): clean(args["--clean"], imports) return - if (not args["--print"] - and not args["--savepath"] - and not args["--force"] - and os.path.exists(path)): - logging.warning("requirements.txt already exists, " - "use --force to overwrite it") + if ( + not args["--print"] + and not args["--savepath"] + and not args["--force"] + and os.path.exists(path) + ): + logging.warning( + "requirements.txt already exists, " "use --force to overwrite it" + ) return if args["--mode"]: @@ -473,8 +503,10 @@ def init(args): if scheme in ["compat", "gt", "no-pin"]: imports, symbol = dynamic_versioning(scheme, imports) else: - raise ValueError("Invalid argument for mode flag, " - "use 'compat', 'gt' or 'no-pin' instead") + raise ValueError( + "Invalid argument for mode flag, " + "use 'compat', 'gt' or 'no-pin' instead" + ) else: symbol = "==" @@ -488,8 +520,8 @@ def init(args): def main(): # pragma: no cover args = docopt(__doc__, version=__version__) - log_level = logging.DEBUG if args['--debug'] else logging.INFO - logging.basicConfig(level=log_level, format='%(levelname)s: %(message)s') + log_level = logging.DEBUG if args["--debug"] else logging.INFO + logging.basicConfig(level=log_level, format="%(levelname)s: %(message)s") try: init(args) @@ -497,5 +529,5 @@ def main(): # pragma: no cover sys.exit(0) -if __name__ == '__main__': +if __name__ == "__main__": main() # pragma: no cover diff --git a/tests/_data/test.py b/tests/_data/test.py index fdb6ec3..73c15d2 100644 --- a/tests/_data/test.py +++ b/tests/_data/test.py @@ -1,56 +1,51 @@ """unused import""" # pylint: disable=undefined-all-variable, import-error, no-absolute-import, too-few-public-methods, missing-docstring +from __future__ import print_function + +import atexit +import curses +import importlib # html/notebookapp.py +import logging +import os +import os.path as test # [unused-import] +import signal +import sqlite3 +import sys +import time import xml.etree # [unused-import] import xml.sax # [unused-import] -import os.path as test # [unused-import] -from sys import argv as test2 # [unused-import] -from sys import flags # [unused-import] -# +1:[unused-import,unused-import] -from collections import deque, OrderedDict, Counter -# All imports above should be ignored -import requests # [unused-import] - +# astroid # setuptools -import zipimport # command/easy_install.py - +import zipimport # manager.py +# +1:[unused-import,unused-import] +from collections import Counter, OrderedDict, deque # twisted from importlib import invalidate_caches # python/test/test_deprecate.py - -# astroid -import zipimport # manager.py # IPython from importlib.machinery import all_suffixes # core/completerlib.py -import importlib # html/notebookapp.py - -from IPython.utils.importstring import import_item # Many files - -# pyflakes -# test/test_doctests.py -from pyflakes.test.test_imports import Test as TestImports - -# Nose -from nose.importer import Importer, add_path, remove_path # loader.py +from sys import argv as test2 # [unused-import] +from sys import flags # [unused-import] # see issue #88 import analytics -import flask_seasurf - -import atexit -from __future__ import print_function -from docopt import docopt -import curses, logging, sqlite3 -import logging -import os -import sqlite3 -import time -import sys -import signal +import boto as b import bs4 -import nonexistendmodule -import boto as b, peewee as p # import django import flask.ext.somext # # # +import flask_seasurf +import nonexistendmodule +import peewee as p +# All imports above should be ignored +import requests # [unused-import] +from docopt import docopt +from IPython.utils.importstring import import_item # Many files +# Nose +from nose.importer import Importer, add_path, remove_path # loader.py +# pyflakes +# test/test_doctests.py +from pyflakes.test.test_imports import Test as TestImports from sqlalchemy import model + try: import ujson as json except ImportError: @@ -62,4 +57,5 @@ import models def main(): pass + import after_method_is_valid_even_if_not_pep8 diff --git a/tests/_data_clean/test.py b/tests/_data_clean/test.py index 8cffb51..13a6d6b 100644 --- a/tests/_data_clean/test.py +++ b/tests/_data_clean/test.py @@ -1,55 +1,50 @@ """unused import""" # pylint: disable=undefined-all-variable, import-error, no-absolute-import, too-few-public-methods, missing-docstring +from __future__ import print_function + +import atexit +import curses +import importlib # html/notebookapp.py +import logging +import os +import os.path as test # [unused-import] +import signal +import sqlite3 +import sys +import time import xml.etree # [unused-import] import xml.sax # [unused-import] -import os.path as test # [unused-import] -from sys import argv as test2 # [unused-import] -from sys import flags # [unused-import] -# +1:[unused-import,unused-import] -from collections import deque, OrderedDict, Counter -# All imports above should be ignored -import requests # [unused-import] - +# astroid # setuptools -import zipimport # command/easy_install.py - +import zipimport # manager.py +# +1:[unused-import,unused-import] +from collections import Counter, OrderedDict, deque # twisted from importlib import invalidate_caches # python/test/test_deprecate.py - -# astroid -import zipimport # manager.py # IPython from importlib.machinery import all_suffixes # core/completerlib.py -import importlib # html/notebookapp.py +from sys import argv as test2 # [unused-import] +from sys import flags # [unused-import] +# see issue #88 +import analytics +import boto as b +import bs4 +# import django +import flask.ext.somext # # # +import flask_seasurf +import nonexistendmodule +import peewee as p +# All imports above should be ignored +import requests # [unused-import] +from docopt import docopt from IPython.utils.importstring import import_item # Many files - +# Nose +from nose.importer import Importer, add_path, remove_path # loader.py # pyflakes # test/test_doctests.py from pyflakes.test.test_imports import Test as TestImports -# Nose -from nose.importer import Importer, add_path, remove_path # loader.py - -# see issue #88 -import analytics -import flask_seasurf - -import atexit -from __future__ import print_function -from docopt import docopt -import curses, logging, sqlite3 -import logging -import os -import sqlite3 -import time -import sys -import signal -import bs4 -import nonexistendmodule -import boto as b, peewee as p -# import django -import flask.ext.somext # # # # from sqlalchemy import model try: import ujson as json @@ -62,4 +57,5 @@ import models def main(): pass + import after_method_is_valid_even_if_not_pep8 diff --git a/tests/_data_ignore/.ignore_second/ignored.py b/tests/_data_ignore/.ignore_second/ignored.py index b970ae3..6ea3598 100644 --- a/tests/_data_ignore/.ignore_second/ignored.py +++ b/tests/_data_ignore/.ignore_second/ignored.py @@ -1,2 +1,2 @@ # Everything in here should be ignored -from pattern.web import Twitter, plaintext \ No newline at end of file +from pattern.web import Twitter, plaintext diff --git a/tests/_data_ignore/test.py b/tests/_data_ignore/test.py index cfd039c..f520669 100644 --- a/tests/_data_ignore/test.py +++ b/tests/_data_ignore/test.py @@ -1,52 +1,48 @@ """unused import""" # pylint: disable=undefined-all-variable, import-error, no-absolute-import, too-few-public-methods, missing-docstring +from __future__ import print_function + +import atexit +import curses +import importlib # html/notebookapp.py +import logging +import os +import os.path as test # [unused-import] +import signal +import sqlite3 +import sys +import time import xml.etree # [unused-import] import xml.sax # [unused-import] -import os.path as test # [unused-import] -from sys import argv as test2 # [unused-import] -from sys import flags # [unused-import] -# +1:[unused-import,unused-import] -from collections import deque, OrderedDict, Counter -# All imports above should be ignored -import requests # [unused-import] - +# astroid # setuptools -import zipimport # command/easy_install.py - +import zipimport # manager.py +# +1:[unused-import,unused-import] +from collections import Counter, OrderedDict, deque # twisted from importlib import invalidate_caches # python/test/test_deprecate.py - -# astroid -import zipimport # manager.py # IPython from importlib.machinery import all_suffixes # core/completerlib.py -import importlib # html/notebookapp.py +from sys import argv as test2 # [unused-import] +from sys import flags # [unused-import] +import boto as b +import bs4 +# import django +import flask.ext.somext # # # +import nonexistendmodule +import peewee as p +# All imports above should be ignored +import requests # [unused-import] +from docopt import docopt from IPython.utils.importstring import import_item # Many files - +# Nose +from nose.importer import Importer, add_path, remove_path # loader.py # pyflakes # test/test_doctests.py from pyflakes.test.test_imports import Test as TestImports - -# Nose -from nose.importer import Importer, add_path, remove_path # loader.py - -import atexit -from __future__ import print_function -from docopt import docopt -import curses, logging, sqlite3 -import logging -import os -import sqlite3 -import time -import sys -import signal -import bs4 -import nonexistendmodule -import boto as b, peewee as p -# import django -import flask.ext.somext # # # from sqlalchemy import model + try: import ujson as json except ImportError: @@ -58,4 +54,5 @@ import models def main(): pass + import after_method_is_valid_even_if_not_pep8 diff --git a/tests/test_pipreqs.py b/tests/test_pipreqs.py index f82d3db..6e1510f 100644 --- a/tests/test_pipreqs.py +++ b/tests/test_pipreqs.py @@ -8,8 +8,9 @@ test_pipreqs Tests for `pipreqs` module. """ -import unittest import os +import unittest + import requests from pipreqs import pipreqs @@ -145,7 +146,7 @@ class TestPipreqs(unittest.TestCase): Test that we can save requirements.txt correctly to a different path """ - pipreqs.init({'': self.project, '--savepath': self.alt_requirement_path, + pipreqs.init({'': self.project, '--savepath': self.alt_requirement_path, '--use-local': None, '--proxy':None, '--pypi-server':None, '--print': False, '--diff': None, '--clean': None, '--mode': None}) assert os.path.exists(self.alt_requirement_path) == 1 @@ -163,7 +164,7 @@ class TestPipreqs(unittest.TestCase): """ with open(self.requirements_path, "w") as f: f.write("should_not_be_overwritten") - pipreqs.init({'': self.project, '--savepath': None, '--use-local': None, + pipreqs.init({'': self.project, '--savepath': None, '--use-local': None, '--force': None, '--proxy':None, '--pypi-server':None, '--print': False, '--diff': None, '--clean': None, '--mode': None}) assert os.path.exists(self.requirements_path) == 1 @@ -203,7 +204,7 @@ class TestPipreqs(unittest.TestCase): Test --ignore parameter """ pipreqs.init( - {'': self.project_with_ignore_directory, '--savepath': None, + {'': self.project_with_ignore_directory, '--savepath': None, '--print': False, '--use-local': None, '--force': True, '--proxy':None, '--pypi-server':None, '--ignore':'.ignored_dir,.ignore_second', @@ -222,7 +223,7 @@ class TestPipreqs(unittest.TestCase): Test --mode=no-pin """ pipreqs.init( - {'': self.project_with_ignore_directory, '--savepath': None, + {'': self.project_with_ignore_directory, '--savepath': None, '--print': False, '--use-local': None, '--force': True, '--proxy': None, '--pypi-server': None, '--diff': None, From b4604535b22a0ea8570a96e4b6c1b0d45b93a361 Mon Sep 17 00:00:00 2001 From: c-w-m Date: Thu, 12 Jan 2023 09:52:39 -0700 Subject: [PATCH 4/7] tox test init --- .vscode/settings.json | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7369a24 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,21 @@ +{ + "workbench.colorCustomizations": { + "activityBar.activeBackground": "#f75e3c", + "activityBar.background": "#f75e3c", + "activityBar.foreground": "#15202b", + "activityBar.inactiveForeground": "#15202b99", + "activityBarBadge.background": "#0af535", + "activityBarBadge.foreground": "#15202b", + "commandCenter.border": "#e7e7e799", + "sash.hoverBorder": "#f75e3c", + "statusBar.background": "#f5350b", + "statusBar.foreground": "#e7e7e7", + "statusBarItem.hoverBackground": "#f75e3c", + "statusBarItem.remoteBackground": "#f5350b", + "statusBarItem.remoteForeground": "#e7e7e7", + "titleBar.activeBackground": "#f5350b", + "titleBar.activeForeground": "#e7e7e7", + "titleBar.inactiveBackground": "#f5350b99", + "titleBar.inactiveForeground": "#e7e7e799" + } +} \ No newline at end of file From 90f94c8a8b746433e0925664aa7ea69a014538a1 Mon Sep 17 00:00:00 2001 From: craigmiller Date: Thu, 12 Jan 2023 22:59:10 -0700 Subject: [PATCH 5/7] fix_SSLError with testing and doc edits --- .eggs/README.txt | 6 + .vscode/cspell.json | 29 +++ .vscode/extensions.json | 185 ++++++++++++++ .vscode/launch.json | 13 + .vscode/settings.json | 32 ++- CONTRIBUTING.rst | 10 +- README.rst | 2 + pipreqs/pipreqs.py | 1 + requirements-dev.txt | 1 + setup.py | 4 + tests/.env.test.example | 8 + tests/.gitignore | 3 + tests/_data_ignore/requirements.txt | 12 + tests/settings.py | 16 ++ tests/test_pipreqs.py | 381 +++++++++++++++++++--------- tox.ini | 40 ++- 16 files changed, 606 insertions(+), 137 deletions(-) create mode 100644 .eggs/README.txt create mode 100644 .vscode/cspell.json create mode 100644 .vscode/extensions.json create mode 100644 .vscode/launch.json create mode 100644 tests/.env.test.example create mode 100644 tests/.gitignore create mode 100644 tests/_data_ignore/requirements.txt create mode 100644 tests/settings.py diff --git a/.eggs/README.txt b/.eggs/README.txt new file mode 100644 index 0000000..5d01668 --- /dev/null +++ b/.eggs/README.txt @@ -0,0 +1,6 @@ +This directory contains eggs that were downloaded by setuptools to build, test, and run plug-ins. + +This directory caches those eggs to prevent repeated downloads. + +However, it is safe to delete this directory. + diff --git a/.vscode/cspell.json b/.vscode/cspell.json new file mode 100644 index 0000000..ff3f350 --- /dev/null +++ b/.vscode/cspell.json @@ -0,0 +1,29 @@ +{ + "version": "0.2", + "ignorePaths": [], + "dictionaryDefinitions": [], + "dictionaries": [], + "words": [ + "beautifulsoup", + "boto", + "compat", + "docopt", + "docstrings", + "dotenv", + "mkvirtualenv", + "nonexistendmodule", + "pipreqs", + "pymongo", + "pypi", + "requiremnts", + "savepath", + "seasurf", + "sqlalchemy", + "ujson", + "virtualenv", + "virtualenvwrapper", + "Yarg" + ], + "ignoreWords": [], + "import": [] +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..f5c874b --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,185 @@ +{ + "recommendations": [ + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // VS Code Editor, Config, Spelling and Themes + // ----------------------------------------------------------------------- + // - Code Spell Checker + "streetsidesoftware.code-spell-checker", + // - EditorConfig for VS Code + "editorconfig.editorconfig", + // - Peacock + "johnpapa.vscode-peacock", + // - Night Owl + "sdras.night-owl", + // - indent-rainbow + "oderwat.indent-rainbow", + // - isort + "ms-python.isort", + // - Prettier - Code formatter + "esbenp.prettier-vscode", + // - vscode-icons + "vscode-icons-team.vscode-icons", + // - vscode-pdf + "tomoki1207.pdf", + // - Workspace Config+ + "swellaby.workspace-config-plus", + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Python + // ----------------------------------------------------------------------- + // - autoDocstring - Python Docstring Generator + //"njpwerner.autodocstring", + // - Django + "batisteo.vscode-django", + // - Pylance + "ms-python.vscode-pylance", + // - Python + "ms-python.python", + // - Python Environment Manager + "donjayamanne.python-environment-manager", + // - Python Extension Pack + "donjayamanne.python-extension-pack", + // - Python Indent + "kevinrose.vsc-python-indent", + // - Test Adapter Converter + "ms-vscode.test-adapter-converter", + // - Test Explorer UI + "hbenl.vscode-test-explorer", + // - python-tox + "the-compiler.python-tox", + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Rust + // ----------------------------------------------------------------------- + // - Rust-Analyzer + "rust-lang.rust-analyzer", + // Better TOML + "bungcip.better-toml", + // - crates + "serayuzgur.crates", + // - Rust Test Explorer + "swellaby.vscode-rust-test-adapter", + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Docker + // ----------------------------------------------------------------------- + // - Docker Compose + "p1c2u.docker-compose", + // - Dev Container + "ms-vscode-remote.remote-containers", + // - Docker + "ms-azuretools.vscode-docker", + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Data + // ----------------------------------------------------------------------- + // - Excel Viewer + "grapecity.gc-excelviewer", + // - MongoDB for VS Code + "mongodb.mongodb-vscode", + // - PlantUML + //"jebbs.plantuml", + // - REST Client + //"humao.rest-client", + // - SQLite Viewer + "qwtel.sqlite-viewer", + // - Thunder Client + "rangav.vscode-thunder-client", + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Git + // ----------------------------------------------------------------------- + // - Git Config User Profiles + "onlyutkarsh.git-config-user-profiles", + // - Git Graph + "mhutchie.git-graph", + // - Git History + "donjayamanne.githistory", + // - git-autoconfig + "shyykoserhiy.git-autoconfig", + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Jupyter Notebook + // ----------------------------------------------------------------------- + // - Jupyter + "ms-toolsai.jupyter", + // - Jupyter Cell Tags + "ms-toolsai.vscode-jupyter-cell-tags", + // - Jupyter Keymap + "ms-toolsai.jupyter-keymap", + // - Jupyter Notebook Renderers + "ms-toolsai.jupyter-renderers", + // - Jupyter PowerToys + //"ms-toolsai.vscode-jupyter-powertoys", + // - Jupyter Slide Show + "ms-toolsai.vscode-jupyter-slideshow", + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Yaml and Json + // ----------------------------------------------------------------------- + // - .NET Install Tool for Extension Authors + "ms-dotnettools.vscode-dotnet-runtime", + // - Azure Resource Manager (ARM) Tools + "msazurermtools.azurerm-vscode-tools", + // - YAML + "redhat.vscode-yaml", + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Markdown + // ----------------------------------------------------------------------- + // - Markdown All in One + "yzhang.markdown-all-in-one", + // - Markdown PDF + "yzane.markdown-pdf", + // - markdownlint + "davidanson.vscode-markdownlint" + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CSS + // ----------------------------------------------------------------------- + // - Auto Rename Tag + //"formulahendry.auto-rename-tag", + // - IntelliSense for CSS class names in HTML + //"zignd.html-css-class-completion", + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // local web server + // ----------------------------------------------------------------------- + // - Live Server + //"ritwickdey.liveserver", + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // JavaScript + // ----------------------------------------------------------------------- + // - Babel JavaScript + //"mgmcdermott.vscode-language-babel", + // - ES7+ React/Redux/React-Native snippets + //"dsznajder.es7-react-js-snippets", + // - ESLint + //"dbaeumer.vscode-eslint", + // - JavaScript (ES6) code snippets + //"xabikos.javascriptsnippets", + // - JavaScript Debugger (Nightly) + //"ms-vscode.js-debug-nightly", + // - Material-UI Snippets + //"vscodeshift.material-ui-snippets", + // - TypeScript + Webpack Problem Matchers + //"amodio.tsl-problem-matcher", + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Java + // ----------------------------------------------------------------------- + // - Debugger for Java + //"vscjava.vscode-java-debug", + // - Extension Pack for Java + //"vscjava.vscode-java-pack", + // - Language Support for Java(TM) by Red Hat + //"redhat.java", + // - Maven for Java + //"vscjava.vscode-maven", + // - Project Manager for Java + //"vscjava.vscode-java-dependency", + // - Test Runner for Java + //"vscjava.vscode-java-test", + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..9197dd3 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Current File", + "type": "python", + "request": "launch", + "program": "${file}", + "console": "integratedTerminal", + "justMyCode": true + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 7369a24..b1f764a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,21 +1,25 @@ { "workbench.colorCustomizations": { - "activityBar.activeBackground": "#f75e3c", - "activityBar.background": "#f75e3c", - "activityBar.foreground": "#15202b", - "activityBar.inactiveForeground": "#15202b99", - "activityBarBadge.background": "#0af535", - "activityBarBadge.foreground": "#15202b", + "activityBar.activeBackground": "#990000", + "activityBar.background": "#990000", + "activityBar.foreground": "#e7e7e7", + "activityBar.inactiveForeground": "#e7e7e799", + "activityBarBadge.background": "#000000", + "activityBarBadge.foreground": "#e7e7e7", "commandCenter.border": "#e7e7e799", - "sash.hoverBorder": "#f75e3c", - "statusBar.background": "#f5350b", + "sash.hoverBorder": "#990000", + "statusBar.background": "#660000", "statusBar.foreground": "#e7e7e7", - "statusBarItem.hoverBackground": "#f75e3c", - "statusBarItem.remoteBackground": "#f5350b", + "statusBarItem.hoverBackground": "#990000", + "statusBarItem.remoteBackground": "#660000", "statusBarItem.remoteForeground": "#e7e7e7", - "titleBar.activeBackground": "#f5350b", + "titleBar.activeBackground": "#660000", "titleBar.activeForeground": "#e7e7e7", - "titleBar.inactiveBackground": "#f5350b99", + "titleBar.inactiveBackground": "#66000099", "titleBar.inactiveForeground": "#e7e7e799" - } -} \ No newline at end of file + }, + "python.testing.unittestArgs": ["-v", "-s", "./tests", "-p", "test_*.py"], + "python.testing.pytestEnabled": false, + "python.testing.unittestEnabled": true, + "peacock.color": "#660000" +} diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 60e73a2..60fcb82 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -66,7 +66,7 @@ Ready to contribute? Here's how to set up `pipreqs` for local development. $ mkvirtualenv pipreqs $ cd pipreqs/ - $ python setup.py develop + $ python setup.py develop (or $pip install -e .) 4. Create a branch for local development:: @@ -80,7 +80,7 @@ Ready to contribute? Here's how to set up `pipreqs` for local development. $ python setup.py test $ tox - To get flake8 and tox, just pip install them into your virtualenv. + To get flake8 and tox, just pip install them into your virtualenv. (or $pip install -r requirements-dev.txt) 6. Commit your changes and push your branch to GitHub:: @@ -99,9 +99,9 @@ Before you submit a pull request, check that it meets these guidelines: 2. If the pull request adds functionality, the docs should be updated. Put your new functionality into a function with a docstring, and add the feature to the list in README.rst. -3. The pull request should work for Python 3.7 to 3.11, and PyPy. Check - https://travis-ci.org/bndr/pipreqs/pull_requests and make sure that the - tests pass for all supported Python versions. +3. The pull request should work for Python 3.7 to 3.10 (3.11 needs work), + and PyPy3. Check https://travis-ci.org/bndr/pipreqs/pull_requests and + make sure that the tests pass for all supported Python versions. Tips ---- diff --git a/README.rst b/README.rst index 16c477a..fe5c87a 100644 --- a/README.rst +++ b/README.rst @@ -44,6 +44,8 @@ Usage environments parameter in your terminal: $ export HTTP_PROXY="http://10.10.1.10:3128" $ export HTTPS_PROXY="https://10.10.1.10:1080" + --verify Use verify to provide a CA_BUNDLE file or directory + with certificates of trusted CAs --debug Print debug information --ignore ... Ignore extra directories, each separated by a comma --no-follow-links Do not follow symbolic links in the project diff --git a/pipreqs/pipreqs.py b/pipreqs/pipreqs.py index 7b1f7e5..2bbb552 100644 --- a/pipreqs/pipreqs.py +++ b/pipreqs/pipreqs.py @@ -187,6 +187,7 @@ def get_imports_info( pypi_server="https://pypi.python.org/pypi/", proxy=None, verify=None, + c=None, ): result = [] diff --git a/requirements-dev.txt b/requirements-dev.txt index e87d699..de3d53b 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,3 +1,4 @@ black flake8 tox +python-dotenv # optional to use .env file instead of environment variables diff --git a/setup.py b/setup.py index 8b826ed..6506d54 100755 --- a/setup.py +++ b/setup.py @@ -17,6 +17,9 @@ with open('HISTORY.rst') as history_file: requirements = [ 'docopt', 'yarg' ] +tests_requirements = [ + 'python-dotenv' +] setup( name='pipreqs', @@ -49,6 +52,7 @@ setup( 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', ], + tests_require=tests_requirements, test_suite='tests', entry_points={ 'console_scripts': [ diff --git a/tests/.env.test.example b/tests/.env.test.example new file mode 100644 index 0000000..5e9f357 --- /dev/null +++ b/tests/.env.test.example @@ -0,0 +1,8 @@ +# create a new file named `.env.test` +# and assign CA_BUNDLE to your system path\ca.pem file + +CA_BUNDLE=C:\your\path\and\certificates.pem + +# alternatively you can set this value as an environment variable +# $ set CA_BUNDLE="C:\your\path\and\certificates.pem" # for win OS +# $ export CA_BUNDLE="C:\your\path\and\certificates.pem" # for nix OS diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000..b3d1e40 --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1,3 @@ +# .env.test is system specific +# do not check in to repository +.env.test \ No newline at end of file diff --git a/tests/_data_ignore/requirements.txt b/tests/_data_ignore/requirements.txt new file mode 100644 index 0000000..b7f100d --- /dev/null +++ b/tests/_data_ignore/requirements.txt @@ -0,0 +1,12 @@ +asposestorage==1.0.2 +beautifulsoup4==4.11.1 +boto==2.49.0 +docopt==0.6.2 +Flask==2.2.2 +ipython==8.8.0 +nose==1.3.7 +peewee==3.15.4 +pyflakes==3.0.1 +requests==2.28.2 +SQLAlchemy==1.4.46 +ujson==5.7.0 diff --git a/tests/settings.py b/tests/settings.py new file mode 100644 index 0000000..f5698b6 --- /dev/null +++ b/tests/settings.py @@ -0,0 +1,16 @@ +import importlib +import os + +CA_BUNDLE = os.environ.get("CA_BUNDLE") + +if CA_BUNDLE is None and importlib.find_loader("dotenv"): + # optional loading of values from .env.test file + from pathlib import Path + + import dotenv + + env_test_path = Path(os.path.dirname(__file__) + "/.env.test") + config = dotenv.dotenv_values(env_test_path) + + if config is not None: + CA_BUNDLE = config["CA_BUNDLE"] diff --git a/tests/test_pipreqs.py b/tests/test_pipreqs.py index 6e1510f..1c861ba 100644 --- a/tests/test_pipreqs.py +++ b/tests/test_pipreqs.py @@ -6,6 +6,11 @@ test_pipreqs ---------------------------------- Tests for `pipreqs` module. + +Environment variables used to mock arguments +e.g., +$ set CA_BUNDLE="certificates.pem" # for win OS +$ export CA_BUNDLE="certificates.pem" # for nix OS """ import os @@ -14,48 +19,55 @@ import unittest import requests from pipreqs import pipreqs +from .settings import CA_BUNDLE class TestPipreqs(unittest.TestCase): - def setUp(self): self.modules = [ - 'flask', 'requests', 'sqlalchemy', 'docopt', 'boto', 'ipython', - 'pyflakes', 'nose', 'analytics', 'flask_seasurf', 'peewee', - 'ujson', 'nonexistendmodule', 'bs4', - 'after_method_is_valid_even_if_not_pep8' - ] - self.modules2 = ['beautifulsoup4'] - self.local = ["docopt", "requests", "nose", 'pyflakes'] + "flask", + "requests", + "sqlalchemy", + "docopt", + "boto", + "ipython", + "pyflakes", + "nose", + "analytics", + "flask_seasurf", + "peewee", + "ujson", + "nonexistendmodule", + "bs4", + "after_method_is_valid_even_if_not_pep8", + ] + self.modules2 = ["beautifulsoup4"] + self.local = ["docopt", "requests", "nose", "pyflakes"] self.project = os.path.join(os.path.dirname(__file__), "_data") self.project_clean = os.path.join( - os.path.dirname(__file__), - "_data_clean" - ) + os.path.dirname(__file__), "_data_clean" + ) self.project_invalid = os.path.join( - os.path.dirname(__file__), - "_invalid_data" - ) + os.path.dirname(__file__), "_invalid_data" + ) self.project_with_ignore_directory = os.path.join( - os.path.dirname(__file__), - "_data_ignore" - ) + os.path.dirname(__file__), "_data_ignore" + ) self.project_with_duplicated_deps = os.path.join( - os.path.dirname(__file__), - "_data_duplicated_deps" - ) + os.path.dirname(__file__), "_data_duplicated_deps" + ) self.requirements_path = os.path.join(self.project, "requirements.txt") self.alt_requirement_path = os.path.join( - self.project, - "requirements2.txt" - ) + self.project, "requirements2.txt" + ) def test_get_all_imports(self): imports = pipreqs.get_all_imports(self.project) self.assertEqual(len(imports), 15) for item in imports: self.assertTrue( - item.lower() in self.modules, "Import is missing: " + item) + item.lower() in self.modules, "Import is missing: " + item + ) self.assertFalse("time" in imports) self.assertFalse("logging" in imports) self.assertFalse("curses" in imports) @@ -74,26 +86,30 @@ class TestPipreqs(unittest.TestCase): Test that invalid python files cannot be imported. """ self.assertRaises( - SyntaxError, pipreqs.get_all_imports, self.project_invalid) + SyntaxError, pipreqs.get_all_imports, self.project_invalid + ) def test_get_imports_info(self): """ Test to see that the right number of packages were found on PyPI """ imports = pipreqs.get_all_imports(self.project) - with_info = pipreqs.get_imports_info(imports) + with_info = pipreqs.get_imports_info( + imports, proxy=None, verify=CA_BUNDLE + ) # Should contain 10 items without the "nonexistendmodule" and # "after_method_is_valid_even_if_not_pep8" self.assertEqual(len(with_info), 13) for item in with_info: self.assertTrue( - item['name'].lower() in self.modules, - "Import item appears to be missing " + item['name']) + item["name"].lower() in self.modules, + "Import item appears to be missing " + item["name"], + ) def test_get_pkg_names(self): - pkgs = ['jury', 'Japan', 'camel', 'Caroline'] + pkgs = ["jury", "Japan", "camel", "Caroline"] actual_output = pipreqs.get_pkg_names(pkgs) - expected_output = ['camel', 'Caroline', 'Japan', 'jury'] + expected_output = ["camel", "Caroline", "Japan", "jury"] self.assertEqual(actual_output, expected_output) def test_get_use_local_only(self): @@ -108,22 +124,34 @@ class TestPipreqs(unittest.TestCase): # should find only docopt and requests imports_with_info = pipreqs.get_import_local(self.modules) for item in imports_with_info: - self.assertTrue(item['name'].lower() in self.local) + self.assertTrue(item["name"].lower() in self.local) def test_init(self): """ Test that all modules we will test upon are in requirements file """ - pipreqs.init({'': self.project, '--savepath': None, '--print': False, - '--use-local': None, '--force': True, '--proxy':None, '--pypi-server':None, - '--diff': None, '--clean': None, '--mode': None}) + pipreqs.init( + { + "": self.project, + "--savepath": None, + "--print": False, + "--use-local": None, + "--force": True, + "--proxy": None, + "--verify": CA_BUNDLE, + "--pypi-server": None, + "--diff": None, + "--clean": None, + "--mode": None, + } + ) assert os.path.exists(self.requirements_path) == 1 with open(self.requirements_path, "r") as f: data = f.read().lower() for item in self.modules[:-3]: self.assertTrue(item.lower() in data) # It should be sorted based on names. - data = data.strip().split('\n') + data = data.strip().split("\n") self.assertEqual(data, sorted(data)) def test_init_local_only(self): @@ -131,9 +159,21 @@ class TestPipreqs(unittest.TestCase): Test that items listed in requirements.text are the same as locals expected """ - pipreqs.init({'': self.project, '--savepath': None, '--print': False, - '--use-local': True, '--force': True, '--proxy':None, '--pypi-server':None, - '--diff': None, '--clean': None, '--mode': None}) + pipreqs.init( + { + "": self.project, + "--savepath": None, + "--print": False, + "--use-local": True, + "--force": True, + "--proxy": None, + "--verify": CA_BUNDLE, + "--pypi-server": None, + "--diff": None, + "--clean": None, + "--mode": None, + } + ) assert os.path.exists(self.requirements_path) == 1 with open(self.requirements_path, "r") as f: data = f.readlines() @@ -146,9 +186,20 @@ class TestPipreqs(unittest.TestCase): Test that we can save requirements.txt correctly to a different path """ - pipreqs.init({'': self.project, '--savepath': self.alt_requirement_path, - '--use-local': None, '--proxy':None, '--pypi-server':None, '--print': False, - '--diff': None, '--clean': None, '--mode': None}) + pipreqs.init( + { + "": self.project, + "--savepath": self.alt_requirement_path, + "--use-local": None, + "--proxy": None, + "--verify": CA_BUNDLE, + "--pypi-server": None, + "--print": False, + "--diff": None, + "--clean": None, + "--mode": None, + } + ) assert os.path.exists(self.alt_requirement_path) == 1 with open(self.alt_requirement_path, "r") as f: data = f.read().lower() @@ -164,9 +215,21 @@ class TestPipreqs(unittest.TestCase): """ with open(self.requirements_path, "w") as f: 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, '--mode': None}) + pipreqs.init( + { + "": self.project, + "--savepath": None, + "--use-local": None, + "--force": None, + "--proxy": None, + "--verify": CA_BUNDLE, + "--pypi-server": None, + "--print": False, + "--diff": None, + "--clean": None, + "--mode": None, + } + ) assert os.path.exists(self.requirements_path) == 1 with open(self.requirements_path, "r") as f: data = f.read().lower() @@ -182,40 +245,59 @@ class TestPipreqs(unittest.TestCase): import_name_with_alias = "requests as R" expected_import_name_without_alias = "requests" import_name_without_aliases = pipreqs.get_name_without_alias( - import_name_with_alias) + import_name_with_alias + ) self.assertEqual( - import_name_without_aliases, - expected_import_name_without_alias - ) + import_name_without_aliases, expected_import_name_without_alias + ) def test_custom_pypi_server(self): """ Test that trying to get a custom pypi sever fails correctly """ self.assertRaises( - requests.exceptions.MissingSchema, pipreqs.init, - {'': self.project, '--savepath': None, '--print': False, - '--use-local': None, '--force': True, '--proxy': None, - '--pypi-server': 'nonexistent'} - ) + requests.exceptions.MissingSchema, + pipreqs.init, + { + "": self.project, + "--savepath": None, + "--print": False, + "--use-local": None, + "--force": True, + "--proxy": None, + "--verify": CA_BUNDLE, + "--pypi-server": "nonexistent", + }, + ) def test_ignored_directory(self): """ Test --ignore parameter """ pipreqs.init( - {'': self.project_with_ignore_directory, '--savepath': None, - '--print': False, '--use-local': None, '--force': True, - '--proxy':None, '--pypi-server':None, - '--ignore':'.ignored_dir,.ignore_second', - '--diff': None, - '--clean': None, - '--mode': None - } + { + "": self.project_with_ignore_directory, + "--savepath": None, + "--print": False, + "--use-local": None, + "--force": True, + "--proxy": None, + "--verify": CA_BUNDLE, + "--pypi-server": None, + "--ignore": ".ignored_dir,.ignore_second", + "--diff": None, + "--clean": None, + "--mode": None, + } ) - with open(os.path.join(self.project_with_ignore_directory, "requirements.txt"), "r") as f: + with open( + os.path.join( + self.project_with_ignore_directory, "requirements.txt" + ), + "r", + ) as f: data = f.read().lower() - for item in ['click', 'getpass']: + for item in ["click", "getpass"]: self.assertFalse(item.lower() in data) def test_dynamic_version_no_pin_scheme(self): @@ -223,17 +305,28 @@ class TestPipreqs(unittest.TestCase): Test --mode=no-pin """ 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, - '--mode': 'no-pin' - } + { + "": self.project_with_ignore_directory, + "--savepath": None, + "--print": False, + "--use-local": None, + "--force": True, + "--proxy": None, + "--verify": CA_BUNDLE, + "--pypi-server": None, + "--diff": None, + "--clean": None, + "--mode": "no-pin", + } ) - with open(os.path.join(self.project_with_ignore_directory, "requirements.txt"), "r") as f: + with open( + os.path.join( + self.project_with_ignore_directory, "requirements.txt" + ), + "r", + ) as f: data = f.read().lower() - for item in ['beautifulsoup4', 'boto']: + for item in ["beautifulsoup4", "boto"]: self.assertTrue(item.lower() in data) def test_dynamic_version_gt_scheme(self): @@ -241,20 +334,30 @@ class TestPipreqs(unittest.TestCase): Test --mode=gt """ 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, - '--mode': 'gt' - } + { + "": self.project_with_ignore_directory, + "--savepath": None, + "--print": False, + "--use-local": None, + "--force": True, + "--proxy": None, + "--verify": CA_BUNDLE, + "--pypi-server": None, + "--diff": None, + "--clean": None, + "--mode": "gt", + } ) - with open(os.path.join(self.project_with_ignore_directory, "requirements.txt"), "r") as f: + with open( + os.path.join( + self.project_with_ignore_directory, "requirements.txt" + ), + "r", + ) as f: data = f.readlines() for item in data: - symbol = '>=' - message = 'symbol is not in item' + symbol = ">=" + message = "symbol is not in item" self.assertIn(symbol, item, message) def test_dynamic_version_compat_scheme(self): @@ -262,20 +365,30 @@ class TestPipreqs(unittest.TestCase): Test --mode=compat """ 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, - '--mode': 'compat' - } + { + "": self.project_with_ignore_directory, + "--savepath": None, + "--print": False, + "--use-local": None, + "--force": True, + "--proxy": None, + "--verify": CA_BUNDLE, + "--pypi-server": None, + "--diff": None, + "--clean": None, + "--mode": "compat", + } ) - with open(os.path.join(self.project_with_ignore_directory, "requirements.txt"), "r") as f: + with open( + os.path.join( + self.project_with_ignore_directory, "requirements.txt" + ), + "r", + ) as f: data = f.readlines() for item in data: - symbol = '~=' - message = 'symbol is not in item' + symbol = "~=" + message = "symbol is not in item" self.assertIn(symbol, item, message) def test_clean(self): @@ -283,18 +396,36 @@ class TestPipreqs(unittest.TestCase): Test --clean parameter """ pipreqs.init( - {'': self.project, '--savepath': None, '--print': False, - '--use-local': None, '--force': True, '--proxy': None, - '--pypi-server': None, '--diff': None, '--clean': None, - '--mode': None} - ) + { + "": self.project, + "--savepath": None, + "--print": False, + "--use-local": None, + "--force": True, + "--proxy": None, + "--verify": CA_BUNDLE, + "--pypi-server": None, + "--diff": None, + "--clean": None, + "--mode": None, + } + ) assert os.path.exists(self.requirements_path) == 1 pipreqs.init( - {'': self.project, '--savepath': None, '--print': False, - '--use-local': None, '--force': None, '--proxy': None, - '--pypi-server': None, '--diff': None, - '--clean': self.requirements_path, '--mode': 'non-pin'} - ) + { + "": self.project, + "--savepath": None, + "--print": False, + "--use-local": None, + "--force": None, + "--proxy": None, + "--verify": CA_BUNDLE, + "--pypi-server": None, + "--diff": None, + "--clean": self.requirements_path, + "--mode": "non-pin", + } + ) with open(self.requirements_path, "r") as f: data = f.read().lower() for item in self.modules[:-3]: @@ -304,21 +435,39 @@ class TestPipreqs(unittest.TestCase): """ Test --clean parameter when there are imports to clean """ - cleaned_module = 'sqlalchemy' + cleaned_module = "sqlalchemy" pipreqs.init( - {'': self.project, '--savepath': None, '--print': False, - '--use-local': None, '--force': True, '--proxy': None, - '--pypi-server': None, '--diff': None, '--clean': None, - '--mode': None} - ) + { + "": self.project, + "--savepath": None, + "--print": False, + "--use-local": None, + "--force": True, + "--proxy": None, + "--verify": CA_BUNDLE, + "--pypi-server": None, + "--diff": None, + "--clean": None, + "--mode": None, + } + ) assert os.path.exists(self.requirements_path) == 1 modules_clean = [m for m in self.modules if m != cleaned_module] pipreqs.init( - {'': self.project_clean, '--savepath': None, - '--print': False, '--use-local': None, '--force': None, - '--proxy': None, '--pypi-server': None, '--diff': None, - '--clean': self.requirements_path, '--mode': 'non-pin'} - ) + { + "": self.project_clean, + "--savepath": None, + "--print": False, + "--use-local": None, + "--force": None, + "--proxy": None, + "--verify": CA_BUNDLE, + "--pypi-server": None, + "--diff": None, + "--clean": self.requirements_path, + "--mode": "non-pin", + } + ) with open(self.requirements_path, "r") as f: data = f.read().lower() self.assertTrue(cleaned_module not in data) @@ -337,5 +486,5 @@ class TestPipreqs(unittest.TestCase): pass -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tox.ini b/tox.ini index aea10ec..ceb5265 100644 --- a/tox.ini +++ b/tox.ini @@ -1,11 +1,12 @@ [tox] -envlist = py37, py38, py39, pypy3, flake8 +envlist = py37, py38, py39, py310, pypy3, flake8 [gh-actions] python = 3.7: py37 3.8: py38 3.9: py39 + 3.10: py310 pypy-3.7: pypy3 [testenv] @@ -13,4 +14,39 @@ setenv = PYTHONPATH = {toxinidir}:{toxinidir}/pipreqs commands = python setup.py test deps = - -r{toxinidir}/requirements.txt \ No newline at end of file + -r{toxinidir}/requirements.txt + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# tox -e dev311 +# Python 3.11 runtime error +# - py310 and py311 were not tested prior to this submission +# - not related to this submission (but this needs further debug to understand) +# +# ====================================================================== +# FAIL: test_get_use_local_only (tests.test_pipreqs.TestPipreqs.test_get_use_local_only) +# Test without checking PyPI, check to see if names of local +# ---------------------------------------------------------------------- +# Traceback (most recent call last): +# File "c:\code\ghcwm\py_dev\src\autoreq\pub\c-w-m\pipreqs\tests\test_pipreqs.py", line 127, in test_get_use_local_only +# self.assertTrue(item["name"].lower() in self.local) +# AssertionError: False is not true +# +# ====================================================================== +# FAIL: test_init_local_only (tests.test_pipreqs.TestPipreqs.test_init_local_only) +# Test that items listed in requirements.text are the same +# ---------------------------------------------------------------------- +# Traceback (most recent call last): +# File "c:\code\ghcwm\py_dev\src\autoreq\pub\c-w-m\pipreqs\tests\test_pipreqs.py", line 182, in test_init_local_only +# self.assertTrue(item[0].lower() in self.local) +# AssertionError: False is not true +# +# ---------------------------------------------------------------------- +[testenv:dev311] +description = development mode environment for debug of py311 +basepython = python3.11 +deps = {[testenv]deps} +# development mode for debuging +usedevelop = True +commands = python setup.py test + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From c83d7154c6f33ced068568f4f9983771d231a489 Mon Sep 17 00:00:00 2001 From: craigmiller Date: Sun, 15 Jan 2023 00:23:09 -0700 Subject: [PATCH 6/7] sync with master --- .gitignore | 8 + .vscode/extensions.json | 2 - .vscode/settings.json | 26 +-- CONTRIBUTING.rst | 7 +- README.rst | 4 + pipreqs/pipreqs.py | 176 ++++++++----------- requirements-dev.txt | 34 +++- requirements.txt | 3 +- setup.py | 5 +- tests/_data/test.py | 76 ++++---- tests/_data_clean/test.py | 74 ++++---- tests/_data_ignore/.ignore_second/ignored.py | 2 +- tests/_data_ignore/test.py | 69 ++++---- tests/settings.py | 12 ++ tests/test_pipreqs.py | 134 ++++++-------- 15 files changed, 325 insertions(+), 307 deletions(-) diff --git a/.gitignore b/.gitignore index 45a067a..f05ae8c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,11 @@ +# fix_SSLError ----- +.env38/ +.vscode/ +pipreqs_flake8_results.txt +pipreqs_setup_test_results.txt +pipreqs_tox_results.txt +# ------------------ + *.py[cod] # C extensions diff --git a/.vscode/extensions.json b/.vscode/extensions.json index f5c874b..f813aaf 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -45,8 +45,6 @@ "ms-vscode.test-adapter-converter", // - Test Explorer UI "hbenl.vscode-test-explorer", - // - python-tox - "the-compiler.python-tox", // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Rust diff --git a/.vscode/settings.json b/.vscode/settings.json index b1f764a..ef5369f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,25 +1,25 @@ { "workbench.colorCustomizations": { - "activityBar.activeBackground": "#990000", - "activityBar.background": "#990000", - "activityBar.foreground": "#e7e7e7", - "activityBar.inactiveForeground": "#e7e7e799", - "activityBarBadge.background": "#000000", - "activityBarBadge.foreground": "#e7e7e7", + "activityBar.activeBackground": "#5d98cd", + "activityBar.background": "#5d98cd", + "activityBar.foreground": "#15202b", + "activityBar.inactiveForeground": "#15202b99", + "activityBarBadge.background": "#f0cee0", + "activityBarBadge.foreground": "#15202b", "commandCenter.border": "#e7e7e799", - "sash.hoverBorder": "#990000", - "statusBar.background": "#660000", + "sash.hoverBorder": "#5d98cd", + "statusBar.background": "#3a7fbd", "statusBar.foreground": "#e7e7e7", - "statusBarItem.hoverBackground": "#990000", - "statusBarItem.remoteBackground": "#660000", + "statusBarItem.hoverBackground": "#5d98cd", + "statusBarItem.remoteBackground": "#3a7fbd", "statusBarItem.remoteForeground": "#e7e7e7", - "titleBar.activeBackground": "#660000", + "titleBar.activeBackground": "#3a7fbd", "titleBar.activeForeground": "#e7e7e7", - "titleBar.inactiveBackground": "#66000099", + "titleBar.inactiveBackground": "#3a7fbd99", "titleBar.inactiveForeground": "#e7e7e799" }, "python.testing.unittestArgs": ["-v", "-s", "./tests", "-p", "test_*.py"], "python.testing.pytestEnabled": false, "python.testing.unittestEnabled": true, - "peacock.color": "#660000" + "peacock.color": "#3a7fbd" } diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 60fcb82..3229623 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -77,11 +77,16 @@ Ready to contribute? Here's how to set up `pipreqs` for local development. 5. When you're done making changes, check that your changes pass flake8 and the tests, including testing other Python versions with tox:: $ flake8 pipreqs tests - $ python setup.py test + $ python setup.py test > pipreqs_setup_test_result.txt $ tox To get flake8 and tox, just pip install them into your virtualenv. (or $pip install -r requirements-dev.txt) + You may also need to provide `CA_BUNDLE` as an environment variable or parameter in the `tests/.env.test` file. + + $ export CA_BUNDLE="/certs/path/certificates.pem" # for nix OS + $ set CA_BUNDLE="C:/certs/path/certificates.pem" # for win OS + 6. Commit your changes and push your branch to GitHub:: $ git add . diff --git a/README.rst b/README.rst index fe5c87a..e1d1931 100644 --- a/README.rst +++ b/README.rst @@ -46,6 +46,10 @@ Usage $ export HTTPS_PROXY="https://10.10.1.10:1080" --verify Use verify to provide a CA_BUNDLE file or directory with certificates of trusted CAs + You can also just set the environment variable in + your terminal: (`export` for nix and `set` for win) + $ export CA_BUNDLE="/certs/path/certificates.pem" + $ set CA_BUNDLE="C:/certs/path/certificates.pem" --debug Print debug information --ignore ... Ignore extra directories, each separated by a comma --no-follow-links Do not follow symbolic links in the project diff --git a/pipreqs/pipreqs.py b/pipreqs/pipreqs.py index 2bbb552..285a523 100644 --- a/pipreqs/pipreqs.py +++ b/pipreqs/pipreqs.py @@ -20,6 +20,10 @@ Options: $ export HTTPS_PROXY="https://10.10.1.10:1080" --verify Use verify to provide a CA_BUNDLE file or directory with certificates of trusted CAs + You can also just set the environment variable in + your terminal: (`export` for nix and `set` for win) + $ export CA_BUNDLE="/certs/path/certificates.pem" #or + $ set CA_BUNDLE="C:/certs/path/certificates.pem" --debug Print debug information --ignore ... Ignore extra directories, each separated by a comma --no-follow-links Do not follow symbolic links in the project @@ -54,13 +58,14 @@ from yarg.exceptions import HTTPError from pipreqs import __version__ REGEXP = [ - re.compile(r"^import (.+)$"), - re.compile(r"^from ((?!\.+).*?) import (?:.*)$"), + re.compile(r'^import (.+)$'), + re.compile(r'^from ((?!\.+).*?) import (?:.*)$') ] +CA_BUNDLE = os.environ.get("CA_BUNDLE") @contextmanager -def _open(filename=None, mode="r"): +def _open(filename=None, mode='r'): """Open a file or ``sys.stdout`` depending on the provided filename. Args: @@ -73,13 +78,13 @@ def _open(filename=None, mode="r"): A file handle. """ - if not filename or filename == "-": - if not mode or "r" in mode: + if not filename or filename == '-': + if not mode or 'r' in mode: file = sys.stdin - elif "w" in mode: + elif 'w' in mode: file = sys.stdout else: - raise ValueError("Invalid mode for file: {}".format(mode)) + raise ValueError('Invalid mode for file: {}'.format(mode)) else: file = open(filename, mode) @@ -91,8 +96,7 @@ def _open(filename=None, mode="r"): def get_all_imports( - path, encoding=None, extra_ignore_dirs=None, follow_links=True -): + path, encoding=None, extra_ignore_dirs=None, follow_links=True): imports = set() raw_imports = set() candidates = [] @@ -141,11 +145,11 @@ def get_all_imports( # Cleanup: We only want to first part of the import. # Ex: from django.conf --> django.conf. But we only want django # as an import. - cleaned_name, _, _ = name.partition(".") + cleaned_name, _, _ = name.partition('.') imports.add(cleaned_name) packages = imports - (set(candidates) & imports) - logging.debug("Found packages: {0}".format(packages)) + logging.debug('Found packages: {0}'.format(packages)) with open(join("stdlib"), "r") as f: data = {x.strip() for x in f} @@ -159,34 +163,26 @@ def filter_line(line): def generate_requirements_file(path, imports, symbol): with _open(path, "w") as out_file: - logging.debug( - "Writing {num} requirements: {imports} to {file}".format( - num=len(imports), - file=path, - imports=", ".join([x["name"] for x in imports]), - ) - ) - fmt = "{name}" + symbol + "{version}" - out_file.write( - "\n".join( - fmt.format(**item) - if item["version"] - else "{name}".format(**item) - for item in imports - ) - + "\n" - ) + logging.debug('Writing {num} requirements: {imports} to {file}'.format( + num=len(imports), + file=path, + imports=", ".join([x['name'] for x in imports]) + )) + fmt = '{name}' + symbol + '{version}' + out_file.write('\n'.join( + fmt.format(**item) if item['version'] else '{name}'.format(**item) + for item in imports) + '\n') def output_requirements(imports, symbol): - generate_requirements_file("-", imports, symbol) + generate_requirements_file('-', imports, symbol) def get_imports_info( imports, pypi_server="https://pypi.python.org/pypi/", proxy=None, - verify=None, + verify=CA_BUNDLE, c=None, ): result = [] @@ -199,20 +195,18 @@ def get_imports_info( verify=verify, ) if response.status_code == 200: - if hasattr(response.content, "decode"): + if hasattr(response.content, 'decode'): data = json2package(response.content.decode()) else: data = json2package(response.content) elif response.status_code >= 300: - raise HTTPError( - status_code=response.status_code, reason=response.reason - ) + raise HTTPError(status_code=response.status_code, + reason=response.reason) except HTTPError: logging.debug( - "Package %s does not exist or network problems", item - ) + 'Package %s does not exist or network problems', item) continue - result.append({"name": item, "version": data.latest_release_id}) + result.append({'name': item, 'version': data.latest_release_id}) return result @@ -232,20 +226,16 @@ def get_locally_installed_packages(encoding=None): # TODO: What errors do we intend to suppress here? continue for i_item in package_import: - if (i_item not in ignore) and ( - package[0] not in ignore - ): + if ((i_item not in ignore) and + (package[0] not in ignore)): version = None if len(package) > 1: - version = ( - package[1] - .replace(".dist", "") - .replace(".egg", "") - ) + version = package[1].replace( + ".dist", "").replace(".egg", "") packages[i_item] = { - "version": version, - "name": package[0], + 'version': version, + 'name': package[0] } return packages @@ -258,7 +248,12 @@ def get_import_local(imports, encoding=None): result.append(local[item.lower()]) # removing duplicates of package/version - result_unique = [dict(t) for t in set([tuple(d.items()) for d in result])] + result_unique = [ + dict(t) + for t in set([ + tuple(d.items()) for d in result + ]) + ] return result_unique @@ -289,7 +284,7 @@ def get_name_without_alias(name): match = REGEXP[0].match(name.strip()) if match: name = match.groups(0)[0] - return name.partition(" as ")[0].partition(".")[0].strip() + return name.partition(' as ')[0].partition('.')[0].strip() def join(f): @@ -375,8 +370,7 @@ def diff(file_, imports): logging.info( "The following modules are in {} but do not seem to be imported: " - "{}".format(file_, ", ".join(x for x in modules_not_imported)) - ) + "{}".format(file_, ", ".join(x for x in modules_not_imported))) def clean(file_, imports): @@ -424,22 +418,30 @@ def dynamic_versioning(scheme, imports): def init(args): - encoding = args.get("--encoding") - extra_ignore_dirs = args.get("--ignore") - follow_links = not args.get("--no-follow-links") - input_path = args[""] + encoding = args.get('--encoding') + extra_ignore_dirs = args.get('--ignore') + follow_links = not args.get('--no-follow-links') + input_path = args[''] if input_path is None: input_path = os.path.abspath(os.curdir) if extra_ignore_dirs: - extra_ignore_dirs = extra_ignore_dirs.split(",") + extra_ignore_dirs = extra_ignore_dirs.split(',') - candidates = get_all_imports( - input_path, - encoding=encoding, - extra_ignore_dirs=extra_ignore_dirs, - follow_links=follow_links, - ) + path = (args["--savepath"] if args["--savepath"] else + os.path.join(input_path, "requirements.txt")) + if (not args["--print"] + and not args["--savepath"] + and not args["--force"] + and os.path.exists(path)): + logging.warning("requirements.txt already exists, " + "use --force to overwrite it") + return + + candidates = get_all_imports(input_path, + encoding=encoding, + extra_ignore_dirs=extra_ignore_dirs, + follow_links=follow_links) candidates = get_pkg_names(candidates) logging.debug("Found imports: " + ", ".join(candidates)) pypi_server = "https://pypi.python.org/pypi/" @@ -449,36 +451,27 @@ def init(args): pypi_server = args["--pypi-server"] if args["--proxy"]: - proxy = {"http": args["--proxy"], "https": args["--proxy"]} + proxy = {'http': args["--proxy"], 'https': args["--proxy"]} if args["--verify"]: verify = args["--verify"] if args["--use-local"]: logging.debug( - "Getting package information ONLY from local installation." - ) + "Getting package information ONLY from local installation.") imports = get_import_local(candidates, encoding=encoding) else: logging.debug("Getting packages information from Local/PyPI") local = get_import_local(candidates, encoding=encoding) # Get packages that were not found locally - difference = [ - x - for x in candidates - if x.lower() not in [z["name"].lower() for z in local] - ] - imports = local + get_imports_info( - difference, proxy=proxy, verify=verify, pypi_server=pypi_server - ) + difference = [x for x in candidates + if x.lower() not in [z['name'].lower() for z in local]] + imports = local + get_imports_info(difference, + proxy=proxy, + verify=verify, + pypi_server=pypi_server) # sort imports based on lowercase name of package, similar to `pip freeze`. - imports = sorted(imports, key=lambda x: x["name"].lower()) - - path = ( - args["--savepath"] - if args["--savepath"] - else os.path.join(input_path, "requirements.txt") - ) + imports = sorted(imports, key=lambda x: x['name'].lower()) if args["--diff"]: diff(args["--diff"], imports) @@ -488,26 +481,13 @@ def init(args): clean(args["--clean"], imports) return - if ( - not args["--print"] - and not args["--savepath"] - and not args["--force"] - and os.path.exists(path) - ): - logging.warning( - "requirements.txt already exists, " "use --force to overwrite it" - ) - return - if args["--mode"]: scheme = args.get("--mode") if scheme in ["compat", "gt", "no-pin"]: imports, symbol = dynamic_versioning(scheme, imports) else: - raise ValueError( - "Invalid argument for mode flag, " - "use 'compat', 'gt' or 'no-pin' instead" - ) + raise ValueError("Invalid argument for mode flag, " + "use 'compat', 'gt' or 'no-pin' instead") else: symbol = "==" @@ -521,8 +501,8 @@ def init(args): def main(): # pragma: no cover args = docopt(__doc__, version=__version__) - log_level = logging.DEBUG if args["--debug"] else logging.INFO - logging.basicConfig(level=log_level, format="%(levelname)s: %(message)s") + log_level = logging.DEBUG if args['--debug'] else logging.INFO + logging.basicConfig(level=log_level, format='%(levelname)s: %(message)s') try: init(args) @@ -530,5 +510,5 @@ def main(): # pragma: no cover sys.exit(0) -if __name__ == "__main__": +if __name__ == '__main__': main() # pragma: no cover diff --git a/requirements-dev.txt b/requirements-dev.txt index de3d53b..322f7d9 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,4 +1,32 @@ -black +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# > python38 -m venv .env38 +# # activate (.env38) virtual environment + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# upgrade pip +# (.env38)> python.exe -m pip install --upgrade pip + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# development packages +# (.env38)> pip install -r requirements-dev.txt + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# development mode installation of `pipreqs` +# (.env38)> pip install -e . + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# fix_SSLError tests.settings (optional) use of .env file +# alternative would be to set CA_BUNDLE environment variable +python-dotenv + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# required per CONTRIBUTING workflow flake8 -tox -python-dotenv # optional to use .env file instead of environment variables +tox # only needed in the environment from which tox is run + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# (optional, personal choice) +# vscode settings: "python.formatting.provider": "black", +#black + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/requirements.txt b/requirements.txt index 959d1b7..3dc71a1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ wheel==0.23.0 Yarg==0.1.9 -docopt==0.6.2 \ No newline at end of file +docopt==0.6.2 +requests==2.28.2 diff --git a/setup.py b/setup.py index 6506d54..f45c23b 100755 --- a/setup.py +++ b/setup.py @@ -7,7 +7,6 @@ except ImportError: from pipreqs import __version__ - with open('README.rst') as readme_file: readme = readme_file.read() @@ -15,10 +14,10 @@ with open('HISTORY.rst') as history_file: history = history_file.read().replace('.. :changelog:', '') requirements = [ - 'docopt', 'yarg' + 'docopt', 'yarg', 'requests' ] tests_requirements = [ - 'python-dotenv' + 'python-dotenv', 'flake8' ] setup( diff --git a/tests/_data/test.py b/tests/_data/test.py index 73c15d2..fdb6ec3 100644 --- a/tests/_data/test.py +++ b/tests/_data/test.py @@ -1,51 +1,56 @@ """unused import""" # pylint: disable=undefined-all-variable, import-error, no-absolute-import, too-few-public-methods, missing-docstring -from __future__ import print_function - -import atexit -import curses -import importlib # html/notebookapp.py -import logging -import os -import os.path as test # [unused-import] -import signal -import sqlite3 -import sys -import time import xml.etree # [unused-import] import xml.sax # [unused-import] -# astroid -# setuptools -import zipimport # manager.py -# +1:[unused-import,unused-import] -from collections import Counter, OrderedDict, deque -# twisted -from importlib import invalidate_caches # python/test/test_deprecate.py -# IPython -from importlib.machinery import all_suffixes # core/completerlib.py +import os.path as test # [unused-import] from sys import argv as test2 # [unused-import] from sys import flags # [unused-import] - -# see issue #88 -import analytics -import boto as b -import bs4 -# import django -import flask.ext.somext # # # -import flask_seasurf -import nonexistendmodule -import peewee as p +# +1:[unused-import,unused-import] +from collections import deque, OrderedDict, Counter # All imports above should be ignored import requests # [unused-import] -from docopt import docopt + +# setuptools +import zipimport # command/easy_install.py + +# twisted +from importlib import invalidate_caches # python/test/test_deprecate.py + +# astroid +import zipimport # manager.py +# IPython +from importlib.machinery import all_suffixes # core/completerlib.py +import importlib # html/notebookapp.py + from IPython.utils.importstring import import_item # Many files -# Nose -from nose.importer import Importer, add_path, remove_path # loader.py + # pyflakes # test/test_doctests.py from pyflakes.test.test_imports import Test as TestImports -from sqlalchemy import model +# Nose +from nose.importer import Importer, add_path, remove_path # loader.py + +# see issue #88 +import analytics +import flask_seasurf + +import atexit +from __future__ import print_function +from docopt import docopt +import curses, logging, sqlite3 +import logging +import os +import sqlite3 +import time +import sys +import signal +import bs4 +import nonexistendmodule +import boto as b, peewee as p +# import django +import flask.ext.somext # # # +from sqlalchemy import model try: import ujson as json except ImportError: @@ -57,5 +62,4 @@ import models def main(): pass - import after_method_is_valid_even_if_not_pep8 diff --git a/tests/_data_clean/test.py b/tests/_data_clean/test.py index 13a6d6b..8cffb51 100644 --- a/tests/_data_clean/test.py +++ b/tests/_data_clean/test.py @@ -1,50 +1,55 @@ """unused import""" # pylint: disable=undefined-all-variable, import-error, no-absolute-import, too-few-public-methods, missing-docstring -from __future__ import print_function - -import atexit -import curses -import importlib # html/notebookapp.py -import logging -import os -import os.path as test # [unused-import] -import signal -import sqlite3 -import sys -import time import xml.etree # [unused-import] import xml.sax # [unused-import] -# astroid -# setuptools -import zipimport # manager.py -# +1:[unused-import,unused-import] -from collections import Counter, OrderedDict, deque -# twisted -from importlib import invalidate_caches # python/test/test_deprecate.py -# IPython -from importlib.machinery import all_suffixes # core/completerlib.py +import os.path as test # [unused-import] from sys import argv as test2 # [unused-import] from sys import flags # [unused-import] - -# see issue #88 -import analytics -import boto as b -import bs4 -# import django -import flask.ext.somext # # # -import flask_seasurf -import nonexistendmodule -import peewee as p +# +1:[unused-import,unused-import] +from collections import deque, OrderedDict, Counter # All imports above should be ignored import requests # [unused-import] -from docopt import docopt + +# setuptools +import zipimport # command/easy_install.py + +# twisted +from importlib import invalidate_caches # python/test/test_deprecate.py + +# astroid +import zipimport # manager.py +# IPython +from importlib.machinery import all_suffixes # core/completerlib.py +import importlib # html/notebookapp.py + from IPython.utils.importstring import import_item # Many files -# Nose -from nose.importer import Importer, add_path, remove_path # loader.py + # pyflakes # test/test_doctests.py from pyflakes.test.test_imports import Test as TestImports +# Nose +from nose.importer import Importer, add_path, remove_path # loader.py + +# see issue #88 +import analytics +import flask_seasurf + +import atexit +from __future__ import print_function +from docopt import docopt +import curses, logging, sqlite3 +import logging +import os +import sqlite3 +import time +import sys +import signal +import bs4 +import nonexistendmodule +import boto as b, peewee as p +# import django +import flask.ext.somext # # # # from sqlalchemy import model try: import ujson as json @@ -57,5 +62,4 @@ import models def main(): pass - import after_method_is_valid_even_if_not_pep8 diff --git a/tests/_data_ignore/.ignore_second/ignored.py b/tests/_data_ignore/.ignore_second/ignored.py index 6ea3598..b970ae3 100644 --- a/tests/_data_ignore/.ignore_second/ignored.py +++ b/tests/_data_ignore/.ignore_second/ignored.py @@ -1,2 +1,2 @@ # Everything in here should be ignored -from pattern.web import Twitter, plaintext +from pattern.web import Twitter, plaintext \ No newline at end of file diff --git a/tests/_data_ignore/test.py b/tests/_data_ignore/test.py index f520669..cfd039c 100644 --- a/tests/_data_ignore/test.py +++ b/tests/_data_ignore/test.py @@ -1,48 +1,52 @@ """unused import""" # pylint: disable=undefined-all-variable, import-error, no-absolute-import, too-few-public-methods, missing-docstring -from __future__ import print_function - -import atexit -import curses -import importlib # html/notebookapp.py -import logging -import os -import os.path as test # [unused-import] -import signal -import sqlite3 -import sys -import time import xml.etree # [unused-import] import xml.sax # [unused-import] -# astroid -# setuptools -import zipimport # manager.py -# +1:[unused-import,unused-import] -from collections import Counter, OrderedDict, deque -# twisted -from importlib import invalidate_caches # python/test/test_deprecate.py -# IPython -from importlib.machinery import all_suffixes # core/completerlib.py +import os.path as test # [unused-import] from sys import argv as test2 # [unused-import] from sys import flags # [unused-import] - -import boto as b -import bs4 -# import django -import flask.ext.somext # # # -import nonexistendmodule -import peewee as p +# +1:[unused-import,unused-import] +from collections import deque, OrderedDict, Counter # All imports above should be ignored import requests # [unused-import] -from docopt import docopt + +# setuptools +import zipimport # command/easy_install.py + +# twisted +from importlib import invalidate_caches # python/test/test_deprecate.py + +# astroid +import zipimport # manager.py +# IPython +from importlib.machinery import all_suffixes # core/completerlib.py +import importlib # html/notebookapp.py + from IPython.utils.importstring import import_item # Many files -# Nose -from nose.importer import Importer, add_path, remove_path # loader.py + # pyflakes # test/test_doctests.py from pyflakes.test.test_imports import Test as TestImports -from sqlalchemy import model +# Nose +from nose.importer import Importer, add_path, remove_path # loader.py + +import atexit +from __future__ import print_function +from docopt import docopt +import curses, logging, sqlite3 +import logging +import os +import sqlite3 +import time +import sys +import signal +import bs4 +import nonexistendmodule +import boto as b, peewee as p +# import django +import flask.ext.somext # # # +from sqlalchemy import model try: import ujson as json except ImportError: @@ -54,5 +58,4 @@ import models def main(): pass - import after_method_is_valid_even_if_not_pep8 diff --git a/tests/settings.py b/tests/settings.py index f5698b6..c870b64 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -1,3 +1,15 @@ +""" +Environment variables can be used as a first choice +$ set CA_BUNDLE="certificates.pem" # for win OS +$ export CA_BUNDLE="certificates.pem" # for nix OS + +If environment variables are not found then a second attempt +will be made by loading the values from a .env.test file in +the same directory + +See ./env.test.example for details. +""" + import importlib import os diff --git a/tests/test_pipreqs.py b/tests/test_pipreqs.py index 1c861ba..1b3ff5e 100644 --- a/tests/test_pipreqs.py +++ b/tests/test_pipreqs.py @@ -6,11 +6,6 @@ test_pipreqs ---------------------------------- Tests for `pipreqs` module. - -Environment variables used to mock arguments -e.g., -$ set CA_BUNDLE="certificates.pem" # for win OS -$ export CA_BUNDLE="certificates.pem" # for nix OS """ import os @@ -19,55 +14,54 @@ import unittest import requests from pipreqs import pipreqs -from .settings import CA_BUNDLE + +CA_BUNDLE = os.environ.get("CA_BUNDLE") + +if CA_BUNDLE is None: + from tests.settings import CA_BUNDLE class TestPipreqs(unittest.TestCase): + def setUp(self): self.modules = [ - "flask", - "requests", - "sqlalchemy", - "docopt", - "boto", - "ipython", - "pyflakes", - "nose", - "analytics", - "flask_seasurf", - "peewee", - "ujson", - "nonexistendmodule", - "bs4", - "after_method_is_valid_even_if_not_pep8", - ] - self.modules2 = ["beautifulsoup4"] - self.local = ["docopt", "requests", "nose", "pyflakes"] + 'flask', 'requests', 'sqlalchemy', 'docopt', 'boto', 'ipython', + 'pyflakes', 'nose', 'analytics', 'flask_seasurf', 'peewee', + 'ujson', 'nonexistendmodule', 'bs4', + 'after_method_is_valid_even_if_not_pep8' + ] + self.modules2 = ['beautifulsoup4'] + self.local = ["docopt", "requests", "nose", 'pyflakes'] self.project = os.path.join(os.path.dirname(__file__), "_data") self.project_clean = os.path.join( - os.path.dirname(__file__), "_data_clean" - ) + os.path.dirname(__file__), + "_data_clean" + ) self.project_invalid = os.path.join( - os.path.dirname(__file__), "_invalid_data" - ) + os.path.dirname(__file__), + "_invalid_data" + ) self.project_with_ignore_directory = os.path.join( - os.path.dirname(__file__), "_data_ignore" - ) + os.path.dirname(__file__), + "_data_ignore" + ) self.project_with_duplicated_deps = os.path.join( - os.path.dirname(__file__), "_data_duplicated_deps" - ) + os.path.dirname(__file__), + "_data_duplicated_deps" + ) self.requirements_path = os.path.join(self.project, "requirements.txt") self.alt_requirement_path = os.path.join( - self.project, "requirements2.txt" - ) + self.project, + "requirements2.txt" + ) + def test_get_all_imports(self): imports = pipreqs.get_all_imports(self.project) self.assertEqual(len(imports), 15) for item in imports: self.assertTrue( - item.lower() in self.modules, "Import is missing: " + item - ) + item.lower() in self.modules, "Import is missing: " + item) self.assertFalse("time" in imports) self.assertFalse("logging" in imports) self.assertFalse("curses" in imports) @@ -86,8 +80,7 @@ class TestPipreqs(unittest.TestCase): Test that invalid python files cannot be imported. """ self.assertRaises( - SyntaxError, pipreqs.get_all_imports, self.project_invalid - ) + SyntaxError, pipreqs.get_all_imports, self.project_invalid) def test_get_imports_info(self): """ @@ -102,14 +95,13 @@ class TestPipreqs(unittest.TestCase): self.assertEqual(len(with_info), 13) for item in with_info: self.assertTrue( - item["name"].lower() in self.modules, - "Import item appears to be missing " + item["name"], - ) + item['name'].lower() in self.modules, + "Import item appears to be missing " + item['name']) def test_get_pkg_names(self): - pkgs = ["jury", "Japan", "camel", "Caroline"] + pkgs = ['jury', 'Japan', 'camel', 'Caroline'] actual_output = pipreqs.get_pkg_names(pkgs) - expected_output = ["camel", "Caroline", "Japan", "jury"] + expected_output = ['camel', 'Caroline', 'Japan', 'jury'] self.assertEqual(actual_output, expected_output) def test_get_use_local_only(self): @@ -124,7 +116,7 @@ class TestPipreqs(unittest.TestCase): # should find only docopt and requests imports_with_info = pipreqs.get_import_local(self.modules) for item in imports_with_info: - self.assertTrue(item["name"].lower() in self.local) + self.assertTrue(item['name'].lower() in self.local) def test_init(self): """ @@ -151,7 +143,7 @@ class TestPipreqs(unittest.TestCase): for item in self.modules[:-3]: self.assertTrue(item.lower() in data) # It should be sorted based on names. - data = data.strip().split("\n") + data = data.strip().split('\n') self.assertEqual(data, sorted(data)) def test_init_local_only(self): @@ -245,11 +237,11 @@ class TestPipreqs(unittest.TestCase): import_name_with_alias = "requests as R" expected_import_name_without_alias = "requests" import_name_without_aliases = pipreqs.get_name_without_alias( - import_name_with_alias - ) + import_name_with_alias) self.assertEqual( - import_name_without_aliases, expected_import_name_without_alias - ) + import_name_without_aliases, + expected_import_name_without_alias + ) def test_custom_pypi_server(self): """ @@ -290,14 +282,9 @@ class TestPipreqs(unittest.TestCase): "--mode": None, } ) - with open( - os.path.join( - self.project_with_ignore_directory, "requirements.txt" - ), - "r", - ) as f: + with open(os.path.join(self.project_with_ignore_directory, "requirements.txt"), "r") as f: data = f.read().lower() - for item in ["click", "getpass"]: + for item in ['click', 'getpass']: self.assertFalse(item.lower() in data) def test_dynamic_version_no_pin_scheme(self): @@ -319,14 +306,9 @@ class TestPipreqs(unittest.TestCase): "--mode": "no-pin", } ) - with open( - os.path.join( - self.project_with_ignore_directory, "requirements.txt" - ), - "r", - ) as f: + with open(os.path.join(self.project_with_ignore_directory, "requirements.txt"), "r") as f: data = f.read().lower() - for item in ["beautifulsoup4", "boto"]: + for item in ['beautifulsoup4', 'boto']: self.assertTrue(item.lower() in data) def test_dynamic_version_gt_scheme(self): @@ -348,16 +330,11 @@ class TestPipreqs(unittest.TestCase): "--mode": "gt", } ) - with open( - os.path.join( - self.project_with_ignore_directory, "requirements.txt" - ), - "r", - ) as f: + with open(os.path.join(self.project_with_ignore_directory, "requirements.txt"), "r") as f: data = f.readlines() for item in data: - symbol = ">=" - message = "symbol is not in item" + symbol = '>=' + message = 'symbol is not in item' self.assertIn(symbol, item, message) def test_dynamic_version_compat_scheme(self): @@ -379,16 +356,11 @@ class TestPipreqs(unittest.TestCase): "--mode": "compat", } ) - with open( - os.path.join( - self.project_with_ignore_directory, "requirements.txt" - ), - "r", - ) as f: + with open(os.path.join(self.project_with_ignore_directory, "requirements.txt"), "r") as f: data = f.readlines() for item in data: - symbol = "~=" - message = "symbol is not in item" + symbol = '~=' + message = 'symbol is not in item' self.assertIn(symbol, item, message) def test_clean(self): @@ -435,7 +407,7 @@ class TestPipreqs(unittest.TestCase): """ Test --clean parameter when there are imports to clean """ - cleaned_module = "sqlalchemy" + cleaned_module = 'sqlalchemy' pipreqs.init( { "": self.project, @@ -486,5 +458,5 @@ class TestPipreqs(unittest.TestCase): pass -if __name__ == "__main__": +if __name__ == '__main__': unittest.main() From e0cfb9abd3d2a3fb13b9b4611064489670b8ceee Mon Sep 17 00:00:00 2001 From: craigmiller Date: Mon, 16 Jan 2023 07:18:34 -0700 Subject: [PATCH 7/7] sync with master --- .vscode/extensions.json | 10 +++- .vscode/launch.json | 109 ++++++++++++++++++++++++++++++++++++---- .vscode/settings.json | 42 ++++++++++------ CONTRIBUTING.rst | 3 +- requirements-dev.txt | 6 ++- tests/test_pipreqs.py | 5 ++ 6 files changed, 147 insertions(+), 28 deletions(-) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index f813aaf..c968d5a 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -123,14 +123,20 @@ "redhat.vscode-yaml", // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // Markdown + // Markdown and reStructured Text // ----------------------------------------------------------------------- // - Markdown All in One "yzhang.markdown-all-in-one", // - Markdown PDF "yzane.markdown-pdf", // - markdownlint - "davidanson.vscode-markdownlint" + "davidanson.vscode-markdownlint", + // - Esbonio (conflicts with reStructuredText) + //"swyddfa.esbonio", + // - reStructuredText + "lextudio.restructuredtext", + // - reStructuredText Syntax highlighting + "trond-snekvik.simple-rst", // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CSS diff --git a/.vscode/launch.json b/.vscode/launch.json index 9197dd3..f2e658b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,13 +1,104 @@ { - "version": "0.2.0", - "configurations": [ + "version": "0.2.0", + "configurations": [ + { + // this will only work with a local python environment + "name": "L-py-file", + "type": "python", + "request": "launch", + "program": "${file}", + "console": "integratedTerminal", + "justMyCode": true + }, + { + "name": "L-dj-server", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}/src/manage.py", + "args": [ + "runserver", + ], + "django": true + }, + { + // launch local FastAPI on default port 8000 + // this will not work with a docker container + "name": "L-p8000-api-uvicorn", + "type": "python", + "request": "launch", + "module": "uvicorn", + "cwd": "${workspaceFolder}/src/api/", + "args": [ + "startup:app", + "--reload", + "--port", + "8000" + ], + "jinja": true, + "justMyCode": false + }, + { + //> Set PYDEVD_DISABLE_FILE_VALIDATION=1 + //> python -m debugpy --listen 8888 --wait-for-client startup.py + // then select this script and start debug (F5) + // finally, view FastAPI from the browser to hit breakpoints + // http://0.0.0.0:8000 + // http://0.0.0.0:8000/docs + // this is the default port 8000 + "name": "L-p8888-api-debugpy", + "type": "python", + "request": "attach", + "connect": { + "host": "localhost", + "port": 8888 + }, + "pathMappings": [ { - "name": "Python: Current File", - "type": "python", - "request": "launch", - "program": "${file}", - "console": "integratedTerminal", - "justMyCode": true + "localRoot": "${workspaceFolder}/src/api/", + "remoteRoot": "." } - ] + ], + "justMyCode": false + }, + { + "name": "C-p5678-app-debugpy", + "type": "python", + "request": "attach", + "connect": { + "host": "localhost", + "port": 5678 + }, + "pathMappings": [ + { + "localRoot": "${workspaceFolder}/src/app", + "remoteRoot": "." + } + ], + "justMyCode": false + }, + { + //> Set PYDEVD_DISABLE_FILE_VALIDATION=1 + // run the docker container that has this entrypoint that forwards to our local port 9988 + // entrypoint: [ "python", "-m", "debugpy", "--listen", "0.0.0.0:$FASTAPI_DOCKER_DEBUG_PORT", "--wait-for-client", "startup.py" ] + // then select this script and start debug (F5) + // finally, view FastAPI from the browser to hit breakpoints + // http://0.0.0.0:8011 + // http://0.0.0.0:8011/docs + // FASTAPI_LOCAL_PORT used to forward to container port to the local port 8011 + "name": "C-p9988-api-debugpy", + "type": "python", + "request": "attach", + "connect": { + "host": "localhost", + "port": 9988 + }, + "pathMappings": [ + { + "localRoot": "${workspaceFolder}/src/api/", + "remoteRoot": "." + } + ], + "justMyCode": false + }, + ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index ef5369f..7f8cbe3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,25 +1,37 @@ { + "python.pythonPath": "${workspaceFolder}/.env38/Scripts/python.exe", + // "workbench.colorCustomizations": { - "activityBar.activeBackground": "#5d98cd", - "activityBar.background": "#5d98cd", - "activityBar.foreground": "#15202b", - "activityBar.inactiveForeground": "#15202b99", - "activityBarBadge.background": "#f0cee0", - "activityBarBadge.foreground": "#15202b", + "activityBar.activeBackground": "#1e535f", + "activityBar.background": "#1e535f", + "activityBar.foreground": "#e7e7e7", + "activityBar.inactiveForeground": "#e7e7e799", + "activityBarBadge.background": "#300f2a", + "activityBarBadge.foreground": "#e7e7e7", "commandCenter.border": "#e7e7e799", - "sash.hoverBorder": "#5d98cd", - "statusBar.background": "#3a7fbd", + "sash.hoverBorder": "#1e535f", + "statusBar.background": "#123138", "statusBar.foreground": "#e7e7e7", - "statusBarItem.hoverBackground": "#5d98cd", - "statusBarItem.remoteBackground": "#3a7fbd", + "statusBarItem.hoverBackground": "#1e535f", + "statusBarItem.remoteBackground": "#123138", "statusBarItem.remoteForeground": "#e7e7e7", - "titleBar.activeBackground": "#3a7fbd", + "titleBar.activeBackground": "#123138", "titleBar.activeForeground": "#e7e7e7", - "titleBar.inactiveBackground": "#3a7fbd99", + "titleBar.inactiveBackground": "#12313899", "titleBar.inactiveForeground": "#e7e7e799" }, - "python.testing.unittestArgs": ["-v", "-s", "./tests", "-p", "test_*.py"], - "python.testing.pytestEnabled": false, + //JWL4-BlueGreen + "peacock.color": "#123138", + // + // reStructuredText, root ReadMe.rst + //"esbonio.sphinx.confDir": "", + // + // test + "python.testing.pytestArgs": [ + "src", + "tests", + ], "python.testing.unittestEnabled": true, - "peacock.color": "#3a7fbd" + "python.testing.pytestEnabled": false, + "esbonio.sphinx.confDir": "", } diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 3229623..1c3d1e6 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -77,7 +77,7 @@ Ready to contribute? Here's how to set up `pipreqs` for local development. 5. When you're done making changes, check that your changes pass flake8 and the tests, including testing other Python versions with tox:: $ flake8 pipreqs tests - $ python setup.py test > pipreqs_setup_test_result.txt + $ python setup.py test $ tox To get flake8 and tox, just pip install them into your virtualenv. (or $pip install -r requirements-dev.txt) @@ -85,6 +85,7 @@ Ready to contribute? Here's how to set up `pipreqs` for local development. You may also need to provide `CA_BUNDLE` as an environment variable or parameter in the `tests/.env.test` file. $ export CA_BUNDLE="/certs/path/certificates.pem" # for nix OS + $ set CA_BUNDLE="C:/certs/path/certificates.pem" # for win OS 6. Commit your changes and push your branch to GitHub:: diff --git a/requirements-dev.txt b/requirements-dev.txt index 322f7d9..2c8fdbd 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -17,6 +17,9 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # fix_SSLError tests.settings (optional) use of .env file # alternative would be to set CA_BUNDLE environment variable +# $ export CA_BUNDLE="/certs/path/certificates.pem" # for nix OS +# $ set CA_BUNDLE="C:/certs/path/certificates.pem" # for win OS + python-dotenv # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -25,8 +28,9 @@ flake8 tox # only needed in the environment from which tox is run # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# (optional, personal choice) +# (optional) # vscode settings: "python.formatting.provider": "black", #black +docutils # reStructured Text support # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/test_pipreqs.py b/tests/test_pipreqs.py index 1b3ff5e..3b2c49c 100644 --- a/tests/test_pipreqs.py +++ b/tests/test_pipreqs.py @@ -6,6 +6,11 @@ test_pipreqs ---------------------------------- Tests for `pipreqs` module. + +Environment variables used to mock arguments +e.g., +$ set CA_BUNDLE="certificates.pem" # for win OS +$ export CA_BUNDLE="certificates.pem" # for nix OS """ import os