Skip to content
This repository was archived by the owner on Dec 3, 2025. It is now read-only.

Commit 69ad2c0

Browse files
authored
Merge pull request #23 from openedx/jenkins/zshkoor/setup-py-updated-c98e1c1
fix: setup.py update using script
2 parents f4253c8 + ae2355e commit 69ad2c0

File tree

1 file changed

+81
-9
lines changed

1 file changed

+81
-9
lines changed

setup.py

Lines changed: 81 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,96 @@
77
def load_requirements(*requirements_paths):
88
"""
99
Load all requirements from the specified requirements files.
10+
11+
Requirements will include any constraints from files specified
12+
with -c in the requirements files.
1013
Returns a list of requirement strings.
1114
"""
12-
requirements = set()
15+
# UPDATED VIA SEMGREP - if you need to remove/modify this method remove this line and add a comment specifying why.
16+
17+
# e.g. {"django": "Django", "confluent-kafka": "confluent_kafka[avro]"}
18+
by_canonical_name = {}
19+
20+
def check_name_consistent(package):
21+
"""
22+
Raise exception if package is named different ways.
23+
24+
This ensures that packages are named consistently so we can match
25+
constraints to packages. It also ensures that if we require a package
26+
with extras we don't constrain it without mentioning the extras (since
27+
that too would interfere with matching constraints.)
28+
"""
29+
canonical = package.lower().replace('_', '-').split('[')[0]
30+
seen_spelling = by_canonical_name.get(canonical)
31+
if seen_spelling is None:
32+
by_canonical_name[canonical] = package
33+
elif seen_spelling != package:
34+
raise Exception(
35+
f'Encountered both "{seen_spelling}" and "{package}" in requirements '
36+
'and constraints files; please use just one or the other.'
37+
)
38+
39+
requirements = {}
40+
constraint_files = set()
41+
42+
# groups "pkg<=x.y.z,..." into ("pkg", "<=x.y.z,...")
43+
re_package_name_base_chars = r"a-zA-Z0-9\-_." # chars allowed in base package name
44+
# Two groups: name[maybe,extras], and optionally a constraint
45+
requirement_line_regex = re.compile(
46+
r"([%s]+(?:\[[%s,\s]+\])?)([<>=][^#\s]+)?"
47+
% (re_package_name_base_chars, re_package_name_base_chars)
48+
)
49+
50+
def add_version_constraint_or_raise(current_line, current_requirements, add_if_not_present):
51+
regex_match = requirement_line_regex.match(current_line)
52+
if regex_match:
53+
package = regex_match.group(1)
54+
version_constraints = regex_match.group(2)
55+
check_name_consistent(package)
56+
existing_version_constraints = current_requirements.get(package, None)
57+
# It's fine to add constraints to an unconstrained package,
58+
# but raise an error if there are already constraints in place.
59+
if existing_version_constraints and existing_version_constraints != version_constraints:
60+
raise BaseException(f'Multiple constraint definitions found for {package}:'
61+
f' "{existing_version_constraints}" and "{version_constraints}".'
62+
f'Combine constraints into one location with {package}'
63+
f'{existing_version_constraints},{version_constraints}.')
64+
if add_if_not_present or package in current_requirements:
65+
current_requirements[package] = version_constraints
66+
67+
# Read requirements from .in files and store the path to any
68+
# constraint files that are pulled in.
1369
for path in requirements_paths:
1470
with open(path) as reqs:
15-
requirements.update(
16-
line.split('#')[0].strip() for line in reqs
17-
if is_requirement(line.strip())
18-
)
19-
return list(requirements)
71+
for line in reqs:
72+
if is_requirement(line):
73+
add_version_constraint_or_raise(line, requirements, True)
74+
if line and line.startswith('-c') and not line.startswith('-c http'):
75+
constraint_files.add(os.path.dirname(path) + '/' + line.split('#')[0].replace('-c', '').strip())
76+
77+
# process constraint files: add constraints to existing requirements
78+
for constraint_file in constraint_files:
79+
with open(constraint_file) as reader:
80+
for line in reader:
81+
if is_requirement(line):
82+
add_version_constraint_or_raise(line, requirements, False)
83+
84+
# process back into list of pkg><=constraints strings
85+
constrained_requirements = [f'{pkg}{version or ""}' for (pkg, version) in sorted(requirements.items())]
86+
return constrained_requirements
2087

2188

2289
def is_requirement(line):
2390
"""
24-
Return True if the requirement line is a package requirement;
25-
that is, it is not blank, a comment, a URL, or an included file.
91+
Return True if the requirement line is a package requirement.
92+
93+
Returns:
94+
bool: True if the line is not blank, a comment,
95+
a URL, or an included file
2696
"""
27-
return line and not line.startswith(('-r', '#', '-e', 'git+', '-c'))
97+
# UPDATED VIA SEMGREP - if you need to remove/modify this method remove this line and add a comment specifying why
98+
99+
return line and line.strip() and not line.startswith(('-r', '#', '-e', 'git+', '-c'))
28100

29101

30102
def get_version(*file_paths):

0 commit comments

Comments
 (0)