Commit 83ec6e9f by Arun Babu Neelicattu Committed by finswimmer

locker: refactor to reduce code complexity

(cherry picked from commit ed43d94b423a7bf53dfb530a549b686d016ab891)
parent 18abfd7b
...@@ -5,11 +5,14 @@ import re ...@@ -5,11 +5,14 @@ import re
from copy import deepcopy from copy import deepcopy
from hashlib import sha256 from hashlib import sha256
from typing import Dict
from typing import Iterable from typing import Iterable
from typing import Iterator from typing import Iterator
from typing import List from typing import List
from typing import Optional from typing import Optional
from typing import Sequence from typing import Sequence
from typing import Set
from typing import Tuple
from typing import Union from typing import Union
from tomlkit import array from tomlkit import array
...@@ -185,21 +188,10 @@ class Locker(object): ...@@ -185,21 +188,10 @@ class Locker(object):
return packages return packages
@classmethod @staticmethod
def get_project_dependencies(
cls, project_requires, locked_packages, pinned_versions=False, with_nested=False
): # type: (List[Dependency], List[Package], bool, bool) -> Iterable[Dependency]
# group packages entries by name, this is required because requirement might use
# different constraints
packages_by_name = {}
for pkg in locked_packages:
if pkg.name not in packages_by_name:
packages_by_name[pkg.name] = []
packages_by_name[pkg.name].append(pkg)
def __get_locked_package( def __get_locked_package(
_dependency, _dependency, packages_by_name
): # type: (Dependency) -> Optional[Package] ): # type: (Dependency, Dict[str, List[Package]]) -> Optional[Package]
""" """
Internal helper to identify corresponding locked package using dependency Internal helper to identify corresponding locked package using dependency
version constraints. version constraints.
...@@ -209,66 +201,43 @@ class Locker(object): ...@@ -209,66 +201,43 @@ class Locker(object):
return _package return _package
return None return None
project_level_dependencies = set() @classmethod
dependencies = [] def __walk_dependency_level(
cls,
for dependency in project_requires: dependencies,
dependency = deepcopy(dependency) level,
locked_package = __get_locked_package(dependency) pinned_versions,
if locked_package: packages_by_name,
locked_dependency = locked_package.to_dependency() project_level_dependencies,
locked_dependency.marker = dependency.marker.intersect( nested_dependencies,
locked_package.marker ): # type: (List[Dependency], int, bool, Dict[str, List[Package]], Set[str], Dict[Tuple[str, str], Dependency]) -> Dict[Tuple[str, str], Dependency]
) if not dependencies:
return nested_dependencies
if not pinned_versions:
locked_dependency.set_constraint(dependency.constraint) next_level_dependencies = []
dependency = locked_dependency
project_level_dependencies.add(dependency.name)
dependencies.append(dependency)
if not with_nested:
# return only with project level dependencies
return dependencies
nested_dependencies = dict()
def __walk_level(
__dependencies, __level
): # type: (List[Dependency], int) -> None
if not __dependencies:
return
__next_level = []
for requirement in __dependencies: for requirement in dependencies:
__locked_package = __get_locked_package(requirement) locked_package = cls.__get_locked_package(requirement, packages_by_name)
if __locked_package: if locked_package:
for require in __locked_package.requires: for require in locked_package.requires:
if require.marker.is_empty(): if require.marker.is_empty():
require.marker = requirement.marker require.marker = requirement.marker
else: else:
require.marker = require.marker.intersect( require.marker = require.marker.intersect(requirement.marker)
requirement.marker
)
require.marker = require.marker.intersect( require.marker = require.marker.intersect(locked_package.marker)
__locked_package.marker next_level_dependencies.append(require)
)
__next_level.append(require)
if requirement.name in project_level_dependencies and __level == 0: if requirement.name in project_level_dependencies and level == 0:
# project level dependencies take precedence # project level dependencies take precedence
continue continue
if __locked_package: if locked_package:
# create dependency from locked package to retain dependency metadata # create dependency from locked package to retain dependency metadata
# if this is not done, we can end-up with incorrect nested dependencies # if this is not done, we can end-up with incorrect nested dependencies
marker = requirement.marker marker = requirement.marker
requirement = __locked_package.to_dependency() requirement = locked_package.to_dependency()
requirement.marker = requirement.marker.intersect(marker) requirement.marker = requirement.marker.intersect(marker)
else: else:
# we make a copy to avoid any side-effects # we make a copy to avoid any side-effects
...@@ -276,7 +245,9 @@ class Locker(object): ...@@ -276,7 +245,9 @@ class Locker(object):
if pinned_versions: if pinned_versions:
requirement.set_constraint( requirement.set_constraint(
__get_locked_package(requirement).to_dependency().constraint cls.__get_locked_package(requirement, packages_by_name)
.to_dependency()
.constraint
) )
# dependencies use extra to indicate that it was activated via parent # dependencies use extra to indicate that it was activated via parent
...@@ -292,9 +263,58 @@ class Locker(object): ...@@ -292,9 +263,58 @@ class Locker(object):
key key
].marker.intersect(requirement.marker) ].marker.intersect(requirement.marker)
return __walk_level(__next_level, __level + 1) return cls.__walk_dependency_level(
dependencies=next_level_dependencies,
level=level + 1,
pinned_versions=pinned_versions,
packages_by_name=packages_by_name,
project_level_dependencies=project_level_dependencies,
nested_dependencies=nested_dependencies,
)
@classmethod
def get_project_dependencies(
cls, project_requires, locked_packages, pinned_versions=False, with_nested=False
): # type: (List[Dependency], List[Package], bool, bool) -> Iterable[Dependency]
# group packages entries by name, this is required because requirement might use different constraints
packages_by_name = {}
for pkg in locked_packages:
if pkg.name not in packages_by_name:
packages_by_name[pkg.name] = []
packages_by_name[pkg.name].append(pkg)
project_level_dependencies = set()
dependencies = []
for dependency in project_requires:
dependency = deepcopy(dependency)
locked_package = cls.__get_locked_package(dependency, packages_by_name)
if locked_package:
locked_dependency = locked_package.to_dependency()
locked_dependency.marker = dependency.marker.intersect(
locked_package.marker
)
if not pinned_versions:
locked_dependency.set_constraint(dependency.constraint)
__walk_level(dependencies, 0) dependency = locked_dependency
project_level_dependencies.add(dependency.name)
dependencies.append(dependency)
if not with_nested:
# return only with project level dependencies
return dependencies
nested_dependencies = cls.__walk_dependency_level(
dependencies=dependencies,
level=0,
pinned_versions=pinned_versions,
packages_by_name=packages_by_name,
project_level_dependencies=project_level_dependencies,
nested_dependencies=dict(),
)
# Merge same dependencies using marker union # Merge same dependencies using marker union
for requirement in dependencies: for requirement in dependencies:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment