diff options
author | Jeppe Fihl-Pearson <jeppe@tenzer.dk> | 2019-02-27 17:43:31 +0000 |
---|---|---|
committer | Jeppe Fihl-Pearson <jeppe@tenzer.dk> | 2019-02-27 17:55:09 +0000 |
commit | b37cd52f8b6cefab664a680b493e9b8fde6f3581 (patch) | |
tree | 164071e33fb7fd5ac02684f631ec3fb734614c23 | |
parent | 70ac53cc80d55079b10e591225f35399b47512b7 (diff) | |
download | isort-b37cd52f8b6cefab664a680b493e9b8fde6f3581.tar.gz |
Add LRU cache to RequirementsFinder._get_files_from_dir
This caches the result of the function for future invocations with the same
input, which can massively speed up future invocations if they have the same
input as previous calls.
In the case of this function this happens a lot, as it always is tried with all
parent paths in the file system from `isort` starting point.
The "backports.functools_lru_cache" package is used for Python 2 as it doesn't
have the built in `lru_cache` decorator which was added in Python 3.2.
Some benchmarks against a folder with 182 Python files with all finders enabled:
Python 2.7.15: Before 32 seconds, after 4 seconds.
Python 3.7.2: Before 28 seconds, after 2 seconds.
-rw-r--r-- | isort/finders.py | 26 | ||||
-rwxr-xr-x | setup.py | 5 |
2 files changed, 24 insertions, 7 deletions
diff --git a/isort/finders.py b/isort/finders.py index ca4cb7bd..c419bec8 100644 --- a/isort/finders.py +++ b/isort/finders.py @@ -35,6 +35,11 @@ try: except ImportError: Pipfile = None +try: + from functools import lru_cache +except ImportError: + from backports.functools_lru_cache import lru_cache + KNOWN_SECTION_MAPPING = { 'STDLIB': 'STANDARD_LIBRARY', @@ -260,6 +265,13 @@ class RequirementsFinder(ReqsBaseFinder): def _get_files_from_dir(self, path): """Return paths to requirements files from passed dir. """ + return RequirementsFinder._get_files_from_dir_cached(path) + + @classmethod + @lru_cache(maxsize=16) + def _get_files_from_dir_cached(cls, path): + result = [] + for fname in os.listdir(path): if 'requirements' not in fname: continue @@ -268,18 +280,20 @@ class RequirementsFinder(ReqsBaseFinder): # *requirements*/*.{txt,in} if os.path.isdir(full_path): for subfile_name in os.listdir(path): - for ext in self.exts: + for ext in cls.exts: if subfile_name.endswith(ext): - yield os.path.join(path, subfile_name) + result.append(os.path.join(path, subfile_name)) continue # *requirements*.{txt,in} if os.path.isfile(full_path): - for ext in self.exts: + for ext in cls.exts: if fname.endswith(ext): - yield full_path + result.append(full_path) break + return result + def _get_names(self, path): """Load required packages from path to requirements file """ @@ -315,8 +329,8 @@ class FindersManager(object): LocalFinder, KnownPatternFinder, PathFinder, - # PipfileFinder, - # RequirementsFinder, + PipfileFinder, + RequirementsFinder, DefaultFinder, ) @@ -27,7 +27,10 @@ setup(name='isort', 'requirements': ['pip', 'pipreqs'], 'xdg_home': ['appdirs'], }, - install_requires=['futures; python_version < "3.2"'], + install_requires=[ + 'futures; python_version < "3.2"', + 'backports.functools_lru_cache; python_version < "3.2"', + ], python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", keywords='Refactor, Python, Python2, Python3, Refactoring, Imports, Sort, Clean', classifiers=['Development Status :: 6 - Mature', |