Skip to content

Latest commit

 

History

History
858 lines (611 loc) · 27 KB

File metadata and controls

858 lines (611 loc) · 27 KB

pylock.toml Specification

The pylock.toml file format is for specifying dependencies to enable reproducible installation in a Python environment.

Note

This specification was originally defined in PEP 751.

File Name

A lock file MUST be named :file:`pylock.toml` or match the regular expression r"^pylock\.([^.]+)\.toml$" if a name for the lock file is desired or if multiple lock files exist (i.e. the regular expression r"^pylock\.([^.]+\.)?toml$" for any file name). The prefix and suffix of a named file MUST be lowercase when possible, for easy detection and removal, e.g.:

if len(filename) > 11 and filename.startswith("pylock.") and filename.endswith(".toml"):
    name = filename.removeprefix("pylock.").removesuffix(".toml")

The expectation is that services that automatically install from lock files will search for:

  1. The lock file with the service's name and doing the default install
  2. A multi-use :file:`pylock.toml` with a dependency group with the name of the service
  3. The default install of :file:`pylock.toml`

E.g. a cloud host service named "spam" would first look for :file:`pylock.spam.toml` to install from, and if that file didn't exist then install from :file:`pylock.toml` and look for a dependency group named "spam" to use if present.

The lock file(s) SHOULD be located in the directory as appropriate for the scope of the lock file. Locking against a single :file:`pyproject.toml`, for instance, would place the :file:`pylock.toml` in the same directory. If the lock file covered multiple projects in a monorepo, then the expectation is the :file:`pylock.toml` file would be in the directory that held all the projects being locked.

File Format

The format of the file is TOML.

Tools SHOULD write their lock files in a consistent way to minimize noise in diff output. Keys in tables -- including the top-level table -- SHOULD be recorded in a consistent order (if inspiration is desired, this specification has tried to write down keys in a logical order). As well, tools SHOULD sort arrays in consistent order. Usage of inline tables SHOULD also be kept consistent.

lock-version

  • Type: string; value of "1.0"
  • Required?: yes
  • Inspiration: :ref:`core-metadata-metadata-version`
  • Record the file format version that the file adheres to.
  • This PEP specifies the initial version -- and only valid value until future updates to the standard change it -- as "1.0".
  • If a tool supports the major version but not the minor version, a tool SHOULD warn when an unknown key is seen.
  • If a tool doesn't support a major version, it MUST raise an error.

environments

  • Type: Array of strings
  • Required?: no
  • Inspiration: uv
  • A list of :ref:`dependency-specifiers-environment-markers` for which the lock file is considered compatible with.
  • Tools SHOULD write exclusive/non-overlapping environment markers to ease in understanding.

requires-python

  • Type: string
  • Required?: no
  • Inspiration: PDM, Poetry, uv
  • Specifies the :ref:`core-metadata-requires-python` for the minimum Python version compatible for any environment supported by the lock file (i.e. the minimum viable Python version for the lock file).

extras

dependency-groups

  • Type: Array of strings
  • Required?: no; defaults to []
  • Inspiration: :ref:`pyproject-tool-table`
  • The list of :ref:`dependency-groups` publicly supported by this lock file (i.e. dependency groups users are expected to be able to specify via a tool's UI).
  • Lockers MAY choose to not support writing lock files that support extras and dependency groups (i.e. tools may only support exporting a single-use lock file).
  • Tools supporting dependency groups MUST also support extras.
  • Tools SHOULD explicitly set this key to an empty array to signal that the inputs used to generate the lock file had no dependency groups (e.g. a :ref:`pyproject.toml <pyproject-toml-spec>` file had no :ref:`[dependency-groups] <dependency-groups>` table), signalling that the lock file is, in effect, multi-use even if it only looks to be single-use.

default-groups

created-by

  • Type: string
  • Required?: yes
  • Inspiration: Tools with their name in their lock file name
  • Records the name of the tool used to create the lock file.
  • Tools MAY use the :ref:`pylock-tool` table to record enough details that it can be inferred what inputs were used to create the lock file.
  • Tools SHOULD record the normalized name of the tool if it is available as a Python package to facilitate finding the tool.

[[packages]]

  • Type: array of tables
  • Required?: yes
  • Inspiration: PDM, Poetry, uv
  • An array containing all packages that may be installed.
  • Packages MAY be listed multiple times with varying data, but all packages to be installed MUST narrow down to a single entry at install time.

packages.name

packages.version

packages.marker

packages.requires-python

[[packages.dependencies]]

  • Type: array of tables
  • Required?: no
  • Inspiration: PDM, Poetry, uv
  • Records the other entries in :ref:`pylock-packages` which are direct dependencies of this package.
  • Each entry is a table which contains the minimum information required to tell which other package entry it corresponds to where doing a key-by-key comparison would find the appropriate package with no ambiguity (e.g. if there are two entries for the spam package, then you can include the version number like {name = "spam", version = "1.0.0"}, or by source like {name = "spam", vcs = { url = "..."}).
  • Tools MUST NOT use this information when doing installation; it is purely informational for auditing purposes.

[packages.vcs]

packages.vcs.type
packages.vcs.url
packages.vcs.path
  • Type: string
  • Required?: if :ref:`pylock-packages-vcs-url` is not specified
  • Inspiration: :ref:`direct-url-data-structure-vcs`
  • The path to the local directory of the source tree.
  • If a relative path is used it MUST be relative to the location of this file.
  • If the path is relative it MAY use POSIX-style path separators explicitly for portability.
packages.vcs.requested-revision
packages.vcs.commit-id
  • Type: string
  • Required?: yes
  • Inspiration: :ref:`direct-url-data-structure-vcs`
  • The exact commit/revision number that is to be installed.
  • If the VCS supports commit-hash based revision identifiers, such a commit-hash, it MUST be used as the commit ID in order to reference an immutable version of the source code.
packages.vcs.subdirectory

[packages.directory]

packages.directory.path
  • Type: string
  • Required?: yes
  • Inspiration: :ref:`direct-url-data-structure-local-directory`
  • The local directory where the source tree is.
  • If the path is relative it MUST be relative to the location of the lock file.
  • If the path is relative it MAY use POSIX-style path separators for portability.
packages.directory.editable
  • Type: boolean
  • Required?: no; defaults to false
  • Inspiration: :ref:`direct-url-data-structure-local-directory`
  • A flag representing whether the source tree was an editable install at lock time.
  • An installer MAY choose to ignore this flag if user actions or context would make an editable install unnecessary or undesirable (e.g. a container image that will not be mounted for development purposes but instead deployed to production where it would be treated at read-only).
packages.directory.subdirectory

See :ref:`pylock-packages-vcs-subdirectory`.

[packages.archive]

  • Type: table
  • Required?: no
  • Inspiration: :ref:`direct-url-data-structure-archive`
  • A direct reference to an archive file to install from (this can include wheels and sdists, as well as other archive formats containing a source tree).
  • Tools MAY choose to not support archive files, both from a locking and/or installation perspective.
  • Tools SHOULD provide a way for users to opt in/out of using archive files.
  • Installation from an archive file is considered originating from a :ref:`direct URL reference <direct-url>`.
packages.archive.url
packages.archive.path
packages.archive.size
  • Type: integer
  • Required?: no
  • Inspiration: uv, :ref:`simple-repository-api`
  • The size of the archive file.
  • Tools SHOULD provide the file size when reasonably possible (e.g. the file size is available via the Content-Length header from a HEAD HTTP request).
packages.archive.upload-time
  • Type: datetime
  • Required?: no
  • Inspiration: :ref:`simple-repository-api`
  • The time the file was uploaded.
  • The date and time MUST be recorded in UTC.
[packages.archive.hashes]
  • Type: Table of strings
  • Required?: yes
  • Inspiration: PDM, Poetry, uv, :ref:`simple-repository-api`
  • A table listing known hash values of the file where the key is the hash algorithm and the value is the hash value.
  • The table MUST contain at least one entry.
  • Hash algorithm keys SHOULD be lowercase.
  • At least one secure algorithm from :py:data:`hashlib.algorithms_guaranteed` SHOULD always be included (at time of writing, sha256 specifically is recommended.
packages.archive.subdirectory

See :ref:`pylock-packages-vcs-subdirectory`.

packages.index

  • Type: string
  • Required?: no
  • Inspiration: uv
  • The base URL for the package index from :ref:`simple-repository-api` where the sdist and/or wheels were found (e.g. https://pypi.org/simple/).
  • When possible, this SHOULD be specified to assist with generating software bill of materials -- aka SBOMs -- and to assist in finding a file if a URL ceases to be valid.
  • Tools MAY support installing from an index if the URL recorded for a specific file is no longer valid (e.g. returns a 404 HTTP error code).

[packages.sdist]

packages.sdist.name
packages.sdist.upload-time

See :ref:`pylock-packages-archive-upload-time`.

packages.sdist.url

See :ref:`pylock-packages-archive-url`.

packages.sdist.path

See :ref:`pylock-packages-archive-path`.

packages.sdist.size

See :ref:`pylock-packages-archive-size`.

packages.sdist.hashes

See :ref:`pylock-packages-archive-hashes`.

[[packages.wheels]]

packages.wheels.name
packages.wheels.upload-time

See :ref:`pylock-packages-archive-upload-time`.

packages.wheels.url

See :ref:`pylock-packages-archive-url`.

packages.wheels.path

See :ref:`pylock-packages-archive-path`.

packages.wheels.size

See :ref:`pylock-packages-archive-size`.

packages.wheels.hashes

See :ref:`pylock-packages-archive-hashes`.

[[packages.attestation-identities]]

  • Type: array of tables
  • Required?: no
  • Inspiration: :ref:`provenance-object`
  • A recording of the attestations for any file recorded for this package.
  • If available, tools SHOULD include the attestation identities found.
  • Publisher-specific keys are to be included in the table as-is (i.e. top-level), following the spec at :ref:`index-hosted-attestations`.
packages.attestation-identities.kind

[packages.tool]

[tool]

Example

.. literalinclude:: pylock-toml/pylock.example.toml


Installation

The following outlines the steps to be taken to install from a lock file (while the requirements are prescriptive, the general steps and order are a suggestion):

  1. Gather the extras and dependency groups to install and set extras and dependency_groups for marker evaluation, respectively.
    1. extras SHOULD be set to the empty set by default.
    2. dependency_groups SHOULD be the set created from :ref:`pylock-default-groups` by default.
  2. Check if the metadata version specified by :ref:`pylock-lock-version` is supported; an error or warning MUST be raised as appropriate.
  3. If :ref:`pylock-requires-python` is specified, check that the environment being installed for meets the requirement; an error MUST be raised if it is not met.
  4. If :ref:`pylock-environments` is specified, check that at least one of the environment marker expressions is satisfied; an error MUST be raised if no expression is satisfied.
  5. For each package listed in :ref:`pylock-packages`:
    1. If :ref:`pylock-packages-marker` is specified, check if it is satisfied; if it isn't, skip to the next package.
    2. If :ref:`pylock-packages-requires-python` is specified, check if it is satisfied; an error MUST be raised if it isn't.
    3. Check that no other conflicting instance of the package has been slated to be installed; an error about the ambiguity MUST be raised otherwise.
    4. Check that the source of the package is specified appropriately (i.e. there are no conflicting sources in the package entry); an error MUST be raised if any issues are found.
    5. Add the package to the set of packages to install.
  6. For each package to be installed:

History

  • April 2025: Initial version, approved via PEP 751.
  • March 2026: Clarify file name precedence for archives, sdists, and wheels.