diff --git a/setup.cfg b/setup.cfg index e096a8c..2b5b9ac 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bdist_wheel] -universal = 1 +python-tag = py3 [doc8] max-line-length = 99 diff --git a/setup.py b/setup.py index 8e7f39c..4e2a679 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,3 @@ -from __future__ import with_statement - import re from os import path @@ -27,7 +25,7 @@ def get_abs_path(pathname): package_dir={'': "src"}, packages=["flake8_requirements"], install_requires=[ - "flake8 >= 2.0.0", + "flake8 >= 4.0.0", "setuptools >= 10.0.0", "tomli>=1.2.1; python_version < '3.11'", ], @@ -43,8 +41,8 @@ def get_abs_path(pathname): "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python", - "Programming Language :: Python :: 2", "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only" "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Quality Assurance", ], diff --git a/src/flake8_requirements/checker.py b/src/flake8_requirements/checker.py index 4bb84e0..3bb1429 100644 --- a/src/flake8_requirements/checker.py +++ b/src/flake8_requirements/checker.py @@ -8,7 +8,6 @@ from functools import wraps from logging import getLogger -import flake8 from pkg_resources import parse_requirements from pkg_resources import yield_lines @@ -18,11 +17,10 @@ import tomli as tomllib from .modules import KNOWN_3RD_PARTIES -from .modules import STDLIB_PY2 from .modules import STDLIB_PY3 # NOTE: Changing this number will alter package version as well. -__version__ = "1.7.8" +__version__ = "2.0.0" __license__ = "MIT" LOG = getLogger('flake8.plugin.requirements') @@ -33,10 +31,7 @@ } STDLIB = set() -if sys.version_info[0] == 2: - STDLIB.update(STDLIB_PY2) -if sys.version_info[0] == 3: - STDLIB.update(STDLIB_PY3) +STDLIB.update(STDLIB_PY3) def memoize(f): @@ -334,48 +329,45 @@ def __init__(self, tree, filename, lines=None): @classmethod def add_options(cls, manager): """Register plug-in specific options.""" - kw = {} - if flake8.__version__ >= '3.0.0': - kw['parse_from_config'] = True manager.add_option( "--known-modules", action='store', default="", + parse_from_config=True, help=( "User defined mapping between a project name and a list of" " provided modules. For example: ``--known-modules=project:" "[Project],extra-project:[extras,utilities]``." - ), - **kw) + )) manager.add_option( "--requirements-file", action='store', + parse_from_config=True, help=( "Specify the name (location) of the requirements text file. " "Unless an absolute path is given, the file will be searched " "relative to the project's root directory. If this option is " "given, requirements from setup.py, setup.cfg or " "pyproject.toml will not be taken into account." - ), - **kw) + )) manager.add_option( "--requirements-max-depth", - type=int if flake8.__version__ >= '3.8.0' else 'int', + type=int, default=1, + parse_from_config=True, help=( "Max depth to resolve recursive requirements. Defaults to 1 " "(one level of recursion allowed)." - ), - **kw) + )) manager.add_option( "--scan-host-site-packages", action='store_true', + parse_from_config=True, help=( "Scan host's site-packages directory for 3rd party projects, " "which provide more than one module or the name of the module" " is different than the project name itself." - ), - **kw) + )) @classmethod def parse_options(cls, options): diff --git a/src/flake8_requirements/modules.py b/src/flake8_requirements/modules.py index d0c0d0e..4a8bb49 100644 --- a/src/flake8_requirements/modules.py +++ b/src/flake8_requirements/modules.py @@ -1,285 +1,3 @@ -# List of all modules (standard library) available in Python 2. -STDLIB_PY2 = ( - "AL", - "BaseHTTPServer", - "Bastion", - "CGIHTTPServer", - "Carbon", - "ColorPicker", - "ConfigParser", - "Cookie", - "DEVICE", - "DocXMLRPCServer", - "EasyDialogs", - "FL", - "FrameWork", - "GL", - "HTMLParser", - "MacOS", - "MimeWriter", - "MiniAEFrame", - "Queue", - "SUNAUDIODEV", - "ScrolledText", - "SimpleHTTPServer", - "SimpleXMLRPCServer", - "SocketServer", - "StringIO", - "Tix", - "Tkinter", - "UserDict", - "UserList", - "UserString", - "__builtin__", - "__future__", - "__main__", - "_winreg", - "abc", - "aepack", - "aetools", - "aetypes", - "aifc", - "al", - "anydbm", - "argparse", - "array", - "ast", - "asynchat", - "asyncore", - "atexit", - "audioop", - "autoGIL", - "base64", - "bdb", - "binascii", - "binhex", - "bisect", - "bsddb", - "bz2", - "cPickle", - "cProfile", - "cStringIO", - "calendar", - "cd", - "cgi", - "cgitb", - "chunk", - "cmath", - "cmd", - "code", - "codecs", - "codeop", - "collections", - "colorsys", - "commands", - "compileall", - "compiler", - "contextlib", - "cookielib", - "copy", - "copy_reg", - "crypt", - "csv", - "ctypes", - "curses", - "datetime", - "dbhash", - "dbm", - "decimal", - "difflib", - "dircache", - "dis", - "distutils", - "dl", - "doctest", - "dumbdbm", - "dummy_thread", - "dummy_threading", - "email", - "ensurepip", - "errno", - "fcntl", - "filecmp", - "fileinput", - "findertools", - "fl", - "flp", - "fm", - "fnmatch", - "formatter", - "fpectl", - "fpformat", - "fractions", - "ftplib", - "functools", - "future_builtins", - "gc", - "gdbm", - "gensuitemodule", - "getopt", - "getpass", - "gettext", - "gl", - "glob", - "grp", - "gzip", - "hashlib", - "heapq", - "hmac", - "hotshot", - "htmlentitydefs", - "htmllib", - "httplib", - "ic", - "imageop", - "imaplib", - "imgfile", - "imghdr", - "imp", - "importlib", - "imputil", - "inspect", - "io", - "itertools", - "jpeg", - "json", - "keyword", - "linecache", - "locale", - "logging", - "macostools", - "macpath", - "mailbox", - "mailcap", - "marshal", - "math", - "md5", - "mhlib", - "mimetools", - "mimetypes", - "mimify", - "mmap", - "modulefinder", - "msilib", - "msvcrt", - "multifile", - "multiprocessing", - "mutex", - "netrc", - "new", - "nis", - "nntplib", - "ntpath", - "numbers", - "operator", - "optparse", - "os", - "os2emxpath", - "ossaudiodev", - "parser", - "pdb", - "pickle", - "pickletools", - "pipes", - "pkgutil", - "platform", - "plistlib", - "popen2", - "poplib", - "posix", - "posixfile", - "posixpath", - "pprint", - "profile", - "pstats", - "pty", - "pwd", - "py_compile", - "pyclbr", - "pydoc", - "quopri", - "random", - "re", - "readline", - "repr", - "resource", - "rexec", - "rfc822", - "rlcompleter", - "robotparser", - "runpy", - "sched", - "select", - "sets", - "sgmllib", - "sha", - "shelve", - "shlex", - "shutil", - "signal", - "site", - "smtpd", - "smtplib", - "sndhdr", - "socket", - "spwd", - "sqlite3", - "ssl", - "stat", - "statvfs", - "string", - "stringprep", - "struct", - "subprocess", - "sunau", - "sunaudiodev", - "symbol", - "symtable", - "sys", - "sysconfig", - "syslog", - "tabnanny", - "tarfile", - "telnetlib", - "tempfile", - "termios", - "test", - "textwrap", - "thread", - "threading", - "time", - "timeit", - "token", - "tokenize", - "trace", - "traceback", - "ttk", - "tty", - "turtle", - "types", - "unicodedata", - "unittest", - "urllib", - "urllib2", - "urlparse", - "user", - "uu", - "uuid", - "warnings", - "wave", - "weakref", - "webbrowser", - "whichdb", - "winsound", - "wsgiref", - "xdrlib", - "xml", - "xmlrpclib", - "zipfile", - "zipimport", - "zlib", -) - # List of all modules (standard library) available in Python 3. STDLIB_PY3 = ( "__future__", diff --git a/test/test_pep621.py b/test/test_pep621.py index b74a46e..9148c8a 100644 --- a/test/test_pep621.py +++ b/test/test_pep621.py @@ -1,16 +1,11 @@ import unittest +from unittest import mock +from unittest.mock import mock_open from flake8_requirements.checker import Flake8Checker from flake8_requirements.checker import ModuleSet from flake8_requirements.checker import memoize -try: - from unittest import mock - builtins_open = 'builtins.open' -except ImportError: - import mock - builtins_open = '__builtin__.open' - class Flake8Options: known_modules = "" @@ -46,7 +41,7 @@ class Options(Flake8Options): ) def test_get_pyproject_toml_pep621(self): - with mock.patch(builtins_open, mock.mock_open(read_data=self.content)): + with mock.patch('builtins.open', mock_open(read_data=self.content)): pep621 = Flake8Checker.get_pyproject_toml_pep621() expected = { "name": "test", @@ -59,15 +54,15 @@ def test_get_pyproject_toml_pep621(self): def test_get_pyproject_toml_invalid(self): content = self.content + b"invalid" - with mock.patch(builtins_open, mock.mock_open(read_data=content)): + with mock.patch('builtins.open', mock_open(read_data=content)): self.assertDictEqual(Flake8Checker.get_pyproject_toml_pep621(), {}) def test_1st_party(self): - with mock.patch(builtins_open, mock.mock_open()) as m: + with mock.patch('builtins.open', mock_open()) as m: m.side_effect = ( IOError("No such file or directory: 'setup.py'"), IOError("No such file or directory: 'setup.cfg'"), - mock.mock_open(read_data=self.content).return_value, + mock_open(read_data=self.content).return_value, ) checker = Flake8Checker(None, None) @@ -75,11 +70,11 @@ def test_1st_party(self): self.assertEqual(mods, ModuleSet({"test": {}})) def test_3rd_party(self): - with mock.patch(builtins_open, mock.mock_open()) as m: + with mock.patch('builtins.open', mock_open()) as m: m.side_effect = ( IOError("No such file or directory: 'setup.py'"), IOError("No such file or directory: 'setup.cfg'"), - mock.mock_open(read_data=self.content).return_value, + mock_open(read_data=self.content).return_value, ) checker = Flake8Checker(None, None) diff --git a/test/test_poetry.py b/test/test_poetry.py index 5637b12..59b513b 100644 --- a/test/test_poetry.py +++ b/test/test_poetry.py @@ -1,16 +1,11 @@ import unittest +from unittest import mock +from unittest.mock import mock_open from flake8_requirements.checker import Flake8Checker from flake8_requirements.checker import ModuleSet from flake8_requirements.checker import memoize -try: - from unittest import mock - builtins_open = 'builtins.open' -except ImportError: - import mock - builtins_open = '__builtin__.open' - class PoetryTestCase(unittest.TestCase): @@ -19,18 +14,18 @@ def setUp(self): def test_get_pyproject_toml_poetry(self): content = b"[tool.poetry]\nname='x'\n[tool.poetry.tag]\nx=0\n" - with mock.patch(builtins_open, mock.mock_open(read_data=content)): + with mock.patch('builtins.open', mock_open(read_data=content)): poetry = Flake8Checker.get_pyproject_toml_poetry() self.assertDictEqual(poetry, {'name': "x", 'tag': {'x': 0}}) def test_1st_party(self): content = b"[tool.poetry]\nname='book'\n" - with mock.patch(builtins_open, mock.mock_open()) as m: + with mock.patch('builtins.open', mock_open()) as m: m.side_effect = ( IOError("No such file or directory: 'setup.py'"), IOError("No such file or directory: 'setup.cfg'"), - mock.mock_open(read_data=content).return_value, + mock_open(read_data=content).return_value, ) checker = Flake8Checker(None, None) @@ -41,11 +36,11 @@ def test_3rd_party(self): content = b"[tool.poetry.dependencies]\ntools='1.0'\n" content += b"[tool.poetry.dev-dependencies]\ndev-tools='1.0'\n" - with mock.patch(builtins_open, mock.mock_open()) as m: + with mock.patch('builtins.open', mock_open()) as m: m.side_effect = ( IOError("No such file or directory: 'setup.py'"), IOError("No such file or directory: 'setup.cfg'"), - mock.mock_open(read_data=content).return_value, + mock_open(read_data=content).return_value, ) checker = Flake8Checker(None, None) @@ -56,11 +51,11 @@ def test_3rd_party_groups(self): content = b"[tool.poetry.dependencies]\ntools='1.0'\n" content += b"[tool.poetry.group.dev.dependencies]\ndev-tools='1.0'\n" - with mock.patch(builtins_open, mock.mock_open()) as m: + with mock.patch('builtins.open', mock_open()) as m: m.side_effect = ( IOError("No such file or directory: 'setup.py'"), IOError("No such file or directory: 'setup.cfg'"), - mock.mock_open(read_data=content).return_value, + mock_open(read_data=content).return_value, ) checker = Flake8Checker(None, None) diff --git a/test/test_requirements.py b/test/test_requirements.py index 99a3094..b31801d 100644 --- a/test/test_requirements.py +++ b/test/test_requirements.py @@ -1,30 +1,25 @@ import os import unittest from collections import OrderedDict +from unittest import mock +from unittest.mock import mock_open from pkg_resources import parse_requirements from flake8_requirements.checker import Flake8Checker from flake8_requirements.checker import memoize -try: - from unittest import mock - builtins_open = 'builtins.open' -except ImportError: - import mock - builtins_open = '__builtin__.open' - def mock_open_with_name(read_data="", name="file.name"): """Mock open call with a specified `name` attribute.""" - m = mock.mock_open(read_data=read_data) + m = mock_open(read_data=read_data) m.return_value.name = name return m def mock_open_multiple(files=OrderedDict()): """Create a mock open object for multiple files.""" - m = mock.mock_open() + m = mock_open() m.side_effect = [ mock_open_with_name(read_data=content, name=name).return_value for name, content in files.items() @@ -60,7 +55,7 @@ def test_resolve_requirement_with_file_beyond_max_depth(self): Flake8Checker.resolve_requirement("-r requirements.txt") def test_resolve_requirement_with_file_empty(self): - with mock.patch(builtins_open, mock.mock_open()) as m: + with mock.patch('builtins.open', mock_open()) as m: self.assertEqual( Flake8Checker.resolve_requirement("-r requirements.txt", 1), [], @@ -68,7 +63,7 @@ def test_resolve_requirement_with_file_empty(self): m.assert_called_once_with("requirements.txt") def test_resolve_requirement_with_file_content(self): - with mock.patch(builtins_open, mock_open_multiple(files=OrderedDict(( + with mock.patch('builtins.open', mock_open_multiple(files=OrderedDict(( ("requirements.txt", "foo >= 1.0.0\nbar <= 1.0.0\n"), )))): self.assertEqual( @@ -77,7 +72,7 @@ def test_resolve_requirement_with_file_content(self): ) def test_resolve_requirement_with_file_content_line_continuation(self): - with mock.patch(builtins_open, mock_open_multiple(files=OrderedDict(( + with mock.patch('builtins.open', mock_open_multiple(files=OrderedDict(( ("requirements.txt", "foo[bar] \\\n>= 1.0.0\n"), )))): self.assertEqual( @@ -86,7 +81,7 @@ def test_resolve_requirement_with_file_content_line_continuation(self): ) def test_resolve_requirement_with_file_content_line_continuation_2(self): - with mock.patch(builtins_open, mock_open_multiple(files=OrderedDict(( + with mock.patch('builtins.open', mock_open_multiple(files=OrderedDict(( ("requirements.txt", "foo \\\n>= 1.0.0 \\\n# comment \\\nbar \\"), )))): self.assertEqual( @@ -95,14 +90,14 @@ def test_resolve_requirement_with_file_content_line_continuation_2(self): ) def test_resolve_requirement_with_file_recursion_beyond_max_depth(self): - with mock.patch(builtins_open, mock_open_multiple(files=OrderedDict(( + with mock.patch('builtins.open', mock_open_multiple(files=OrderedDict(( ("requirements.txt", "-r requirements.txt\n"), )))): with self.assertRaises(RuntimeError): Flake8Checker.resolve_requirement("-r requirements.txt", 1), def test_resolve_requirement_with_file_recursion(self): - with mock.patch(builtins_open, mock_open_multiple(files=OrderedDict(( + with mock.patch('builtins.open', mock_open_multiple(files=OrderedDict(( ("requirements.txt", "--requirement inner.txt\nbar <= 1.0.0\n"), ("inner.txt", "# inner\nbaz\n\nqux\n"), )))): @@ -112,7 +107,7 @@ def test_resolve_requirement_with_file_recursion(self): ) def test_resolve_requirement_with_relative_include(self): - with mock.patch(builtins_open, mock_open_multiple(files=OrderedDict(( + with mock.patch('builtins.open', mock_open_multiple(files=OrderedDict(( ("requirements.txt", "-r requirements/production.txt"), ("requirements/production.txt", "-r node/one.txt\nfoo"), ("requirements/node/one.txt", "-r common.txt\n-r /abs/path.txt"), @@ -132,13 +127,13 @@ def test_resolve_requirement_with_relative_include(self): ]) def test_init_with_no_requirements(self): - with mock.patch(builtins_open, mock.mock_open()) as m: + with mock.patch('builtins.open', mock_open()) as m: m.side_effect = IOError("No such file or directory"), checker = Flake8Checker(None, None) self.assertEqual(checker.get_requirements_txt(), ()) def test_init_with_user_requirements(self): - with mock.patch(builtins_open, mock_open_multiple(files=OrderedDict(( + with mock.patch('builtins.open', mock_open_multiple(files=OrderedDict(( ("requirements/base.txt", "foo >= 1.0.0\n-r inner.txt\n"), ("requirements/inner.txt", "bar\n"), )))) as m: @@ -160,7 +155,7 @@ def test_init_with_user_requirements(self): Flake8Checker.requirements_file = None def test_init_with_simple_requirements(self): - with mock.patch(builtins_open, mock_open_multiple(files=OrderedDict(( + with mock.patch('builtins.open', mock_open_multiple(files=OrderedDict(( ("requirements.txt", "foo >= 1.0.0\nbar <= 1.0.0\n"), )))): checker = Flake8Checker(None, None) @@ -173,7 +168,7 @@ def test_init_with_simple_requirements(self): ) def test_init_with_recursive_requirements_beyond_max_depth(self): - with mock.patch(builtins_open, mock_open_multiple(files=OrderedDict(( + with mock.patch('builtins.open', mock_open_multiple(files=OrderedDict(( ("requirements.txt", "foo >= 1.0.0\n-r inner.txt\nbar <= 1.0.0\n"), ("inner.txt", "# inner\nbaz\n\nqux\n"), )))): @@ -186,7 +181,7 @@ def test_init_with_recursive_requirements_beyond_max_depth(self): Flake8Checker.requirements_max_depth = 1 def test_init_with_recursive_requirements(self): - with mock.patch(builtins_open, mock_open_multiple(files=OrderedDict(( + with mock.patch('builtins.open', mock_open_multiple(files=OrderedDict(( ("requirements.txt", "foo >= 1.0.0\n-r inner.txt\nbar <= 1.0.0\n"), ("inner.txt", "# inner\nbaz\n\nqux\n"), )))): @@ -205,7 +200,7 @@ def test_init_misc(self): curdir = os.path.abspath(os.path.dirname(__file__)) with open(os.path.join(curdir, "test_requirements.txt")) as f: requirements_content = f.read() - with mock.patch(builtins_open, mock_open_multiple(files=OrderedDict(( + with mock.patch('builtins.open', mock_open_multiple(files=OrderedDict(( ("requirements.txt", requirements_content), )))): checker = Flake8Checker(None, None) diff --git a/test/test_setup.py b/test/test_setup.py index 83dc89f..3a23e2d 100644 --- a/test/test_setup.py +++ b/test/test_setup.py @@ -1,19 +1,14 @@ import ast import os import unittest +from unittest import mock +from unittest.mock import mock_open from pkg_resources import parse_requirements from flake8_requirements.checker import Flake8Checker from flake8_requirements.checker import SetupVisitor -try: - from unittest import mock - builtins_open = 'builtins.open' -except ImportError: - import mock - builtins_open = '__builtin__.open' - class SetupTestCase(unittest.TestCase): @@ -100,7 +95,7 @@ def test_get_setup_cfg_requirements(self): curdir = os.path.abspath(os.path.dirname(__file__)) with open(os.path.join(curdir, "test_setup.cfg")) as f: content = f.read() - with mock.patch(builtins_open, mock.mock_open(read_data=content)): + with mock.patch('builtins.open', mock_open(read_data=content)): checker = Flake8Checker(None, None) self.assertEqual( checker.get_setup_cfg_requirements(False),