Skip to content

Commit

Permalink
Merge pull request #53 from jwodder/onbuild
Browse files Browse the repository at this point in the history
Support "onbuild" step when using Hatch
  • Loading branch information
jwodder committed Dec 14, 2023
2 parents d9bc4c5 + ba530a7 commit 1bc3347
Show file tree
Hide file tree
Showing 22 changed files with 741 additions and 114 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
v2.4.0 (in development)
v3.0.0 (in development)
-----------------------
- Migrated from setuptools to hatch
- Support using the `onbuild` step with Hatch
- **Breaking**: The `build_dir` argument passed to `Versioningit.do_onbuild()`
and `onbuild` method callables has been changed to an `OnbuildFileProvider`
ABC

v2.3.0 (2023-11-19)
-------------------
Expand Down
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ extraction & calculation.
- Can optionally write the final version and other details to a file for
loading at runtime

- Provides custom setuptools commands for inserting the final version and other
details into a source file at build time
- Provides custom hooks for inserting the final version and other details into
a source file at build time

- The individual methods for VCS querying, tag-to-version calculation, version
bumping, version formatting, and writing the version to a file can all be
Expand Down
6 changes: 5 additions & 1 deletion docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
Changelog
=========

v2.4.0 (in development)
v3.0.0 (in development)
-----------------------
- Migrated from setuptools to hatch
- Support using the ``onbuild`` step with Hatch
- **Breaking**: The ``build_dir`` argument passed to
`Versioningit.do_onbuild()` and ``onbuild`` method callables has been changed
to an `OnbuildFileProvider` ABC


v2.3.0 (2023-11-19)
Expand Down
82 changes: 56 additions & 26 deletions docs/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -538,36 +538,30 @@ which takes the following parameters:

.. _onbuild:

The ``[tool.versioningit.onbuild]`` Subtable
--------------------------------------------

.. attention::

Currently, the ``onbuild`` step is not supported when using
``versioningit`` with Hatch. See `issue #54`__ for more information.

__ https://github.com/jwodder/versioningit/issues/54
Enabling & Configuring the ``onbuild`` Step
-------------------------------------------

.. versionadded:: 1.1.0

.. versionadded:: 2.2.0
``versioningit`` provides custom setuptools and Hatch hooks for enabling an
optional feature (called the "``onbuild`` step") in which your project's
version and/or other fields are inserted into a file in sdists & wheels at
build time while leaving your local project directory alone.

``sdist`` and ``build_py`` classes added for use in :file:`setup.cfg` and
:file:`pyproject.toml`
The steps for enabling the ``onbuild`` step differ depending on whether you're
using setuptools or Hatch as your build backend. The configuration options for
the step are the same between the backends, but where you put the configuration
and how you tell the backend to enable the hooks differs.

The ``onbuild`` subtable configures an optional feature, inserting the project
version and/or other fields into built project trees when building an sdist or
wheel. Specifically, this feature allows you to create sdists & wheels in
which some file has been modified to contain the line ``__version__ = "<project
version>"`` or similar while leaving your repository alone.
Using ``onbuild`` with setuptools
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Enabling ``onbuild``
~~~~~~~~~~~~~~~~~~~~

In order to use this feature, in addition to filling out the subtable, you must
configure setuptools to use ``versioningit``'s custom command classes. How to
do this depends on what file you've placed your project's setuptools
configuration in.
There are two steps to enabling the ``onbuild`` step with setuptools. First,
add a ``[tool.versioningit.onbuild]`` table to your :file:`pyproject.toml`
containing your desired configuration for the step (`see below
<onbuild_opts_>`_). Second, you need to tell setuptools to use
``versioningit``'s custom command classes. How to do this depends on what file
you've placed your project's setuptools configuration in.

- If you're configuring setuptools via :file:`setup.cfg`, you can simply add
the following field to its ``[options]`` table:
Expand Down Expand Up @@ -611,8 +605,44 @@ may have to manually modify or subclass your command classes and add a call to
`run_onbuild()` at the appropriate location; see the function's documentation
for more information, but you'll largely be on your own at this point.

Configuring ``onbuild``
~~~~~~~~~~~~~~~~~~~~~~~
.. versionadded:: 2.2.0

``sdist`` and ``build_py`` classes added for use in :file:`setup.cfg` and
:file:`pyproject.toml`

Using ``onbuild`` with Hatch
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. versionadded:: 3.0.0

Support for using the ``onbuild`` step with Hatch

In order to enable & configure the ``onbuild`` step when using ``versioningit``
with Hatch, simply place all of your desired configuration for the step under a
``[tool.hatch.build.hooks.versioningit-onbuild]`` table. Do not use the
``[tool.versioningit.onbuild]`` table with Hatch; it will be ignored, and its
presence will generate a warning.

.. note::

The ``versioningit-onbuild`` build hook is only usable when also using
``versioningit`` as a Hatch version source. Trying to use the build hook
with a different version source will result in an error.

.. note::

The ``versioningit-onbuild`` build hook is only supported when building an
sdist or wheel. Using other Hatch builders (such as `the application
builder`__) with ``versioningit-onbuild`` is not supported or endorsed in
any way.

__ https://hatch.pypa.io/latest/plugins/builder/app/


.. _onbuild_opts:

``onbuild`` Configuration Options
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

``versioningit`` provides one ``onbuild`` method, ``"replace-version"`` (the
default). It scans a given file for a line matching a given regex and inserts
Expand Down
23 changes: 11 additions & 12 deletions docs/hatch.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ way as for setuptools:
[tool.hatch.version]
source = "versioningit"
- Configure ``versioningit`` as normal. However, with Hatch, you have two
possible locations to put ``versioningit``'s configuration in: either a
``[tool.versioningit]`` table as used with setuptools or under the
``[tool.hatch.version]`` table. Moreover, unlike when using setuptools, you
don't even need the ``[tool.versioningit]`` table if it's just going to be
empty.
- Configure ``versioningit`` as normal (mostly; see the note about ``onbuild``
below). However, with Hatch, you have two possible locations to put
``versioningit``'s configuration in: either the ``[tool.versioningit]`` table
as used with setuptools or under the ``[tool.hatch.version]`` table.
Moreover, unlike when using setuptools, you don't even need the
``[tool.versioningit]`` table if it's just going to be empty.

For example, the following configurations are equivalent:

Expand Down Expand Up @@ -91,12 +91,11 @@ way as for setuptools:
# `write` step:
artifacts = ["src/mypackage/_version.py"]
.. attention::

Currently, :ref:`the onbuild step <onbuild>` is not supported when using
``versioningit`` with Hatch. See `issue #54`__ for more information.

__ https://github.com/jwodder/versioningit/issues/54
- The configuration for the ``onbuild`` step is placed in the
``[tool.hatch.build.hooks.versioningit-onbuild]`` table (not in
``[tool.versioningit.onbuild]`` or ``[tool.hatch.version.onbuild]``). In
addition, filling out this table is all you need to do to enable the
``onbuild`` step — no fiddling with command classes necessary!

.. note::

Expand Down
10 changes: 5 additions & 5 deletions docs/how.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ creates a file at a specified path containing the project's version.
``onbuild`` Step
^^^^^^^^^^^^^^^^

When a project is built that uses ``versioningit``'s custom setuptools
commands, the ``onbuild`` step becomes added to the build process. The default
``onbuild`` method updates one of the files in the built distribution to
contain the project version while leaving the source files in the actual
project alone. See ":ref:`onbuild`" for more information.
When a project is built that uses ``versioningit``'s custom setuptools commands
or Hatch build hook, the ``onbuild`` step becomes added to the build process.
The default ``onbuild`` method updates one of the files in the built
distribution to contain the project version while leaving the source files in
the actual project alone. See ":ref:`onbuild`" for more information.
4 changes: 2 additions & 2 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ extraction & calculation.
- Can optionally write the final version and other details to a file for
loading at runtime

- Provides custom setuptools commands for inserting the final version and other
details into a source file at build time
- Provides custom hooks for inserting the final version and other details into
a source file at build time

- The individual methods for VCS querying, tag-to-version calculation, version
bumping, version formatting, and writing the version to a file can all be
Expand Down
16 changes: 6 additions & 10 deletions docs/runtime-version.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ Automatically setting your project's version is all well and good, but you
usually also want to expose that version at runtime, usually via a
``__version__`` variable. There are three options for doing this:

1. Use the `~importlib.metadata.version()` function in `importlib.metadata` to
get your package's version, like so:
1. Use the `~importlib.metadata.version()` function from `importlib.metadata`
to get your package's version, like so:

.. code:: python
Expand Down Expand Up @@ -68,12 +68,10 @@ usually also want to expose that version at runtime, usually via a
from pathlib import Path
__version__ = Path(__file__).with_name("VERSION").read_text().strip()
3. *(New in version 1.1.0)* Fill out the ``[tool.versioningit.onbuild]``
subtable in :file:`pyproject.toml` and configure setuptools to use
``versioningit``'s custom build commands. This will allow you to create
sdists & wheels in which some file has been modified to contain the line
``__version__ = "<project version>"`` or similar while leaving your
repository alone. See ":ref:`onbuild`" for more information.
3. *(New in version 1.1.0)* Use the :ref:`onbuild step <onbuild>` and its
custom hooks to create sdists & wheels in which some file has been modified
to contain the line ``__version__ = "<project version>"`` or similar while
leaving your repository's contents alone.

.. tip::

Expand All @@ -90,9 +88,7 @@ usually also want to expose that version at runtime, usually via a
Should affected file be under version control? **No** **Yes**
Affected file must already exist? **No** **Yes**
Modifies working tree? [#f1]_ **Yes** **No**
Requires configuration in ``setup.{py,cfg}``? **No** **Yes**
Run when installing in editable mode? **Yes** **No**
Usable with Hatch? **Yes** **No**
============================================== ========= ===========

.. [#f1] That is, the ``write`` method causes a file to be present (though
Expand Down
19 changes: 15 additions & 4 deletions docs/writing-methods.rst
Original file line number Diff line number Diff line change
Expand Up @@ -168,13 +168,13 @@ A custom ``write`` method is a callable with the following synopsis:

A custom ``onbuild`` method is a callable with the following synopsis:

.. function:: funcname(*, build_dir: str | pathlib.Path, is_source: bool, template_fields: dict[str, Any], params: dict[str, Any]) -> None
.. function:: funcname(*, file_provider: OnbuildFileProvider, is_source: bool, template_fields: dict[str, Any], params: dict[str, Any]) -> None
:noindex:

Modifies one or more files in ``build_dir``
Modifies the files about to be included in an sdist or wheel

:param path build_dir:
the path to the directory where the project is being built
:param file_provider:
an object for accessing files being built into an sdist or wheel
:param bool is_source:
true if an sdist or other artifact that preserves source paths is being
built, false if a wheel or other artifact that uses installation paths
Expand All @@ -187,6 +187,17 @@ A custom ``onbuild`` method is a callable with the following synopsis:

``version`` argument replaced with ``template_fields``

.. versionchanged:: 3.0.0

``build_dir`` argument replaced with ``file_provider``

``onbuild`` methods are provided with instances of the following abstract base
classes for operating on:

.. autoclass:: versioningit.OnbuildFileProvider

.. autoclass:: versioningit.OnbuildFile


Distributing Your Methods in an Extension Package
-------------------------------------------------
Expand Down
9 changes: 6 additions & 3 deletions src/versioningit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
- Can optionally write the final version to a file for loading at runtime
- Provides custom setuptools commands for inserting the final version into a
source file at build time
- Provides custom hooks for inserting the final version into a source file at
build time
- The individual methods for VCS querying, tag-to-version calculation, version
bumping, version formatting, and writing the version to a file can all be
Expand All @@ -43,7 +43,7 @@
<https://versioningit.rtfd.io> for more information.
"""

__version__ = "2.4.0.dev1"
__version__ = "3.0.0.dev1"
__author__ = "John Thorvald Wodder II"
__author_email__ = "versioningit@varonathe.org"
__license__ = "MIT"
Expand Down Expand Up @@ -72,6 +72,7 @@
NotVersioningitError,
)
from .get_cmdclasses import get_cmdclasses
from .onbuild import OnbuildFile, OnbuildFileProvider

__all__ = [
"ConfigError",
Expand All @@ -84,6 +85,8 @@
"NotSdistError",
"NotVCSError",
"NotVersioningitError",
"OnbuildFile",
"OnbuildFileProvider",
"Report",
"VCSDescription",
"Versioningit",
Expand Down
6 changes: 6 additions & 0 deletions src/versioningit/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ def parse_toml_file(cls, filepath: str | Path) -> Config:
table = hatch_config
elif table is None:
table = hatch_config
if table.get("onbuild") is not None:
log.warning(
"onbuild configuration in versioningit table detected."
" When using Hatch, onbuild must be configured via"
" [tool.hatch.build.hooks.versioningit-onbuild]."
)
if table is None:
raise NotVersioningitError("versioningit not enabled in pyproject.toml")
return cls.parse_obj(table)
Expand Down
23 changes: 15 additions & 8 deletions src/versioningit/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from .errors import Error, MethodError, NotSdistError, NotVCSError, NotVersioningitError
from .logging import log, warn_bad_version
from .methods import VersioningitMethod
from .onbuild import OnbuildFileProvider, SetuptoolsFileProvider
from .util import is_sdist, parse_version_from_metadata

if TYPE_CHECKING:
Expand Down Expand Up @@ -426,7 +427,7 @@ def do_write(self, template_fields: dict[str, Any]) -> None:

def do_onbuild(
self,
build_dir: str | Path,
file_provider: OnbuildFileProvider,
is_source: bool,
template_fields: dict[str, Any],
) -> None:
Expand All @@ -438,10 +439,14 @@ def do_onbuild(
.. versionchanged:: 2.0.0
``version`` argument replaced with ``template_fields``
.. versionchanged:: 3.0.0
``build_dir`` argument replaced with ``file_provider``
"""
if self.onbuild is not None:
self.onbuild(
build_dir=build_dir,
file_provider=file_provider,
is_source=is_source,
template_fields=template_fields,
)
Expand Down Expand Up @@ -557,12 +562,12 @@ def run_onbuild(
"""
.. versionadded:: 1.1.0
Run the ``onbuild`` step for the given project.
Run the ``onbuild`` step for the given setuptools project.
This function is intended to be used by custom setuptools commands that are
used in place of ``versioningit``'s custom commands but still need to be
able to run the ``onbuild`` step. The ``template_fields`` value can be
obtained by passing the command's ``distribution`` attribute to
This function is intended to be used by custom setuptools command classes
that are used in place of ``versioningit``'s command classes but still need
to be able to run the ``onbuild`` step. The ``template_fields`` value can
be obtained by passing a command class's ``distribution`` attribute to
`get_template_fields_from_distribution()`; if this returns `None`, then we
are building from an sdist, and `run_onbuild()` should not be called.
Expand Down Expand Up @@ -594,7 +599,9 @@ def run_onbuild(
"""
vgit = Versioningit.from_project_dir(project_dir, config)
vgit.do_onbuild(
build_dir=build_dir, is_source=is_source, template_fields=template_fields
file_provider=SetuptoolsFileProvider(build_dir=Path(build_dir)),
is_source=is_source,
template_fields=template_fields,
)


Expand Down
Loading

0 comments on commit 1bc3347

Please sign in to comment.