Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for dependency groups #183

Merged
merged 1 commit into from
Jul 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 58 additions & 18 deletions poetry/core/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class Factory(object):
"""

def create_poetry(
self, cwd: Optional[Path] = None, with_dev: bool = True
self, cwd: Optional[Path] = None, with_groups: bool = True
) -> "Poetry":
from .poetry import Poetry
from .pyproject.toml import PyProjectTOML
Expand All @@ -49,7 +49,7 @@ def create_poetry(
version = local_config["version"]
package = self.get_package(name, version)
package = self.configure_package(
package, local_config, poetry_file.parent, with_dev=with_dev
package, local_config, poetry_file.parent, with_groups=with_groups
)

return Poetry(poetry_file, local_config, package)
Expand All @@ -66,9 +66,10 @@ def configure_package(
package: "ProjectPackage",
config: Dict[str, Any],
root: Path,
with_dev: bool = True,
with_groups: bool = True,
) -> "ProjectPackage":
from .packages.dependency import Dependency
from .packages.dependency_group import DependencyGroup
from .spdx.helpers import license_by_id

package.root_dir = root
Expand Down Expand Up @@ -99,46 +100,82 @@ def configure_package(
package.platform = config["platform"]

if "dependencies" in config:
group = DependencyGroup("default")
for name, constraint in config["dependencies"].items():
if name.lower() == "python":
package.python_versions = constraint
continue

if isinstance(constraint, list):
for _constraint in constraint:
package.add_dependency(
group.add_dependency(
cls.create_dependency(
name, _constraint, root_dir=package.root_dir
)
)

continue

package.add_dependency(
group.add_dependency(
cls.create_dependency(name, constraint, root_dir=package.root_dir)
)

if with_dev and "dev-dependencies" in config:
package.add_dependency_group(group)

if with_groups and "group" in config:
for group_name, group_config in config["group"].items():
group = DependencyGroup(
group_name, optional=group_config.get("optional", False)
)
for name, constraint in group_config["dependencies"].items():
if isinstance(constraint, list):
for _constraint in constraint:
group.add_dependency(
cls.create_dependency(
name,
_constraint,
groups=[group_name],
root_dir=package.root_dir,
)
)

continue

group.add_dependency(
cls.create_dependency(
name,
constraint,
groups=[group_name],
root_dir=package.root_dir,
)
)

package.add_dependency_group(group)

if with_groups and "dev-dependencies" in config:
group = DependencyGroup("dev")
for name, constraint in config["dev-dependencies"].items():
if isinstance(constraint, list):
for _constraint in constraint:
package.add_dependency(
group.add_dependency(
cls.create_dependency(
name,
_constraint,
category="dev",
groups=["dev"],
root_dir=package.root_dir,
)
)

continue

package.add_dependency(
group.add_dependency(
cls.create_dependency(
name, constraint, category="dev", root_dir=package.root_dir
name, constraint, groups=["dev"], root_dir=package.root_dir
)
)

package.add_dependency_group(group)

extras = config.get("extras", {})
for extra_name, requirements in extras.items():
package.extras[extra_name] = []
Expand Down Expand Up @@ -191,7 +228,7 @@ def create_dependency(
cls,
name: str,
constraint: Union[str, Dict[str, Any]],
category: str = "main",
groups: Optional[List[str]] = None,
root_dir: Optional[Path] = None,
) -> "DependencyTypes":
from .packages.constraints import parse_constraint as parse_generic_constraint
Expand All @@ -204,6 +241,9 @@ def create_dependency(
from .version.markers import AnyMarker
from .version.markers import parse_marker

if groups is None:
groups = ["default"]

if constraint is None:
constraint = "*"

Expand Down Expand Up @@ -234,7 +274,7 @@ def create_dependency(
branch=constraint.get("branch", None),
tag=constraint.get("tag", None),
rev=constraint.get("rev", None),
category=category,
groups=groups,
optional=optional,
develop=constraint.get("develop", False),
extras=constraint.get("extras", []),
Expand All @@ -245,7 +285,7 @@ def create_dependency(
dependency = FileDependency(
name,
file_path,
category=category,
groups=groups,
base=root_dir,
extras=constraint.get("extras", []),
)
Expand All @@ -261,7 +301,7 @@ def create_dependency(
dependency = FileDependency(
name,
path,
category=category,
groups=groups,
optional=optional,
base=root_dir,
extras=constraint.get("extras", []),
Expand All @@ -270,7 +310,7 @@ def create_dependency(
dependency = DirectoryDependency(
name,
path,
category=category,
groups=groups,
optional=optional,
base=root_dir,
develop=constraint.get("develop", False),
Expand All @@ -280,7 +320,7 @@ def create_dependency(
dependency = URLDependency(
name,
constraint["url"],
category=category,
groups=groups,
optional=optional,
extras=constraint.get("extras", []),
)
Expand All @@ -291,7 +331,7 @@ def create_dependency(
name,
version,
optional=optional,
category=category,
groups=groups,
allows_prereleases=allows_prereleases,
extras=constraint.get("extras", []),
)
Expand Down Expand Up @@ -324,7 +364,7 @@ def create_dependency(

dependency.source_name = constraint.get("source")
else:
dependency = Dependency(name, constraint, category=category)
dependency = Dependency(name, constraint, groups=groups)

return dependency

Expand Down
26 changes: 26 additions & 0 deletions poetry/core/json/schemas/poetry-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,32 @@
}
}
},
"group": {
"type": "object",
"description": "This represents groups of dependencies",
"patternProperties": {
"^[a-zA-Z-_.0-9]+$": {
"type": "object",
"description": "This represents a single dependency group",
"required": [
"dependencies"
],
"properties": {
"optional": {
"type": "boolean",
"description": "Whether the dependency group is optional or not"
},
"dependencies": {
"type": "object",
"description": "The dependencies of this dependency group",
"$ref": "#/definitions/dependencies",
"additionalProperties": false
}
},
"additionalProperties": false
}
}
},
"build": {
"$ref": "#/definitions/build-section"
},
Expand Down
6 changes: 3 additions & 3 deletions poetry/core/masonry/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def get_requires_for_build_wheel(
def prepare_metadata_for_build_wheel(
metadata_directory: str, config_settings: Optional[Dict[str, Any]] = None
) -> str:
poetry = Factory().create_poetry(Path(".").resolve(), with_dev=False)
poetry = Factory().create_poetry(Path(".").resolve(), with_groups=False)
builder = WheelBuilder(poetry)

dist_info = Path(metadata_directory, builder.dist_info)
Expand All @@ -64,7 +64,7 @@ def build_wheel(
metadata_directory: Optional[str] = None,
) -> str:
"""Builds a wheel, places it in wheel_directory"""
poetry = Factory().create_poetry(Path(".").resolve(), with_dev=False)
poetry = Factory().create_poetry(Path(".").resolve(), with_groups=False)

return WheelBuilder.make_in(poetry, Path(wheel_directory))

Expand All @@ -73,7 +73,7 @@ def build_sdist(
sdist_directory: str, config_settings: Optional[Dict[str, Any]] = None
) -> str:
"""Builds an sdist, places it in sdist_directory"""
poetry = Factory().create_poetry(Path(".").resolve(), with_dev=False)
poetry = Factory().create_poetry(Path(".").resolve(), with_groups=False)

path = SdistBuilder(poetry).build(Path(sdist_directory))

Expand Down
14 changes: 9 additions & 5 deletions poetry/core/packages/dependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def __init__(
name: str,
constraint: Union[str, "VersionTypes"],
optional: bool = False,
category: str = "main",
groups: Optional[List[str]] = None,
allows_prereleases: bool = False,
extras: Union[List[str], FrozenSet[str]] = None,
source_type: Optional[str] = None,
Expand All @@ -58,7 +58,11 @@ def __init__(

self._pretty_constraint = str(constraint)
self._optional = optional
self._category = category

if not groups:
groups = ["default"]

self._groups = frozenset(groups)

if (
isinstance(self._constraint, VersionRangeConstraint)
Expand Down Expand Up @@ -113,8 +117,8 @@ def pretty_name(self) -> str:
return self._pretty_name

@property
def category(self) -> str:
return self._category
def groups(self) -> FrozenSet[str]:
return self._groups

@property
def python_versions(self) -> str:
Expand Down Expand Up @@ -387,7 +391,7 @@ def with_constraint(self, constraint: Union[str, "VersionTypes"]) -> "Dependency
self.pretty_name,
constraint,
optional=self.is_optional(),
category=self.category,
groups=list(self._groups),
allows_prereleases=self.allows_prereleases(),
extras=self._extras,
source_type=self._source_type,
Expand Down
54 changes: 54 additions & 0 deletions poetry/core/packages/dependency_group.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from typing import TYPE_CHECKING
from typing import List


if TYPE_CHECKING:
from .types import DependencyTypes


class DependencyGroup:
def __init__(self, name: str, optional: bool = False) -> None:
self._name: str = name
self._optional: bool = optional
self._dependencies: List["DependencyTypes"] = []

@property
def name(self) -> str:
return self._name

@property
def dependencies(self) -> List["DependencyTypes"]:
return self._dependencies

def is_optional(self) -> bool:
return self._optional

def add_dependency(self, dependency: "DependencyTypes") -> None:
self._dependencies.append(dependency)

def remove_dependency(self, name: "str") -> None:
from poetry.core.utils.helpers import canonicalize_name

name = canonicalize_name(name)

dependencies = []
for dependency in dependencies:
if dependency.name == name:
continue

dependencies.append(dependency)

self._dependencies = dependencies

def __eq__(self, other: "DependencyGroup") -> bool:
if not isinstance(other, DependencyGroup):
return NotImplemented

return self._name == other.name and set(self._dependencies) == set(
other.dependencies
)

def __repr__(self) -> str:
return "{}({}, optional={})".format(
self.__class__.__name__, self._name, self._optional
)
6 changes: 3 additions & 3 deletions poetry/core/packages/directory_dependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def __init__(
self,
name: str,
path: Path,
category: str = "main",
groups: Optional[List[str]] = None,
optional: bool = False,
base: Optional[Path] = None,
develop: bool = False,
Expand Down Expand Up @@ -61,7 +61,7 @@ def __init__(
super(DirectoryDependency, self).__init__(
name,
"*",
category=category,
groups=groups,
optional=optional,
allows_prereleases=True,
source_type="directory",
Expand Down Expand Up @@ -97,7 +97,7 @@ def with_constraint(self, constraint: "BaseConstraint") -> "DirectoryDependency"
path=self.path,
base=self.base,
optional=self.is_optional(),
category=self.category,
groups=list(self._groups),
develop=self._develop,
extras=self._extras,
)
Expand Down
Loading