profile
viewpoint
Bruno Oliveira nicoddemus ESSS Florianopolis, Brazil https://www.patreon.com/nicoddemus Software developer, OS enthusiast. Maintainer of the Pytest project and assorted plugins. Contributing to @pytest-dev, @tox-dev, @conda and @conda-forge.

fabioz/mu-repo 199

Tool to help in dealing with multiple git repositories

hackebrot/pytest-tricks 151

:smirk: Tips and Tricks for the Python Testing Tool

gabrielcnr/pytest-datadir 128

pytest plugin for manipulating test data directories and files

ESSS/conda-devenv 76

A conda tool to work with multiple projects in development mode.

nicoddemus/awesome-stars 2

Awesome List of my own!

hackebrot/pytest 1

The pytest testing tool makes it easy to write small tests, yet scales to support complex functional testing

hackebrot/qutebrowser 1

A keyboard-driven, vim-like browser based on PyQt5 and QtWebKit.

nicoddemus/boltons 1

Like builtins, but boltons. Constructs/recipes/snippets that would be handy in the standard library. Nothing like Michael Bolton.

birdsarah/staged-recipes 0

A place to submit conda recipes before they become fully fledged conda-forge feedstocks

dawelter2/test_sanic_tornado 0

The goal of this project is to validate the use of websockets, file upload/download using Sanic lib.

issue commentpytest-dev/pytest

Pytest unable to execute files with same name in different folders

Also see the "Good Integration Practices" docs explaining why this happens at what you can do about it.

h-rueda

comment created time in 28 minutes

startedpyca/cryptography

started time in 2 hours

pull request commentpytest-dev/pytest

Add plugin list

Yep it will most likely be retired, unless someone wants to maintain it.

Thanks for confirming! Just curious what benefits would maintaining it have over just using the product of this PR?

mcsitter

comment created time in 6 hours

issue commentpytest-dev/pytest-xdist

Hello, About -- Dist usage

pytest -n=2 mod4 mod3 -v --dist=loadfile

I just tried this again. If I have more than one.py file under mod1, it's going to be processed by more than one process. I want only one process to execute

[gw1] [ 9%] PASSED mod4/test_mod4_module2.py::test_mode4_one2 [gw0] [ 18%] PASSED mod4/test_mod4_module.py::test_one

I don't want GW1 to handle the use cases below MOD4, and GW0 to handle only the use cases below MOD3. Is there a way

meilisong1989

comment created time in 6 hours

issue commentpytest-dev/pytest-xdist

Hello, About -- Dist usage

very thankful,

But then, can the use cases in the directories of module A and Module B be executed sequently in different processes?

I am now able to do this in a multi-process way, but only to combine test reports, such as:

def func(name, report, modules): print(f"my{name}") # time.sleep(random.randrange(1, 30)) # print(f"{name}finish {report},{modules}") os.system(f"pytest -v {modules} --html={report}")

if name == 'main': p1 = Process(target=func, args=("process1",), kwargs={"report": "11.html", "modules": "mod1"}) p2 = Process(target=func, args=("process2",), kwargs={"report": "22.html", "modules": "mod3"}) p1.start() p2.start()

I don't know if pytest-n X --dict= loadFile works the same way, right?

meilisong1989

comment created time in 7 hours

push eventESSS/upptime

igortg

commit sha ccd0f9f1b450be1ed081e60ecf655f7b08e2ba5f

Deploy to GitHub Pages

view details

push time in 9 hours

push eventESSS/upptime

Upptime Bot

commit sha abdfe1124bd61c320597316c73d7e4f12c00d402

:pencil: Update summary in README [skip ci] [upptime]

view details

Upptime Bot

commit sha 33d69e549b5d2efaab4ddd8b391e0b34431eccbc

:card_file_box: Update status summary [skip ci] [upptime]

view details

push time in 10 hours

PR opened mcsitter/pytest-plugin-list

[automated] Update plugin list

[automated] Update plugin list

+2 -2

0 comment

1 changed file

pr created time in 10 hours

create barnchmcsitter/pytest-plugin-list

branch : update-plugin-list/patch-b0e0556

created branch time in 10 hours

push eventESSS/upptime

Upptime Bot

commit sha 6fb83e1823960f59cf5d8e1317995966fbe2f5dd

:bento: Update graphs [skip ci]

view details

push time in 10 hours

PR opened pytest-dev/unittest2pytest

Fix remove_class

This is to fix #49

+61 -13

0 comment

3 changed files

pr created time in 11 hours

push eventESSS/upptime

Upptime Bot

commit sha 163e806d8853f60ed7c9bb2d70e35f54b64cdd7c

🟩 Peneira is up (200 in 922 ms) [skip ci] [upptime]

view details

Upptime Bot

commit sha e832e505d5d1fcfab743280291b2ea56e859d5a0

🟩 RF-DAP (Stage) is up (200 in 915 ms) [skip ci] [upptime]

view details

Upptime Bot

commit sha 0315d78394e25782278dc29c7184164c704985c2

🟩 RF-DAP (Demo) is up (200 in 948 ms) [skip ci] [upptime]

view details

Upptime Bot

commit sha 323681d94981922cc7c0d385573a7e8284bf6d55

🟩 RF-DAP (Internal) is up (200 in 918 ms) [skip ci] [upptime]

view details

Upptime Bot

commit sha 9f82f3c0de59232fbde0f90584e569ea007ad5e7

🟩 STORMS is up (200 in 1374 ms) [skip ci] [upptime]

view details

Upptime Bot

commit sha 401789ec61c3ef4c032a5e4776351fd724ddd145

🟩 Atlantis is up (200 in 696 ms) [skip ci] [upptime]

view details

push time in 12 hours

Pull request review commentpytest-dev/pytest

Docs: Note lifetime of temporary directories

 def _mk_tmp(request: FixtureRequest, factory: TempPathFactory) -> Path: def tmpdir(tmp_path: Path) -> py.path.local:     """Return a temporary directory path object which is unique to each test     function invocation, created as a sub directory of the base temporary-    directory.+    directory. After 3 sessions the directory will be removed by default,

Thanks, that sounds good, particularly the extra link! I updated with 6a25660. I left out your first sentence since I thought it was sufficiently covered in the existing docs, but I can be persuaded otherwise.

matthewhughes934

comment created time in 13 hours

issue closedpytest-dev/pytest

Pytest unable to execute files with same name in different folders

Hello,

Pytest has a conflict when there are two files with the same name in different folders. I have the following folders and files:

parent parent / folder1 parent / folder1 / my_test.py parent / folder2 parent / folder2 / my_test.py

I have two different my_test.py files in two different folders.

When I execute Pytest from parent , I get:

imported module 'my_test.py' has this __file__ attribute: /parent/folder1/my_test.py which is not the same as the test file we want to collect: /parent/folder2/my_test.py HINT: remove __pycache__/ .pyc files

I suppose this is due to the way how Pytets manages the rootdir ? https://docs.pytest.org/en/stable/pythonpath.html

closed time in 14 hours

h-rueda

issue commentpytest-dev/pytest

Pytest unable to execute files with same name in different folders

I realized that including __init__.py files in both folder1 and folder2 solves this issue.

h-rueda

comment created time in 14 hours

Pull request review commentpytest-dev/pytest

refactor runner terminal summary and add more durations coverage

 def pytest_addoption(parser: Parser) -> None:   def pytest_terminal_summary(terminalreporter: "TerminalReporter") -> None:-    durations = terminalreporter.config.option.durations-    durations_min = terminalreporter.config.option.durations_min-    verbose = terminalreporter.config.getvalue("verbose")+    durations = terminalreporter.config.getoption("durations")     if durations is None:         return-    tr = terminalreporter-    dlist = []-    for replist in tr.stats.values():-        for rep in replist:-            if hasattr(rep, "duration"):-                dlist.append(rep)-    if not dlist:++    durations_min = terminalreporter.config.getoption("durations_min")+    verbose = terminalreporter.config.getvalue("verbose")+    reporter = terminalreporter+    durations_list = []+    for report_list in reporter.stats.values():+        for report in report_list:+            if hasattr(report, "duration"):+                durations_list.append(report)+    if not durations_list:         return-    dlist.sort(key=lambda x: x.duration, reverse=True)  # type: ignore[no-any-return]++    durations_list.sort(key=attrgetter("duration"), reverse=True)

(I mean type checked)

symonk

comment created time in 14 hours

Pull request review commentpytest-dev/pytest

refactor runner terminal summary and add more durations coverage

 def pytest_addoption(parser: Parser) -> None:   def pytest_terminal_summary(terminalreporter: "TerminalReporter") -> None:-    durations = terminalreporter.config.option.durations-    durations_min = terminalreporter.config.option.durations_min-    verbose = terminalreporter.config.getvalue("verbose")+    durations = terminalreporter.config.getoption("durations")     if durations is None:         return-    tr = terminalreporter-    dlist = []-    for replist in tr.stats.values():-        for rep in replist:-            if hasattr(rep, "duration"):-                dlist.append(rep)-    if not dlist:++    durations_min = terminalreporter.config.getoption("durations_min")+    verbose = terminalreporter.config.getvalue("verbose")+    reporter = terminalreporter+    durations_list = []+    for report_list in reporter.stats.values():+        for report in report_list:+            if hasattr(report, "duration"):+                durations_list.append(report)+    if not durations_list:         return-    dlist.sort(key=lambda x: x.duration, reverse=True)  # type: ignore[no-any-return]++    durations_list.sort(key=attrgetter("duration"), reverse=True)

I prefer the lambda only because attrgetter gets the field name as a string which means it cannot be typed.

symonk

comment created time in 14 hours

Pull request review commentpytest-dev/pytest

refactor runner terminal summary and add more durations coverage

 def pytest_addoption(parser: Parser) -> None:   def pytest_terminal_summary(terminalreporter: "TerminalReporter") -> None:-    durations = terminalreporter.config.option.durations-    durations_min = terminalreporter.config.option.durations_min-    verbose = terminalreporter.config.getvalue("verbose")+    durations = terminalreporter.config.getoption("durations")     if durations is None:         return-    tr = terminalreporter-    dlist = []-    for replist in tr.stats.values():-        for rep in replist:-            if hasattr(rep, "duration"):-                dlist.append(rep)-    if not dlist:++    durations_min = terminalreporter.config.getoption("durations_min")+    verbose = terminalreporter.config.getvalue("verbose")+    reporter = terminalreporter+    durations_list = []+    for report_list in reporter.stats.values():+        for report in report_list:+            if hasattr(report, "duration"):+                durations_list.append(report)+    if not durations_list:         return-    dlist.sort(key=lambda x: x.duration, reverse=True)  # type: ignore[no-any-return]++    durations_list.sort(key=attrgetter("duration"), reverse=True)+     if not durations:-        tr.write_sep("=", "slowest durations")+        reporter.write_sep("=", "slowest durations")     else:-        tr.write_sep("=", "slowest %s durations" % durations)-        dlist = dlist[:durations]--    for i, rep in enumerate(dlist):-        if verbose < 2 and rep.duration < durations_min:-            tr.write_line("")-            tr.write_line(-                "(%s durations < %gs hidden.  Use -vv to show these durations.)"-                % (len(dlist) - i, durations_min)+        reporter.write_sep("=", "slowest %s durations" % durations)+        durations_list = durations_list[:durations]++    for index, test_report in enumerate(durations_list):+        if verbose < 2 and test_report.duration < durations_min:+            total = len(durations_list) - index+            pronoun, dur = (

I suggest dur -> subject

symonk

comment created time in 14 hours

pull request commentpytest-dev/pytest

Clarify fixture execution order and provide visual aids

@nicoddemus all set to be merged! 😁

SalmonMode

comment created time in 14 hours

Pull request review commentpytest-dev/pytest

[RFC] code location as a namedtuple

 def write_fixture(fixture_def: fixtures.FixtureDef[object]) -> None:     def write_item(item: nodes.Item) -> None:         # Not all items have _fixtureinfo attribute.         info: Optional[FuncFixtureInfo] = getattr(item, "_fixtureinfo", None)+        function: Optional[Callable[..., Any]] = getattr(item, "function", None)         if info is None or not info.name2fixturedefs:             # This test item does not use any fixtures.             return+        if function is None:

Only python item have that

RonnyPfannschmidt

comment created time in 14 hours

issue commentpytest-dev/pytest

--last-failed --last-failed-no-failures none is now collecting much more tests than it did in 5.4.3

@nicoddemus I put together a simple POC here, that does not highlight the issue, which is a similar basic setup to mine in work, the important thing to note here with this small poc is that when entering the _multicall for pytest_collect_modifyitems the items are already filtered correctly before even a hookwrapper has a chance at modifying them in place, from this i can conclude that the change in behaviour must be to do with our layout and something between 5.4.3 -> 6.0.1 changed what pytest is collecting etc for our given setup, now just to figure out what that is exactly...? and why @hookwrapper=True, tryfirst=True makes it even work, it seems insane.

# lib/myplugin.py
import pytest


@pytest.hookimpl
def pytest_collection_modifyitems(items):
    breakpoint()
    print(items)
# root conftest.py
pytest_plugins = ['lib.myplugin']

import pytest


@pytest.hookimpl
def pytest_collection_modifyitems(items):
    breakpoint()
    print(items)
# tests/test_one.py


def test_bar():
    assert False
# test_two.py



def test_foo():
    assert True

with lastfailed cache:

{
  "tests/test_one.py::test_bar": true
}

In this POC, when we enter _multicall, not a single collection_modifyitems hook has executed (even pre-yield at this point) and we see:

<HookImpl plugin_name='nfplugin', plugin=<_pytest.cacheprovider.NFPlugin object at 0x10a8cf650>>
(Pdb) pp args
[[<Function test_bar>]]

This is completely in contrast to my work setup, seems like a fundamental change to how its collecting tests in our project, I've noticed some of the (now 2600) tests listed, some of them are tests that never got collected before we moved to pytest 6.x (and weirdly why does hookwrapper=True, trylast=True in our plugin make it work? :/ can you point me where to look at what is building the items before handing them off to collection_modifyitems? as I feel thats where the fundamental difference lies here.

Contrast the above to my work scenario, once again no pre-yield hookwrappers have even fired at this point:

(Pdb) hook_impl
<HookImpl plugin_name='nfplugin', plugin=<_pytest.cacheprovider.NFPlugin object at 0x111525650>>
(Pdb) len(args[0])
2590
symonk

comment created time in 14 hours

pull request commentpytest-dev/pytest

Issue 2044 - show skipping reason in verbose mode

I applied the changes mentioned above, rebased and also added support for XPASSED, so I think this should be good to go.

CarycaKatarzyna

comment created time in 14 hours

issue commentpytest-dev/pytest

--last-failed --last-failed-no-failures none is now collecting much more tests than it did in 5.4.3

@nicoddemus I put together a simple POC here, that does not highlight the issue, which is a similar basic setup to mine in work, the important thing to note here with this small poc is that when entering the _multicall for pytest_collect_modifyitems the items are already filtered correctly before even a hookwrapper has a chance at modifying them in place, from this i can conclude that the change in behaviour must be to do with our layout and something between 5.4.3 -> 6.0.1 changed what pytest is collecting etc for our given setup, now just to figure out what that is exactly...? and why @hookwrapper=True, tryfirst=True makes it even work, it seems insane.

# lib/myplugin.py
import pytest


@pytest.hookimpl
def pytest_collection_modifyitems(items):
    breakpoint()
    print(items)
# root conftest.py
pytest_plugins = ['lib.myplugin']

import pytest


@pytest.hookimpl
def pytest_collection_modifyitems(items):
    breakpoint()
    print(items)
# tests/test_one.py


def test_bar():
    assert False
# test_two.py



def test_foo():
    assert True

with lastfailed cache:

{
  "tests/test_one.py::test_bar": true
}

In this POC, when we enter _multicall, not a single collection_modifyitems hook has executed (even pre-yield at this point) and we see:

<HookImpl plugin_name='nfplugin', plugin=<_pytest.cacheprovider.NFPlugin object at 0x10a8cf650>>
(Pdb) pp args
[[<Function test_bar>]]

This is completely in contrast to my work setup, seems like a fundamental change to how its collecting tests in our project, I've noticed some of the (now 2600) tests listed, some of them are tests that never got collected before we moved to pytest 6.x (and weirdly why does hookwrapper=True, trylast=True in our plugin make it work? :/ can you point me where to look at what is building the items before handing them off to collection_modifyitems? as I feel thats where the fundamental difference lies here.

symonk

comment created time in 15 hours

Pull request review commentpytest-dev/pytest

[RFC] code location as a namedtuple

 def write_fixture(fixture_def: fixtures.FixtureDef[object]) -> None:     def write_item(item: nodes.Item) -> None:         # Not all items have _fixtureinfo attribute.         info: Optional[FuncFixtureInfo] = getattr(item, "_fixtureinfo", None)+        function: Optional[Callable[..., Any]] = getattr(item, "function", None)         if info is None or not info.name2fixturedefs:             # This test item does not use any fixtures.             return+        if function is None:

Seems like the previous code assumed item.function exists. Maybe this should be assert function is not None then?

RonnyPfannschmidt

comment created time in 16 hours

Pull request review commentpytest-dev/pytest

[RFC] code location as a namedtuple

  import py -from _pytest.compat import assert_never

Interesting, didn't know about this partially initialized state.

RonnyPfannschmidt

comment created time in 16 hours

Pull request review commentpytest-dev/pytest

[RFC] code location as a namedtuple

 def _showfixtures_main(config: Config, session: Session) -> None:             continue         tw.write(argname, green=True)         if fixturedef.scope != "function":-            tw.write(" [%s scope]" % fixturedef.scope, cyan=True)+            tw.write(f" [{fixturedef.scope} scope]", cyan=True)         if verbose > 0:-            tw.write(" -- %s" % bestrel, yellow=True)+            tw.write(f" -- {bestrel}", yellow=True)

Should bestrel be changed to loc (or location)?

RonnyPfannschmidt

comment created time in 16 hours

Pull request review commentpytest-dev/pytest

[RFC] code location as a namedtuple

 def is_async_function(func: object) -> bool:     return iscoroutinefunction(func) or inspect.isasyncgenfunction(func)  -def getlocation(function, curdir: Optional[str] = None) -> str:+class CodeLocation(NamedTuple):+    path: Path+    lineno: int+++# TODO: integrate after pytest 3.6.0 has been dropped+def CodeLocation__str__(self: CodeLocation) -> str:+    """Python 3.6.0 hack for NamedTuple __str__"""+    return f"{self.path}:{self.lineno}"+++setattr(CodeLocation, "__str__", CodeLocation__str__)+++def getlocation(+    function, *, relative_to: Optional[Path], allow_escape: bool

A docstring would be helpful, it was not very clear to me from the name what allow_escape means.

RonnyPfannschmidt

comment created time in 16 hours

Pull request review commentpytest-dev/pytest

[RFC] code location as a namedtuple

 def is_async_function(func: object) -> bool:     return iscoroutinefunction(func) or inspect.isasyncgenfunction(func)  -def getlocation(function, curdir: Optional[str] = None) -> str:+class CodeLocation(NamedTuple):+    path: Path+    lineno: int+++# TODO: integrate after pytest 3.6.0 has been dropped
# TODO: integrate after Python 3.6.0 has been dropped
RonnyPfannschmidt

comment created time in 16 hours

issue commentpytest-dev/pytest

--last-failed --last-failed-no-failures none is now collecting much more tests than it did in 5.4.3

on further inspection, this also exists & one in main but they are standard hooks; not wrappers or tryfirst/last

def pytest_collection_modifyitems(items: "List[Item]", config: Config) -> None:
    deselect_by_keyword(items, config)
    deselect_by_mark(items, config)
symonk

comment created time in 16 hours

issue commentpytest-dev/pytest

Add more info on set_log_path()

@nicoddemus https://github.com/pytest-dev/pytest/issues/4707#issuecomment-460415617 Shouldn't this example be added to Docs ? (set_log_filename be replaced with set_log_path)

prakhargurunani

comment created time in 16 hours

more