@@ -32,20 +32,48 @@ def load_requirements(*requirements_paths):
32
32
"""
33
33
# UPDATED VIA SEMGREP - if you need to remove/modify this method remove this line and add a comment specifying why.
34
34
35
+ # e.g. {"django": "Django", "confluent-kafka": "confluent_kafka[avro]"}
36
+ by_canonical_name = {}
37
+
38
+ def check_name_consistent (package ):
39
+ """
40
+ Raise exception if package is named different ways.
41
+
42
+ This ensures that packages are named consistently so we can match
43
+ constraints to packages. It also ensures that if we require a package
44
+ with extras we don't constrain it without mentioning the extras (since
45
+ that too would interfere with matching constraints.)
46
+ """
47
+ canonical = package .lower ().replace ('_' , '-' ).split ('[' )[0 ]
48
+ seen_spelling = by_canonical_name .get (canonical )
49
+ if seen_spelling is None :
50
+ by_canonical_name [canonical ] = package
51
+ elif seen_spelling != package :
52
+ raise Exception (
53
+ f'Encountered both "{ seen_spelling } " and "{ package } " in requirements '
54
+ 'and constraints files; please use just one or the other.'
55
+ )
56
+
35
57
requirements = {}
36
58
constraint_files = set ()
37
59
38
- # groups "my-package-name<=x.y.z,..." into ("my-package-name", "<=x.y.z,...")
39
- requirement_line_regex = re .compile (r"([a-zA-Z0-9-_.]+)([<>=][^#\s]+)?" )
60
+ # groups "pkg<=x.y.z,..." into ("pkg", "<=x.y.z,...")
61
+ re_package_name_base_chars = r"a-zA-Z0-9\-_." # chars allowed in base package name
62
+ # Two groups: name[maybe,extras], and optionally a constraint
63
+ requirement_line_regex = re .compile (
64
+ r"([%s]+(?:\[[%s,\s]+\])?)([<>=][^#\s]+)?"
65
+ % (re_package_name_base_chars , re_package_name_base_chars )
66
+ )
40
67
41
68
def add_version_constraint_or_raise (current_line , current_requirements , add_if_not_present ):
42
69
regex_match = requirement_line_regex .match (current_line )
43
70
if regex_match :
44
71
package = regex_match .group (1 )
45
72
version_constraints = regex_match .group (2 )
73
+ check_name_consistent (package )
46
74
existing_version_constraints = current_requirements .get (package , None )
47
- # it 's fine to add constraints to an unconstrained package, but raise an error if there are already
48
- # constraints in place
75
+ # It 's fine to add constraints to an unconstrained package,
76
+ # but raise an error if there are already constraints in place.
49
77
if existing_version_constraints and existing_version_constraints != version_constraints :
50
78
raise BaseException (f'Multiple constraint definitions found for { package } :'
51
79
f' "{ existing_version_constraints } " and "{ version_constraints } ".'
@@ -54,7 +82,8 @@ def add_version_constraint_or_raise(current_line, current_requirements, add_if_n
54
82
if add_if_not_present or package in current_requirements :
55
83
current_requirements [package ] = version_constraints
56
84
57
- # process .in files and store the path to any constraint files that are pulled in
85
+ # Read requirements from .in files and store the path to any
86
+ # constraint files that are pulled in.
58
87
for path in requirements_paths :
59
88
with open (path ) as reqs :
60
89
for line in reqs :
@@ -63,7 +92,7 @@ def add_version_constraint_or_raise(current_line, current_requirements, add_if_n
63
92
if line and line .startswith ('-c' ) and not line .startswith ('-c http' ):
64
93
constraint_files .add (os .path .dirname (path ) + '/' + line .split ('#' )[0 ].replace ('-c' , '' ).strip ())
65
94
66
- # process constraint files and add any new constraints found to existing requirements
95
+ # process constraint files: add constraints to existing requirements
67
96
for constraint_file in constraint_files :
68
97
with open (constraint_file ) as reader :
69
98
for line in reader :
0 commit comments