Skip to content

Commit

Permalink
Use normalised names inside packages mapping for user-defined mapping
Browse files Browse the repository at this point in the history
If there is more than one custom mapping source (config or files) the resulting custom mapping is a combination of all of them. When a key (pakcage name) that is repeated (with respect to a normalised name) is encountered, all import names are gathered in a list
  • Loading branch information
mknorps committed Apr 17, 2023
1 parent 010aa26 commit 0a0546a
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 43 deletions.
64 changes: 36 additions & 28 deletions fawltydeps/packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from contextlib import contextmanager
from dataclasses import dataclass, field
from enum import Enum
from itertools import chain
from pathlib import Path
from typing import Dict, Iterable, Iterator, List, Optional, Set

Expand All @@ -24,7 +25,7 @@
_top_level_inferred,
)

from fawltydeps.types import CustomMapping, UnparseablePathException, add_mapping_dicts
from fawltydeps.types import CustomMapping, UnparseablePathException
from fawltydeps.utils import calculated_once, hide_dataclass_fields

if sys.version_info >= (3, 11):
Expand Down Expand Up @@ -130,6 +131,26 @@ def __init__(
# We enumerate packages declared in the mapping _once_ and cache the result here:
self._packages: Optional[Dict[str, Package]] = None

@staticmethod
def add_mapping_dicts(
mapping1: CustomMapping, mapping2: CustomMapping
) -> CustomMapping:
"""Add mapping dictionaries and normalise key (package) names."""
result: CustomMapping = {}
for key, value in chain(mapping1.items(), mapping2.items()):
normalised_name = Package.normalize_name(key)
if normalised_name in result:
logger.info(
"Mapping for %s already found. Import names "
"from the second mapping are appended to ones "
"found in the first mapping.",
normalised_name,
)
result[normalised_name].extend(value)
else:
result[normalised_name] = value
return result

@property
@calculated_once
def packages(self) -> Dict[str, Package]:
Expand All @@ -148,41 +169,28 @@ def packages(self) -> Dict[str, Package]:
logger.debug(f"Loading user-defined mapping from {self.mapping_paths}")
for path in self.mapping_paths:
with open(path, "rb") as mapping_file:
custom_mapping_from_files = add_mapping_dicts(
custom_mapping_from_files = self.add_mapping_dicts(
custom_mapping_from_files, tomllib.load(mapping_file)
)

mapping = {
Package.normalize_name(name): Package(
name,
{DependenciesMapping.USER_DEFINED: set(imports)},
)
for name, imports in custom_mapping_from_files.items()
}
custom_mapping = custom_mapping_from_files

if self.custom_mapping is not None:
logger.debug("Applying user-defined mapping from settings.")

for name, imports in self.custom_mapping.items():
normalised_name = Package.normalize_name(name)
if normalised_name in mapping:
logger.info(
"Mapping for %s already found in %s. Import names "
"from the configuration file are appended to ones "
"found in the mapping file.",
normalised_name,
self.mapping_paths,
)
mapping[normalised_name].add_import_names(
*imports, mapping=DependenciesMapping.USER_DEFINED
)
else:
mapping[normalised_name] = Package(
name,
{DependenciesMapping.USER_DEFINED: set(imports)},
)
custom_mapping = self.add_mapping_dicts(
self.custom_mapping, custom_mapping_from_files
)

return mapping
# package name is normalised at this stage, `add_mapping_dicts` was called on
# input files and mapping from the configuration
return {
name: Package(
name,
{DependenciesMapping.USER_DEFINED: set(imports)},
)
for name, imports in custom_mapping.items()
}

def lookup_packages(self, package_names: Set[str]) -> Dict[str, Package]:
"""Convert package names to locally available Package objects."""
Expand Down
12 changes: 0 additions & 12 deletions fawltydeps/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,15 +223,3 @@ def render_problematic_dependency(
f"\n {loc}" for loc in sorted(unique_locations)
)
return ret


def add_mapping_dicts(
mapping1: CustomMapping, mapping2: CustomMapping, normalised_name: bool = True
) -> CustomMapping:
result = mapping1.copy()
for key, value in mapping2.items():
if key in result:
result[key].extend(value)
else:
result[key] = value
return result
6 changes: 3 additions & 3 deletions tests/test_packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ def test_LocalPackageResolver_lookup_packages(dep_name, expect_import_names):
},
{
"apache_airflow": Package(
"apache-airflow", {DependenciesMapping.USER_DEFINED: {"airflow"}}
"apache_airflow", {DependenciesMapping.USER_DEFINED: {"airflow"}}
),
"pip": Package("pip", {DependenciesMapping.LOCAL_ENV: {"pip"}}),
"pandas": Package("pandas", {DependenciesMapping.IDENTITY: {"pandas"}}),
Expand All @@ -354,7 +354,7 @@ def test_LocalPackageResolver_lookup_packages(dep_name, expect_import_names):
{"configuration": {"apache-airflow": ["airflow"]}},
{
"apache_airflow": Package(
"apache-airflow", {DependenciesMapping.USER_DEFINED: {"airflow"}}
"apache_airflow", {DependenciesMapping.USER_DEFINED: {"airflow"}}
),
"pip": Package("pip", {DependenciesMapping.LOCAL_ENV: {"pip"}}),
"pandas": Package("pandas", {DependenciesMapping.IDENTITY: {"pandas"}}),
Expand All @@ -369,7 +369,7 @@ def test_LocalPackageResolver_lookup_packages(dep_name, expect_import_names):
},
{
"apache_airflow": Package(
"apache-airflow",
"apache_airflow",
{DependenciesMapping.USER_DEFINED: {"airflow", "foo", "bar"}},
),
"pip": Package("pip", {DependenciesMapping.LOCAL_ENV: {"pip"}}),
Expand Down

0 comments on commit 0a0546a

Please sign in to comment.