-
Notifications
You must be signed in to change notification settings - Fork 180
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Revert to boolean no-default-feature
- Loading branch information
1 parent
7661d8a
commit 2c7d9fc
Showing
13 changed files
with
111 additions
and
303 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
"""A canonical schema definition for the ``pixi.toml`` manifest file.""" | ||
|
||
from __future__ import annotations | ||
|
||
import json | ||
|
@@ -62,6 +63,7 @@ class Config: | |
|
||
class ChannelInlineTable(StrictBaseModel): | ||
"""A precise description of a `conda` channel, with an optional priority.""" | ||
|
||
channel: ChannelName = Field(description="The channel the packages needs to be fetched from") | ||
priority: int | None = Field(None, description="The priority of the channel") | ||
|
||
|
@@ -71,21 +73,28 @@ class ChannelInlineTable(StrictBaseModel): | |
|
||
class Project(StrictBaseModel): | ||
"""The project's metadata information.""" | ||
|
||
name: NonEmptyStr = Field( | ||
description="The name of the project; we advise use of the name of the repository" | ||
) | ||
version: NonEmptyStr | None = Field( | ||
None, description="The version of the project; we advise use of [SemVer](https://semver.org)", examples=["1.2.3"] | ||
None, | ||
description="The version of the project; we advise use of [SemVer](https://semver.org)", | ||
examples=["1.2.3"], | ||
) | ||
description: NonEmptyStr | None = Field(None, description="A short description of the project") | ||
authors: list[NonEmptyStr] | None = Field( | ||
None, description="The authors of the project", examples=["John Doe <[email protected]>"] | ||
) | ||
channels: list[Channel] = Field( | ||
None, description="The `conda` channels that can be used in the project. Unless overridden by `priority`, the first channel listed will be preferred." | ||
None, | ||
description="The `conda` channels that can be used in the project. Unless overridden by `priority`, the first channel listed will be preferred.", | ||
) | ||
platforms: list[Platform] = Field(description="The platforms that the project supports") | ||
license: NonEmptyStr | None = Field(None, description="The license of the project; we advise using an [SPDX](https://spdx.org/licenses/) identifier.") | ||
license: NonEmptyStr | None = Field( | ||
None, | ||
description="The license of the project; we advise using an [SPDX](https://spdx.org/licenses/) identifier.", | ||
) | ||
license_file: PathNoBackslash | None = Field( | ||
None, alias="license-file", description="The path to the license file of the project" | ||
) | ||
|
@@ -111,6 +120,7 @@ class Project(StrictBaseModel): | |
|
||
class MatchspecTable(StrictBaseModel): | ||
"""A precise description of a `conda` package version.""" | ||
|
||
version: NonEmptyStr | None = Field( | ||
None, | ||
description="The version of the package in [MatchSpec](https://github.com/conda/conda/blob/078e7ee79381060217e1ec7f9b0e9cf80ecc8f3f/conda/models/match_spec.py) format", | ||
|
@@ -134,7 +144,10 @@ class MatchspecTable(StrictBaseModel): | |
|
||
|
||
class _PyPIRequirement(StrictBaseModel): | ||
extras: list[NonEmptyStr] | None = Field(None, description="The [PEP 508 extras](https://peps.python.org/pep-0508/#extras) of the package") | ||
extras: list[NonEmptyStr] | None = Field( | ||
None, | ||
description="The [PEP 508 extras](https://peps.python.org/pep-0508/#extras) of the package", | ||
) | ||
|
||
|
||
class _PyPiGitRequirement(_PyPIRequirement): | ||
|
@@ -198,7 +211,8 @@ class PyPIVersion(_PyPIRequirement): | |
HostDependenciesField = Field( | ||
None, | ||
alias="host-dependencies", | ||
description="The host `conda` dependencies, used in the build process", examples=[{"python": ">=3.8"}] | ||
description="The host `conda` dependencies, used in the build process", | ||
examples=[{"python": ">=3.8"}], | ||
) | ||
BuildDependenciesField = Field( | ||
None, | ||
|
@@ -212,21 +226,26 @@ class PyPIVersion(_PyPIRequirement): | |
################ | ||
TaskName = Annotated[str, Field(pattern=r"^[^\s\$]+$", description="A valid task name.")] | ||
|
||
|
||
class TaskInlineTable(StrictBaseModel): | ||
"""A precise definition of a task.""" | ||
|
||
cmd: list[NonEmptyStr] | NonEmptyStr | None = Field( | ||
None, description="A shell command to run the task in the limited, but cross-platform `bash`-like `deno_task_shell`. See the documentation for [supported syntax](https://pixi.sh/latest/features/advanced_tasks/#syntax)" | ||
None, | ||
description="A shell command to run the task in the limited, but cross-platform `bash`-like `deno_task_shell`. See the documentation for [supported syntax](https://pixi.sh/latest/features/advanced_tasks/#syntax)", | ||
) | ||
cwd: PathNoBackslash | None = Field(None, description="The working directory to run the task") | ||
depends_on: list[TaskName] | TaskName | None = Field( | ||
None, description="The tasks that this task depends on. Environment variables will **not** be expanded." | ||
None, | ||
description="The tasks that this task depends on. Environment variables will **not** be expanded.", | ||
) | ||
inputs: list[Glob] | None = Field( | ||
None, | ||
description="A list of `.gitignore`-style glob patterns that should be watched for changes before this command is run. Environment variables _will_ be expanded.", | ||
) | ||
outputs: list[Glob] | None = Field( | ||
None, description="A list of `.gitignore`-style glob patterns that are generated by this command. Environment variables _will_ be expanded." | ||
None, | ||
description="A list of `.gitignore`-style glob patterns that are generated by this command. Environment variables _will_ be expanded.", | ||
) | ||
env: dict[NonEmptyStr, NonEmptyStr] | None = Field( | ||
None, | ||
|
@@ -247,6 +266,7 @@ class LibcFamily(StrictBaseModel): | |
|
||
class SystemRequirements(StrictBaseModel): | ||
"""Platform-specific requirements""" | ||
|
||
linux: PositiveFloat | NonEmptyStr | None = Field( | ||
None, description="The minimum version of the Linux kernel" | ||
) | ||
|
@@ -269,19 +289,11 @@ class SystemRequirements(StrictBaseModel): | |
EnvironmentName = Annotated[str, Field(pattern=r"^[a-z\d\-]+$")] | ||
FeatureName = NonEmptyStr | ||
SolveGroupName = NonEmptyStr | ||
Component = ( | ||
Literal["system-requirements"] | ||
| Literal["channels"] | ||
| Literal["platforms"] | ||
| Literal["dependencies"] | ||
| Literal["pypi-dependencies"] | ||
| Literal["activation"] | ||
| Literal["tasks"] | ||
) | ||
|
||
|
||
class Environment(StrictBaseModel): | ||
"""A composition of the dependencies of features which can be activated to run tasks or provide a shell""" | ||
|
||
features: list[FeatureName] | None = Field( | ||
None, description="The features that define the environment" | ||
) | ||
|
@@ -290,15 +302,10 @@ class Environment(StrictBaseModel): | |
alias="solve-group", | ||
description="The group name for environments that should be solved together", | ||
) | ||
include_default: list[Component] | None = Field( | ||
False, | ||
alias="include-default", | ||
description="Components of the default feature to include", | ||
) | ||
exclude_default: list[Component] | None = Field( | ||
no_default_feature: Optional[bool] = Field( | ||
False, | ||
alias="exclude-default", | ||
description="Components of the default feature to exclude", | ||
alias="no-default-feature", | ||
description="Whether to add the default feature to this environment", | ||
) | ||
|
||
|
||
|
@@ -307,6 +314,7 @@ class Environment(StrictBaseModel): | |
###################### | ||
class Activation(StrictBaseModel): | ||
"""A description of steps performed when an environment is activated""" | ||
|
||
scripts: list[NonEmptyStr] | None = Field( | ||
None, | ||
description="The scripts to run when the environment is activated", | ||
|
@@ -322,6 +330,7 @@ class Activation(StrictBaseModel): | |
|
||
class Target(StrictBaseModel): | ||
"""A machine-specific configuration of dependencies and tasks""" | ||
|
||
dependencies: Dependencies = DependenciesField | ||
host_dependencies: Dependencies = HostDependenciesField | ||
build_dependencies: Dependencies = BuildDependenciesField | ||
|
@@ -341,8 +350,10 @@ class Target(StrictBaseModel): | |
################### | ||
class Feature(StrictBaseModel): | ||
"""A composable aspect of the project which can contribute dependencies and tasks to an environment""" | ||
|
||
channels: list[Channel] | None = Field( | ||
None, description="The `conda` channels that can be considered when solving environments containing this feature" | ||
None, | ||
description="The `conda` channels that can be considered when solving environments containing this feature", | ||
) | ||
platforms: list[NonEmptyStr] | None = Field( | ||
None, | ||
|
@@ -377,19 +388,20 @@ class Feature(StrictBaseModel): | |
|
||
class BaseManifest(StrictBaseModel): | ||
"""The configuration for a [`pixi`](https://pixi.sh) project.""" | ||
|
||
class Config: | ||
json_schema_extra = { | ||
"$id": SCHEMA_URI, | ||
"$schema": SCHEMA_DRAFT, | ||
"title": "`pixi.toml` manifest file" | ||
"title": "`pixi.toml` manifest file", | ||
} | ||
|
||
schema_: str | None = Field( | ||
SCHEMA_URI, | ||
alias="$schema", | ||
title="Schema", | ||
description="The schema identifier for the project's configuration", | ||
format="uri-reference" | ||
format="uri-reference", | ||
) | ||
|
||
project: Project = Field(..., description="The project's metadata information") | ||
|
@@ -406,7 +418,8 @@ class Config: | |
None, alias="system-requirements", description="The system requirements of the project" | ||
) | ||
environments: dict[EnvironmentName, Environment | list[FeatureName]] | None = Field( | ||
None, description="The environments of the project, defined as a full object or a list of feature names." | ||
None, | ||
description="The environments of the project, defined as a full object or a list of feature names.", | ||
) | ||
feature: dict[FeatureName, Feature] | None = Field( | ||
None, description="The features of the project" | ||
|
@@ -419,7 +432,9 @@ class Config: | |
description="The targets of the project", | ||
examples=[{"linux": {"dependencies": {"python": "3.8"}}}], | ||
) | ||
tool: dict[str, Any] = Field(None, description="Third-party tool configurations, ignored by pixi") | ||
tool: dict[str, Any] = Field( | ||
None, description="Third-party tool configurations, ignored by pixi" | ||
) | ||
|
||
|
||
######################### | ||
|
@@ -429,6 +444,7 @@ class Config: | |
|
||
class SchemaJsonEncoder(json.JSONEncoder): | ||
"""A custom schema encoder for normalizing schema to be used with TOML files.""" | ||
|
||
HEADER_ORDER = [ | ||
"$schema", | ||
"$id", | ||
|
@@ -440,8 +456,7 @@ class SchemaJsonEncoder(json.JSONEncoder): | |
"required", | ||
"additionalProperties", | ||
"default", | ||
"items" | ||
"properties", | ||
"items" "properties", | ||
"patternProperties", | ||
"allOf", | ||
"anyOf", | ||
|
@@ -483,7 +498,7 @@ class SchemaJsonEncoder(json.JSONEncoder): | |
def encode(self, obj): | ||
"""Overload the default ``encode`` behavior.""" | ||
if isinstance(obj, dict): | ||
obj = self.normalize_schema(deepcopy(obj)) | ||
obj = self.normalize_schema(deepcopy(obj)) | ||
|
||
return super().encode(obj) | ||
|
||
|
@@ -534,7 +549,8 @@ def strip_nulls(self, obj: dict[str, Any]) -> dict[str, Any]: | |
|
||
for nest in self.SORT_NESTED_ARR: | ||
some_of = [ | ||
self.normalize_schema(option) for option in obj.get(nest, []) | ||
self.normalize_schema(option) | ||
for option in obj.get(nest, []) | ||
if option.get("type") != "null" | ||
] | ||
|
||
|
@@ -552,22 +568,14 @@ def sort_nested(self, obj: dict[str, Any], key: str) -> dict[str, Any]: | |
return obj | ||
obj[key] = { | ||
k: self.normalize_schema(v) if isinstance(v, dict) else v | ||
for k, v in sorted( | ||
obj[key].items(), | ||
key=lambda kv: kv[0] | ||
) | ||
for k, v in sorted(obj[key].items(), key=lambda kv: kv[0]) | ||
} | ||
return obj | ||
|
||
|
||
########################## | ||
# Command Line Interface # | ||
########################## | ||
|
||
if __name__ == "__main__": | ||
print( | ||
json.dumps( | ||
BaseManifest.model_json_schema(), | ||
indent=2, | ||
cls=SchemaJsonEncoder | ||
) | ||
) | ||
print(json.dumps(BaseManifest.model_json_schema(), indent=2, cls=SchemaJsonEncoder)) |
Oops, something went wrong.