Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PyTest FixtureRequest #74

Open
dylan-at-na opened this issue Jun 13, 2024 · 7 comments
Open

PyTest FixtureRequest #74

dylan-at-na opened this issue Jun 13, 2024 · 7 comments
Labels
enhancement New feature or request

Comments

@dylan-at-na
Copy link

dylan-at-na commented Jun 13, 2024

Bug description

# Given some PyTest class with a setup_teardown
class TestFile:
    @pytest.fixture(scope="class")
    def setup_teardown_environment(self, request: pytest.FixtureRequest):
        # The following line assigns a value to `temp1` which can be accessed throughout
        # the test class via `self`
        request.cls.temp1 = 54321
        print(self.temp1) # This executes via PyTest successfully
        # PyLint check throws this error: Instance of 'TestFile' has no 'temp1' member 
        # PylintE1101:no-member

Command used

pylint ${file}

Pylint output

Instance of 'TestFile' has no 'temp1' member PylintE1101:no-member

Expected behavior

PyLint should not identify this as a problem at all, as request.cls and self are intrinsically linked when operating within the same test class.

Pylint version

pylint 3.2.3
astroid 3.2.2
Python 3.11.4 (main, May  8 2024, 12:11:54) [GCC 9.4.0]

OS / Environment

Ubuntu 20

@jacobtylerwalls
Copy link
Member

jacobtylerwalls commented Jul 9, 2024

I think this is better raised as a feature request at pylint-dev/pylint-pytest

@jacobtylerwalls jacobtylerwalls transferred this issue from pylint-dev/pylint Jul 9, 2024
@stdedos stdedos added the enhancement New feature or request label Jul 9, 2024
@stdedos
Copy link
Collaborator

stdedos commented Jul 9, 2024

Hello @dylan-at-na!

Are you sure this is working like you are demonstrating?

We do actually have a test like that in the repo: https://github.com/pylint-dev/pylint-pytest/blob/8310a88916e4b0b7462fc525c56d60b9af4dc126/tests/input/no-member/not_using_cls.py

I have tried to replicate your setup

$ git --no-pager diff 
diff --git a/tests/input/no-member/not_using_cls.py b/tests/input/no-member/not_using_cls.py
index 95438af..16caf33 100644
--- a/tests/input/no-member/not_using_cls.py
+++ b/tests/input/no-member/not_using_cls.py
@@ -7,6 +7,14 @@ class TestClass:
     def setup_class(request):
         clls = request.cls
         clls.defined_in_setup_class = 123
+        print(clls.defined_in_setup_class)
 
     def test_foo(self):
         assert self.defined_in_setup_class
+
+    @pytest.fixture(scope="class")
+    def setup_teardown_environment(self, request: pytest.FixtureRequest):
+        # The following line assigns a value to `temp1`
+        # which can be accessed throughout the test class via `self`.
+        request.cls.temp1 = 54321
+        print(self.temp1)
$ pytest tests/input/no-member/not_using_cls.py -s
======================================= test session starts =======================================
platform linux -- Python 3.11.9, pytest-7.4.3, pluggy-1.3.0 -- ~/pylint-pytest/.venv/bin/python3.11
cachedir: .pytest_cache
rootdir: ~/pylint-pytest
configfile: pyproject.toml
plugins: cov-5.0.0
collected 1 item                                                                                                                                                                                          

tests/input/no-member/not_using_cls.py::TestClass::test_foo 123
PASSED

======================================== 1 passed in 0.01s ========================================

but, as you can see, I am unable to make your fixture work.

The test is printing out 123 (clls.defined_in_setup_class), but not 54321.

You MUST mark the fixture as autouse=True, according to the documentation: https://docs.pytest.org/en/latest/how-to/unittest.html#using-autouse-fixtures-and-accessing-other-fixtures

@jacobtylerwalls
Copy link
Member

(Let's find out if the reporter is using pylint-pytest or not.)

@dylan-at-na
Copy link
Author

dylan-at-na commented Jul 10, 2024

@stdedos Please see the below example which demonstrates a functional example (autouse is ignored in the first example, but is used further down)...

import pytest

class TestExample:
    @pytest.fixture(scope="class")
    def setup_teardown_username(self, request: pytest.FixtureRequest):
        request.cls.username = 'dylan'
        yield True
        del request.cls.username
    
    @pytest.fixture(scope="function")
    def setup_teardown_password(self, request: pytest.FixtureRequest, setup_teardown_username):
        request.cls.password = '*****'
        yield setup_teardown_username, True
        del request.cls.password
    
    def test_username_and_password(self, setup_teardown_password):
        assert self.username == 'dylan'
        assert self.password == '*****'

And the log output from running the above...

source .../.venv/bin/activate.csh
% (pycldqa-py3.11) %  /usr/bin/env .../.venv/bin/python /u/dylanl/.vscode-server/extensions/ms-python.debugpy-2024.7.11591012-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher 55139 -- -m pytest /u/dylanl/repos/local/scratch/test_scratch.py 
================================= test session starts ==================================
platform linux -- Python 3.11.4, pytest-8.2.2, pluggy-1.5.0
rootdir: /u/dylanl/repos/local
configfile: pyproject.toml
plugins: xdist-3.6.1
collected 1 item                                                                       

../local/scratch/test_scratch.py .                                               [100%]

================================== 1 passed in 0.04s ===================================

The following screenshot demonstrates the error being thrown...
image

@jacobtylerwalls The following is the result of running pylint against the above code with pylint-pytest plugin enabled. Relevant lines are marked with ***

(pycldqa-py3.11) %  cd ...; /usr/bin/env .../.venv/bin/python /u/dylanl/.vscode-server/extensions/ms-python.debugpy-2024.7.11591012-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher 36313 -- -m pylint --load-plugins=pylint_pytest /u/dylanl/repos/local/scratch/test_scratch.py 
************* Module test_scratch
/u/dylanl/repos/local/scratch/test_scratch.py:9:0: C0303: Trailing whitespace (trailing-whitespace)
/u/dylanl/repos/local/scratch/test_scratch.py:15:0: C0303: Trailing whitespace (trailing-whitespace)
/u/dylanl/repos/local/scratch/test_scratch.py:1:0: C0114: Missing module docstring (missing-module-docstring)
/u/dylanl/repos/local/scratch/test_scratch.py:3:0: C0115: Missing class docstring (missing-class-docstring)
/u/dylanl/repos/local/scratch/test_scratch.py:5:4: C0116: Missing function or method docstring (missing-function-docstring)
/u/dylanl/repos/local/scratch/test_scratch.py:11:4: C0116: Missing function or method docstring (missing-function-docstring)
/u/dylanl/repos/local/scratch/test_scratch.py:16:4: C0116: Missing function or method docstring (missing-function-docstring)
***/u/dylanl/repos/local/scratch/test_scratch.py:17:15: E1101: Instance of 'TestExample' has no 'username' member (no-member)
***/u/dylanl/repos/local/scratch/test_scratch.py:18:15: E1101: Instance of 'TestExample' has no 'password' member (no-member)

-----------------------------------
Your code has been rated at 0.00/10

If I now add autouse=True to the fixtures and make the necessary changes we end up with the following code...

import pytest

class TestExample:
    @pytest.fixture(scope="class", autouse=True)
    def setup_teardown_username(self, request: pytest.FixtureRequest):
        request.cls.username = 'dylan'
        yield True
        del request.cls.username
    
    @pytest.fixture(scope="function", autouse=True)
    def setup_teardown_password(self, request: pytest.FixtureRequest):
        request.cls.password = '*****'
        yield True
        del request.cls.password
    
    def test_username_and_password(self):
        assert self.username == 'dylan'
        assert self.password == '*****'

Which again, passes.

================================= test session starts ==================================
platform linux -- Python 3.11.4, pytest-8.2.2, pluggy-1.5.0
rootdir: /u/dylanl/repos/local
configfile: pyproject.toml
plugins: xdist-3.6.1
collected 1 item                                                                       

../local/scratch/test_scratch.py .                                               [100%]

================================== 1 passed in 0.06s ===================================

However, running PyLint on this produces the same errors (relevant lines marked with ***)...

pylint --load-plugins=pylint_pytest /u/dylanl/repos/local/scratch/test_scratch.py 
************* Module test_scratch
/u/dylanl/repos/local/scratch/test_scratch.py:9:0: C0303: Trailing whitespace (trailing-whitespace)
/u/dylanl/repos/local/scratch/test_scratch.py:15:0: C0303: Trailing whitespace (trailing-whitespace)
/u/dylanl/repos/local/scratch/test_scratch.py:1:0: C0114: Missing module docstring (missing-module-docstring)
/u/dylanl/repos/local/scratch/test_scratch.py:3:0: C0115: Missing class docstring (missing-class-docstring)
/u/dylanl/repos/local/scratch/test_scratch.py:5:4: C0116: Missing function or method docstring (missing-function-docstring)
/u/dylanl/repos/local/scratch/test_scratch.py:11:4: C0116: Missing function or method docstring (missing-function-docstring)
/u/dylanl/repos/local/scratch/test_scratch.py:16:4: C0116: Missing function or method docstring (missing-function-docstring)
***/u/dylanl/repos/local/scratch/test_scratch.py:17:15: E1101: Instance of 'TestExample' has no 'username' member (no-member)
***/u/dylanl/repos/local/scratch/test_scratch.py:18:15: E1101: Instance of 'TestExample' has no 'password' member (no-member)

------------------------------------------------------------------
Your code has been rated at 0.00/10 (previous run: 3.75/10, -3.75)

Interestingly enough if I use your code sample located at https://github.com/pylint-dev/pylint-pytest/blob/8310a88916e4b0b7462fc525c56d60b9af4dc126/tests/input/no-member/not_using_cls.py

I don't get the error

************* Module test_scratch
/u/dylanl/repos/local/scratch/test_scratch.py:12:0: C0304: Final newline missing (missing-final-newline)
/u/dylanl/repos/local/scratch/test_scratch.py:1:0: C0114: Missing module docstring (missing-module-docstring)
/u/dylanl/repos/local/scratch/test_scratch.py:4:0: C0115: Missing class docstring (missing-class-docstring)
/u/dylanl/repos/local/scratch/test_scratch.py:7:4: C0116: Missing function or method docstring (missing-function-docstring)
/u/dylanl/repos/local/scratch/test_scratch.py:11:4: C0116: Missing function or method docstring (missing-function-docstring)

------------------------------------------------------------------
Your code has been rated at 2.86/10 (previous run: 0.00/10, +2.86)

This prompted me to attempt PyLint with @staticmethod applied to my fixtures but this did not work.

In a last ditch effort I assigned request.cls to clls as you do above...

import pytest

class TestExample:
    @pytest.fixture(scope="class", autouse=True)
    def setup_teardown_username(self, request: pytest.FixtureRequest):
        clls = request.cls
        clls.username = 'dylan'
        yield True
        del request.cls.username
    
    @pytest.fixture(scope="function", autouse=True)
    def setup_teardown_password(self, request: pytest.FixtureRequest):
        clls = request.cls
        clls.password = '*****'
        yield True
        del request.cls.password
    
    def test_username_and_password(self):
        assert self.username == 'dylan'
        assert self.password == '*****'

Again, this passes.

And it removes the error line for the class scoped fixture (setup_teardown_username), but not for the function scoped fixture (setup_teardown_password). Relevant line marked with ***.

************* Module test_scratch
/u/dylanl/repos/local/scratch/test_scratch.py:10:0: C0303: Trailing whitespace (trailing-whitespace)
/u/dylanl/repos/local/scratch/test_scratch.py:17:0: C0303: Trailing whitespace (trailing-whitespace)
/u/dylanl/repos/local/scratch/test_scratch.py:1:0: C0114: Missing module docstring (missing-module-docstring)
/u/dylanl/repos/local/scratch/test_scratch.py:3:0: C0115: Missing class docstring (missing-class-docstring)
/u/dylanl/repos/local/scratch/test_scratch.py:5:4: C0116: Missing function or method docstring (missing-function-docstring)
/u/dylanl/repos/local/scratch/test_scratch.py:12:4: C0116: Missing function or method docstring (missing-function-docstring)
/u/dylanl/repos/local/scratch/test_scratch.py:18:4: C0116: Missing function or method docstring (missing-function-docstring)
***/u/dylanl/repos/local/scratch/test_scratch.py:20:15: E1101: Instance of 'TestExample' has no 'password' member (no-member)

------------------------------------------------------------------
Your code has been rated at 2.00/10 (previous run: 2.86/10, -0.86)

(Incorrect assumption, see follow up comment for clarification) So it would seem that clls is a somewhat special variable as far as PyLint is concerned? Though based on this search there doesn't seem to be much reference to it https://www.google.com/search?q=pylint+%22clls%22&client=firefox-b-d&sca_esv=41efd453413bdc83&sca_upv=1&ei=1kKOZrm0GdiB9u8P0YCu0A0&ved=0ahUKEwi59_Dag5yHAxXYgP0HHVGAC9oQ4dUDCA8&uact=5&oq=pylint+%22clls%22&gs_lp=Egxnd3Mtd2l6LXNlcnAiDXB5bGludCAiY2xscyIyCBAhGKABGMMESNw1UIEVWP4zcAF4AZABAJgBjwGgAegDqgEDMC40uAEDyAEA-AEBmAIFoAKBBMICChAAGLADGNYEGEfCAggQABiABBiiBMICCBAAGKIEGIkFwgIFECEYoAGYAwCIBgGQBgiSBwMxLjSgB6cG&sclient=gws-wiz-serp

@dylan-at-na
Copy link
Author

dylan-at-na commented Jul 10, 2024

Quick follow up - it isn't clls that resolves it in the class scoped fixture. It is simply the act of assigning request.cls to a variable. Any variable name will do.

import pytest

class TestExample:
    @pytest.fixture(scope="class", autouse=True)
    def setup_teardown_username(self, request: pytest.FixtureRequest):
        mocha = request.cls
        mocha.username = 'dylan'
        yield True
        del request.cls.username
    
    @pytest.fixture(scope="function", autouse=True)
    def setup_teardown_password(self, request: pytest.FixtureRequest):
        clls = request.cls
        clls.password = '*****'
        yield True
        del request.cls.password
    
    def test_username_and_password(self):
        assert self.username == 'dylan'
        assert self.password == '*****'

Passes.

PyLint:

************* Module test_scratch
/u/dylanl/repos/local/scratch/test_scratch.py:10:0: C0303: Trailing whitespace (trailing-whitespace)
/u/dylanl/repos/local/scratch/test_scratch.py:17:0: C0303: Trailing whitespace (trailing-whitespace)
/u/dylanl/repos/local/scratch/test_scratch.py:1:0: C0114: Missing module docstring (missing-module-docstring)
/u/dylanl/repos/local/scratch/test_scratch.py:3:0: C0115: Missing class docstring (missing-class-docstring)
/u/dylanl/repos/local/scratch/test_scratch.py:5:4: C0116: Missing function or method docstring (missing-function-docstring)
/u/dylanl/repos/local/scratch/test_scratch.py:12:4: C0116: Missing function or method docstring (missing-function-docstring)
/u/dylanl/repos/local/scratch/test_scratch.py:18:4: C0116: Missing function or method docstring (missing-function-docstring)
***/u/dylanl/repos/local/scratch/test_scratch.py:20:15: E1101: Instance of 'TestExample' has no 'password' member (no-member)

------------------------------------------------------------------
Your code has been rated at 2.00/10 (previous run: 2.00/10, +0.00)

Again this does not resolve the issue in the functionscoped fixture.

@stdedos
Copy link
Collaborator

stdedos commented Jul 10, 2024

So it would seem that clls is a somewhat special variable as far as PyLint is concerned? ...

FWIW: Your search result gives exactly one result for me

image

clls name is not "special" per-se; any name would do:

and node.expr.name in self.request_cls

... but for now, it MUST be like that.

I am not sure why the original author chose to write this test (clls.defined_in_setup_class = 123) and skipped the most obvious request.cls.X = Y (coming in a commit soon).
It is an issue with "contrived/MWE" examples that you cannot see "where" are they coming from.

Quick follow up - it isn't clls that resolves it in the class scoped fixture. It is simply the act of assigning request.cls to a variable. Any variable name will do.

Exactly 🙃


@pytest.fixture(scope="function")

I will try this locally too. However, as of now, for a request.cls to be considered eligible, it needs to satisfy

def _is_class_autouse_fixture(function):
try:
for decorator in function.decorators.nodes:
if isinstance(decorator, astroid.Call):
func = decorator.func
if (
func
and func.attrname in ("fixture", "yield_fixture")
and func.expr.name == "pytest"
):
is_class = is_autouse = False
for kwarg in decorator.keywords or []:
if kwarg.arg == "scope" and kwarg.value.value == "class":
is_class = True
if kwarg.arg == "autouse" and kwarg.value.value is True:
is_autouse = True
if is_class and is_autouse:
return True
except AttributeError:
pass
return False

I will try all scopes and see what their result is. And then code/test appropriately.


... it seems that this is getting quick traction, so I'll push a branch within the day.

One thing that I haven't been able to figure out, unfortunately, is that the pylint/pylint-pytest is sensitive to ordering.

tl;dr:

class TestClass:
    @staticmethod
    @pytest.fixture(scope="class", autouse=True)
    def setup_class(request):
        clls = request.cls
        clls.defined_in_setup_class = 123

    def test_foo(self):
        assert self.defined_in_setup_class

works,

class TestClass:
    def test_foo(self):
        assert self.defined_in_setup_class

    @staticmethod
    @pytest.fixture(scope="class", autouse=True)
    def setup_class(request):
        clls = request.cls
        clls.defined_in_setup_class = 123

fails.

astroid visits top-to-bottom. In order to fix this "correctly" we MUST first visit eligible @pytest.fixture(autouse=True) fixtures.
Perhaps after a possible __init__?
Maybe even strictly in the correct call order (session, package, module, class, function)

@dylan-at-na
Copy link
Author

dylan-at-na commented Jul 10, 2024

For anybody else who comes across this issue - the easiest temporary workaround with minimal changes to your code is to introduce a fixture which is class scoped, and autouse and initializes all relevant variables to None within your request.cls. See below for an example relevant to the above code snippet...

import pytest

class TestExample:
    @pytest.fixture(scope='class', autouse=True)
    def setup_teardown_request_cls(self, request: pytest.FixtureRequest):
        _cls = request.cls
        _cls.username = None
        _cls.password = None

    @pytest.fixture(scope="class")
    def setup_teardown_username(self, request: pytest.FixtureRequest):
        request.cls.username = 'dylan'
        yield True
        del request.cls.username
    
    @pytest.fixture(scope="function")
    def setup_teardown_password(self, request: pytest.FixtureRequest, setup_teardown_username: bool):
        request.cls.password = '*****'
        yield True
        del request.cls.password
    
    def test_username_and_password(self, setup_teardown_password: bool):
        assert self.username == 'dylan'
        assert self.password == '*****'

This has the added benefit of isolating the initialization, thus being easy to remove when and if @stdedos changes are in place. You can of course initialize your variables to any default value you like but for demonstrations sake I have used None.

stdedos added a commit that referenced this issue Jul 13, 2024
It seems we already support the (weird) scenario that someone does
`clls = request.cls`, and subsequently uses `clls.X = Y`

However, it appears that we are missing the trivial `request.cls.X = Y` case

References #74

Additionally:

* Factorize condititons for semantic naming
* `pylint_pytest/utils.py#_is_class_autouse_fixture`:
  Class-defined `@pytest.fixture(autouse=True)` need not explicitly
  define `scope="class"`
  We set `is_class` via `isinstance(function.parent, astroid.ClassDef)`,
  and un-set it if explicitly defined as "not `"class"`"
* The test currently is not passing, so we surgically mark it as `xfail`
  (for details, see the code)

Signed-off-by: Stavros Ntentos <[email protected]>

Small improvements following the `no-member` improvements

We can "never know" what `node.targets` is.
Add a type guard and a `logging.warning` for non-matches.

Which leads to creating the `node_line_as_string_w_highlight`,
to be able to have a more direct visual feedback of "what a `node` is".

We are also creating a `no_error()`, `noerr_or_default()` family of
functions, since using functions as complex as
`node_line_as_string_w_highlight` could lead to errors that are
really not desired in the context of logging.

Additionally, make the `pprint(self.msgs)` testing function
conditional on very verbose - and expand it with
`node_line_as_string_w_highlight`.

Finally, make some "not-docstrings" comments, and fix some grammar issues.

Signed-off-by: Stavros Ntentos <[email protected]>

`tests/base_tester.py`: Warn on using the short Message ID for instantiation

With `PylintPytestWarning`, `PylintMessageDefinition`, give (me) a notice
when creating new not-compliant `BasePytestTester` sub-classes

Signed-off-by: Stavros Ntentos <[email protected]>

v2: `no-member`: Support tracking/ignoring `request.cls.X` / `self.X`

v3: `no-member`: Support fine-grained attribute declaration

In order to "properly" analyze fixtures that might change the class itself
(which it can usually be out of order typed), we need to walk the
`fixture` `FunctionDef`s in advance, in their topological order, per-scope

For that, we need to hand-roll out own ASTWalker / ASTVisitor
(pylint's is a bit tight to their `checker` implementation)

This enables us to (almost) correctly allow pylint to introspect
`used-before-assignment` issues
(see `tests/input/no-member/not_using_cls.py` changes)

Signed-off-by: Stavros Ntentos <[email protected]>
stdedos added a commit that referenced this issue Aug 25, 2024
It seems we already support the (weird) scenario that someone does
`clls = request.cls`, and subsequently uses `clls.X = Y`

However, it appears that we are missing the trivial `request.cls.X = Y` case

Fixes #74

Additionally:

* Factorize condititons for semantic naming
* Make some "not-docstrings" comments, and fix some grammar issues.

In order to "properly" analyze fixtures that might change the class itself
(which it can usually be out of order typed), we need to walk the
`fixture` `FunctionDef`s in advance, in their topological order, per-scope.

For that, we need to hand-roll out own ASTWalker / ASTVisitor
(pylint's is a bit tight to their `checker` implementation).

This enables us to (almost) correctly allow pylint to introspect
`used-before-assignment` issues
(see `tests/input/no-member/not_using_cls.py` changes)

For project internals:

* Split `pylint_pytest/utils.py` to modules

Signed-off-by: Stavros Ntentos <[email protected]>
stdedos added a commit that referenced this issue Aug 25, 2024
It seems we already support the (weird) scenario that someone does
`clls = request.cls`, and subsequently uses `clls.X = Y`

However, it appears that we are missing the trivial `request.cls.X = Y` case

Fixes #74

Additionally:

* Factorize condititons for semantic naming
* Make some "not-docstrings" comments, and fix some grammar issues.

In order to "properly" analyze fixtures that might change the class itself
(which it can usually be out of order typed), we need to walk the
`fixture` `FunctionDef`s in advance, in their topological order, per-scope.

For that, we need to hand-roll out own ASTWalker / ASTVisitor
(pylint's is a bit tight to their `checker` implementation).

This enables us to (almost) correctly allow pylint to introspect
`used-before-assignment` issues
(see `tests/input/no-member/not_using_cls.py` changes)

For project internals:

* Split `pylint_pytest/utils.py` to modules

Signed-off-by: Stavros Ntentos <[email protected]>
stdedos added a commit that referenced this issue Oct 4, 2024
It seems we already support the (weird) scenario that someone does
`clls = request.cls`, and subsequently uses `clls.X = Y`

However, it appears that we are missing the trivial `request.cls.X = Y` case

Fixes #74

Additionally:

* Factorize condititons for semantic naming
* Make some "not-docstrings" comments, and fix some grammar issues.

In order to "properly" analyze fixtures that might change the class itself
(which it can usually be out of order typed), we need to walk the
`fixture` `FunctionDef`s in advance, in their topological order, per-scope.

For that, we need to hand-roll out own ASTWalker / ASTVisitor
(pylint's is a bit tight to their `checker` implementation).

This enables us to (almost) correctly allow pylint to introspect
`used-before-assignment` issues
(see `tests/input/no-member/not_using_cls.py` changes)

For project internals:

* Split `pylint_pytest/utils.py` to modules

Signed-off-by: Stavros Ntentos <[email protected]>
stdedos added a commit that referenced this issue Oct 4, 2024
It seems we already support the (weird) scenario that someone does
`clls = request.cls`, and subsequently uses `clls.X = Y`

However, it appears that we are missing the trivial `request.cls.X = Y` case

Fixes #74

Additionally:

* Factorize condititons for semantic naming
* Make some "not-docstrings" comments, and fix some grammar issues.

In order to "properly" analyze fixtures that might change the class itself
(which it can usually be out of order typed), we need to walk the
`fixture` `FunctionDef`s in advance, in their topological order, per-scope.

For that, we need to hand-roll out own ASTWalker / ASTVisitor
(pylint's is a bit tight to their `checker` implementation).

This enables us to (almost) correctly allow pylint to introspect
`used-before-assignment` issues
(see `tests/input/no-member/not_using_cls.py` changes)

For project internals:

* Split `pylint_pytest/utils.py` to modules

Signed-off-by: Stavros Ntentos <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants