Skip to content

verri.version(func=None, /, *, fallback=None)

Decorator that will validate a resulting version is PEP-440 compliant, optionally resorting to a fallback value.

Parameters:

Name Type Description Default

func

The function to decorate.

None

fallback

A fallback version, either a str value or a Callable that returns a str.

None

Returns:

Type Description

A PEP-440 compliant version.

Source code in verri/__init__.py
def version(func=None, /, *, fallback=None):
    """
    Decorator that will validate a resulting version is PEP-440 compliant, optionally resorting to a fallback value.

    :param func: The function to decorate.
    :param fallback: A fallback version, either a `str` value or a `Callable` that returns a `str`.
    :return: A PEP-440 compliant version.
    """

    def validate(*args, **kwargs):
        try:
            value = func(*args, **kwargs)
            return str(parse(value))
        except Exception as e:
            match fallback:
                case None:
                    value = _FALLBACK_VERSION
                case str():
                    value = fallback
                case Callable():
                    value = fallback()
                case _:
                    raise TypeError(f'invalid fallback for version "{func.__name__}": {fallback!r}')

            value = parse(value)
            if local := getattr(e, 'version_local', None):
                # the error type provided a specific value for the local version component
                # TODO: use copy.replace() when requires-python reaches >=3.13
                value = value.__replace__(local=local)

            warnings.warn(
                dedent(
                    f"""
                    WARNING: {__name__} failed to determine {func.__name__} version during build:

                        {e!r}

                    Using fallback version "{value}".
                    """
                ).strip(),
                UserWarning,
                stacklevel=2,
            )

            return str(value)

    if func:
        # form @version
        return update_wrapper(validate, func)
    else:
        # form @version(fallback=...)
        return partial(version, fallback=fallback)