Skip to content

Commit 2103e00

Browse files
Merge branch 'main' into prefer-pyi
2 parents 3e3333f + 7a3b482 commit 2103e00

File tree

11 files changed

+109
-30
lines changed

11 files changed

+109
-30
lines changed

.github/workflows/ci.yaml

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ jobs:
2424
timeout-minutes: 20
2525
steps:
2626
- name: Check out code from GitHub
27-
uses: actions/[email protected].1
27+
uses: actions/[email protected].2
2828
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
2929
id: python
30-
uses: actions/setup-python@v5.0.0
30+
uses: actions/setup-python@v5.1.0
3131
with:
3232
python-version: ${{ env.DEFAULT_PYTHON }}
3333
check-latest: true
@@ -39,7 +39,7 @@ jobs:
3939
'requirements_full.txt', 'requirements_minimal.txt') }}" >> $GITHUB_OUTPUT
4040
- name: Restore Python virtual environment
4141
id: cache-venv
42-
uses: actions/[email protected].0
42+
uses: actions/[email protected].2
4343
with:
4444
path: venv
4545
key: >-
@@ -59,7 +59,7 @@ jobs:
5959
hashFiles('.pre-commit-config.yaml') }}" >> $GITHUB_OUTPUT
6060
- name: Restore pre-commit environment
6161
id: cache-precommit
62-
uses: actions/[email protected].0
62+
uses: actions/[email protected].2
6363
with:
6464
path: ${{ env.PRE_COMMIT_CACHE }}
6565
key: >-
@@ -86,10 +86,10 @@ jobs:
8686
python-key: ${{ steps.generate-python-key.outputs.key }}
8787
steps:
8888
- name: Check out code from GitHub
89-
uses: actions/[email protected].1
89+
uses: actions/[email protected].2
9090
- name: Set up Python ${{ matrix.python-version }}
9191
id: python
92-
uses: actions/setup-python@v5.0.0
92+
uses: actions/setup-python@v5.1.0
9393
with:
9494
python-version: ${{ matrix.python-version }}
9595
check-latest: true
@@ -106,7 +106,7 @@ jobs:
106106
'requirements_full.txt', 'requirements_minimal.txt') }}" >> $GITHUB_OUTPUT
107107
- name: Restore Python virtual environment
108108
id: cache-venv
109-
uses: actions/[email protected].0
109+
uses: actions/[email protected].2
110110
with:
111111
path: venv
112112
key: >-
@@ -145,10 +145,10 @@ jobs:
145145
# Workaround to set correct temp directory on Windows
146146
# https://github.com/actions/virtual-environments/issues/712
147147
- name: Check out code from GitHub
148-
uses: actions/[email protected].1
148+
uses: actions/[email protected].2
149149
- name: Set up Python ${{ matrix.python-version }}
150150
id: python
151-
uses: actions/setup-python@v5.0.0
151+
uses: actions/setup-python@v5.1.0
152152
with:
153153
python-version: ${{ matrix.python-version }}
154154
check-latest: true
@@ -160,7 +160,7 @@ jobs:
160160
'requirements_full.txt', 'requirements_minimal.txt') }}" >> $GITHUB_OUTPUT
161161
- name: Restore Python virtual environment
162162
id: cache-venv
163-
uses: actions/[email protected].0
163+
uses: actions/[email protected].2
164164
with:
165165
path: venv
166166
key: >-
@@ -195,10 +195,10 @@ jobs:
195195
python-version: ["pypy3.8", "pypy3.10"]
196196
steps:
197197
- name: Check out code from GitHub
198-
uses: actions/[email protected].1
198+
uses: actions/[email protected].2
199199
- name: Set up Python ${{ matrix.python-version }}
200200
id: python
201-
uses: actions/setup-python@v5.0.0
201+
uses: actions/setup-python@v5.1.0
202202
with:
203203
python-version: ${{ matrix.python-version }}
204204
check-latest: true
@@ -210,7 +210,7 @@ jobs:
210210
}}" >> $GITHUB_OUTPUT
211211
- name: Restore Python virtual environment
212212
id: cache-venv
213-
uses: actions/[email protected].0
213+
uses: actions/[email protected].2
214214
with:
215215
path: venv
216216
key: >-
@@ -241,17 +241,17 @@ jobs:
241241
needs: ["tests-linux", "tests-windows", "tests-pypy"]
242242
steps:
243243
- name: Check out code from GitHub
244-
uses: actions/[email protected].1
244+
uses: actions/[email protected].2
245245
- name: Set up Python 3.12
246246
id: python
247-
uses: actions/setup-python@v5.0.0
247+
uses: actions/setup-python@v5.1.0
248248
with:
249249
python-version: "3.12"
250250
check-latest: true
251251
- name: Install dependencies
252252
run: pip install -U -r requirements_minimal.txt
253253
- name: Download all coverage artifacts
254-
uses: actions/[email protected].2
254+
uses: actions/[email protected].4
255255
- name: Combine Linux coverage results
256256
run: |
257257
coverage combine coverage-linux*/.coverage

.github/workflows/codeql-analysis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ jobs:
4646

4747
steps:
4848
- name: Checkout repository
49-
uses: actions/[email protected].1
49+
uses: actions/[email protected].2
5050

5151
# Initializes the CodeQL tools for scanning.
5252
- name: Initialize CodeQL

.github/workflows/release-tests.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ jobs:
1313
timeout-minutes: 5
1414
steps:
1515
- name: Check out code from GitHub
16-
uses: actions/[email protected].1
16+
uses: actions/[email protected].2
1717
- name: Set up Python 3.9
1818
id: python
19-
uses: actions/setup-python@v5.0.0
19+
uses: actions/setup-python@v5.1.0
2020
with:
2121
# virtualenv 15.1.0 cannot be installed on Python 3.10+
2222
python-version: 3.9

.github/workflows/release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ jobs:
2020
url: https://pypi.org/project/astroid/
2121
steps:
2222
- name: Check out code from Github
23-
uses: actions/[email protected].1
23+
uses: actions/[email protected].2
2424
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
2525
id: python
26-
uses: actions/setup-python@v5.0.0
26+
uses: actions/setup-python@v5.1.0
2727
with:
2828
python-version: ${{ env.DEFAULT_PYTHON }}
2929
check-latest: true

.pre-commit-config.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ repos:
1010
- id: end-of-file-fixer
1111
exclude: tests/testdata
1212
- repo: https://github.com/astral-sh/ruff-pre-commit
13-
rev: "v0.2.1"
13+
rev: "v0.3.4"
1414
hooks:
1515
- id: ruff
1616
exclude: tests/testdata
@@ -23,7 +23,7 @@ repos:
2323
exclude: tests/testdata|setup.py
2424
types: [python]
2525
- repo: https://github.com/asottile/pyupgrade
26-
rev: v3.15.0
26+
rev: v3.15.2
2727
hooks:
2828
- id: pyupgrade
2929
exclude: tests/testdata
@@ -34,7 +34,7 @@ repos:
3434
- id: black-disable-checker
3535
exclude: tests/test_nodes_lineno.py
3636
- repo: https://github.com/psf/black
37-
rev: 24.2.0
37+
rev: 24.3.0
3838
hooks:
3939
- id: black
4040
args: [--safe, --quiet]
@@ -54,7 +54,7 @@ repos:
5454
]
5555
exclude: tests/testdata|conf.py
5656
- repo: https://github.com/pre-commit/mirrors-mypy
57-
rev: v1.8.0
57+
rev: v1.9.0
5858
hooks:
5959
- id: mypy
6060
name: mypy

ChangeLog

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,23 @@ What's New in astroid 3.2.0?
77
============================
88
Release date: TBA
99

10+
1011
* ``.pyi`` stub files are now preferred over ``.py`` files when resolving imports.
1112

1213
Closes pylint-dev/#9185
1314

15+
* ``igetattr()`` returns the last same-named function in a class (instead of
16+
the first). This avoids false positives in pylint with ``@overload``.
17+
18+
Closes #1015
19+
Refs pylint-dev/pylint#4696
20+
21+
* Adds ``module_denylist`` to ``AstroidManager`` for modules to be skipped during AST
22+
generation. Modules in this list will cause an ``AstroidImportError`` to be raised
23+
when an AST for them is requested.
24+
25+
Refs pylint-dev/pylint#9442
26+
1427

1528
What's New in astroid 3.1.1?
1629
============================

astroid/manager.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class AstroidManager:
5959
"optimize_ast": False,
6060
"max_inferable_values": 100,
6161
"extension_package_whitelist": set(),
62+
"module_denylist": set(),
6263
"_transform": TransformVisitor(),
6364
}
6465

@@ -70,6 +71,7 @@ def __init__(self) -> None:
7071
self.extension_package_whitelist = AstroidManager.brain[
7172
"extension_package_whitelist"
7273
]
74+
self.module_denylist = AstroidManager.brain["module_denylist"]
7375
self._transform = AstroidManager.brain["_transform"]
7476

7577
@property
@@ -200,6 +202,8 @@ def ast_from_module_name( # noqa: C901
200202
# importing a module with the same name as the file that is importing
201203
# we want to fallback on the import system to make sure we get the correct
202204
# module.
205+
if modname in self.module_denylist:
206+
raise AstroidImportError(f"Skipping ignored module {modname!r}")
203207
if modname in self.astroid_cache and use_cache:
204208
return self.astroid_cache[modname]
205209
if modname == "__main__":
@@ -305,7 +309,6 @@ def file_from_module_name(
305309
modname.split("."), context_file=contextfile
306310
)
307311
except ImportError as e:
308-
# pylint: disable-next=redefined-variable-type
309312
value = AstroidImportError(
310313
"Failed to import module {modname} with error:\n{error}.",
311314
modname=modname,
@@ -402,8 +405,7 @@ def infer_ast_from_something(
402405
# take care, on living object __module__ is regularly wrong :(
403406
modastroid = self.ast_from_module_name(modname)
404407
if klass is obj:
405-
for inferred in modastroid.igetattr(name, context):
406-
yield inferred
408+
yield from modastroid.igetattr(name, context)
407409
else:
408410
for inferred in modastroid.igetattr(name, context):
409411
yield inferred.instantiate_class()

astroid/nodes/scoped_nodes/scoped_nodes.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2508,12 +2508,21 @@ def igetattr(
25082508
# to the attribute happening *after* the attribute's definition (e.g. AugAssigns on lists)
25092509
if len(attributes) > 1:
25102510
first_attr, attributes = attributes[0], attributes[1:]
2511-
first_scope = first_attr.scope()
2511+
first_scope = first_attr.parent.scope()
25122512
attributes = [first_attr] + [
25132513
attr
25142514
for attr in attributes
25152515
if attr.parent and attr.parent.scope() == first_scope
25162516
]
2517+
functions = [attr for attr in attributes if isinstance(attr, FunctionDef)]
2518+
if functions:
2519+
# Prefer only the last function, unless a property is involved.
2520+
last_function = functions[-1]
2521+
attributes = [
2522+
a
2523+
for a in attributes
2524+
if a not in functions or a is last_function or bases._is_property(a)
2525+
]
25172526

25182527
for inferred in bases._infer_stmts(attributes, context, frame=self):
25192528
# yield Uninferable object instead of descriptors when necessary

astroid/test_utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,5 @@ def brainless_manager():
7474
m._mod_file_cache = {}
7575
m._transform = transforms.TransformVisitor()
7676
m.extension_package_whitelist = set()
77+
m.module_denylist = set()
7778
return m

tests/test_inference.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
)
3131
from astroid import decorators as decoratorsmod
3232
from astroid.arguments import CallSite
33-
from astroid.bases import BoundMethod, Instance, UnboundMethod, UnionType
33+
from astroid.bases import BoundMethod, Generator, Instance, UnboundMethod, UnionType
3434
from astroid.builder import AstroidBuilder, _extract_single_node, extract_node, parse
3535
from astroid.const import IS_PYPY, PY39_PLUS, PY310_PLUS, PY312_PLUS
3636
from astroid.context import CallContext, InferenceContext
@@ -4321,6 +4321,53 @@ class Test(Outer.Inner):
43214321
assert isinstance(inferred, nodes.Const)
43224322
assert inferred.value == 123
43234323

4324+
def test_infer_method_empty_body(self) -> None:
4325+
# https://github.com/PyCQA/astroid/issues/1015
4326+
node = extract_node(
4327+
"""
4328+
class A:
4329+
def foo(self): ...
4330+
4331+
A().foo() #@
4332+
"""
4333+
)
4334+
inferred = next(node.infer())
4335+
assert isinstance(inferred, nodes.Const)
4336+
assert inferred.value is None
4337+
4338+
def test_infer_method_overload(self) -> None:
4339+
# https://github.com/PyCQA/astroid/issues/1015
4340+
node = extract_node(
4341+
"""
4342+
class A:
4343+
def foo(self): ...
4344+
4345+
def foo(self):
4346+
yield
4347+
4348+
A().foo() #@
4349+
"""
4350+
)
4351+
inferred = list(node.infer())
4352+
assert len(inferred) == 1
4353+
assert isinstance(inferred[0], Generator)
4354+
4355+
def test_infer_function_under_if(self) -> None:
4356+
node = extract_node(
4357+
"""
4358+
if 1 in [1]:
4359+
def func():
4360+
return 42
4361+
else:
4362+
def func():
4363+
return False
4364+
4365+
func() #@
4366+
"""
4367+
)
4368+
inferred = list(node.inferred())
4369+
assert [const.value for const in inferred] == [42, False]
4370+
43244371
def test_delayed_attributes_without_slots(self) -> None:
43254372
ast_node = extract_node(
43264373
"""

0 commit comments

Comments
 (0)