In these two cases which re-raise an immediately-caught exception, do
the re-raising with `raise` instead of `raise exc`, because the `raise
exc` adds an uninteresting entry to the exception's traceback (that of
itself), while `raise` doesn't.
* added test case in testing/python/approx.py based on test case provided by reporter in issue #12114
* test cases pass for pytest testing/python/approx.py
* expanded the type annotation to include objects which may cast to a array and renamed other_side to other_side_as_array and asserted that it is not none
Now `importlib` mode will correctly set the imported modules as an attribute of their parent modules.
As helpfully posted on #12194, that's how the Python import module works so we should follow suit.
In addition, we also try to import the parent modules as part of the process of importing a child module, again mirroring how Python importing works.
Fix#12194
Previously we used a hand crafted approach to detect namespace packages, however we should rely on ``importlib`` to detect them for us.
Fix#12112
---------
Co-authored-by: Ran Benita <ran@unusedvar.com>
Creating and initializing the cache directory is interruptible; this
avoids a pathological case where interrupting a cache write can cause
the cache directory to never be properly initialized with its supporting
files.
Unify `Cache.mkdir` with `Cache.set` while I'm here so the former also
properly initializes the cache directory.
Closes#12167.
It makes more sense, also, we have a long term idea of generalizing
fixture support to items defined by other plugins, not just python, in
which case `--fixtures` would definitely not be python-plugin
specific.
Based on pylint's message ``consider-iterating-dictionary`` suggestion.
Surprisingly using a dict or set comprehension instead of a new temp var is
actually consistently slower here, which was not intuitive for me.
```python
from timeit import timeit
families = {1: {"testcase": [1, 2, 3, 5, 8]}}
attrs = {1: "a", 2: "b", 3: "c", 4: "d", 5: "e", 6: "f", 7: "g", 8: "h"}
class Old:
def old(self):
self.attrs = attrs
temp_attrs = {}
for key in self.attrs.keys():
if key in families[1]["testcase"]:
temp_attrs[key] = self.attrs[key]
self.attrs = temp_attrs
class OldBis:
def old(self):
self.attrs = attrs
temp_attrs = {}
for key in self.attrs:
if key in families[1]["testcase"]:
temp_attrs[key] = self.attrs[key]
self.attrs = temp_attrs
class New:
def new(self):
self.attrs = attrs
self.attrs = { # Even worse with k: v for k in self.attrs.items()
k: self.attrs[k] for k in self.attrs if k in families[1]["testcase"]
}
if __name__ == "__main__":
n = 1000000
print(f"Old: {timeit(Old().old, number=n)}")
print(f"Just removing the keys(): {timeit(OldBis().old, number=n)}")
print(f"List comp, no temp var: {timeit(New().new, number=n)}")
```
Result:
Old: 0.9493889989680611
Just removing the keys(): 0.9042672360083088
List comp, no temp var: 0.9916125109884888
It's also true for the other example with similar benchmark, but the exact
code probably does not need to be in the commit message.
and also fixes a regression in pytest 8.0.0 where `setup_method` crashes
if the class has static or class method tests.
It is allowed to have a test class with static/class methods which
request non-static/class method fixtures (including `setup_method`
xunit-fixture). I take it as a given that we need to support this
somewhat odd scenario (stdlib unittest also supports it).
This raises a question -- when a staticmethod test requests a bound
fixture, what is that fixture's `self`?
stdlib unittest says - a fresh instance for the test.
Previously, pytest said - some instance that is shared by all
static/class methods. This is definitely broken since it breaks test
isolation.
Change pytest to behave like stdlib unittest here.
In practice, this means stopping to rely on `self.obj.__self__` to get
to the instance from the test function's binding. This doesn't work
because staticmethods are not bound to anything.
Instead, keep the instance explicitly and use that.
BTW, I think this will allow us to change `Class`'s fixture collection
(`parsefactories`) to happen on the class itself instead of a class
instance, allowing us to avoid one class instantiation. But needs more
work.
Fixes#12065.
- Separate the requesting from the requested.
- Avoid the term "factory", I think most people don't distinguish
between "fixture" and "fixture function" (i.e. "factory") and would
find the term "factory" unfamiliar.
There are two non-optimal things in the current way scope checking is
done:
- It runs on `SubRequest`, but doesn't use the `SubRequest's scope,
which is confusing. Instead it takes `invoking_scope` and
`requested_scope`.
- Because `_check_scope` is only defined on `SubRequest` and not
`TopRequest`, `_compute_fixture_value` first creates the `SubRequest`
only then checks the scope (hence the need for the previous point).
Instead, also define `_check_scope` on `TopRequest` (always valid), and
remove `invoking_scope`, using `self._scope` instead.
Previously, the `obj` of a `TestCaseFunction` (the unittest plugin item
type) was the unbound method. This is unlike regular `Class` where the
`obj` is a bound method to a fresh instance.
This difference necessitated several special cases in in places outside
of the unittest plugin, such as `FixtureDef` and `FixtureRequest`, and
made things a bit harder to understand.
Instead, match how the python plugin does it, including collecting
fixtures from a fresh instance.
The downside is that now this instance for fixture-collection is kept
around in memory, but it's the same as `Class` so nothing new. Users
should only initialize stuff in `setUp`/`setUpClass` and similar
methods, and not in `__init__` which is generally off-limits in
`TestCase` subclasses.
I am not sure why there was a difference in the first place, though I
will say the previous unittest approach is probably the preferable one,
but first let's get consistency.