summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeppe Fihl-Pearson <jeppe@tenzer.dk>2019-02-27 17:43:31 +0000
committerJeppe Fihl-Pearson <jeppe@tenzer.dk>2019-02-27 17:55:09 +0000
commitb37cd52f8b6cefab664a680b493e9b8fde6f3581 (patch)
tree164071e33fb7fd5ac02684f631ec3fb734614c23
parent70ac53cc80d55079b10e591225f35399b47512b7 (diff)
downloadisort-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.py26
-rwxr-xr-xsetup.py5
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,
)
diff --git a/setup.py b/setup.py
index 839ebf3c..e7795f9b 100755
--- a/setup.py
+++ b/setup.py
@@ -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',