Skip to content

API Reference: Release

Building a data package

create_data_package(registry, release_spec, fn_out, resolve_references=True)

Create a data package release specification from a dictionary or a YAML/JSON file.

Parameters:

Name Type Description Default
registry CrossRegistry

The registry to use for validating contract references.

required
release_spec Path | CrossDataPackageReleaseSpec | str

The release specification as a CrossDataPackageReleaseSpec instance or a path to a YAML/JSON file containing the release specification.

required
fn_out Path | str

File path to write the data package containing the data as well as the data package descriptor (a YAML and JSON file) to.

required
resolve_references bool

Whether to resolve and include referenced resources (e.g., dimensions) in the package. When False, foreign keys to excluded resources are dropped from the released schemas to keep the package Frictionless-compliant. Defaults to True.

True
Source code in src/crosscontract/release/data_package/create_data_package.py
def create_data_package(
    registry: CrossRegistry,
    release_spec: Path | CrossDataPackageReleaseSpec | str,
    fn_out: Path | str,
    resolve_references: bool = True,
) -> None:
    """Create a data package release specification from a dictionary or a YAML/JSON
    file.

    Args:
        registry (CrossRegistry): The registry to use for validating contract
            references.
        release_spec (Path | CrossDataPackageReleaseSpec | str): The release
            specification as a `CrossDataPackageReleaseSpec` instance or a path
            to a YAML/JSON file containing the release specification.
        fn_out (Path | str): File path to write the data package containing the
            data as well as the data package descriptor (a YAML and JSON file) to.
        resolve_references (bool, optional): Whether to resolve and include
            referenced resources (e.g., dimensions) in the package. When `False`,
            foreign keys to excluded resources are dropped from the released schemas
            to keep the package Frictionless-compliant. Defaults to `True`.
    """
    if isinstance(release_spec, (str, Path)):
        release_spec_dict = read_yaml_or_json_file(release_spec)
        release_spec = CrossDataPackageReleaseSpec.model_validate(release_spec_dict)

    # get the data for each resource according to the release specification
    my_resources = resolve_resources(
        registry, release_spec, resolve_references=resolve_references
    )

    # dump files and create the package descriptor
    save_data_package(release_spec, my_resources, fn_out)

Release specification

Bases: PackageMetaData

Release specification for a data package.

Carries the package-level metadata (inherited from frictionless.PackageMetaData) together with a CrossDataResourceReleaseSpec per resource, each bundling the resource's metadata with the DataInstructions for fetching its data. This is a build recipe, not a Frictionless descriptor: a later build step pairs it with a resolver to fetch the data and materialize the package.

Source code in src/crosscontract/release/data_package/release_specification.py
class CrossDataPackageReleaseSpec(PackageMetaData):
    """Release specification for a data package.

    Carries the package-level metadata (inherited from `frictionless.PackageMetaData`)
    together with a `CrossDataResourceReleaseSpec` per resource, each bundling the
    resource's metadata with the `DataInstructions` for fetching its data. This is
    a build recipe, not a Frictionless descriptor: a later build step pairs it with
    a resolver to fetch the data and materialize the package.
    """

    model_config = ConfigDict(extra="allow", str_strip_whitespace=True)

    name: str = Field(
        pattern=CONTRACT_NAME_PATTERN,
        max_length=100,
        description=(
            "A unique identifier for the data contract. Must consist only of "
            "lowercase alphanumeric characters, '.', '_', and '-'."
        ),
    )

    resources: list[CrossDataResourceReleaseSpec] = Field(
        min_length=1,
        description=(
            "A list of release specifications for the data resources included in the "
            "data package. Each resource specification describes a specific dataset "
            "and its associated metadata and data-fetching instructions. A package "
            "MUST contain at least one resource specification."
        ),
    )

    @model_validator(mode="after")
    def _validate_unique_resource_names(self) -> Self:
        """Validate that all resource names in the package are unique."""
        resource_names = [res.name for res in self.resources]
        if len(resource_names) != len(set(resource_names)):
            raise ValueError("All resource names in the package must be unique.")
        return self

Bases: ResourceMetaData

Release specification for a single data resource.

Carries the resource's descriptive metadata (inherited from frictionless.ResourceMetaData) together with the DataInstructions describing how to fetch its data from the platform. This is a build recipe, not a Frictionless descriptor: a later build step pairs it with a resolver to fetch the data and materialize the resource.

name is optional and defaults to the name of the contract used for fetching; the remaining descriptive metadata must be supplied by the specification.

Source code in src/crosscontract/release/data_package/release_specification.py
class CrossDataResourceReleaseSpec(ResourceMetaData):
    """Release specification for a single data resource.

    Carries the resource's descriptive metadata (inherited from
    `frictionless.ResourceMetaData`) together with the `DataInstructions` describing
    how to fetch its data from the platform. This is a build recipe, not a
    Frictionless descriptor: a later build step pairs it with a resolver to fetch
    the data and materialize the resource.

    `name` is optional and defaults to the name of the contract used for
    fetching; the remaining descriptive metadata must be supplied by the
    specification.
    """

    model_config = ConfigDict(extra="allow", str_strip_whitespace=True)
    # Deliberately relax the inherited required `name` to optional: it defaults
    # to the contract name in `_fill_name_from_contract`.
    name: str | None = Field(  # type: ignore[assignment]
        default=None,
        pattern=CONTRACT_NAME_PATTERN,
        max_length=100,
        description=(
            "A unique identifier for the data resource. Must consist only of "
            "lowercase alphanumeric characters, '.', '_', and '-'."
            "If not provided, will be the same as the name of the contract "
            "used for fetching the data."
        ),
    )
    # Resource-level contributors are a deliberate CROSS extension (upstream
    # Frictionless places `contributors` on the package only): a contract may
    # carry contributors, so a released resource is allowed to as well.
    contributors: OptionalNonEmptyList[Contributor] = Field(
        default=None, description="A list of contributors to the data resource."
    )
    data_instructions: DataInstructions = Field(
        description=("Instructions for fetching the data for the data resource."),
    )

    @model_validator(mode="after")
    def _fill_name_from_contract(self) -> Self:
        """If the resource name is not provided, fill it from the contract name."""
        if self.name is not None:
            raise NotImplementedError(
                "Explicit resource names are not supported yet. "
                "Automatically filling from contract name."
            )
        self.name = self.name or self.data_instructions.fetch.contract
        return self

Bases: BaseModel

Instructions for obtaining a resource's data from the platform.

Bundles the fetch specification (fetch) describing how to retrieve the data. It is the extension point for further data-shaping instructions (e.g. transformations) that may be added alongside fetch in the future.

Source code in src/crosscontract/release/data_package/release_specification.py
class DataInstructions(BaseModel):
    """Instructions for obtaining a resource's data from the platform.

    Bundles the fetch specification (`fetch`) describing how to retrieve the
    data. It is the extension point for further data-shaping instructions (e.g.
    transformations) that may be added alongside `fetch` in the future.
    """

    model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)

    fetch: FetchSpecMixin = Field(
        description=(
            "The data fetching specification, which defines how to retrieve the "
            "data for this resource from the server."
        )
    )