Skip to content

Conversation

@nicoddemus
Copy link
Member

@nicoddemus nicoddemus commented Aug 1, 2020

Often plugins need to identify the current pytest version in order to
handle some incompatibility or support newer features without breaking
the plugin to users of older pytest versions.

Currently plugin authors are required to either:

  1. Parse the version themselves:

    https://github.com/pytest-dev/pytest-timeout/blob/f9ab1213c5242c0ba081ba50ec970859d22e8ff4/pytest_timeout.py#L389-L394

  2. Or use feature checking:

    https://github.com/pytest-dev/pytest-xdist/blob/c6255faad4bde9385f5e5880f488b02206b1f073/src/xdist/remote.py#L104-L105

  3. Or use brittle try/except semantics:

    https://github.com/pytest-dev/pytest-subtests/blob/96fc692a151f0709bf8ee209f8ce5d37b035f076/pytest_subtests.py#L178-L185

All the above solutions have problems:

  1. Parsing using a library or by hand might break depending on the version scheme used by pytest. An example of that was pytest-timeout, which used distutils.StrictVersion to check for a feature, and that broke when we released 6.0.0rc1.
  2. Feature checking works, but doesn't make it explicit which pytest versions are being handled, which might leave the code obsolete when support for old pytest versions is dropped and that code is no longer required (as opposed to explicit version checking, which is often easy to find).
  3. Same problem as 2, but even worse because the expected exception might have other cause. In the subtests example above, TypeError might be raised for other reasons, making that code break with a confusing error message.

So this introduces a public API to get the version information from pytest, pytest.version_tuple().

It returns (major, minor, patch, release candidate, dev), which allow plugin developers and users to safely check version similar to how it is done with sys.version_info.

Decided to name it version_tuple() instead of version_info (for parity with sys.version_info) because sys.version_info is a tuple, while I wanted to make it a function to avoid executing that code during import (module-level __getattr__ would be a good fit for that, but alas Python 3.8+ only).

Missing:

  • Docs
  • Changelog

Often plugins need to identify the current pytest version in order to
handle some incompatibility or support newer features without breaking
the plugin to users of older pytest versions.

Currently plugin authors are required to either:

1. Parse the version themselves:

https://github.com/pytest-dev/pytest-timeout/blob/f9ab1213c5242c0ba081ba50ec970859d22e8ff4/pytest_timeout.py#L389-L394

2. Or use brittle feature checking:

https://github.com/pytest-dev/pytest-xdist/blob/c6255faad4bde9385f5e5880f488b02206b1f073/src/xdist/remote.py#L104-L105

3. Or use brittle try/except semantics:

https://github.com/pytest-dev/pytest-subtests/blob/96fc692a151f0709bf8ee209f8ce5d37b035f076/pytest_subtests.py#L178-L185

All the above solutions have problems:

1. Parsing using a library or by hand might break depending on the version scheme used by pytest. An example of that was `pytest-timeout`, which used `distutils.StrictVersion` to check for a feature, and that broke when we released `6.0.0rc1`.
2. Feature checking works, but doesn't make it explicit which pytest versions are being handled, which might leave the code obsolete when support for old pytest versions is dropped and that code is no longer required (as opposed to explicit version checking, which is often easy to find).
3. Same problem as 2, but even worse because the expected exception might have other cause. In the `subtests` example above, `TypeError` might be raised for other reasons, making that code break with a confusing error message.

So this introduces a public API to get the version information from pytest, `pytest.version_tuple()`.

It returns `(major, minor, patch, release candidate, dev)`, which allow plugin developers and users to safely check version similar to how it is done with `sys.version_info`.

Decided to name it `version_tuple()` instead of `version_info` (for parity with `sys.version_info`) because `sys.version_info` is a tuple, while I wanted to make it a function to avoid executing that code during import (module-level `__getattr__` would be a good fit for that, but alas Python 3.8+ only).

Missing:

- [ ] Docs
- [ ] Changelog
("6.23.1rc2.dev39+ga", (6, 23, 1, "rc2", "dev39+ga")),
],
)
def test_passe_version_tuple(v, expected):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def test_passe_version_tuple(v, expected):
def test_parse_version_tuple(v, expected):

😛

@bluetech
Copy link
Member

bluetech commented Aug 1, 2020

Since we already depend on the packaging package, have you considered using that? I have a slight preference to not expose it in the API, so we reserve the option to use something else, but can use it internally

@The-Compiler
Copy link
Member

I think a somewhat standard way to expose this is a __version_info__ attribute (akin to __version__). I'd prefer if we set that instead of inventing our own API. I don't find it problematic to do some simple string manipulation at import time FWIW.

@RonnyPfannschmidt
Copy link
Member

How about extending setuptools_scm with a template that will create a lazy version class that will defer to a later parsed packaging version class

It could also put in a normal split attribute

@nicoddemus
Copy link
Member Author

Thanks everyone for chiming in! I opened this issue exactly to stir this discussion. 😁

How about extending setuptools_scm with a template that will create a lazy version class that will defer to a later parsed packaging version class

This would be the ideal solution I think: it would provide a static tuple without runtime overhead, and everyone using setuptools_scm would benefit. 😁

@nicoddemus nicoddemus closed this Aug 15, 2020
@nicoddemus nicoddemus deleted the version-tuple branch June 14, 2021 11:11
nicoddemus added a commit to nicoddemus/pytest that referenced this pull request Jun 14, 2021
This adds `pytest.version_tuple`, which makes it simpler for users to do something depending on the pytest version (such as declaring plugins which are introduced in later versions) more easily than parsing the version themselves.

This feature was added originally in pypa/setuptools-scm#475.

Followup to pytest-dev#7605.
nicoddemus added a commit to nicoddemus/pytest that referenced this pull request Jun 14, 2021
This adds `pytest.version_tuple`, which makes it simpler for users to do something depending on the pytest version, such as declaring hooks which are introduced in later versions.

This feature was added originally in pypa/setuptools-scm#475.

Followup to pytest-dev#7605.
nicoddemus added a commit to nicoddemus/pytest that referenced this pull request Jun 14, 2021
This adds `pytest.version_tuple`, which makes it simpler for users to do something depending on the pytest version, such as declaring hooks which are introduced in later versions.

This feature was added originally in pypa/setuptools-scm#475.

Followup to pytest-dev#7605.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants