* Fix case sensitivity issue

This commit is contained in:
j3rome 2021-07-29 14:28:37 -04:00
parent 9a04d4ce0e
commit 965d3d0e38
2 changed files with 64 additions and 41 deletions

View File

@ -6,7 +6,10 @@ from .utils import get_mapping_files_from_pipreqs, get_local_modules, get_packag
class Guesser: class Guesser:
def __init__(self, force_guess=None, keep_unused_packages=False): def __init__(self, force_guess=None, keep_unused_packages=False):
self.keep_unused_packages = keep_unused_packages
# Retrive mapping files from https://github.com/bndr/pipreqs # Retrive mapping files from https://github.com/bndr/pipreqs
# The mapping keys are all lowercase (case insensitive match)
self.stdlib_list, self.import_to_package_mapping, self.package_to_import_mapping = get_mapping_files_from_pipreqs() self.stdlib_list, self.import_to_package_mapping, self.package_to_import_mapping = get_mapping_files_from_pipreqs()
# Get local packages # Get local packages
@ -21,26 +24,44 @@ class Guesser:
# Retrieve all imported packages in project # Retrieve all imported packages in project
all_imported_packages = set(get_all_imports(self.stdlib_list)) all_imported_packages = set(get_all_imports(self.stdlib_list))
# Retrieve packages in requirements.txt # Retrieve packages in requirements.txt
if os.path.exists('requirements.txt'): packages_in_requirements = get_packages_from_requirements('requirements.txt')
packages_in_requirements_version_map = get_packages_from_requirements('requirements.txt')
self.packages_in_requirements = set(packages_in_requirements_version_map.keys())
else:
packages_in_requirements_version_map = {}
self.packages_in_requirements = set()
# Merge packages in requirements.txt and imports # Do mapping between import name and package name
self.all_packages = packages_in_requirements_version_map self.all_packages = {}
extra_packages = all_imported_packages - self.packages_in_requirements for package_name, version in packages_in_requirements.items():
for extra_package in extra_packages: package_name_lowercase = package_name.lower()
self.all_packages[extra_package] = None import_name = self.package_to_import_mapping.get(package_name_lowercase, package_name)
self.keep_unused_packages = keep_unused_packages self.all_packages[package_name.lower()] = {
'import_name': import_name,
'package_name': package_name,
'version': version,
'in_requirements': True
}
for import_name in all_imported_packages:
package_name = self.import_to_package_mapping.get(import_name, import_name)
package_name_lowercase = package_name.lower()
if package_name_lowercase not in self.all_packages:
self.all_packages[package_name_lowercase] = {
'import_name': import_name,
'package_name': package_name,
'version': None,
'in_requirements': False
}
def guess_package_versions(self): def guess_package_versions(self):
packages = [] packages = []
for package_name, version in self.all_packages.items(): for package_name_lowercase, package_info in self.all_packages.items():
package_name = package_info['package_name']
version = package_info['version']
import_name = package_info['import_name']
package_in_requirements = package_info['in_requirements']
print("\n" + "-"*40) print("\n" + "-"*40)
print(f"PACKAGE : {package_name}") print(f"PACKAGE : {package_name}")
if version is None: if version is None:
@ -52,12 +73,8 @@ class Guesser:
import_version = None import_version = None
req_version = None req_version = None
# Pypi package to import mapping
import_name = self.package_to_import_mapping.get(package_name, package_name)
pypi_package_name = self.import_to_package_mapping.get(package_name, package_name)
# Get available versions from Pypi # Get available versions from Pypi
available_versions = get_pypi_history(pypi_package_name, ignore_release_candidat=True) available_versions = get_pypi_history(package_name, ignore_release_candidat=True)
if available_versions is None: if available_versions is None:
print(f"[INFO] Couldn't find Pypi releases for package '{package_name}', ignoring") print(f"[INFO] Couldn't find Pypi releases for package '{package_name}', ignoring")
@ -65,7 +82,10 @@ class Guesser:
# Retrieve candidate version based on the first time the package was imported in *.py # Retrieve candidate version based on the first time the package was imported in *.py
date_added_via_import = get_date_when_package_committed(import_name, via_requirements=False) date_added_via_import = get_date_when_package_committed(import_name, via_requirements=False)
if date_added_via_import is None: if date_added_via_import is not None:
date_added_via_import_str = date_added_via_import.strftime("%Y-%m-%d")
import_version = find_version_at_date(available_versions, date_added_via_import)
else:
print(f" [INFO] Package '{package_name}' is defined in requirements.txt but not used (Or committed), ") print(f" [INFO] Package '{package_name}' is defined in requirements.txt but not used (Or committed), ")
if self.keep_unused_packages: if self.keep_unused_packages:
print(" will attempts guessing version anyways since --keep_unused_packages is set set") print(" will attempts guessing version anyways since --keep_unused_packages is set set")
@ -73,34 +93,33 @@ class Guesser:
else: else:
print(f"[INFO] Ignoring package '{package_name}' (Use --keep_unused_packages if you want to keep it)") print(f"[INFO] Ignoring package '{package_name}' (Use --keep_unused_packages if you want to keep it)")
continue continue
else:
date_added_via_import_str = date_added_via_import.strftime("%Y-%m-%d")
import_version = find_version_at_date(available_versions, date_added_via_import)
# Retrieve candidate version based on the first time the package was added to requirements.txt # Retrieve candidate version based on the first time the package was added to requirements.txt
if pypi_package_name.lower() in self.packages_in_requirements: if package_in_requirements:
date_added_via_req = get_date_when_package_committed(pypi_package_name, via_requirements=True) date_added_via_req = get_date_when_package_committed(package_name, via_requirements=True)
if date_added_via_req is not None: if date_added_via_req is not None:
req_version = find_version_at_date(available_versions, date_added_via_req) req_version = find_version_at_date(available_versions, date_added_via_req)
date_added_via_req_str = date_added_via_req.strftime("%Y-%m-%d") date_added_via_req_str = date_added_via_req.strftime("%Y-%m-%d")
else: else:
print(f" [INFO] Package '{package_name}' was not in requirements.txt, using date of first import (Version {import_version} / {date_added_via_import_str})") print(f" [INFO] Package '{package_name}' was not in requirements.txt, using date of first import (Version {import_version} / {date_added_via_import_str})")
choice = 1 choice = 1
if choice is None:
if req_version != import_version:
# Ask user to choose version based on either first import date or first added to requirements.txt date
choice = user_response_multi_choices(f"Choose guessing strategy for package '{package_name}'", [
f'{"First time the package was imported".ljust(50)} (Version {import_version} / {date_added_via_import_str})',
f'{"When the package was added to requirements.txt".ljust(50)} (Version {req_version} / {date_added_via_req_str})'
])
else:
# Both requirements.txt and first import resolve to the same version
choice = 1
else: else:
print(f" [INFO] Package '{package_name}' was not found in requirements.txt, using date of first import (Version {import_version} / {date_added_via_import_str})") print(f" [INFO] Package '{package_name}' was not found in requirements.txt, using date of first import (Version {import_version} / {date_added_via_import_str})")
choice = 1 choice = 1
# Ask user to choose version based on either first import date or first added to requirements.txt date
if choice is None:
if req_version != import_version:
choice = user_response_multi_choices(f"Choose guessing strategy for package '{package_name}'", [
f'{"First time the package was imported".ljust(50)} (Version {import_version} / {date_added_via_import_str})',
f'{"When the package was added to requirements.txt".ljust(50)} (Version {req_version} / {date_added_via_req_str})'
])
else:
# Both requirements.txt and first import resolve to the same version
choice = 1
if choice == 2: if choice == 2:
version = req_version version = req_version
date = date_added_via_req_str date = date_added_via_req_str

View File

@ -137,6 +137,7 @@ def find_version_at_date(available_versions, date):
def get_mapping_files_from_pipreqs(tmp_path="/tmp/.py-reqs-guesser"): def get_mapping_files_from_pipreqs(tmp_path="/tmp/.py-reqs-guesser"):
""" """
Retrieve 'import -> package' name mapping and standard lib module list Retrieve 'import -> package' name mapping and standard lib module list
The mapping key is lowercase so that we can match case insensitive
These files come from https://github.com/bndr/pipreqs These files come from https://github.com/bndr/pipreqs
""" """
@ -181,8 +182,8 @@ def get_mapping_files_from_pipreqs(tmp_path="/tmp/.py-reqs-guesser"):
for line in f.readlines(): for line in f.readlines():
import_name, package_name = line.strip().split(":") import_name, package_name = line.strip().split(":")
from_import_to_package_mapping[import_name] = package_name from_import_to_package_mapping[import_name.lower()] = package_name
from_package_to_import_mapping[package_name] = import_name from_package_to_import_mapping[package_name.lower()] = import_name
with open(stdlib_filepath, 'r') as f: with open(stdlib_filepath, 'r') as f:
stdlib = set([l.strip() for l in f.readlines()]) stdlib = set([l.strip() for l in f.readlines()])
@ -196,13 +197,16 @@ def get_packages_from_requirements(filepath):
""" """
# TODO : Handle multiple version conditions # TODO : Handle multiple version conditions
# TODO : Handle greater than (>). If version contains >, should take the greatest available version at that date. # TODO : Handle greater than (>). If version contains >, should take the greatest available version at that date.
packages = {}
if not os.path.exists(filepath):
return packages
with open(filepath, 'r') as f: with open(filepath, 'r') as f:
lines = f.readlines() lines = f.readlines()
split_reg = re.compile(r'==|<=|>=|<|>') split_reg = re.compile(r'==|<=|>=|<|>')
packages = {}
for line in lines: for line in lines:
splitted = re.split(split_reg, line.strip()) splitted = re.split(split_reg, line.strip())
if len(splitted) > 1: if len(splitted) > 1:
@ -210,7 +214,7 @@ def get_packages_from_requirements(filepath):
else: else:
version = None version = None
packages[splitted[0].lower()] = version packages[splitted[0]] = version
return packages return packages