Skip to content

Commit

Permalink
[DRAFT] Add version to metadata hook, use version to retrieve deps
Browse files Browse the repository at this point in the history
This is a very draft proposal on how to fix #1348 and #1349 - more
to see if this is a good direction. It should likely be split to
two PRs (and of course tests and docs are needed):

* extending custom metadata plugin to allow different versions for
  standard and editable builds (also including extending the hatchling
  CLIs.

* adding version to CLI where hatch queries hatchling to include standard/
  editable version when querying for available dependencies.

Not all changes have been yet applied, this is more to check if
this is the right direction.
  • Loading branch information
potiuk committed May 20, 2024
1 parent ae8c3fb commit f86ef9a
Show file tree
Hide file tree
Showing 7 changed files with 30 additions and 17 deletions.
18 changes: 8 additions & 10 deletions backend/src/hatchling/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ def build_sdist(sdist_directory: str, config_settings: dict[str, Any] | None = N
"""
from hatchling.builders.sdist import SdistBuilder

builder = SdistBuilder(os.getcwd())
return os.path.basename(next(builder.build(directory=sdist_directory, versions=['standard'])))
builder = SdistBuilder(os.getcwd(), versions=['standard'])
return os.path.basename(next(builder.build(directory=sdist_directory)))


def get_requires_for_build_wheel(config_settings: dict[str, Any] | None = None) -> list[str]: # noqa: ARG001
Expand All @@ -54,8 +54,8 @@ def build_wheel(
"""
from hatchling.builders.wheel import WheelBuilder

builder = WheelBuilder(os.getcwd())
return os.path.basename(next(builder.build(directory=wheel_directory, versions=['standard'])))
builder = WheelBuilder(os.getcwd(), versions=['standard'])
return os.path.basename(next(builder.build(directory=wheel_directory)))


def get_requires_for_build_editable(config_settings: dict[str, Any] | None = None) -> list[str]: # noqa: ARG001
Expand All @@ -79,9 +79,8 @@ def build_editable(
"""
from hatchling.builders.wheel import WheelBuilder

builder = WheelBuilder(os.getcwd())
return os.path.basename(next(builder.build(directory=wheel_directory, versions=['editable'])))

builder = WheelBuilder(os.getcwd(), versions=['editable'])
return os.path.basename(next(builder.build(directory=wheel_directory)))

# Any builder that has build-time hooks like Hatchling and setuptools cannot technically keep PEP 517's identical
# metadata promise e.g. C extensions would require different tags in the `WHEEL` file. Therefore, we consider the
Expand All @@ -106,8 +105,7 @@ def prepare_metadata_for_build_wheel(
https://peps.python.org/pep-0517/#prepare-metadata-for-build-wheel
"""
from hatchling.builders.wheel import WheelBuilder

builder = WheelBuilder(os.getcwd())
builder = WheelBuilder(os.getcwd(), versions=["standard"])

directory = os.path.join(metadata_directory, f'{builder.artifact_project_id}.dist-info')
if not os.path.isdir(directory):
Expand All @@ -128,7 +126,7 @@ def prepare_metadata_for_build_editable(
from hatchling.builders.constants import EDITABLES_REQUIREMENT
from hatchling.builders.wheel import WheelBuilder

builder = WheelBuilder(os.getcwd())
builder = WheelBuilder(os.getcwd(), versions=['editable'])

directory = os.path.join(metadata_directory, f'{builder.artifact_project_id}.dist-info')
if not os.path.isdir(directory):
Expand Down
9 changes: 5 additions & 4 deletions backend/src/hatchling/builders/plugin/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,15 @@ def __init__(
config: dict[str, Any] | None = None,
metadata: ProjectMetadata | None = None,
app: Application | None = None,
versions: list[str] | None = None,
) -> None:
self.__root = root
self.__plugin_manager = cast(PluginManagerBound, plugin_manager)
self.__raw_config = config
self.__metadata = metadata
self.__app = app
self.__config = cast(BuilderConfigBound, None)
self.__versions = versions
self.__project_config: dict[str, Any] | None = None
self.__hatch_config: dict[str, Any] | None = None
self.__build_config: dict[str, Any] | None = None
Expand All @@ -80,7 +82,6 @@ def build(
self,
*,
directory: str | None = None,
versions: list[str] | None = None,
hooks_only: bool | None = None,
clean: bool | None = None,
clean_hooks_after: bool | None = None,
Expand All @@ -101,7 +102,7 @@ def build(

version_api = self.get_version_api()

versions = versions or self.config.versions
versions = self.__versions or self.config.versions
if versions:
unknown_versions = set(versions) - set(version_api)
if unknown_versions:
Expand Down Expand Up @@ -290,8 +291,8 @@ def metadata(self) -> ProjectMetadata:
if self.__metadata is None:
from hatchling.metadata.core import ProjectMetadata

self.__metadata = ProjectMetadata(self.root, self.plugin_manager, self.__raw_config)

self.__metadata = ProjectMetadata(self.root, self.plugin_manager, self.__raw_config,
self.__versions)
return self.__metadata

@property
Expand Down
1 change: 0 additions & 1 deletion backend/src/hatchling/builders/wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,6 @@ def build_editable_detection(self, directory: str, **build_data: Any) -> str:
from editables import EditableProject

build_data['tag'] = self.get_default_tag()

with WheelArchive(
self.artifact_project_id, reproducible=self.config.reproducible
) as archive, RecordFile() as records:
Expand Down
4 changes: 3 additions & 1 deletion backend/src/hatchling/cli/metadata/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ def metadata_impl(
called_by_app: bool, # noqa: ARG001
field: str,
compact: bool,
version: str = "standard",
) -> None:
import json
import os
Expand All @@ -22,7 +23,7 @@ def metadata_impl(

root = os.getcwd()
plugin_manager = PluginManager()
project_metadata = ProjectMetadata(root, plugin_manager)
project_metadata = ProjectMetadata(root, plugin_manager, build_versions=[version])

metadata = resolve_metadata_fields(project_metadata)
if field: # no cov
Expand Down Expand Up @@ -55,4 +56,5 @@ def metadata_command(
parser.add_argument('field', nargs='?')
parser.add_argument('-c', '--compact', action='store_true')
parser.add_argument('--app', dest='called_by_app', action='store_true', help=argparse.SUPPRESS)
parser.add_argument('--version', dest='version', default="standard")
parser.set_defaults(func=metadata_impl)
5 changes: 5 additions & 0 deletions backend/src/hatchling/metadata/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def __init__(
root: str,
plugin_manager: PluginManagerBound | None,
config: dict[str, Any] | None = None,
build_versions: list[str] | None = None,
) -> None:
self.root = root
self.plugin_manager = plugin_manager
Expand All @@ -57,6 +58,7 @@ def __init__(
self._name: str | None = None
self._version: str | None = None
self._project_file: str | None = None
self._build_versions = build_versions

# App already loaded config
if config is not None and root is not None:
Expand Down Expand Up @@ -194,6 +196,9 @@ def core(self) -> CoreMetadata:
if metadata.dynamic:
for metadata_hook in metadata_hooks.values():
metadata_hook.update(self.core_raw_metadata)
if hasattr(metadata_hook, "update_for_version") and self._build_versions:
for version in self._build_versions:
metadata_hook.update_for_version(self.core_raw_metadata, version)
metadata.add_known_classifiers(metadata_hook.get_known_classifiers())

new_fields = set(self.core_raw_metadata) - static_fields
Expand Down
7 changes: 7 additions & 0 deletions backend/src/hatchling/metadata/plugin/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ def update(self, metadata: dict) -> None:
This updates the metadata mapping of the `project` table in-place.
"""

def update_for_version(self, metadata: dict, version: str) -> None:
"""
Optional. This updates the metadata mapping of the `project` table in-place - for a specific version
(standard/editable). This is run after "update" method and can update or replace metadata
specific for a version.
"""

def get_known_classifiers(self) -> list[str]: # noqa: PLR6301
"""
This returns extra classifiers that should be considered valid in addition to the ones known to PyPI.
Expand Down
3 changes: 2 additions & 1 deletion src/hatch/utils/dep.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ def get_project_dependencies_complex(
from packaging.requirements import Requirement

with environment.root.as_cwd(), environment.build_environment(environment.metadata.build.requires):
command = ['python', '-u', '-W', 'ignore', '-m', 'hatchling', 'metadata', '--compact']
command = ['python', '-u', '-W', 'ignore', '-m', 'hatchling', 'metadata', '--compact',
"--version", "editable" if environment.dev_mode else "standard"]
output = environment.platform.check_command_output(
command,
# Only capture stdout
Expand Down

0 comments on commit f86ef9a

Please sign in to comment.