Skip to content

Commit fec4e1b

Browse files
More fixes
1 parent e4e7a30 commit fec4e1b

File tree

1 file changed

+64
-44
lines changed
  • packages/pyodide-kernel/py/piplite/piplite

1 file changed

+64
-44
lines changed

packages/pyodide-kernel/py/piplite/piplite/cli.py

Lines changed: 64 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,30 @@ async def install(
3535

3636
@dataclass
3737
class RequirementsContext:
38-
"""Track state while parsing requirements files."""
38+
"""Track state while parsing requirements files.
3939
40-
index_url: Optional[str] = None
40+
This class maintains state about requirements and their associated index URLs.
41+
Multiple index URLs can be tracked to support searching in multiple indices
42+
in order of specification.
43+
"""
44+
45+
index_urls: List[str] = None
4146
requirements: List[str] = None
4247

4348
def __post_init__(self):
4449
if self.requirements is None:
4550
self.requirements = []
51+
if self.index_urls is None:
52+
self.index_urls = []
53+
54+
def add_index_url(self, url: str) -> None:
55+
"""Add an index URL to the list of URLs to search from."""
56+
if url not in self.index_urls:
57+
self.index_urls.append(url)
4658

4759
def add_requirement(self, req: str):
48-
"""Add a requirement with the currently active index URL."""
49-
self.requirements.append((req, self.index_url))
60+
"""Add a requirement that will use the current index URLs."""
61+
self.requirements.append((req, self.index_urls[:] if self.index_urls else None))
5062

5163

5264
REQ_FILE_PREFIX = r"^(-r|--requirements)\s*=?\s*(.*)\s*"
@@ -141,49 +153,45 @@ async def get_action_kwargs(argv: list[str]) -> tuple[typing.Optional[str], dict
141153
action = args.action
142154

143155
if action == "install":
156+
all_index_urls = []
157+
if args.index_url:
158+
all_index_urls.append(args.index_url)
159+
144160
all_requirements = []
145161

146162
if args.packages:
147-
all_requirements.extend((pkg, args.index_url) for pkg in args.packages)
163+
all_requirements.extend((pkg, all_index_urls[:]) for pkg in args.packages)
148164

149165
# Process requirements files
150166
for req_file in args.requirements or []:
151-
context = RequirementsContext()
152-
153-
if not Path(req_file).exists():
154-
warn(f"piplite could not find requirements file {req_file}")
155-
continue
156-
157-
# First let the file be processed normally to capture any index URL
158-
for line_no, line in enumerate(
159-
Path(req_file).read_text(encoding="utf-8").splitlines()
160-
):
161-
await _packages_from_requirements_line(
162-
Path(req_file), line_no + 1, line, context
167+
try:
168+
requirements, file_index_urls = await _packages_from_requirements_file(
169+
Path(req_file)
163170
)
164171

165-
# If CLI provided an index URL, it should override the file's index URL
166-
# We update all requirements to use the CLI index URL instead. Or, we use
167-
# whatever index URL was found in the file (if any).
168-
if args.index_url:
169-
all_requirements.extend(
170-
(req, args.index_url) for req, _ in context.requirements
171-
)
172-
else:
173-
all_requirements.extend(context.requirements)
172+
# If CLI provided an index URL, it should override the file's index URL
173+
# We update all requirements to use the CLI index URL instead. Or, we use
174+
# whatever index URL was found in the file (if any).
175+
if args.index_url:
176+
all_requirements.extend(
177+
(req, all_index_urls) for req, _ in requirements
178+
)
179+
else:
180+
for url in file_index_urls:
181+
if url not in all_index_urls:
182+
all_index_urls.append(url)
183+
all_requirements.extend(requirements)
184+
except Exception as e:
185+
warn(f"Error processing requirements file {req_file}: {e}")
186+
continue
174187

175188
if all_requirements:
176189
kwargs["requirements"] = []
177-
active_index_url = None
190+
kwargs["requirements"].extend(req for req, _ in all_requirements)
178191

179-
for req, idx in all_requirements:
180-
if idx is not None:
181-
active_index_url = idx
182-
kwargs["requirements"].append(req)
183-
184-
# Set the final index URL, if we found one
185-
if active_index_url is not None:
186-
kwargs["index_urls"] = active_index_url
192+
# Set the final index URLs, if we found any
193+
if all_index_urls:
194+
kwargs["index_urls"] = all_index_urls
187195

188196
if args.pre:
189197
kwargs["pre"] = True
@@ -199,22 +207,29 @@ async def get_action_kwargs(argv: list[str]) -> tuple[typing.Optional[str], dict
199207

200208
async def _packages_from_requirements_file(
201209
req_path: Path,
202-
) -> Tuple[List[str], Optional[str]]:
203-
"""Extract (potentially nested) package requirements from a requirements file.
210+
) -> Tuple[List[Tuple[str, Optional[List[str]]]], List[str]]:
211+
"""Extract package requirements and index URLs from a requirements file.
212+
213+
This function processes a requirements file to collect both package requirements
214+
and any index URLs specified in it (with support for nested requirements).
204215
205216
Returns:
206-
Tuple of (list of package requirements, optional index URL)
217+
A tuple of:
218+
- List of (requirement, index_urls) pairs, where index_urls is a list of URLs
219+
that should be used for this requirement
220+
- List of index URLs found in the file
207221
"""
222+
208223
if not req_path.exists():
209224
warn(f"piplite could not find requirements file {req_path}")
210-
return []
225+
return [], []
211226

212227
context = RequirementsContext()
213228

214229
for line_no, line in enumerate(req_path.read_text(encoding="utf-8").splitlines()):
215230
await _packages_from_requirements_line(req_path, line_no + 1, line, context)
216231

217-
return context.requirements, context.index_url
232+
return context.requirements, context.index_urls
218233

219234

220235
async def _packages_from_requirements_line(
@@ -237,15 +252,20 @@ async def _packages_from_requirements_line(
237252
sub_req = Path(sub_path)
238253
else:
239254
sub_req = req_path.parent / sub_path
240-
sub_reqs, _ = await _packages_from_requirements_file(sub_req)
241-
# Use current context's index_url for nested requirements
242-
context.requirements.extend(sub_reqs)
255+
# Create a new context for the nested file to maintain its own index URLs.
256+
nested_context = RequirementsContext()
257+
nested_context.index_urls = context.index_urls[
258+
:
259+
] # i nherit parent's index URLs
260+
await _packages_from_requirements_file(sub_req, nested_context)
261+
# Extend our requirements with the nested ones
262+
context.requirements.extend(nested_context.requirements)
243263
return
244264

245265
# Check for index URL specification
246266
index_match = re.match(INDEX_URL_PREFIX, req)
247267
if index_match:
248-
context.index_url = index_match[2].strip()
268+
context.add_index_url(index_match[2].strip())
249269
return
250270

251271
if req.startswith("-"):

0 commit comments

Comments
 (0)