Skip to content

Commit

Permalink
Add dependency_name_map option.
Browse files Browse the repository at this point in the history
  • Loading branch information
bwoodsend committed Oct 26, 2023
1 parent 63ce288 commit 201da6c
Show file tree
Hide file tree
Showing 13 changed files with 58 additions and 12 deletions.
11 changes: 11 additions & 0 deletions docs/source/schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,17 @@ test_files:
# you need. Globs are expanded using `pathlib.Path.glob`. All paths are
# relative to the directory containing the ``polycotylus.yaml``.

dependency_name_map:
GitPython:
debian: python3-git
# An override for `polycotylus`\ 's mapping of pip/PyPI package to Linux
# package equivalents. To be used if one of your dependencies is available in
# the Linux package repositories but `polycotylus` can't find it because it's
# been named something that breaks the distribution's naming convention. Note
# that this option does not exist for ``fedora`` or ``opensuse`` due to their
# handling the mapping using package *capabilities* rather than a naming
# pattern.


# --------------------
# CLI/GUI only options
Expand Down
2 changes: 1 addition & 1 deletion docs/source/schema_to_rst.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
yaml[key].append(m[2])
i += 1
value = yaml
if key == "actions":
if key in {"actions", "dependency_name_map"}:
chunk = []
while not comment_re.match(lines[i]):
chunk.append(lines[i])
Expand Down
Binary file not shown.
20 changes: 16 additions & 4 deletions polycotylus/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def evaluate_requirements_marker(cls, requirement: Requirement):
})

@classmethod
def python_package(cls, requirement):
def python_package(cls, requirement, dependency_name_map=None):
requirement = Requirement(requirement)
name = re.sub("[._-]+", "-", requirement.name.lower())
available = cls.available_packages_normalized()
Expand All @@ -107,13 +107,15 @@ def python_package(cls, requirement):
return
else:
requirement.marker = None
if cls.python_package_convention(name) in available:
if dependency_name_map and name in dependency_name_map:
name = dependency_name_map[name]
elif cls.python_package_convention(name) in available:
name = available[cls.python_package_convention(name)]
elif name in available:
name = available[name]
elif m := re.match("(python|py)3?-?(.*)", name.lower()):
try:
name = cls.python_package(m[2])
name = cls.python_package(m[2], dependency_name_map)
except _exceptions.PackageUnavailableError:
raise _exceptions.PackageUnavailableError(requirement.name, cls.name) from None
else:
Expand All @@ -123,6 +125,16 @@ def python_package(cls, requirement):
requirement.extras = set()
return str(requirement)

@property
def dependency_name_map(self):
out = {}
for (package, map) in self.project.dependency_name_map.items():
for key in map:
if self.name in key.split():
out[re.sub("[._-]+", "-", package.lower())] = map[key]
break
return out

@abc.abstractmethod
def fix_package_name(name):
"""Apply the distribution's package naming rules for case folding/
Expand Down Expand Up @@ -191,7 +203,7 @@ def _dependencies(self, dependencies):
for extra in dependencies.get("python", []):
out += self.python_extras.get(extra, [])
for package in dependencies.get("pip", []):
out.append(self.python_package(package))
out.append(self.python_package(package, self.dependency_name_map))
out += dependencies.get(self.name, [])
return list(filter(None, out))

Expand Down
12 changes: 10 additions & 2 deletions polycotylus/_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,18 @@ def __init__(self, package, distribution):

def __str__(self):
return _unravel(f"""
Dependency "{self.package}" is not available on
Dependency "{self.package}" appears to be unavailable on
{self.distribution.title()} Linux. You will need to submit
{self.package} to {self.distribution.title()} Linux's package
repositories before you can build your own project.
repositories before you can build your own project. It's also
possible that it is already there but is named something weird,
in which case, supply its name to the dependency_name_map option in
the polycotylus.yaml:
# polycoylus.yaml
dependency_name_map:
{self.package}:
{self.distribution}: whatever-its-really-called
""")


Expand Down
2 changes: 1 addition & 1 deletion polycotylus/_fedora.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def python_version(cls):
return _docker.run(cls.base_image, command, tty=True).output.strip()

@classmethod
def python_package(cls, requirement):
def python_package(cls, requirement, _=None):
requirement = Requirement(requirement)
requirement.name = f"python3dist({cls.fix_package_name(requirement.name)})"
if not cls.evaluate_requirements_marker(requirement):
Expand Down
2 changes: 1 addition & 1 deletion polycotylus/_opensuse.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def fix_package_name(name):
return re.sub(r"[^a-z0-9]+", "-", name.lower())

@classmethod
def python_package(cls, requirement):
def python_package(cls, requirement, _=None):
requirement = Requirement(requirement)
name = re.sub("[._-]+", "-", requirement.name.lower())
available = cls.available_packages_normalized()
Expand Down
2 changes: 2 additions & 0 deletions polycotylus/_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class Project:
dependencies: dict
build_dependencies: dict
test_dependencies: dict
dependency_name_map: dict
test_command: str
test_files: list
license_names: list
Expand Down Expand Up @@ -313,6 +314,7 @@ def from_root(cls, root):
build_dependencies=dependencies["build"],
test_dependencies=dependencies["test"],
test_command=test_command,
dependency_name_map=polycotylus_options.get("dependency_name_map", {}),
test_files=test_files,
url=project["urls"]["homepage"],
license_names=license_names,
Expand Down
2 changes: 1 addition & 1 deletion polycotylus/_yaml_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ def validate_scalar(self, chunk):
Optional("dependencies"): Map({
Optional(type): dependencies_group for type in ["run", "build", "test"]
}),
Optional("dependency_map"): MapPattern(Str(), MapPattern(Str(), Str())),
Optional("maintainer"): Maintainer(),
Optional("gui"): Bool(),
Optional("spdx"): MapPattern(Str(), EmptyDict()),
Expand All @@ -130,6 +129,7 @@ def validate_scalar(self, chunk):
Regex("(any|none)"),
WhitespaceDelimited(Regex("!?(" + "|".join(architectures) + ")")),
),
Optional("dependency_name_map"): MapPattern(Str(), MapPattern(Str(), Str())),
})


Expand Down
4 changes: 4 additions & 0 deletions tests/mock-packages/kitchen-sink/polycotylus.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ dependencies:
python: sqlite3 tkinter
pip: pytest[feet]

dependency_name_map:
tzlocal:
arch manjaro: gnu-netcat

test_command: TEST_VARIABLE=hello pytest -k 'not unrunable' && python -c 'print("hello")'

test_files:
Expand Down
2 changes: 1 addition & 1 deletion tests/mock-packages/kitchen-sink/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ authors = [
]
dynamic = ["version"]
license = { file="The license file" }
dependencies = ["certifi>=2020.4", "pywin32-ctypes; platform_system == 'Windows'"]
dependencies = ["certifi>=2020.4", "pywin32-ctypes; platform_system == 'Windows'", "tzlocal"]

[build-system]
requires = ["colorama; platform_system == 'Linux' and python_version >= '3.8' and implementation_name == 'cpython'", "setuptools", "setuptools-scm"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,12 @@ def test_unrunable():

def test_environment_variable():
assert os.environ["TEST_VARIABLE"] == "hello"


def test_dependency_name_map():
if shutil.which("pacman"):
assert shutil.which("netcat")
with pytest.raises(ImportError):
import tzlocal
else:
import tzlocal
2 changes: 1 addition & 1 deletion tests/test_alpine.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ def test_unknown_package(polycotylus_yaml):
""")
self = Alpine(Project.from_root(shared.dumb_text_viewer))
with pytest.raises(_exceptions.PolycotylusUsageError,
match="Dependency \"Hippos_can_fly\" is not .* on Alpine Linux. "
match="Dependency \"Hippos_can_fly\" appears .* on Alpine Linux. "
".* submit Hippos_can_fly to Alpine Linux\'s package"):
self.apkbuild()
polycotylus_yaml("""
Expand Down

0 comments on commit 201da6c

Please sign in to comment.