44
55from pathlib import Path
66from posixpath import expandvars
7- from typing import TYPE_CHECKING , Dict , List , Literal , Optional , Tuple
7+ from typing import TYPE_CHECKING , Dict , FrozenSet , List , Literal , Optional , Tuple , Union
88from urllib .parse import urldefrag , urlsplit , urlunsplit
99
1010from clikit .api .io .flags import VERY_VERBOSE
1111from clikit .io import ConsoleIO , NullIO
1212from packaging .tags import compatible_tags , cpython_tags , mac_platforms
1313from packaging .version import Version
1414
15+ from conda_lock ._vendor .poetry .core .semver import VersionConstraint
1516from conda_lock .interfaces .vendored_poetry import (
1617 Chooser ,
1718 Env ,
1819 Factory ,
20+ Link ,
1921 PoetryDependency ,
2022 PoetryPackage ,
2123 PoetryProjectPackage ,
@@ -278,12 +280,51 @@ def parse_pip_requirement(requirement: str) -> Optional[Dict[str, str]]:
278280 return match .groupdict ()
279281
280282
283+ class PoetryDependencyWithHash (PoetryDependency ):
284+ def __init__ (
285+ self ,
286+ name , # type: str
287+ constraint , # type: Union[str, VersionConstraint]
288+ optional = False , # type: bool
289+ category = "main" , # type: str
290+ allows_prereleases = False , # type: bool
291+ extras = None , # type: Optional[Union[List[str], FrozenSet[str]]]
292+ source_type = None , # type: Optional[str]
293+ source_url = None , # type: Optional[str]
294+ source_reference = None , # type: Optional[str]
295+ source_resolved_reference = None , # type: Optional[str]
296+ hash : Optional [str ] = None ,
297+ ) -> None :
298+ super ().__init__ (
299+ name ,
300+ constraint ,
301+ optional = optional ,
302+ category = category ,
303+ allows_prereleases = allows_prereleases ,
304+ extras = extras , # type: ignore # upstream type hint is wrong
305+ source_type = source_type ,
306+ source_url = source_url ,
307+ source_reference = source_reference ,
308+ source_resolved_reference = source_resolved_reference ,
309+ )
310+ self .hash = hash
311+
312+ def get_hash_model (self ) -> Optional [HashModel ]:
313+ if self .hash :
314+ algo , value = self .hash .split (":" )
315+ return HashModel (** {algo : value })
316+ return None
317+
318+
281319def get_dependency (dep : lock_spec .Dependency ) -> PoetryDependency :
282320 # FIXME: how do deal with extras?
283321 extras : List [str ] = []
284322 if isinstance (dep , lock_spec .VersionedDependency ):
285- return PoetryDependency (
286- name = dep .name , constraint = dep .version or "*" , extras = dep .extras
323+ return PoetryDependencyWithHash (
324+ name = dep .name ,
325+ constraint = dep .version or "*" ,
326+ extras = dep .extras ,
327+ hash = dep .hash ,
287328 )
288329 elif isinstance (dep , lock_spec .URLDependency ):
289330 return PoetryURLDependency (
@@ -359,14 +400,9 @@ def get_requirements(
359400 # https://github.com/conda/conda-lock/blob/ac31f5ddf2951ed4819295238ccf062fb2beb33c/conda_lock/_vendor/poetry/installation/executor.py#L557
360401 else :
361402 link = chooser .choose_for (op .package )
362- parsed_url = urlsplit (link .url )
363- link .url = link .url .replace (parsed_url .netloc , str (parsed_url .hostname ))
364- url = link .url_without_fragment
365- hashes : Dict [str , str ] = {}
366- if link .hash_name is not None and link .hash is not None :
367- hashes [link .hash_name ] = link .hash
368- hash = HashModel .parse_obj (hashes )
369-
403+ url = _get_url (link )
404+ hash_chooser = _HashChooser (link , op .package .dependency )
405+ hash = hash_chooser .get_hash ()
370406 if source_repository :
371407 url = source_repository .normalize_solver_url (url )
372408
@@ -387,6 +423,34 @@ def get_requirements(
387423 return requirements
388424
389425
426+ def _get_url (link : Link ) -> str :
427+ parsed_url = urlsplit (link .url )
428+ link .url = link .url .replace (parsed_url .netloc , str (parsed_url .hostname ))
429+ return link .url_without_fragment
430+
431+
432+ class _HashChooser :
433+ def __init__ (
434+ self , link : Link , dependency : Union [PoetryDependency , PoetryDependencyWithHash ]
435+ ):
436+ self .link = link
437+ self .dependency = dependency
438+
439+ def get_hash (self ) -> HashModel :
440+ return self ._get_hash_from_dependency () or self ._get_hash_from_link ()
441+
442+ def _get_hash_from_dependency (self ) -> Optional [HashModel ]:
443+ if isinstance (self .dependency , PoetryDependencyWithHash ):
444+ return self .dependency .get_hash_model ()
445+ return None
446+
447+ def _get_hash_from_link (self ) -> HashModel :
448+ hashes : Dict [str , str ] = {}
449+ if self .link .hash_name is not None and self .link .hash is not None :
450+ hashes [self .link .hash_name ] = self .link .hash
451+ return HashModel .parse_obj (hashes )
452+
453+
390454def solve_pypi (
391455 pip_specs : Dict [str , lock_spec .Dependency ],
392456 use_latest : List [str ],
0 commit comments