Repository navigation
feat(mark): expose pytest.ParameterSet in public API (#13431) - #15193
paneendrakumar0 wants to merge 3 commits into
Conversation
ab3cb09 to
f03863b
Compare
RonnyPfannschmidt
left a comment
There was a problem hiding this comment.
looks good, please add the extra documentation - the NOTSET followup is something we need to tinker a bit
|
|
||
| class ParameterSet(NamedTuple): | ||
| """A set of values for a set of parameters along with associated marks and | ||
| class _ParameterSetBase(NamedTuple): |
There was a problem hiding this comment.
lets document hte minimal python version that makes this unnecessary for future cleanups
| parameters.append( | ||
| ParameterSet( | ||
| values=(NOTSET,) * len(argnames), marks=[mark], id="NOTSET" | ||
| values=(NOTSET,) * len(argnames), |
There was a problem hiding this comment.
followup note - we might want to rethink this NOTSET hack - most recent python added sentinels and it muddles the types,
|
i jsut noted that i was wrong on a detail, i'm reassessing a bit more |
RonnyPfannschmidt
left a comment
There was a problem hiding this comment.
🤖 Written by Claude Opus 5.5 via Claude Code for the pytest maintainers; I prompted it, it did the work, I read it.
Correcting my earlier review: my initial assessment was wrong. I'd like ParameterSet to be a completely public structure, not a private-constructor type.
Requested changes:
- Drop
_ispytest, the__new__/__reduce__override and_ParameterSetBase. Go back to a plainclass ParameterSet(NamedTuple). Direct construction has always worked (it was a plain NamedTuple), so the deprecation warning would be new breakage for existing users. Pickling works natively once__module__points atpytest. - Type
valuesasSequence[object].object | NotSetTypecollapses toobjectanyway, so theNotSetTypepart was only decorative. - Drop
test_parameterset_direct_init_deprecatedand keep the public-API and pickle tests. - That also resolves my line-85 comment: no Python version lifts the NamedTuple
__new__/super()restriction (still aTypeErroron 3.15), so there's no version to document once the split is gone.
I checked this locally on the PR head: mypy 2.4.0 and pyright 1.1.414 pass, and the full test suite passes.
One catch: mypy rejects __module__ = "pytest" inside a NamedTuple class body ("NamedTuple field name cannot start with an underscore"), so it has to be set after the class:
class ParameterSet(NamedTuple):
...
ParameterSet.__module__ = "pytest"@bluetech, a detail I'd like your take on before we settle this:
- Set
__module__after the class definition, as above. This is the minimal change, but it's the first public class done this way; everything else sets__module__ = "pytest"in the class body (approx,config,warning_types). - Put it in a public submodule of
pytestso__module__is naturally right.pytestcurrently has no public submodules, so this has its own rattail: a new import path we'd have to support (and that pickles would reference forever), docs and Sphinx paths, and import-cycle risk, since_pytestwould import frompytest.*whilepytest/__init__imports_pytest.
My lean is option 1, since the rattail of option 2 seems larger than this type justifies. If we expect more NamedTuple/dataclass-style public types, though, it may be worth deciding the submodule question once.
The NOTSET placeholder for empty parameter sets stays as it is for now; I'll track that as a separate followup.
Generated by Claude Code
) Expose ParameterSet publicly from pytest as the return type of pytest.param() for type annotations and isinstance checks. - Re-export ParameterSet in src/pytest/__init__.py and include in __all__ - Keep ParameterSet as a plain NamedTuple with values: Sequence[object] - Set ParameterSet.__module__ = "pytest" after class definition - Mark internal factory methods with :meta private: for Sphinx autodoc - Document pytest.ParameterSet in doc/en/reference/reference.rst under Objects - Add changelog entry and unit tests for public API and pickle roundtrip
f03863b to
9ae02e6
Compare
|
Thanks @RonnyPfannschmidt! Updated as requested:
|
|
Thanks im waiting for @bluetech 's assessment now |
| ~~~~~~~~~~~~ | ||
|
|
||
| .. autoclass:: pytest.ParameterSet() | ||
| :members: |
There was a problem hiding this comment.
- The members are undocumented and are shown as "Alias for field number 2" which is not so nice.
- One of the fields has
_HiddenParamtype which is undocumented and errors out the docs build
Really I'm not sure we really want to document the members at this time. I guess it doesn't hurt but not essential since we only need it for typing purposes of the return value.
IOW, for now I'd just remove the :members:, which will fix the two issues I've pointed out.
|
|
||
| .. versionadded:: 9.2 | ||
|
|
||
| Examples:: |
There was a problem hiding this comment.
The examples are too much for this public docstring, especially if we decide to hide the :members:. Maybe let's move it from the docstring to a code comment.
| # ParameterSet(values=(40, 2, 42), marks=(), id="everything") | ||
| """ | ||
|
|
||
| values: Sequence[object | NotSetType] |
There was a problem hiding this comment.
What @RonnyPfannschmidt said about NotSetType being subsumed by object is correct, however the reason I did it is as a sort of documentation. It's meant to convey "this can be some value (any object allowed) or not set (NotSetType)". So I'd like to keep it, which should be OK if we hide :members:.
| assert pytest.param(id=s) | ||
|
|
||
|
|
||
| def test_parameterset_public_api() -> None: |
There was a problem hiding this comment.
This test seems not needed to me, I'd remove it.
| assert direct.id == "custom_id" | ||
|
|
||
|
|
||
| def test_parameterset_pickle() -> None: |
There was a problem hiding this comment.
We don't usually test pickle-ability and I don't see a particular reason to start here... I'd remove this test.
| return argnames, parameters | ||
|
|
||
|
|
||
| ParameterSet.__module__ = "pytest" |
There was a problem hiding this comment.
I suppose a clarifying comment would be nice:
| ParameterSet.__module__ = "pytest" | |
| # mypy doesn't like `__module__` defined inline in the NamedTuple. | |
| ParameterSet.__module__ = "pytest" |
| ParameterSet | ||
| ~~~~~~~~~~~~ | ||
|
|
||
| .. autoclass:: pytest.ParameterSet() |
There was a problem hiding this comment.
When defined like this the documentation doesn't show that this is a namedtuple. But that's fine for now, not sure we really want to promise this officially.
Description
This PR addresses #13431 (part of the public API typing roadmap #7469) by exposing
ParameterSetin the publicpytestnamespace as the return type ofpytest.param().Currently, developers using
pytest.paramin typed helper functions that return parameter sets receive private import warnings (such as Pyright'sreportPrivateImportUsage) when importingParameterSetfrom_pytest.mark.structures.Summary of Changes
pytest.ParameterSetinsrc/pytest/__init__.pyand included it in__all__.__module__ = "pytest"onParameterSet.ParameterSetas aNamedTuplesubclass with a__new__constructor that callscheck_ispytest(_ispytest)so direct instantiation issues aPytestDeprecationWarning, while internal factories (pytest.param(),extract_from(), etc.) instantiate with_ispytest=True.param,extract_from) with:meta private:so Sphinx autodoc does not surface them underpytest.ParameterSet.pytest.ParameterSettodoc/en/reference/reference.rstunderObjects, and removed the obsolete entry fromnitpick_ignoreindoc/en/conf.py.changelog/13431.improvement.rst.testing/test_mark.pyverifying public export,isinstancechecking, deprecation warning on unflagged initialization, andpickleserialization.AUTHORS.Closes #13431.