Run autopep8 on code

This commit is contained in:
Krzysztof Rudnicki 2023-03-22 09:32:16 +00:00
parent 7435a26030
commit 6c55a51756
865 changed files with 62182 additions and 108 deletions

195
main.py
View File

@ -21,30 +21,33 @@ Does not work if no Start (Should print out NO START FOUND)
Does not work if no End (Should print out NO END FOUND)
Does not work if no path (Should print out NO PATH FOUND)
"""
import heapq
class MazeSolver:
# self corresponds to "this" in js, it refers to object of MazeSolver class
def __init__(self, maze):
# assign readed maze 2D array to parameter from class MazeSolver
self.maze = maze
self.start, self.end = self.find_start_and_end()
# self corresponds to "this" in js, it refers to object of MazeSolver class
def __init__(self, maze):
# assign readed maze 2D array to parameter from class MazeSolver
self.maze = maze
self.start, self.end = self.find_start_and_end()
# go through each character in 2D array and find one that corresponds to Start/End character
# go through each character in 2D array and find one that corresponds to
# Start/End character
def find_start_and_end(self):
start = end = None
for row in range(len(self.maze)):
for col in range(len(self.maze[row])):
if self.maze[row][col] == 'S':
start = (row, col)
elif self.maze[row][col] == 'E':
end = (row, col)
if start != None and end != None:
return start, end
print(f"DID NOT FOUND START OR END, Start: {start}, End: {end}")
def find_start_and_end(self):
start = end = None
for row in range(len(self.maze)):
for col in range(len(self.maze[row])):
if self.maze[row][col] == 'S':
start = (row, col)
elif self.maze[row][col] == 'E':
end = (row, col)
if start is not None and end is not None:
return start, end
print(f"DID NOT FOUND START OR END, Start: {start}, End: {end}")
# Go through each neighboor
# N
@ -52,94 +55,102 @@ class MazeSolver:
# N
# If it is not a "wall" (#) add its position to list of neighbors
def get_neighbors(self, position):
row, col = position
neighbors = []
if row > 0 and self.maze[row - 1][col] != '#':
neighbors.append((row - 1, col))
if col > 0 and self.maze[row][col - 1] != '#':
neighbors.append((row, col - 1))
if row < len(self.maze) - 1 and self.maze[row + 1][col] != '#':
neighbors.append((row + 1, col))
if col < len(self.maze[row]) - 1 and self.maze[row][col + 1] != '#':
neighbors.append((row, col + 1))
return neighbors
def get_neighbors(self, position):
row, col = position
neighbors = []
if row > 0 and self.maze[row - 1][col] != '#':
neighbors.append((row - 1, col))
if col > 0 and self.maze[row][col - 1] != '#':
neighbors.append((row, col - 1))
if row < len(self.maze) - 1 and self.maze[row + 1][col] != '#':
neighbors.append((row + 1, col))
if col < len(self.maze[row]) - 1 and self.maze[row][col + 1] != '#':
neighbors.append((row, col + 1))
return neighbors
# find path through maze
def solve(self):
queue = []
# set means that values inside can not repeat
visited = set()
# https://docs.python.org/3/library/heapq.html
# push onto the queue (which becomes heapq), element containinig values
# we use heapq so the element with lowest heurisitc value will always be at the top of heap
heapq.heappush(
queue, (self.heuristicEuclidean(self.start), self.start, [self.start]))
def solve(self):
queue = []
# set means that values inside can not repeat
visited = set()
# https://docs.python.org/3/library/heapq.html
# push onto the queue (which becomes heapq), element containinig values
# we use heapq so the element with lowest heurisitc value will always
# be at the top of heap
heapq.heappush(
queue, (self.heuristicEuclidean(
self.start), self.start, [
self.start]))
# go through queue until it's empty
# find neighbour (which is not wall) closests to END point (based on heuristic)
# go there and repeat
# if cannot find path it starts over but skips the path that lead it to dead end
while queue:
# pop first element of heap
# first value is skipped and we only save current position and path on heap
_, current, path = heapq.heappop(queue)
# if we already visited current skip code and go to next iteration
if current in visited:
continue
# go through queue until it's empty
# find neighbour (which is not wall) closests to END point (based on heuristic)
# go there and repeat
# if cannot find path it starts over but skips the path that lead it to
# dead end
while queue:
# pop first element of heap
# first value is skipped and we only save current position and path
# on heap
_, current, path = heapq.heappop(queue)
# if we already visited current skip code and go to next iteration
if current in visited:
continue
# if we found the end return path
if current == self.end:
return path
visited.add(current)
for neighbor in self.get_neighbors(current):
if neighbor not in visited:
new_path = path + [neighbor]
heapq.heappush(queue,
(self.heuristicEuclidean(neighbor), neighbor, new_path))
print_maze(self.maze, new_path)
print()
if current == self.end:
return path
visited.add(current)
for neighbor in self.get_neighbors(current):
if neighbor not in visited:
new_path = path + [neighbor]
heapq.heappush(
queue, (self.heuristicEuclidean(neighbor), neighbor, new_path))
print_maze(self.maze, new_path)
print()
# This heuristic returns the Manhatan distance between the given position and the maze's end
def heuristicManhatan(self, position):
return abs(position[0] - self.end[0]) + abs(position[1] - self.end[1])
# This heuristic returns the Manhatan distance between the given position
# and the maze's end
def heuristicManhatan(self, position):
return abs(position[0] - self.end[0]) + abs(position[1] - self.end[1])
# This heuristic returns the Euclidean distance between the given position and the maze's end
def heuristicEuclidean(self, position):
return (abs(position[0] - self.end[0])**2 +
abs(position[1] - self.end[1])**2)**0.5
# This heuristic returns the Euclidean distance between the given position
# and the maze's end
def heuristicEuclidean(self, position):
return (abs(position[0] - self.end[0])**2 +
abs(position[1] - self.end[1])**2)**0.5
# Open and load text file to array
def load_maze(filename):
# Open for reading only and save to fileContents
fileContents = open(filename, 'r')
# strip() removes extra white spaces from the beginning and the end of a string
# list() changes string to array of chars
# Inside of square brackets we will have an array of characters for each line of file
# after going through every line in a file we will have 2D array of arrays of characters of every line
maze = [list(line.strip()) for line in fileContents]
return maze
# Open for reading only and save to fileContents
fileContents = open(filename, 'r')
# strip() removes extra white spaces from the beginning and the end of a string
# list() changes string to array of chars
# Inside of square brackets we will have an array of characters for each line of file
# after going through every line in a file we will have 2D array of arrays
# of characters of every line
maze = [list(line.strip()) for line in fileContents]
return maze
def print_maze(maze, path=None):
if path is None:
path = []
for row in range(len(maze)):
for col in range(len(maze[row])):
if (row, col) in path:
print('*', end='')
else:
print(maze[row][col], end='')
print()
if path is None:
path = []
for row in range(len(maze)):
for col in range(len(maze[row])):
if (row, col) in path:
print('*', end='')
else:
print(maze[row][col], end='')
print()
# Ran first in the code
if __name__ == '__main__':
# Open and load text file to array
maze = load_maze('mazes/mazeDeadEnd.txt')
# Initialize MazeSolver object with maze as paramater
solver = MazeSolver(maze)
# Find path using MazeSolver solve method
path = solver.solve()
print_maze(maze, path)
# Open and load text file to array
maze = load_maze('mazes/mazeDeadEnd.txt')
# Initialize MazeSolver object with maze as paramater
solver = MazeSolver(maze)
# Find path using MazeSolver solve method
path = solver.solve()
print_maze(maze, path)

8
venv/bin/autopep8 Executable file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import re
import sys
from autopep8 import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
venv/bin/epylint Executable file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import re
import sys
from pylint import run_epylint
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(run_epylint())

1
venv/bin/get_objgraph Symbolic link
View File

@ -0,0 +1 @@
/home/runner/.cache/pip/pool/6a/50/3f/1f2a45ac215d6ff2ad0866b0c04c341528fa5265298b72142c813ce4da

8
venv/bin/isort Executable file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import re
import sys
from isort.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View File

@ -0,0 +1,8 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import re
import sys
from isort.main import identify_imports_main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(identify_imports_main())

8
venv/bin/pycodestyle Executable file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import re
import sys
from pycodestyle import _main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(_main())

8
venv/bin/pylint Executable file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import re
import sys
from pylint import run_pylint
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(run_pylint())

8
venv/bin/pylint-config Executable file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import re
import sys
from pylint import _run_pylint_config
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(_run_pylint_config())

8
venv/bin/pyreverse Executable file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import re
import sys
from pylint import run_pyreverse
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(run_pyreverse())

8
venv/bin/symilar Executable file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import re
import sys
from pylint import run_symilar
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(run_symilar())

1
venv/bin/undill Symbolic link
View File

@ -0,0 +1 @@
/home/runner/.cache/pip/pool/e2/49/4a/6f73df3fa16a5661da7e3c9b169500e2697bc26be21656ce72fcca59af

View File

@ -0,0 +1,199 @@
# This file is autocompleted by 'contributors-txt',
# using the configuration in 'script/.contributors_aliases.json'.
# Do not add new persons manually and only add information without
# using '-' as the line first character.
# Please verify that your change are stable if you modify manually.
Ex-maintainers
--------------
- Claudiu Popa <pcmanticore@gmail.com>
- Sylvain Thénault <thenault@gmail.com>
- Torsten Marek <shlomme@gmail.com>
Maintainers
-----------
- Pierre Sassoulas <pierre.sassoulas@gmail.com>
- Daniël van Noord <13665637+DanielNoord@users.noreply.github.com>
- Hippo91 <guillaume.peillex@gmail.com>
- Marc Mueller <30130371+cdce8p@users.noreply.github.com>
- Jacob Walls <jacobtylerwalls@gmail.com>
- Bryce Guinta <bryce.paul.guinta@gmail.com>
- Ceridwen <ceridwenv@gmail.com>
- Mark Byrne <31762852+mbyrnepr2@users.noreply.github.com>
- Łukasz Rogalski <rogalski.91@gmail.com>
- Florian Bruhin <me@the-compiler.org>
- Ashley Whetter <ashley@awhetter.co.uk>
- Dimitri Prybysh <dmand@yandex.ru>
- Areveny <areveny@protonmail.com>
Contributors
------------
- Emile Anclin <emile.anclin@logilab.fr>
- Nick Drozd <nicholasdrozd@gmail.com>
- Andrew Haigh <hello@nelf.in>
- Julien Cristau <julien.cristau@logilab.fr>
- David Liu <david@cs.toronto.edu>
- Alexandre Fayolle <alexandre.fayolle@logilab.fr>
- Eevee (Alex Munroe) <amunroe@yelp.com>
- David Gilman <davidgilman1@gmail.com>
- Julien Jehannet <julien.jehannet@logilab.fr>
- Calen Pennington <calen.pennington@gmail.com>
- Tushar Sadhwani <86737547+tushar-deepsource@users.noreply.github.com>
- Hugo van Kemenade <hugovk@users.noreply.github.com>
- Tim Martin <tim@asymptotic.co.uk>
- Phil Schaf <flying-sheep@web.de>
- Alex Hall <alex.mojaki@gmail.com>
- Raphael Gaschignard <raphael@makeleaps.com>
- Radosław Ganczarek <radoslaw@ganczarek.in>
- Paligot Gérard <androwiiid@gmail.com>
- Ioana Tagirta <ioana.tagirta@gmail.com>
- Derek Gustafson <degustaf@gmail.com>
- David Shea <dshea@redhat.com>
- Daniel Harding <dharding@gmail.com>
- Christian Clauss <cclauss@me.com>
- Ville Skyttä <ville.skytta@iki.fi>
- Rene Zhang <rz99@cornell.edu>
- Philip Lorenz <philip@bithub.de>
- Nicolas Chauvat <nicolas.chauvat@logilab.fr>
- Michael K <michael-k@users.noreply.github.com>
- Mario Corchero <mariocj89@gmail.com>
- Marien Zwart <marienz@gentoo.org>
- Laura Médioni <laura.medioni@logilab.fr>
- James Addison <55152140+jayaddison@users.noreply.github.com>
- FELD Boris <lothiraldan@gmail.com>
- Enji Cooper <yaneurabeya@gmail.com>
- Dani Alcala <112832187+clavedeluna@users.noreply.github.com>
- Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
- tristanlatr <19967168+tristanlatr@users.noreply.github.com>
- emile@crater.logilab.fr <emile@crater.logilab.fr>
- doranid <ddandd@gmail.com>
- brendanator <brendan.maginnis@gmail.com>
- Tomas Gavenciak <gavento@ucw.cz>
- Tim Paine <t.paine154@gmail.com>
- Thomas Hisch <t.hisch@gmail.com>
- Stefan Scherfke <stefan@sofa-rockers.org>
- Sergei Lebedev <185856+superbobry@users.noreply.github.com>
- Saugat Pachhai (सौगात) <suagatchhetri@outlook.com>
- Ram Rachum <ram@rachum.com>
- Pierre-Yves David <pierre-yves.david@logilab.fr>
- Peter Pentchev <roam@ringlet.net>
- Peter Kolbus <peter.kolbus@gmail.com>
- Omer Katz <omer.drow@gmail.com>
- Moises Lopez <moylop260@vauxoo.com>
- Michal Vasilek <michal@vasilek.cz>
- Keichi Takahashi <keichi.t@me.com>
- Kavins Singh <kavinsingh@hotmail.com>
- Karthikeyan Singaravelan <tir.karthi@gmail.com>
- Joshua Cannon <joshdcannon@gmail.com>
- John Vandenberg <jayvdb@gmail.com>
- Jacob Bogdanov <jacob@bogdanov.dev>
- Google, Inc. <no-reply@google.com>
- David Euresti <github@euresti.com>
- David Douard <david.douard@logilab.fr>
- David Cain <davidjosephcain@gmail.com>
- Anthony Truchet <anthony.truchet@logilab.fr>
- Anthony Sottile <asottile@umich.edu>
- Alexander Shadchin <alexandr.shadchin@gmail.com>
- wgehalo <wgehalo@gmail.com>
- rr- <rr-@sakuya.pl>
- raylu <lurayl@gmail.com>
- plucury <plucury@gmail.com>
- ostr00000 <ostr00000@gmail.com>
- noah-weingarden <33741795+noah-weingarden@users.noreply.github.com>
- nathannaveen <42319948+nathannaveen@users.noreply.github.com>
- mathieui <mathieui@users.noreply.github.com>
- markmcclain <markmcclain@users.noreply.github.com>
- ioanatia <ioanatia@users.noreply.github.com>
- grayjk <grayjk@gmail.com>
- adam-grant-hendry <59346180+adam-grant-hendry@users.noreply.github.com>
- Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
- Zac Hatfield-Dodds <Zac-HD@users.noreply.github.com>
- Vilnis Termanis <vilnis.termanis@iotics.com>
- Valentin Valls <valentin.valls@esrf.fr>
- Uilian Ries <uilianries@gmail.com>
- Tomas Novak <ext.Tomas.Novak@skoda-auto.cz>
- Thirumal Venkat <me@thirumal.in>
- SupImDos <62866982+SupImDos@users.noreply.github.com>
- Stanislav Levin <slev@altlinux.org>
- Simon Hewitt <si@sjhewitt.co.uk>
- Serhiy Storchaka <storchaka@gmail.com>
- Roy Wright <roy@wright.org>
- Robin Jarry <robin.jarry@6wind.com>
- René Fritze <47802+renefritze@users.noreply.github.com>
- Redoubts <Redoubts@users.noreply.github.com>
- Philipp Hörist <philipp@hoerist.com>
- Peter de Blanc <peter@standard.ai>
- Peter Talley <peterctalley@gmail.com>
- Ovidiu Sabou <ovidiu@sabou.org>
- Nicolas Noirbent <nicolas@noirbent.fr>
- Neil Girdhar <mistersheik@gmail.com>
- Michał Masłowski <m.maslowski@clearcode.cc>
- Mateusz Bysiek <mb@mbdev.pl>
- Leandro T. C. Melo <ltcmelo@gmail.com>
- Konrad Weihmann <kweihmann@outlook.com>
- Kian Meng, Ang <kianmeng.ang@gmail.com>
- Kai Mueller <15907922+kasium@users.noreply.github.com>
- Jörg Thalheim <Mic92@users.noreply.github.com>
- Jonathan Striebel <jstriebel@users.noreply.github.com>
- John Belmonte <john@neggie.net>
- Jeff Widman <jeff@jeffwidman.com>
- Jeff Quast <contact@jeffquast.com>
- Jarrad Hope <me@jarradhope.com>
- Jared Garst <jgarst@users.noreply.github.com>
- Jakub Wilk <jwilk@jwilk.net>
- Iva Miholic <ivamiho@gmail.com>
- Ionel Maries Cristian <contact@ionelmc.ro>
- HoverHell <hoverhell@gmail.com>
- HQupgradeHQ <18361586+HQupgradeHQ@users.noreply.github.com>
- Grygorii Iermolenko <gyermolenko@gmail.com>
- Gregory P. Smith <greg@krypto.org>
- Giuseppe Scrivano <gscrivan@redhat.com>
- Frédéric Chapoton <fchapoton2@gmail.com>
- Francis Charette Migneault <francis.charette.migneault@gmail.com>
- Felix Mölder <felix.moelder@uni-due.de>
- Federico Bond <federicobond@gmail.com>
- DudeNr33 <3929834+DudeNr33@users.noreply.github.com>
- Dmitry Shachnev <mitya57@users.noreply.github.com>
- Denis Laxalde <denis.laxalde@logilab.fr>
- Deepyaman Datta <deepyaman.datta@utexas.edu>
- David Poirier <david-poirier-csn@users.noreply.github.com>
- Dave Hirschfeld <dave.hirschfeld@gmail.com>
- Dave Baum <dbaum@google.com>
- Daniel Martin <daniel.martin@crowdstrike.com>
- Daniel Colascione <dancol@dancol.org>
- Damien Baty <damien@damienbaty.com>
- Craig Franklin <craigjfranklin@gmail.com>
- Colin Kennedy <colinvfx@gmail.com>
- Cole Robinson <crobinso@redhat.com>
- Christoph Reiter <reiter.christoph@gmail.com>
- Chris Philip <chrisp533@gmail.com>
- BioGeek <jeroen.vangoey@gmail.com>
- Bianca Power <30207144+biancapower@users.noreply.github.com>
- Benjamin Elven <25181435+S3ntinelX@users.noreply.github.com>
- Ben Elliston <bje@air.net.au>
- Becker Awqatty <bawqatty@mide.com>
- Batuhan Taskaya <isidentical@gmail.com>
- BasPH <BasPH@users.noreply.github.com>
- Azeem Bande-Ali <A.BandeAli@gmail.com>
- Avram Lubkin <aviso@rockhopper.net>
- Aru Sahni <arusahni@gmail.com>
- Artsiom Kaval <lezeroq@gmail.com>
- Anubhav <35621759+anubh-v@users.noreply.github.com>
- Antoine Boellinger <aboellinger@hotmail.com>
- Alphadelta14 <alpha@alphaservcomputing.solutions>
- Alexander Scheel <alexander.m.scheel@gmail.com>
- Alexander Presnyakov <flagist0@gmail.com>
- Ahmed Azzaoui <ahmed.azzaoui@engie.com>
Co-Author
---------
The following persons were credited manually but did not commit themselves
under this name, or we did not manage to find their commits in the history.
- François Mockers
- platings
- carl
- alain lefroy
- Mark Gius

View File

@ -0,0 +1 @@
/home/runner/.cache/pip/pool/fe/a1/6b/da9e734dea0d9c8d9f5b909878ef4171626354329609fffcf3db42cb24

View File

@ -0,0 +1,128 @@
Metadata-Version: 2.1
Name: astroid
Version: 2.15.0
Summary: An abstract syntax tree for Python with inference support.
Author-email: Python Code Quality Authority <code-quality@python.org>
License: LGPL-2.1-or-later
Project-URL: Docs, https://pylint.readthedocs.io/projects/astroid/en/latest/
Project-URL: Source Code, https://github.com/PyCQA/astroid
Project-URL: Bug tracker, https://github.com/PyCQA/astroid/issues
Project-URL: Discord server, https://discord.gg/Egy6P8AMB5
Keywords: static code analysis,python,abstract syntax tree
Classifier: Development Status :: 6 - Mature
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU Lesser General Public License v2 (LGPLv2)
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Software Development :: Testing
Requires-Python: >=3.7.2
Description-Content-Type: text/x-rst
License-File: LICENSE
License-File: CONTRIBUTORS.txt
Requires-Dist: lazy-object-proxy (>=1.4.0)
Requires-Dist: typed-ast (<2.0,>=1.4.0) ; implementation_name == "cpython" and python_version < "3.8"
Requires-Dist: wrapt (<2,>=1.11) ; python_version < "3.11"
Requires-Dist: typing-extensions (>=4.0.0) ; python_version < "3.11"
Requires-Dist: wrapt (<2,>=1.14) ; python_version >= "3.11"
Astroid
=======
.. image:: https://codecov.io/gh/PyCQA/astroid/branch/main/graph/badge.svg?token=Buxy4WptLb
:target: https://codecov.io/gh/PyCQA/astroid
:alt: Coverage badge from codecov
.. image:: https://readthedocs.org/projects/astroid/badge/?version=latest
:target: http://astroid.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/ambv/black
.. image:: https://results.pre-commit.ci/badge/github/PyCQA/astroid/main.svg
:target: https://results.pre-commit.ci/latest/github/PyCQA/astroid/main
:alt: pre-commit.ci status
.. |tidelift_logo| image:: https://raw.githubusercontent.com/PyCQA/astroid/main/doc/media/Tidelift_Logos_RGB_Tidelift_Shorthand_On-White.png
:width: 200
:alt: Tidelift
.. list-table::
:widths: 10 100
* - |tidelift_logo|
- Professional support for astroid is available as part of the
`Tidelift Subscription`_. Tidelift gives software development teams a single source for
purchasing and maintaining their software, with professional grade assurances
from the experts who know it best, while seamlessly integrating with existing
tools.
.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-astroid?utm_source=pypi-astroid&utm_medium=referral&utm_campaign=readme
What's this?
------------
The aim of this module is to provide a common base representation of
python source code. It is currently the library powering pylint's capabilities.
It provides a compatible representation which comes from the `_ast`
module. It rebuilds the tree generated by the builtin _ast module by
recursively walking down the AST and building an extended ast. The new
node classes have additional methods and attributes for different
usages. They include some support for static inference and local name
scopes. Furthermore, astroid can also build partial trees by inspecting living
objects.
Installation
------------
Extract the tarball, jump into the created directory and run::
pip install .
If you want to do an editable installation, you can run::
pip install -e .
If you have any questions, please mail the code-quality@python.org
mailing list for support. See
http://mail.python.org/mailman/listinfo/code-quality for subscription
information and archives.
Documentation
-------------
http://astroid.readthedocs.io/en/latest/
Python Versions
---------------
astroid 2.0 is currently available for Python 3 only. If you want Python 2
support, use an older version of astroid (though note that these versions
are no longer supported).
Test
----
Tests are in the 'test' subdirectory. To launch the whole tests suite, you can use
either `tox` or `pytest`::
tox
pytest

View File

@ -0,0 +1,209 @@
astroid-2.15.0.dist-info/CONTRIBUTORS.txt,sha256=_R56rA3okHgrKxY42SDN2zOaFZV49Oks0iFtQ_tIIBs,8038
astroid-2.15.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
astroid-2.15.0.dist-info/LICENSE,sha256=_qFr2p5zTeoNnI2fW5CYeO9BcWJjVDKWCf_889tCyyQ,26516
astroid-2.15.0.dist-info/METADATA,sha256=rju1DTgF4pzdcf_H6Kb8EQeonNs7FtpDgLyaecs6tmg,4786
astroid-2.15.0.dist-info/RECORD,,
astroid-2.15.0.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
astroid-2.15.0.dist-info/top_level.txt,sha256=HsdW4O2x7ZXRj6k-agi3RaQybGLobI3VSE-jt4vQUXM,8
astroid/__init__.py,sha256=HKHncgrj70qSs9Gg4aDpFyiAQFHhrSoR1O20OQ3K0Bo,5091
astroid/__pkginfo__.py,sha256=yDKgWZv5-RlTCQCeK9XRzNWKAN03w8wVDGG2JiXtjZM,274
astroid/__pycache__/__init__.cpython-310.pyc,,
astroid/__pycache__/__pkginfo__.cpython-310.pyc,,
astroid/__pycache__/_ast.cpython-310.pyc,,
astroid/__pycache__/_backport_stdlib_names.cpython-310.pyc,,
astroid/__pycache__/_cache.cpython-310.pyc,,
astroid/__pycache__/arguments.cpython-310.pyc,,
astroid/__pycache__/astroid_manager.cpython-310.pyc,,
astroid/__pycache__/bases.cpython-310.pyc,,
astroid/__pycache__/builder.cpython-310.pyc,,
astroid/__pycache__/const.cpython-310.pyc,,
astroid/__pycache__/constraint.cpython-310.pyc,,
astroid/__pycache__/context.cpython-310.pyc,,
astroid/__pycache__/decorators.cpython-310.pyc,,
astroid/__pycache__/exceptions.cpython-310.pyc,,
astroid/__pycache__/filter_statements.cpython-310.pyc,,
astroid/__pycache__/helpers.cpython-310.pyc,,
astroid/__pycache__/inference.cpython-310.pyc,,
astroid/__pycache__/inference_tip.cpython-310.pyc,,
astroid/__pycache__/manager.cpython-310.pyc,,
astroid/__pycache__/mixins.cpython-310.pyc,,
astroid/__pycache__/modutils.cpython-310.pyc,,
astroid/__pycache__/node_classes.cpython-310.pyc,,
astroid/__pycache__/objects.cpython-310.pyc,,
astroid/__pycache__/protocols.cpython-310.pyc,,
astroid/__pycache__/raw_building.cpython-310.pyc,,
astroid/__pycache__/rebuilder.cpython-310.pyc,,
astroid/__pycache__/scoped_nodes.cpython-310.pyc,,
astroid/__pycache__/test_utils.cpython-310.pyc,,
astroid/__pycache__/transforms.cpython-310.pyc,,
astroid/__pycache__/typing.cpython-310.pyc,,
astroid/__pycache__/util.cpython-310.pyc,,
astroid/_ast.py,sha256=fx6vCj7YJJRQSf3GQYRllJ9hRKPh9-QczU3crjt3IrA,4146
astroid/_backport_stdlib_names.py,sha256=pmMEGwionQpfJdJaJomDF6Qc6peNMxChcOsNa8U2IDo,7016
astroid/_cache.py,sha256=ZuO1Kl9HXaxoJ_hJXbzWqkMGmQR7CGf-R4cPen9odzM,786
astroid/arguments.py,sha256=9GeVion6IpISnxQGyXU6uHxfJ_kuDXOCYm3Jv6SJNUg,12958
astroid/astroid_manager.py,sha256=02l_ltGWEglvkoL_qMGmYxuHpDA5-ySPf0r1cGwIQqU,572
astroid/bases.py,sha256=9GT3_gPrLdlS3zmvW3Nmv2X2pQcY5_vywz1MVky4ero,25594
astroid/brain/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
astroid/brain/__pycache__/__init__.cpython-310.pyc,,
astroid/brain/__pycache__/brain_argparse.cpython-310.pyc,,
astroid/brain/__pycache__/brain_attrs.cpython-310.pyc,,
astroid/brain/__pycache__/brain_boto3.cpython-310.pyc,,
astroid/brain/__pycache__/brain_builtin_inference.cpython-310.pyc,,
astroid/brain/__pycache__/brain_collections.cpython-310.pyc,,
astroid/brain/__pycache__/brain_crypt.cpython-310.pyc,,
astroid/brain/__pycache__/brain_ctypes.cpython-310.pyc,,
astroid/brain/__pycache__/brain_curses.cpython-310.pyc,,
astroid/brain/__pycache__/brain_dataclasses.cpython-310.pyc,,
astroid/brain/__pycache__/brain_dateutil.cpython-310.pyc,,
astroid/brain/__pycache__/brain_fstrings.cpython-310.pyc,,
astroid/brain/__pycache__/brain_functools.cpython-310.pyc,,
astroid/brain/__pycache__/brain_gi.cpython-310.pyc,,
astroid/brain/__pycache__/brain_hashlib.cpython-310.pyc,,
astroid/brain/__pycache__/brain_http.cpython-310.pyc,,
astroid/brain/__pycache__/brain_hypothesis.cpython-310.pyc,,
astroid/brain/__pycache__/brain_io.cpython-310.pyc,,
astroid/brain/__pycache__/brain_mechanize.cpython-310.pyc,,
astroid/brain/__pycache__/brain_multiprocessing.cpython-310.pyc,,
astroid/brain/__pycache__/brain_namedtuple_enum.cpython-310.pyc,,
astroid/brain/__pycache__/brain_nose.cpython-310.pyc,,
astroid/brain/__pycache__/brain_numpy_core_einsumfunc.cpython-310.pyc,,
astroid/brain/__pycache__/brain_numpy_core_fromnumeric.cpython-310.pyc,,
astroid/brain/__pycache__/brain_numpy_core_function_base.cpython-310.pyc,,
astroid/brain/__pycache__/brain_numpy_core_multiarray.cpython-310.pyc,,
astroid/brain/__pycache__/brain_numpy_core_numeric.cpython-310.pyc,,
astroid/brain/__pycache__/brain_numpy_core_numerictypes.cpython-310.pyc,,
astroid/brain/__pycache__/brain_numpy_core_umath.cpython-310.pyc,,
astroid/brain/__pycache__/brain_numpy_ma.cpython-310.pyc,,
astroid/brain/__pycache__/brain_numpy_ndarray.cpython-310.pyc,,
astroid/brain/__pycache__/brain_numpy_random_mtrand.cpython-310.pyc,,
astroid/brain/__pycache__/brain_numpy_utils.cpython-310.pyc,,
astroid/brain/__pycache__/brain_pathlib.cpython-310.pyc,,
astroid/brain/__pycache__/brain_pkg_resources.cpython-310.pyc,,
astroid/brain/__pycache__/brain_pytest.cpython-310.pyc,,
astroid/brain/__pycache__/brain_qt.cpython-310.pyc,,
astroid/brain/__pycache__/brain_random.cpython-310.pyc,,
astroid/brain/__pycache__/brain_re.cpython-310.pyc,,
astroid/brain/__pycache__/brain_regex.cpython-310.pyc,,
astroid/brain/__pycache__/brain_responses.cpython-310.pyc,,
astroid/brain/__pycache__/brain_scipy_signal.cpython-310.pyc,,
astroid/brain/__pycache__/brain_signal.cpython-310.pyc,,
astroid/brain/__pycache__/brain_six.cpython-310.pyc,,
astroid/brain/__pycache__/brain_sqlalchemy.cpython-310.pyc,,
astroid/brain/__pycache__/brain_ssl.cpython-310.pyc,,
astroid/brain/__pycache__/brain_subprocess.cpython-310.pyc,,
astroid/brain/__pycache__/brain_threading.cpython-310.pyc,,
astroid/brain/__pycache__/brain_type.cpython-310.pyc,,
astroid/brain/__pycache__/brain_typing.cpython-310.pyc,,
astroid/brain/__pycache__/brain_unittest.cpython-310.pyc,,
astroid/brain/__pycache__/brain_uuid.cpython-310.pyc,,
astroid/brain/__pycache__/helpers.cpython-310.pyc,,
astroid/brain/brain_argparse.py,sha256=ozU4z8-HTSX6tl6g2ysoqFGn6b8jK4Bt_NlAKl_jYyQ,1557
astroid/brain/brain_attrs.py,sha256=PGFhUbL428Mc_cuyFgZIB2alt2ICfeaamWB-0C_kxAk,2857
astroid/brain/brain_boto3.py,sha256=gZOkDoY1YZk24EpOMVQVj0MBuNfBWn_XfDmmlH4jyHU,1012
astroid/brain/brain_builtin_inference.py,sha256=N-B5FxLAID8wztOTdiZEoc42qrQh5M8MrtSH4BaQwZs,34254
astroid/brain/brain_collections.py,sha256=__vh_SUp3ymY68i_UYW1OMlAjDN-Hiv_NHdDQs98HV4,4416
astroid/brain/brain_crypt.py,sha256=Zo66z94cQOL-HNOcAQSPNs_Ib_xNLLY9qEtxZ1VkbAM,863
astroid/brain/brain_ctypes.py,sha256=55flnAIj_Th_eqqG1HRMDR5ctt74ww1vDsSF42F26Es,2660
astroid/brain/brain_curses.py,sha256=XXyCeLASFFksO2zSbrZgB_AImGBlIGZ7Pgjdm04x-jg,3477
astroid/brain/brain_dataclasses.py,sha256=81fglaiPlsUkbImjLpSIpdVCdmmZa8vYUcCKQFo9YAI,22089
astroid/brain/brain_dateutil.py,sha256=1INt87VBa9Qt0DzEuI1r7cEtdyg5CvNDUIdVCv-j_mc,767
astroid/brain/brain_fstrings.py,sha256=VU14-7tVsJWlZt0r3UMB8lPS-Bb72dyYcDvd1PmTPJM,2471
astroid/brain/brain_functools.py,sha256=91kJd49eYZGh9fG45uBS4I6j635Q7VctZND-iqB2dRg,5986
astroid/brain/brain_gi.py,sha256=LYtvbe48qmyugTP31CcrqfM6X0ra_h6ntTBuKGCIrcM,7543
astroid/brain/brain_hashlib.py,sha256=WE7fQJCA3Rp1ZFDIseQjhrLEcsYhOfrka2PcvvuZ6Tg,2821
astroid/brain/brain_http.py,sha256=mYLcMdh_ka5d11IpdWg6WrG3R7R2wN4bKOLVG0W3vPk,10640
astroid/brain/brain_hypothesis.py,sha256=K4LfRb2KT6H5B7oGxAXQLcJFl9bkeKfFW8IEceGAbfw,1732
astroid/brain/brain_io.py,sha256=l499fbVi5HUbPWoyQn1xTHaPgRcf0hsKjjI90BdHzyQ,1526
astroid/brain/brain_mechanize.py,sha256=45syVjTGklYjS469vPsuHmyic09OTZtcJuM7FEXcMYI,2646
astroid/brain/brain_multiprocessing.py,sha256=htHZ3zSyv4eqh6c-AFRPt2GlyyPb4Jg8OQfAolojR8Q,3211
astroid/brain/brain_namedtuple_enum.py,sha256=j9GnadFsrVT6A-tz_w-HQcOBUHU4IiG09qKpJNSdA0s,22725
astroid/brain/brain_nose.py,sha256=DCUwKzR14Se5tF-s54AMwFoRvhsHH_nf6agrh966VpQ,2320
astroid/brain/brain_numpy_core_einsumfunc.py,sha256=CuZtZYZGDhPzV46l1xyNl_7RfMCaQ4bYyZgJ9f8KxcQ,825
astroid/brain/brain_numpy_core_fromnumeric.py,sha256=3UFRtK5U51AVQNxawf9ElhFv2tizhj5RfyCSnPT3u54,732
astroid/brain/brain_numpy_core_function_base.py,sha256=_k-WRQ_x0QEHhvr9IwuTLnpGoCYOVO0GAH7e3DyoHNQ,1298
astroid/brain/brain_numpy_core_multiarray.py,sha256=NIxnvno-mhp-P6IKfyRaKOFtiHx8H9cEchjgx69oht0,4238
astroid/brain/brain_numpy_core_numeric.py,sha256=VAc51Ud8QDujsh29e-RQK5SBcKW_jzjZIFmntCslCKU,1629
astroid/brain/brain_numpy_core_numerictypes.py,sha256=HVJ_paQwjh2V8qz0Juei6b2ZRm_dmDJodiDKfAcE-mE,8546
astroid/brain/brain_numpy_core_umath.py,sha256=2EhXmtiw8wQcdUtbnlLLTjHAOHpQ1c9BXHdc6kHJGbA,4893
astroid/brain/brain_numpy_ma.py,sha256=1XHvZH1C3CEXTiRH3BJxpFiztgqBYEGd9JDFquGsUMk,896
astroid/brain/brain_numpy_ndarray.py,sha256=HohawmatzpNMOJAhYbEPJGZdCTNmYO1Oz-IPxYDd5mM,8998
astroid/brain/brain_numpy_random_mtrand.py,sha256=Wrpm9SX8kH0Xsk9b3qpR0rhs-MEb0I5aN4E-66wkLkM,3436
astroid/brain/brain_numpy_utils.py,sha256=wgSRUgGdn8Io0AoTe6avll35oceRq2S6ZXqNviljvGI,2637
astroid/brain/brain_pathlib.py,sha256=Ec8Xuo-4IIG2wH4875c8c2Xe_I0fqPbPqoKCJOttVlE,1542
astroid/brain/brain_pkg_resources.py,sha256=W3Q4G6mYTYtJY9iWQv3vEO8_lpmLFAin9aQLtBRLxAc,2200
astroid/brain/brain_pytest.py,sha256=suTDBHCJ_p4F7TGXjwVJAFtiAP-VlkFE2gncXjLRQKM,2223
astroid/brain/brain_qt.py,sha256=qvexV4IFa4YKL0Nyo6qxmz_DfDDNwFVwBTJGADtVkiI,2808
astroid/brain/brain_random.py,sha256=grXJrYL3rZpzm8SmuEnWkLwWNqWKtd5YmwbBoV6mjN4,2890
astroid/brain/brain_re.py,sha256=aSU-HyEWsCrc1seiFohZw54ivcNtC-_AyiChJOSU-7Q,2870
astroid/brain/brain_regex.py,sha256=UzW2lF2ctbdD8BX4fkC7PFtXDdGNUcdBKZx7sJiO4Z0,3362
astroid/brain/brain_responses.py,sha256=Jn7jS8L26T5hnUwOcHX469FTkVs3_Yz8OiVRPAx3Bjo,1868
astroid/brain/brain_scipy_signal.py,sha256=Mi93D6-j94tqhqDHCbabVs3_eDAhti88CL1_rOvnG_I,2276
astroid/brain/brain_signal.py,sha256=18rOCgLVmM1rtc6BFYPx4qziSrfPt6CrP-A2fJyMWBY,3880
astroid/brain/brain_six.py,sha256=MWQm81s9Zb_i1NIqY3MnXuawlsXqgK1BDj1vBDZ-MdE,7625
astroid/brain/brain_sqlalchemy.py,sha256=onKAxgKY-GYLe2v6PVK3APBn_z8txokEZfDcXt33GuE,1009
astroid/brain/brain_ssl.py,sha256=8MdXhl9ZvYVe6U_gtSTtgnm_Dned2Ic9MbgfSj56RHU,6554
astroid/brain/brain_subprocess.py,sha256=Kayri4dMqwtXbZTOhB0E05p2ckKc7hIGPt1jA3zv2xA,2996
astroid/brain/brain_threading.py,sha256=rN-dQ_4Zo0AZOOiPQigxF3NEgmDC7DY-r0ujLN6W52c,870
astroid/brain/brain_type.py,sha256=VUwQsehFIShvKrm98ywa5-gGz7eLwJnBHCpQdreGOGM,2483
astroid/brain/brain_typing.py,sha256=uficlx7AzFIkcBQKeOvmzg_75kxAZENTDilXTYv-rfE,14315
astroid/brain/brain_unittest.py,sha256=X_xqI70br7JgIrUiUwP4Hm9mQwCx9jBfvNW5h0wmp-0,1147
astroid/brain/brain_uuid.py,sha256=t0fj_QeNzbPga03GS0YP92sjjEmxN04rlgZ4dt82JHE,667
astroid/brain/helpers.py,sha256=qtThXG2zllaFm8Ril8Mjbb6yuRPUqy-elXz4Qu8UKX0,908
astroid/builder.py,sha256=bkCDciVprfLz3vyg6BfoTaUMe34tRB1n0z3hCXvoyLE,18788
astroid/const.py,sha256=-C9gZEVAgp83YpjnG4k6BKBlTkn22J3UeR59IzPzC-s,1095
astroid/constraint.py,sha256=RgYVUe0CiEXeXB0iGDd896CEDgCHpwALdzZEFogagwo,5043
astroid/context.py,sha256=BwdZndGFMeP9ldxt-c4LP21N61ZGCFjySNCASiGHWhw,5994
astroid/decorators.py,sha256=4_SEOBUSxU60_7SaOkACXvBiiwGxYVd7E6YJdhB-5AY,10090
astroid/exceptions.py,sha256=wcJFoxkuWUslQMsjjBsvQadlTl-CCLin4I5Mg9EA4XQ,13089
astroid/filter_statements.py,sha256=zd55vGal1W6k1DZRsZoTQodtTZCtKrmebUVkECeoUS4,9643
astroid/helpers.py,sha256=2ppef_tEbjaFyvFb2QrNq36I8pNk-wxLDkpfwXN0dc8,11312
astroid/inference.py,sha256=IJZGg3YLTIXfHxDuOnEdd5IAfdk7sTPWSGt8OXqEHpM,45121
astroid/inference_tip.py,sha256=4ims3HAlCZwVybV1CyLxreDtPVNEnvta_OKb_ELAbyA,2888
astroid/interpreter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
astroid/interpreter/__pycache__/__init__.cpython-310.pyc,,
astroid/interpreter/__pycache__/dunder_lookup.cpython-310.pyc,,
astroid/interpreter/__pycache__/objectmodel.cpython-310.pyc,,
astroid/interpreter/_import/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
astroid/interpreter/_import/__pycache__/__init__.cpython-310.pyc,,
astroid/interpreter/_import/__pycache__/spec.cpython-310.pyc,,
astroid/interpreter/_import/__pycache__/util.cpython-310.pyc,,
astroid/interpreter/_import/spec.py,sha256=1s6GkO0yVgdtXHJAhD8v8W27ZmtkfT5p-mAKf8v4xmY,16381
astroid/interpreter/_import/util.py,sha256=b5ggIRSth_I5Uwv3s44jMwf3OlnFAWIV-57wX3XK9yM,4592
astroid/interpreter/dunder_lookup.py,sha256=77YNmgp6l2sPA7UIaUpjaP6-4x26NP93IihPR5EEv-c,2172
astroid/interpreter/objectmodel.py,sha256=SVtDFz0kAlHgkRTcIp4r3t2UEjeJLE2jXSxZdo8QhXw,31177
astroid/manager.py,sha256=g17lbC6NM9ieO3hZVJLtwE6Gb_JlCsEJJ42YtK7B27Q,17598
astroid/mixins.py,sha256=4fuPIi4N5ucNbocjVrS5UpEc_6Jkn3gsYD--JG85TII,1182
astroid/modutils.py,sha256=nmwwzrvSGIl4DRHC6WoyGPDkDtKgyKpcHSidjw_B8UU,23481
astroid/node_classes.py,sha256=ws0UW2SFejWF75iHfxx-u80XQt4beDAiDyabWrOwlPE,1827
astroid/nodes/__init__.py,sha256=Uuli4TfBDzdUTPvVvjp-aEB0SpMv-6gdoWajJt1fguo,5043
astroid/nodes/__pycache__/__init__.cpython-310.pyc,,
astroid/nodes/__pycache__/_base_nodes.cpython-310.pyc,,
astroid/nodes/__pycache__/as_string.cpython-310.pyc,,
astroid/nodes/__pycache__/const.cpython-310.pyc,,
astroid/nodes/__pycache__/node_classes.cpython-310.pyc,,
astroid/nodes/__pycache__/node_ng.cpython-310.pyc,,
astroid/nodes/__pycache__/utils.cpython-310.pyc,,
astroid/nodes/_base_nodes.py,sha256=oQ4ueaxb5-JAnG1w17lK8TRo4xs3KatHrY985M0qgss,7398
astroid/nodes/as_string.py,sha256=i4s5M3Ghaef0d-Jgqi5NkPz8AYcXG3ZL7N3HPYZsp_0,24451
astroid/nodes/const.py,sha256=iyQn_v-wEzK6uXc-dEMoliPVSRy0NZ8T3XmvvPXLuP4,797
astroid/nodes/node_classes.py,sha256=vmiMXFjaRS7o8ag4yShavJxfyd3CIh9xOfJiORxxQ2M,172738
astroid/nodes/node_ng.py,sha256=pqrceCAgS64qDmFGBghjWnneodH6P9KYsUFhsi_9Aq8,28223
astroid/nodes/scoped_nodes/__init__.py,sha256=CRdThe_LiW7SgcJz3pHSL8oFqHKNIJWg1WkQOkws994,1219
astroid/nodes/scoped_nodes/__pycache__/__init__.cpython-310.pyc,,
astroid/nodes/scoped_nodes/__pycache__/mixin.cpython-310.pyc,,
astroid/nodes/scoped_nodes/__pycache__/scoped_nodes.cpython-310.pyc,,
astroid/nodes/scoped_nodes/__pycache__/utils.cpython-310.pyc,,
astroid/nodes/scoped_nodes/mixin.py,sha256=mN3oqKpS2AWOtrBjHDDfReVO7OxAMhl_es-jzsn89Js,6917
astroid/nodes/scoped_nodes/scoped_nodes.py,sha256=DdqlbBVNPoQbP3AE8nJGsnHjMH0uU92Tp32B8F87v1w,106494
astroid/nodes/scoped_nodes/utils.py,sha256=Nnjdkcbm9zs72HcoV9b_hE6P-SLZ7MCB9urU-WUDNVg,1216
astroid/nodes/utils.py,sha256=Uy6xoownLyWwDtuZ5qUpjbq19P2pUIcj0J04khbH5HY,423
astroid/objects.py,sha256=8roM53sWwFzusAIvz3nOj0LaQEXdzJw0ANfb6mDMy5w,12757
astroid/protocols.py,sha256=dkQszq5bOlJ7Jlyu4hdF8l7sv7hVfH7glKWVblf3bkU,32684
astroid/raw_building.py,sha256=TI55TaZL35Zi3bk2DThToKEQ8rMOhZCgAMayfktxbAM,22875
astroid/rebuilder.py,sha256=ura2IJRixG6FQjgHFXP3-XrGfhPKoW6t1nGXuHl8lQs,79566
astroid/scoped_nodes.py,sha256=j51jEOiN1rkMqmrhvVtYje8d-EWaGbzrgCwvg_s4TE0,958
astroid/test_utils.py,sha256=7wyVL8A8WYQXbix1mT05lh8yO4kXk1gRjCCuqwfV4f8,2434
astroid/transforms.py,sha256=eg7b0lehQu_GsFHCsLdUsNNvbxYBGcTC0p7rF2EKIXc,3271
astroid/typing.py,sha256=OTOZbQ7tHSMq1tlASsVgRMC90GTjFoVSCgevZarAwhI,1983
astroid/util.py,sha256=T5ux2LDjSNv2et5blQuUU7xCBr1id-CeU8lorr-yAVo,4729

View File

@ -0,0 +1 @@
/home/runner/.cache/pip/pool/db/07/a9/3359e4e034b8785a58ad6d534ea3dca0635f1e184efe2e66e1c3a299ba

View File

@ -0,0 +1 @@
/home/runner/.cache/pip/pool/1e/c7/56/e0edb1ed95d18fa93e6a08b745a4326c62e86c8dd5484fa3b78bd05173

View File

@ -0,0 +1 @@
/home/runner/.cache/pip/pool/1c/a1/e7/720ae3ef4a92b3d1a0e1a0e91728804051e1ad2a11d4edb4390dcad01a

View File

@ -0,0 +1,6 @@
# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE
# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt
__version__ = "2.15.0"
version = __version__

View File

@ -0,0 +1 @@
/home/runner/.cache/pip/pool/7f/1e/af/0a3ed824945049fdc6418465949f6144a3e1f7e41ccd4ddcae3b7722b0

View File

@ -0,0 +1,356 @@
# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE
# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt
"""
Shim to support Python versions < 3.10 that don't have sys.stdlib_module_names
These values were created by cherry-picking the commits from
https://bugs.python.org/issue42955 into each version, but may be updated
manually if changes are needed.
"""
import sys
# TODO: Remove this file when Python 3.9 is no longer supported
PY_3_7 = frozenset(
{
"__future__",
"_abc",
"_ast",
"_asyncio",
"_bisect",
"_blake2",
"_bootlocale",
"_bz2",
"_codecs",
"_codecs_cn",
"_codecs_hk",
"_codecs_iso2022",
"_codecs_jp",
"_codecs_kr",
"_codecs_tw",
"_collections",
"_collections_abc",
"_compat_pickle",
"_compression",
"_contextvars",
"_crypt",
"_csv",
"_ctypes",
"_curses",
"_curses_panel",
"_datetime",
"_dbm",
"_decimal",
"_dummy_thread",
"_elementtree",
"_functools",
"_gdbm",
"_hashlib",
"_heapq",
"_imp",
"_io",
"_json",
"_locale",
"_lsprof",
"_lzma",
"_markupbase",
"_md5",
"_msi",
"_multibytecodec",
"_multiprocessing",
"_opcode",
"_operator",
"_osx_support",
"_pickle",
"_posixsubprocess",
"_py_abc",
"_pydecimal",
"_pyio",
"_queue",
"_random",
"_sha1",
"_sha256",
"_sha3",
"_sha512",
"_signal",
"_sitebuiltins",
"_socket",
"_sqlite3",
"_sre",
"_ssl",
"_stat",
"_string",
"_strptime",
"_struct",
"_symtable",
"_thread",
"_threading_local",
"_tkinter",
"_tracemalloc",
"_uuid",
"_warnings",
"_weakref",
"_weakrefset",
"_winapi",
"abc",
"aifc",
"antigravity",
"argparse",
"array",
"ast",
"asynchat",
"asyncio",
"asyncore",
"atexit",
"audioop",
"base64",
"bdb",
"binascii",
"binhex",
"bisect",
"builtins",
"bz2",
"cProfile",
"calendar",
"cgi",
"cgitb",
"chunk",
"cmath",
"cmd",
"code",
"codecs",
"codeop",
"collections",
"colorsys",
"compileall",
"concurrent",
"configparser",
"contextlib",
"contextvars",
"copy",
"copyreg",
"crypt",
"csv",
"ctypes",
"curses",
"dataclasses",
"datetime",
"dbm",
"decimal",
"difflib",
"dis",
"distutils",
"doctest",
"dummy_threading",
"email",
"encodings",
"ensurepip",
"enum",
"errno",
"faulthandler",
"fcntl",
"filecmp",
"fileinput",
"fnmatch",
"formatter",
"fractions",
"ftplib",
"functools",
"gc",
"genericpath",
"getopt",
"getpass",
"gettext",
"glob",
"grp",
"gzip",
"hashlib",
"heapq",
"hmac",
"html",
"http",
"idlelib",
"imaplib",
"imghdr",
"imp",
"importlib",
"inspect",
"io",
"ipaddress",
"itertools",
"json",
"keyword",
"lib2to3",
"linecache",
"locale",
"logging",
"lzma",
"macpath",
"mailbox",
"mailcap",
"marshal",
"math",
"mimetypes",
"mmap",
"modulefinder",
"msilib",
"msvcrt",
"multiprocessing",
"netrc",
"nis",
"nntplib",
"nt",
"ntpath",
"nturl2path",
"numbers",
"opcode",
"operator",
"optparse",
"os",
"ossaudiodev",
"parser",
"pathlib",
"pdb",
"pickle",
"pickletools",
"pipes",
"pkgutil",
"platform",
"plistlib",
"poplib",
"posix",
"posixpath",
"pprint",
"profile",
"pstats",
"pty",
"pwd",
"py_compile",
"pyclbr",
"pydoc",
"pydoc_data",
"pyexpat",
"queue",
"quopri",
"random",
"re",
"readline",
"reprlib",
"resource",
"rlcompleter",
"runpy",
"sched",
"secrets",
"select",
"selectors",
"shelve",
"shlex",
"shutil",
"signal",
"site",
"smtpd",
"smtplib",
"sndhdr",
"socket",
"socketserver",
"spwd",
"sqlite3",
"sre_compile",
"sre_constants",
"sre_parse",
"ssl",
"stat",
"statistics",
"string",
"stringprep",
"struct",
"subprocess",
"sunau",
"symbol",
"symtable",
"sys",
"sysconfig",
"syslog",
"tabnanny",
"tarfile",
"telnetlib",
"tempfile",
"termios",
"textwrap",
"this",
"threading",
"time",
"timeit",
"tkinter",
"token",
"tokenize",
"trace",
"traceback",
"tracemalloc",
"tty",
"turtle",
"turtledemo",
"types",
"typing",
"unicodedata",
"unittest",
"urllib",
"uu",
"uuid",
"venv",
"warnings",
"wave",
"weakref",
"webbrowser",
"winreg",
"winsound",
"wsgiref",
"xdrlib",
"xml",
"xmlrpc",
"zipapp",
"zipfile",
"zipimport",
"zlib",
}
)
PY_3_8 = frozenset(
PY_3_7
- {
"macpath",
}
| {
"_posixshmem",
"_statistics",
"_xxsubinterpreters",
}
)
PY_3_9 = frozenset(
PY_3_8
- {
"_dummy_thread",
"dummy_threading",
}
| {
"_aix_support",
"_bootsubprocess",
"_peg_parser",
"_zoneinfo",
"graphlib",
"zoneinfo",
}
)
if sys.version_info[:2] == (3, 7):
stdlib_module_names = PY_3_7
elif sys.version_info[:2] == (3, 8):
stdlib_module_names = PY_3_8
elif sys.version_info[:2] == (3, 9):
stdlib_module_names = PY_3_9
else:
raise AssertionError("This module is only intended as a backport for Python <= 3.9")

View File

@ -0,0 +1 @@
/home/runner/.cache/pip/pool/66/e3/b5/2a5f475dac6827f8495dbcd6aa430699047b0867fe47870f7a7f687733

View File

@ -0,0 +1,309 @@
# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE
# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt
from __future__ import annotations
from astroid import nodes
from astroid.bases import Instance
from astroid.context import CallContext, InferenceContext
from astroid.exceptions import InferenceError, NoDefault
from astroid.util import Uninferable, UninferableBase
class CallSite:
"""Class for understanding arguments passed into a call site.
It needs a call context, which contains the arguments and the
keyword arguments that were passed into a given call site.
In order to infer what an argument represents, call :meth:`infer_argument`
with the corresponding function node and the argument name.
:param callcontext:
An instance of :class:`astroid.context.CallContext`, that holds
the arguments for the call site.
:param argument_context_map:
Additional contexts per node, passed in from :attr:`astroid.context.Context.extra_context`
:param context:
An instance of :class:`astroid.context.Context`.
"""
def __init__(
self,
callcontext: CallContext,
argument_context_map=None,
context: InferenceContext | None = None,
):
if argument_context_map is None:
argument_context_map = {}
self.argument_context_map = argument_context_map
args = callcontext.args
keywords = callcontext.keywords
self.duplicated_keywords: set[str] = set()
self._unpacked_args = self._unpack_args(args, context=context)
self._unpacked_kwargs = self._unpack_keywords(keywords, context=context)
self.positional_arguments = [
arg for arg in self._unpacked_args if not isinstance(arg, UninferableBase)
]
self.keyword_arguments = {
key: value
for key, value in self._unpacked_kwargs.items()
if not isinstance(value, UninferableBase)
}
@classmethod
def from_call(cls, call_node, context: InferenceContext | None = None):
"""Get a CallSite object from the given Call node.
context will be used to force a single inference path.
"""
# Determine the callcontext from the given `context` object if any.
context = context or InferenceContext()
callcontext = CallContext(call_node.args, call_node.keywords)
return cls(callcontext, context=context)
def has_invalid_arguments(self):
"""Check if in the current CallSite were passed *invalid* arguments.
This can mean multiple things. For instance, if an unpacking
of an invalid object was passed, then this method will return True.
Other cases can be when the arguments can't be inferred by astroid,
for example, by passing objects which aren't known statically.
"""
return len(self.positional_arguments) != len(self._unpacked_args)
def has_invalid_keywords(self) -> bool:
"""Check if in the current CallSite were passed *invalid* keyword arguments.
For instance, unpacking a dictionary with integer keys is invalid
(**{1:2}), because the keys must be strings, which will make this
method to return True. Other cases where this might return True if
objects which can't be inferred were passed.
"""
return len(self.keyword_arguments) != len(self._unpacked_kwargs)
def _unpack_keywords(self, keywords, context: InferenceContext | None = None):
values = {}
context = context or InferenceContext()
context.extra_context = self.argument_context_map
for name, value in keywords:
if name is None:
# Then it's an unpacking operation (**)
try:
inferred = next(value.infer(context=context))
except InferenceError:
values[name] = Uninferable
continue
except StopIteration:
continue
if not isinstance(inferred, nodes.Dict):
# Not something we can work with.
values[name] = Uninferable
continue
for dict_key, dict_value in inferred.items:
try:
dict_key = next(dict_key.infer(context=context))
except InferenceError:
values[name] = Uninferable
continue
except StopIteration:
continue
if not isinstance(dict_key, nodes.Const):
values[name] = Uninferable
continue
if not isinstance(dict_key.value, str):
values[name] = Uninferable
continue
if dict_key.value in values:
# The name is already in the dictionary
values[dict_key.value] = Uninferable
self.duplicated_keywords.add(dict_key.value)
continue
values[dict_key.value] = dict_value
else:
values[name] = value
return values
def _unpack_args(self, args, context: InferenceContext | None = None):
values = []
context = context or InferenceContext()
context.extra_context = self.argument_context_map
for arg in args:
if isinstance(arg, nodes.Starred):
try:
inferred = next(arg.value.infer(context=context))
except InferenceError:
values.append(Uninferable)
continue
except StopIteration:
continue
if isinstance(inferred, UninferableBase):
values.append(Uninferable)
continue
if not hasattr(inferred, "elts"):
values.append(Uninferable)
continue
values.extend(inferred.elts)
else:
values.append(arg)
return values
def infer_argument(self, funcnode, name, context): # noqa: C901
"""Infer a function argument value according to the call context.
Arguments:
funcnode: The function being called.
name: The name of the argument whose value is being inferred.
context: Inference context object
"""
if name in self.duplicated_keywords:
raise InferenceError(
"The arguments passed to {func!r} have duplicate keywords.",
call_site=self,
func=funcnode,
arg=name,
context=context,
)
# Look into the keywords first, maybe it's already there.
try:
return self.keyword_arguments[name].infer(context)
except KeyError:
pass
# Too many arguments given and no variable arguments.
if len(self.positional_arguments) > len(funcnode.args.args):
if not funcnode.args.vararg and not funcnode.args.posonlyargs:
raise InferenceError(
"Too many positional arguments "
"passed to {func!r} that does "
"not have *args.",
call_site=self,
func=funcnode,
arg=name,
context=context,
)
positional = self.positional_arguments[: len(funcnode.args.args)]
vararg = self.positional_arguments[len(funcnode.args.args) :]
argindex = funcnode.args.find_argname(name)[0]
kwonlyargs = {arg.name for arg in funcnode.args.kwonlyargs}
kwargs = {
key: value
for key, value in self.keyword_arguments.items()
if key not in kwonlyargs
}
# If there are too few positionals compared to
# what the function expects to receive, check to see
# if the missing positional arguments were passed
# as keyword arguments and if so, place them into the
# positional args list.
if len(positional) < len(funcnode.args.args):
for func_arg in funcnode.args.args:
if func_arg.name in kwargs:
arg = kwargs.pop(func_arg.name)
positional.append(arg)
if argindex is not None:
boundnode = getattr(context, "boundnode", None)
# 2. first argument of instance/class method
if argindex == 0 and funcnode.type in {"method", "classmethod"}:
# context.boundnode is None when an instance method is called with
# the class, e.g. MyClass.method(obj, ...). In this case, self
# is the first argument.
if boundnode is None and funcnode.type == "method" and positional:
return positional[0].infer(context=context)
if boundnode is None:
# XXX can do better ?
boundnode = funcnode.parent.frame(future=True)
if isinstance(boundnode, nodes.ClassDef):
# Verify that we're accessing a method
# of the metaclass through a class, as in
# `cls.metaclass_method`. In this case, the
# first argument is always the class.
method_scope = funcnode.parent.scope()
if method_scope is boundnode.metaclass():
return iter((boundnode,))
if funcnode.type == "method":
if not isinstance(boundnode, Instance):
boundnode = boundnode.instantiate_class()
return iter((boundnode,))
if funcnode.type == "classmethod":
return iter((boundnode,))
# if we have a method, extract one position
# from the index, so we'll take in account
# the extra parameter represented by `self` or `cls`
if funcnode.type in {"method", "classmethod"} and boundnode:
argindex -= 1
# 2. search arg index
try:
return self.positional_arguments[argindex].infer(context)
except IndexError:
pass
if funcnode.args.kwarg == name:
# It wants all the keywords that were passed into
# the call site.
if self.has_invalid_keywords():
raise InferenceError(
"Inference failed to find values for all keyword arguments "
"to {func!r}: {unpacked_kwargs!r} doesn't correspond to "
"{keyword_arguments!r}.",
keyword_arguments=self.keyword_arguments,
unpacked_kwargs=self._unpacked_kwargs,
call_site=self,
func=funcnode,
arg=name,
context=context,
)
kwarg = nodes.Dict(
lineno=funcnode.args.lineno,
col_offset=funcnode.args.col_offset,
parent=funcnode.args,
)
kwarg.postinit(
[(nodes.const_factory(key), value) for key, value in kwargs.items()]
)
return iter((kwarg,))
if funcnode.args.vararg == name:
# It wants all the args that were passed into
# the call site.
if self.has_invalid_arguments():
raise InferenceError(
"Inference failed to find values for all positional "
"arguments to {func!r}: {unpacked_args!r} doesn't "
"correspond to {positional_arguments!r}.",
positional_arguments=self.positional_arguments,
unpacked_args=self._unpacked_args,
call_site=self,
func=funcnode,
arg=name,
context=context,
)
args = nodes.Tuple(
lineno=funcnode.args.lineno,
col_offset=funcnode.args.col_offset,
parent=funcnode.args,
)
args.postinit(vararg)
return iter((args,))
# Check if it's a default parameter.
try:
return funcnode.args.default_value(name).infer(context)
except NoDefault:
pass
raise InferenceError(
"No value found for argument {arg} to {func!r}",
call_site=self,
func=funcnode,
arg=name,
context=context,
)

View File

@ -0,0 +1 @@
/home/runner/.cache/pip/pool/d3/69/7f/96d19612096f9282ffa8c1a6631b87a43039fb248f7f4af5706c0842a5

View File

@ -0,0 +1,711 @@
# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE
# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt
"""This module contains base classes and functions for the nodes and some
inference utils.
"""
from __future__ import annotations
import collections
import collections.abc
import sys
from collections.abc import Sequence
from typing import TYPE_CHECKING, Any, ClassVar
from astroid import decorators, nodes
from astroid.const import PY310_PLUS
from astroid.context import (
CallContext,
InferenceContext,
bind_context_to_node,
copy_context,
)
from astroid.exceptions import (
AstroidTypeError,
AttributeInferenceError,
InferenceError,
NameInferenceError,
)
from astroid.typing import InferBinaryOp, InferenceErrorInfo, InferenceResult
from astroid.util import Uninferable, UninferableBase, lazy_descriptor, lazy_import
if sys.version_info >= (3, 8):
from typing import Literal
else:
from typing_extensions import Literal
if TYPE_CHECKING:
from astroid.constraint import Constraint
objectmodel = lazy_import("interpreter.objectmodel")
helpers = lazy_import("helpers")
manager = lazy_import("manager")
# TODO: check if needs special treatment
BOOL_SPECIAL_METHOD = "__bool__"
BUILTINS = "builtins" # TODO Remove in 2.8
PROPERTIES = {"builtins.property", "abc.abstractproperty"}
if PY310_PLUS:
PROPERTIES.add("enum.property")
# List of possible property names. We use this list in order
# to see if a method is a property or not. This should be
# pretty reliable and fast, the alternative being to check each
# decorator to see if its a real property-like descriptor, which
# can be too complicated.
# Also, these aren't qualified, because each project can
# define them, we shouldn't expect to know every possible
# property-like decorator!
POSSIBLE_PROPERTIES = {
"cached_property",
"cachedproperty",
"lazyproperty",
"lazy_property",
"reify",
"lazyattribute",
"lazy_attribute",
"LazyProperty",
"lazy",
"cache_readonly",
"DynamicClassAttribute",
}
def _is_property(meth, context: InferenceContext | None = None) -> bool:
decoratornames = meth.decoratornames(context=context)
if PROPERTIES.intersection(decoratornames):
return True
stripped = {
name.split(".")[-1]
for name in decoratornames
if not isinstance(name, UninferableBase)
}
if any(name in stripped for name in POSSIBLE_PROPERTIES):
return True
# Lookup for subclasses of *property*
if not meth.decorators:
return False
for decorator in meth.decorators.nodes or ():
inferred = helpers.safe_infer(decorator, context=context)
if inferred is None or isinstance(inferred, UninferableBase):
continue
if inferred.__class__.__name__ == "ClassDef":
for base_class in inferred.bases:
if base_class.__class__.__name__ != "Name":
continue
module, _ = base_class.lookup(base_class.name)
if module.name == "builtins" and base_class.name == "property":
return True
return False
class Proxy:
"""A simple proxy object.
Note:
Subclasses of this object will need a custom __getattr__
if new instance attributes are created. See the Const class
"""
_proxied: nodes.ClassDef | nodes.Lambda | Proxy | None = (
None # proxied object may be set by class or by instance
)
def __init__(
self, proxied: nodes.ClassDef | nodes.Lambda | Proxy | None = None
) -> None:
if proxied is None:
# This is a hack to allow calling this __init__ during bootstrapping of
# builtin classes and their docstrings.
# For Const, Generator, and UnionType nodes the _proxied attribute
# is set during bootstrapping
# as we first need to build the ClassDef that they can proxy.
# Thus, if proxied is None self should be a Const or Generator
# as that is the only way _proxied will be correctly set as a ClassDef.
assert isinstance(self, (nodes.Const, Generator, UnionType))
else:
self._proxied = proxied
def __getattr__(self, name):
if name == "_proxied":
return self.__class__._proxied
if name in self.__dict__:
return self.__dict__[name]
return getattr(self._proxied, name)
def infer( # type: ignore[return]
self, context: InferenceContext | None = None, **kwargs: Any
) -> collections.abc.Generator[InferenceResult, None, InferenceErrorInfo | None]:
yield self
def _infer_stmts(
stmts: Sequence[nodes.NodeNG | UninferableBase | Instance],
context: InferenceContext | None,
frame: nodes.NodeNG | Instance | None = None,
) -> collections.abc.Generator[InferenceResult, None, None]:
"""Return an iterator on statements inferred by each statement in *stmts*."""
inferred = False
constraint_failed = False
if context is not None:
name = context.lookupname
context = context.clone()
constraints = context.constraints.get(name, {})
else:
name = None
constraints = {}
context = InferenceContext()
for stmt in stmts:
if isinstance(stmt, UninferableBase):
yield stmt
inferred = True
continue
# 'context' is always InferenceContext and Instances get '_infer_name' from ClassDef
context.lookupname = stmt._infer_name(frame, name) # type: ignore[union-attr]
try:
stmt_constraints: set[Constraint] = set()
for constraint_stmt, potential_constraints in constraints.items():
if not constraint_stmt.parent_of(stmt):
stmt_constraints.update(potential_constraints)
for inf in stmt.infer(context=context):
if all(constraint.satisfied_by(inf) for constraint in stmt_constraints):
yield inf
inferred = True
else:
constraint_failed = True
except NameInferenceError:
continue
except InferenceError:
yield Uninferable
inferred = True
if not inferred and constraint_failed:
yield Uninferable
elif not inferred:
raise InferenceError(
"Inference failed for all members of {stmts!r}.",
stmts=stmts,
frame=frame,
context=context,
)
def _infer_method_result_truth(instance, method_name, context):
# Get the method from the instance and try to infer
# its return's truth value.
meth = next(instance.igetattr(method_name, context=context), None)
if meth and hasattr(meth, "infer_call_result"):
if not meth.callable():
return Uninferable
try:
context.callcontext = CallContext(args=[], callee=meth)
for value in meth.infer_call_result(instance, context=context):
if isinstance(value, UninferableBase):
return value
try:
inferred = next(value.infer(context=context))
except StopIteration as e:
raise InferenceError(context=context) from e
return inferred.bool_value()
except InferenceError:
pass
return Uninferable
class BaseInstance(Proxy):
"""An instance base class, which provides lookup methods for potential
instances.
"""
special_attributes = None
def display_type(self) -> str:
return "Instance of"
def getattr(self, name, context: InferenceContext | None = None, lookupclass=True):
try:
values = self._proxied.instance_attr(name, context)
except AttributeInferenceError as exc:
if self.special_attributes and name in self.special_attributes:
return [self.special_attributes.lookup(name)]
if lookupclass:
# Class attributes not available through the instance
# unless they are explicitly defined.
return self._proxied.getattr(name, context, class_context=False)
raise AttributeInferenceError(
target=self, attribute=name, context=context
) from exc
# since we've no context information, return matching class members as
# well
if lookupclass:
try:
return values + self._proxied.getattr(
name, context, class_context=False
)
except AttributeInferenceError:
pass
return values
def igetattr(self, name, context: InferenceContext | None = None):
"""Inferred getattr."""
if not context:
context = InferenceContext()
try:
context.lookupname = name
# avoid recursively inferring the same attr on the same class
if context.push(self._proxied):
raise InferenceError(
message="Cannot infer the same attribute again",
node=self,
context=context,
)
# XXX frame should be self._proxied, or not ?
get_attr = self.getattr(name, context, lookupclass=False)
yield from _infer_stmts(
self._wrap_attr(get_attr, context), context, frame=self
)
except AttributeInferenceError:
try:
# fallback to class.igetattr since it has some logic to handle
# descriptors
# But only if the _proxied is the Class.
if self._proxied.__class__.__name__ != "ClassDef":
raise
attrs = self._proxied.igetattr(name, context, class_context=False)
yield from self._wrap_attr(attrs, context)
except AttributeInferenceError as error:
raise InferenceError(**vars(error)) from error
def _wrap_attr(self, attrs, context: InferenceContext | None = None):
"""Wrap bound methods of attrs in a InstanceMethod proxies."""
for attr in attrs:
if isinstance(attr, UnboundMethod):
if _is_property(attr):
yield from attr.infer_call_result(self, context)
else:
yield BoundMethod(attr, self)
elif hasattr(attr, "name") and attr.name == "<lambda>":
if attr.args.arguments and attr.args.arguments[0].name == "self":
yield BoundMethod(attr, self)
continue
yield attr
else:
yield attr
def infer_call_result(
self, caller: nodes.Call | Proxy, context: InferenceContext | None = None
):
"""Infer what a class instance is returning when called."""
context = bind_context_to_node(context, self)
inferred = False
# If the call is an attribute on the instance, we infer the attribute itself
if isinstance(caller, nodes.Call) and isinstance(caller.func, nodes.Attribute):
for res in self.igetattr(caller.func.attrname, context):
inferred = True
yield res
# Otherwise we infer the call to the __call__ dunder normally
for node in self._proxied.igetattr("__call__", context):
if isinstance(node, UninferableBase) or not node.callable():
continue
for res in node.infer_call_result(caller, context):
inferred = True
yield res
if not inferred:
raise InferenceError(node=self, caller=caller, context=context)
class Instance(BaseInstance):
"""A special node representing a class instance."""
_proxied: nodes.ClassDef
# pylint: disable=unnecessary-lambda
special_attributes = lazy_descriptor(lambda: objectmodel.InstanceModel())
def __init__(self, proxied: nodes.ClassDef | None) -> None:
super().__init__(proxied)
infer_binary_op: ClassVar[InferBinaryOp[Instance]]
def __repr__(self) -> str:
return "<Instance of {}.{} at 0x{}>".format(
self._proxied.root().name, self._proxied.name, id(self)
)
def __str__(self) -> str:
return f"Instance of {self._proxied.root().name}.{self._proxied.name}"
def callable(self) -> bool:
try:
self._proxied.getattr("__call__", class_context=False)
return True
except AttributeInferenceError:
return False
def pytype(self) -> str:
return self._proxied.qname()
def display_type(self) -> str:
return "Instance of"
def bool_value(self, context: InferenceContext | None = None):
"""Infer the truth value for an Instance.
The truth value of an instance is determined by these conditions:
* if it implements __bool__ on Python 3 or __nonzero__
on Python 2, then its bool value will be determined by
calling this special method and checking its result.
* when this method is not defined, __len__() is called, if it
is defined, and the object is considered true if its result is
nonzero. If a class defines neither __len__() nor __bool__(),
all its instances are considered true.
"""
context = context or InferenceContext()
context.boundnode = self
try:
result = _infer_method_result_truth(self, BOOL_SPECIAL_METHOD, context)
except (InferenceError, AttributeInferenceError):
# Fallback to __len__.
try:
result = _infer_method_result_truth(self, "__len__", context)
except (AttributeInferenceError, InferenceError):
return True
return result
def getitem(self, index, context: InferenceContext | None = None):
new_context = bind_context_to_node(context, self)
if not context:
context = new_context
method = next(self.igetattr("__getitem__", context=context), None)
# Create a new CallContext for providing index as an argument.
new_context.callcontext = CallContext(args=[index], callee=method)
if not isinstance(method, BoundMethod):
raise InferenceError(
"Could not find __getitem__ for {node!r}.", node=self, context=context
)
if len(method.args.arguments) != 2: # (self, index)
raise AstroidTypeError(
"__getitem__ for {node!r} does not have correct signature",
node=self,
context=context,
)
return next(method.infer_call_result(self, new_context), None)
class UnboundMethod(Proxy):
"""A special node representing a method not bound to an instance."""
# pylint: disable=unnecessary-lambda
special_attributes = lazy_descriptor(lambda: objectmodel.UnboundMethodModel())
def __repr__(self) -> str:
frame = self._proxied.parent.frame(future=True)
return "<{} {} of {} at 0x{}".format(
self.__class__.__name__, self._proxied.name, frame.qname(), id(self)
)
def implicit_parameters(self) -> Literal[0]:
return 0
def is_bound(self) -> Literal[False]:
return False
def getattr(self, name, context: InferenceContext | None = None):
if name in self.special_attributes:
return [self.special_attributes.lookup(name)]
return self._proxied.getattr(name, context)
def igetattr(self, name, context: InferenceContext | None = None):
if name in self.special_attributes:
return iter((self.special_attributes.lookup(name),))
return self._proxied.igetattr(name, context)
def infer_call_result(self, caller, context):
"""
The boundnode of the regular context with a function called
on ``object.__new__`` will be of type ``object``,
which is incorrect for the argument in general.
If no context is given the ``object.__new__`` call argument will
be correctly inferred except when inside a call that requires
the additional context (such as a classmethod) of the boundnode
to determine which class the method was called from
"""
# If we're unbound method __new__ of a builtin, the result is an
# instance of the class given as first argument.
if self._proxied.name == "__new__":
qname = self._proxied.parent.frame(future=True).qname()
# Avoid checking builtins.type: _infer_type_new_call() does more validation
if qname.startswith("builtins.") and qname != "builtins.type":
return self._infer_builtin_new(caller, context)
return self._proxied.infer_call_result(caller, context)
def _infer_builtin_new(
self,
caller: nodes.Call,
context: InferenceContext,
) -> collections.abc.Generator[
nodes.Const | Instance | UninferableBase, None, None
]:
if not caller.args:
return
# Attempt to create a constant
if len(caller.args) > 1:
value = None
if isinstance(caller.args[1], nodes.Const):
value = caller.args[1].value
else:
inferred_arg = next(caller.args[1].infer(), None)
if isinstance(inferred_arg, nodes.Const):
value = inferred_arg.value
if value is not None:
yield nodes.const_factory(value)
return
node_context = context.extra_context.get(caller.args[0])
for inferred in caller.args[0].infer(context=node_context):
if isinstance(inferred, UninferableBase):
yield inferred
if isinstance(inferred, nodes.ClassDef):
yield Instance(inferred)
raise InferenceError
def bool_value(self, context: InferenceContext | None = None) -> Literal[True]:
return True
class BoundMethod(UnboundMethod):
"""A special node representing a method bound to an instance."""
# pylint: disable=unnecessary-lambda
special_attributes = lazy_descriptor(lambda: objectmodel.BoundMethodModel())
def __init__(self, proxy, bound):
super().__init__(proxy)
self.bound = bound
def implicit_parameters(self) -> Literal[0, 1]:
if self.name == "__new__":
# __new__ acts as a classmethod but the class argument is not implicit.
return 0
return 1
def is_bound(self) -> Literal[True]:
return True
def _infer_type_new_call(self, caller, context): # noqa: C901
"""Try to infer what type.__new__(mcs, name, bases, attrs) returns.
In order for such call to be valid, the metaclass needs to be
a subtype of ``type``, the name needs to be a string, the bases
needs to be a tuple of classes
"""
# pylint: disable=import-outside-toplevel; circular import
from astroid.nodes import Pass
# Verify the metaclass
try:
mcs = next(caller.args[0].infer(context=context))
except StopIteration as e:
raise InferenceError(context=context) from e
if mcs.__class__.__name__ != "ClassDef":
# Not a valid first argument.
return None
if not mcs.is_subtype_of("builtins.type"):
# Not a valid metaclass.
return None
# Verify the name
try:
name = next(caller.args[1].infer(context=context))
except StopIteration as e:
raise InferenceError(context=context) from e
if name.__class__.__name__ != "Const":
# Not a valid name, needs to be a const.
return None
if not isinstance(name.value, str):
# Needs to be a string.
return None
# Verify the bases
try:
bases = next(caller.args[2].infer(context=context))
except StopIteration as e:
raise InferenceError(context=context) from e
if bases.__class__.__name__ != "Tuple":
# Needs to be a tuple.
return None
try:
inferred_bases = [next(elt.infer(context=context)) for elt in bases.elts]
except StopIteration as e:
raise InferenceError(context=context) from e
if any(base.__class__.__name__ != "ClassDef" for base in inferred_bases):
# All the bases needs to be Classes
return None
# Verify the attributes.
try:
attrs = next(caller.args[3].infer(context=context))
except StopIteration as e:
raise InferenceError(context=context) from e
if attrs.__class__.__name__ != "Dict":
# Needs to be a dictionary.
return None
cls_locals = collections.defaultdict(list)
for key, value in attrs.items:
try:
key = next(key.infer(context=context))
except StopIteration as e:
raise InferenceError(context=context) from e
try:
value = next(value.infer(context=context))
except StopIteration as e:
raise InferenceError(context=context) from e
# Ignore non string keys
if key.__class__.__name__ == "Const" and isinstance(key.value, str):
cls_locals[key.value].append(value)
# Build the class from now.
cls = mcs.__class__(
name=name.value,
lineno=caller.lineno,
col_offset=caller.col_offset,
parent=caller,
)
empty = Pass()
cls.postinit(
bases=bases.elts,
body=[empty],
decorators=[],
newstyle=True,
metaclass=mcs,
keywords=[],
)
cls.locals = cls_locals
return cls
def infer_call_result(self, caller, context: InferenceContext | None = None):
context = bind_context_to_node(context, self.bound)
if (
self.bound.__class__.__name__ == "ClassDef"
and self.bound.name == "type"
and self.name == "__new__"
and len(caller.args) == 4
):
# Check if we have a ``type.__new__(mcs, name, bases, attrs)`` call.
new_cls = self._infer_type_new_call(caller, context)
if new_cls:
return iter((new_cls,))
return super().infer_call_result(caller, context)
def bool_value(self, context: InferenceContext | None = None) -> Literal[True]:
return True
class Generator(BaseInstance):
"""A special node representing a generator.
Proxied class is set once for all in raw_building.
"""
_proxied: nodes.ClassDef
special_attributes = lazy_descriptor(objectmodel.GeneratorModel)
def __init__(
self, parent=None, generator_initial_context: InferenceContext | None = None
):
super().__init__()
self.parent = parent
self._call_context = copy_context(generator_initial_context)
@decorators.cached
def infer_yield_types(self):
yield from self.parent.infer_yield_result(self._call_context)
def callable(self) -> Literal[False]:
return False
def pytype(self) -> Literal["builtins.generator"]:
return "builtins.generator"
def display_type(self) -> str:
return "Generator"
def bool_value(self, context: InferenceContext | None = None) -> Literal[True]:
return True
def __repr__(self) -> str:
return f"<Generator({self._proxied.name}) l.{self.lineno} at 0x{id(self)}>"
def __str__(self) -> str:
return f"Generator({self._proxied.name})"
class AsyncGenerator(Generator):
"""Special node representing an async generator."""
def pytype(self) -> Literal["builtins.async_generator"]:
return "builtins.async_generator"
def display_type(self) -> str:
return "AsyncGenerator"
def __repr__(self) -> str:
return f"<AsyncGenerator({self._proxied.name}) l.{self.lineno} at 0x{id(self)}>"
def __str__(self) -> str:
return f"AsyncGenerator({self._proxied.name})"
class UnionType(BaseInstance):
"""Special node representing new style typing unions.
Proxied class is set once for all in raw_building.
"""
_proxied: nodes.ClassDef
def __init__(
self,
left: UnionType | nodes.ClassDef | nodes.Const,
right: UnionType | nodes.ClassDef | nodes.Const,
parent: nodes.NodeNG | None = None,
) -> None:
super().__init__()
self.parent = parent
self.left = left
self.right = right
def callable(self) -> Literal[False]:
return False
def bool_value(self, context: InferenceContext | None = None) -> Literal[True]:
return True
def pytype(self) -> Literal["types.UnionType"]:
return "types.UnionType"
def display_type(self) -> str:
return "UnionType"
def __repr__(self) -> str:
return f"<UnionType({self._proxied.name}) l.{self.lineno} at 0x{id(self)}>"
def __str__(self) -> str:
return f"UnionType({self._proxied.name})"

View File

@ -0,0 +1 @@
/home/runner/.cache/pip/pool/e3/b0/c4/4298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

Some files were not shown because too many files have changed in this diff Show More