Skip to content

Commit

Permalink
Merge branch 'main' into prefer-pyi
Browse files Browse the repository at this point in the history
  • Loading branch information
Pierre-Sassoulas authored Apr 22, 2024
2 parents 3e3333f + 7a3b482 commit 2103e00
Show file tree
Hide file tree
Showing 11 changed files with 109 additions and 30 deletions.
32 changes: 16 additions & 16 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ jobs:
timeout-minutes: 20
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v5.0.0
uses: actions/setup-python@v5.1.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
Expand All @@ -39,7 +39,7 @@ jobs:
'requirements_full.txt', 'requirements_minimal.txt') }}" >> $GITHUB_OUTPUT
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache@v4.0.0
uses: actions/cache@v4.0.2
with:
path: venv
key: >-
Expand All @@ -59,7 +59,7 @@ jobs:
hashFiles('.pre-commit-config.yaml') }}" >> $GITHUB_OUTPUT
- name: Restore pre-commit environment
id: cache-precommit
uses: actions/cache@v4.0.0
uses: actions/cache@v4.0.2
with:
path: ${{ env.PRE_COMMIT_CACHE }}
key: >-
Expand All @@ -86,10 +86,10 @@ jobs:
python-key: ${{ steps.generate-python-key.outputs.key }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.2
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v5.0.0
uses: actions/setup-python@v5.1.0
with:
python-version: ${{ matrix.python-version }}
check-latest: true
Expand All @@ -106,7 +106,7 @@ jobs:
'requirements_full.txt', 'requirements_minimal.txt') }}" >> $GITHUB_OUTPUT
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache@v4.0.0
uses: actions/cache@v4.0.2
with:
path: venv
key: >-
Expand Down Expand Up @@ -145,10 +145,10 @@ jobs:
# Workaround to set correct temp directory on Windows
# https://github.com/actions/virtual-environments/issues/712
- name: Check out code from GitHub
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.2
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v5.0.0
uses: actions/setup-python@v5.1.0
with:
python-version: ${{ matrix.python-version }}
check-latest: true
Expand All @@ -160,7 +160,7 @@ jobs:
'requirements_full.txt', 'requirements_minimal.txt') }}" >> $GITHUB_OUTPUT
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache@v4.0.0
uses: actions/cache@v4.0.2
with:
path: venv
key: >-
Expand Down Expand Up @@ -195,10 +195,10 @@ jobs:
python-version: ["pypy3.8", "pypy3.10"]
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.2
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v5.0.0
uses: actions/setup-python@v5.1.0
with:
python-version: ${{ matrix.python-version }}
check-latest: true
Expand All @@ -210,7 +210,7 @@ jobs:
}}" >> $GITHUB_OUTPUT
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache@v4.0.0
uses: actions/cache@v4.0.2
with:
path: venv
key: >-
Expand Down Expand Up @@ -241,17 +241,17 @@ jobs:
needs: ["tests-linux", "tests-windows", "tests-pypy"]
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.2
- name: Set up Python 3.12
id: python
uses: actions/setup-python@v5.0.0
uses: actions/setup-python@v5.1.0
with:
python-version: "3.12"
check-latest: true
- name: Install dependencies
run: pip install -U -r requirements_minimal.txt
- name: Download all coverage artifacts
uses: actions/download-artifact@v4.1.2
uses: actions/download-artifact@v4.1.4
- name: Combine Linux coverage results
run: |
coverage combine coverage-linux*/.coverage
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.2

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ jobs:
timeout-minutes: 5
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.2
- name: Set up Python 3.9
id: python
uses: actions/setup-python@v5.0.0
uses: actions/setup-python@v5.1.0
with:
# virtualenv 15.1.0 cannot be installed on Python 3.10+
python-version: 3.9
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ jobs:
url: https://pypi.org/project/astroid/
steps:
- name: Check out code from Github
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4.1.2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v5.0.0
uses: actions/setup-python@v5.1.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
Expand Down
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ repos:
- id: end-of-file-fixer
exclude: tests/testdata
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: "v0.2.1"
rev: "v0.3.4"
hooks:
- id: ruff
exclude: tests/testdata
Expand All @@ -23,7 +23,7 @@ repos:
exclude: tests/testdata|setup.py
types: [python]
- repo: https://github.com/asottile/pyupgrade
rev: v3.15.0
rev: v3.15.2
hooks:
- id: pyupgrade
exclude: tests/testdata
Expand All @@ -34,7 +34,7 @@ repos:
- id: black-disable-checker
exclude: tests/test_nodes_lineno.py
- repo: https://github.com/psf/black
rev: 24.2.0
rev: 24.3.0
hooks:
- id: black
args: [--safe, --quiet]
Expand All @@ -54,7 +54,7 @@ repos:
]
exclude: tests/testdata|conf.py
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.8.0
rev: v1.9.0
hooks:
- id: mypy
name: mypy
Expand Down
13 changes: 13 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,23 @@ What's New in astroid 3.2.0?
============================
Release date: TBA


* ``.pyi`` stub files are now preferred over ``.py`` files when resolving imports.

Closes pylint-dev/#9185

* ``igetattr()`` returns the last same-named function in a class (instead of
the first). This avoids false positives in pylint with ``@overload``.

Closes #1015
Refs pylint-dev/pylint#4696

* Adds ``module_denylist`` to ``AstroidManager`` for modules to be skipped during AST
generation. Modules in this list will cause an ``AstroidImportError`` to be raised
when an AST for them is requested.

Refs pylint-dev/pylint#9442


What's New in astroid 3.1.1?
============================
Expand Down
8 changes: 5 additions & 3 deletions astroid/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class AstroidManager:
"optimize_ast": False,
"max_inferable_values": 100,
"extension_package_whitelist": set(),
"module_denylist": set(),
"_transform": TransformVisitor(),
}

Expand All @@ -70,6 +71,7 @@ def __init__(self) -> None:
self.extension_package_whitelist = AstroidManager.brain[
"extension_package_whitelist"
]
self.module_denylist = AstroidManager.brain["module_denylist"]
self._transform = AstroidManager.brain["_transform"]

@property
Expand Down Expand Up @@ -200,6 +202,8 @@ def ast_from_module_name( # noqa: C901
# importing a module with the same name as the file that is importing
# we want to fallback on the import system to make sure we get the correct
# module.
if modname in self.module_denylist:
raise AstroidImportError(f"Skipping ignored module {modname!r}")
if modname in self.astroid_cache and use_cache:
return self.astroid_cache[modname]
if modname == "__main__":
Expand Down Expand Up @@ -305,7 +309,6 @@ def file_from_module_name(
modname.split("."), context_file=contextfile
)
except ImportError as e:
# pylint: disable-next=redefined-variable-type
value = AstroidImportError(
"Failed to import module {modname} with error:\n{error}.",
modname=modname,
Expand Down Expand Up @@ -402,8 +405,7 @@ def infer_ast_from_something(
# take care, on living object __module__ is regularly wrong :(
modastroid = self.ast_from_module_name(modname)
if klass is obj:
for inferred in modastroid.igetattr(name, context):
yield inferred
yield from modastroid.igetattr(name, context)
else:
for inferred in modastroid.igetattr(name, context):
yield inferred.instantiate_class()
Expand Down
11 changes: 10 additions & 1 deletion astroid/nodes/scoped_nodes/scoped_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2508,12 +2508,21 @@ def igetattr(
# to the attribute happening *after* the attribute's definition (e.g. AugAssigns on lists)
if len(attributes) > 1:
first_attr, attributes = attributes[0], attributes[1:]
first_scope = first_attr.scope()
first_scope = first_attr.parent.scope()
attributes = [first_attr] + [
attr
for attr in attributes
if attr.parent and attr.parent.scope() == first_scope
]
functions = [attr for attr in attributes if isinstance(attr, FunctionDef)]
if functions:
# Prefer only the last function, unless a property is involved.
last_function = functions[-1]
attributes = [
a
for a in attributes
if a not in functions or a is last_function or bases._is_property(a)
]

for inferred in bases._infer_stmts(attributes, context, frame=self):
# yield Uninferable object instead of descriptors when necessary
Expand Down
1 change: 1 addition & 0 deletions astroid/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,5 @@ def brainless_manager():
m._mod_file_cache = {}
m._transform = transforms.TransformVisitor()
m.extension_package_whitelist = set()
m.module_denylist = set()
return m
49 changes: 48 additions & 1 deletion tests/test_inference.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
)
from astroid import decorators as decoratorsmod
from astroid.arguments import CallSite
from astroid.bases import BoundMethod, Instance, UnboundMethod, UnionType
from astroid.bases import BoundMethod, Generator, Instance, UnboundMethod, UnionType
from astroid.builder import AstroidBuilder, _extract_single_node, extract_node, parse
from astroid.const import IS_PYPY, PY39_PLUS, PY310_PLUS, PY312_PLUS
from astroid.context import CallContext, InferenceContext
Expand Down Expand Up @@ -4321,6 +4321,53 @@ class Test(Outer.Inner):
assert isinstance(inferred, nodes.Const)
assert inferred.value == 123

def test_infer_method_empty_body(self) -> None:
# https://github.com/PyCQA/astroid/issues/1015
node = extract_node(
"""
class A:
def foo(self): ...
A().foo() #@
"""
)
inferred = next(node.infer())
assert isinstance(inferred, nodes.Const)
assert inferred.value is None

def test_infer_method_overload(self) -> None:
# https://github.com/PyCQA/astroid/issues/1015
node = extract_node(
"""
class A:
def foo(self): ...
def foo(self):
yield
A().foo() #@
"""
)
inferred = list(node.infer())
assert len(inferred) == 1
assert isinstance(inferred[0], Generator)

def test_infer_function_under_if(self) -> None:
node = extract_node(
"""
if 1 in [1]:
def func():
return 42
else:
def func():
return False
func() #@
"""
)
inferred = list(node.inferred())
assert [const.value for const in inferred] == [42, False]

def test_delayed_attributes_without_slots(self) -> None:
ast_node = extract_node(
"""
Expand Down
7 changes: 7 additions & 0 deletions tests/test_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,13 @@ def test_raises_exception_for_empty_modname(self) -> None:
with pytest.raises(AstroidBuildingError):
self.manager.ast_from_module_name(None)

def test_denied_modules_raise(self) -> None:
self.manager.module_denylist.add("random")
with pytest.raises(AstroidImportError, match="random"):
self.manager.ast_from_module_name("random")
# and module not in the deny list shouldn't raise
self.manager.ast_from_module_name("math")


class IsolatedAstroidManagerTest(resources.AstroidCacheSetupMixin, unittest.TestCase):
def test_no_user_warning(self):
Expand Down

0 comments on commit 2103e00

Please sign in to comment.