From 9762262921520291a9db3e3af3de8f4d4f743a83 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sat, 24 Feb 2024 00:06:32 -0800 Subject: [PATCH] Use Ruff for linting and import sorting (#724) --- .github/workflows/lint.yml | 18 ++++ .github/workflows/publish.yml | 48 ++++----- .github/workflows/test.yml | 4 +- .pre-commit-config.yaml | 23 +++++ .readthedocs.yaml | 2 +- CONTRIBUTING.md | 3 +- docs/conf.py | 1 + pyanalyze/analysis_lib.py | 2 +- pyanalyze/annotated_types.py | 4 +- pyanalyze/annotations.py | 30 +++--- pyanalyze/arg_spec.py | 21 ++-- pyanalyze/attributes.py | 8 +- pyanalyze/boolability.py | 4 +- pyanalyze/checker.py | 17 ++-- pyanalyze/extensions.py | 8 +- pyanalyze/find_unused.py | 1 + pyanalyze/format_strings.py | 4 +- pyanalyze/functions.py | 10 +- pyanalyze/implementation.py | 39 ++++---- pyanalyze/importer.py | 2 +- pyanalyze/name_check_visitor.py | 98 +++++++++---------- pyanalyze/node_visitor.py | 2 +- pyanalyze/options.py | 1 - pyanalyze/patma.py | 18 ++-- pyanalyze/predicates.py | 6 +- pyanalyze/reexport.py | 3 +- pyanalyze/runtime.py | 5 +- pyanalyze/signature.py | 38 +++---- pyanalyze/stacked_scopes.py | 12 +-- .../stubs/_pyanalyze_tests-stubs/callable.pyi | 2 - .../_pyanalyze_tests-stubs/deprecated.pyi | 3 +- .../_pyanalyze_tests-stubs/evaluated.pyi | 2 +- .../stubs/_pyanalyze_tests-stubs/initnew.pyi | 2 +- .../_pyanalyze_tests-stubs/recursion.pyi | 1 + pyanalyze/suggested_type.py | 9 +- pyanalyze/test.toml | 2 +- pyanalyze/test_annotated_types.py | 33 ++++--- pyanalyze/test_annotations.py | 43 ++++---- pyanalyze/test_arg_spec.py | 3 +- pyanalyze/test_ast_annotator.py | 21 ++-- pyanalyze/test_async_await.py | 2 +- pyanalyze/test_asynq.py | 6 +- pyanalyze/test_asynq_checker.py | 16 +-- pyanalyze/test_attributes.py | 8 +- pyanalyze/test_boolability.py | 2 +- pyanalyze/test_config.py | 1 - pyanalyze/test_definite_value.py | 2 + pyanalyze/test_deprecated.py | 13 ++- pyanalyze/test_enum.py | 5 +- pyanalyze/test_extensions.py | 2 +- pyanalyze/test_format_strings.py | 5 +- pyanalyze/test_functions.py | 12 ++- pyanalyze/test_implementation.py | 11 ++- pyanalyze/test_import.py | 19 ++-- pyanalyze/test_name_check_visitor.py | 58 ++++++----- pyanalyze/test_never.py | 3 +- pyanalyze/test_node_visitor.py | 6 +- pyanalyze/test_operations.py | 2 +- pyanalyze/test_patma.py | 54 ++++++---- pyanalyze/test_pep673.py | 4 +- pyanalyze/test_runtime.py | 5 +- pyanalyze/test_signature.py | 25 ++--- pyanalyze/test_stacked_scopes.py | 8 +- pyanalyze/test_thrift_enum.py | 2 +- pyanalyze/test_try.py | 29 ++++-- pyanalyze/test_type_aliases.py | 21 ++-- pyanalyze/test_type_evaluation.py | 4 +- pyanalyze/test_type_object.py | 8 +- pyanalyze/test_typeddict.py | 26 +++-- pyanalyze/test_typeis.py | 51 +++++++--- pyanalyze/test_typeshed.py | 29 +++--- pyanalyze/test_typevar.py | 13 ++- pyanalyze/test_value.py | 4 +- pyanalyze/test_yield_checker.py | 5 +- pyanalyze/tests.py | 4 +- pyanalyze/type_evaluation.py | 8 +- pyanalyze/type_object.py | 6 +- pyanalyze/typeshed.py | 29 +++--- pyanalyze/typevar.py | 3 +- pyanalyze/value.py | 6 +- pyanalyze/yield_checker.py | 4 +- pyproject.toml | 36 +++++-- setup.py | 2 +- tox.ini | 56 +---------- 84 files changed, 649 insertions(+), 519 deletions(-) create mode 100644 .github/workflows/lint.yml create mode 100644 .pre-commit-config.yaml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000..a40b8b57 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,18 @@ +name: Lint + +on: [push, pull_request] + +jobs: + precommit: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Set up latest Python + uses: actions/setup-python@v4 + with: + python-version: "3.12" + + - name: Run pre-commit hooks + uses: pre-commit/action@v3.0.0 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 79c78e29..b921a864 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -10,27 +10,27 @@ jobs: name: Build and publish Python distributions to PyPI runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - name: Set up Python 3.11 - uses: actions/setup-python@v4 - with: - python-version: "3.11" - - name: Install pypa/build - run: >- - python -m - pip install - build - --user - - name: Build a binary wheel and a source tarball - run: >- - python -m - build - --sdist - --wheel - --outdir dist/ - . - - name: Publish distribution to PyPI - if: startsWith(github.ref, 'refs/tags') - uses: pypa/gh-action-pypi-publish@release/v1 - with: - password: ${{ secrets.PYPI_API_TOKEN }} \ No newline at end of file + - uses: actions/checkout@v4 + - name: Set up Python 3.11 + uses: actions/setup-python@v4 + with: + python-version: "3.11" + - name: Install pypa/build + run: >- + python -m + pip install + build + --user + - name: Build a binary wheel and a source tarball + run: >- + python -m + build + --sdist + --wheel + --outdir dist/ + . + - name: Publish distribution to PyPI + if: startsWith(github.ref, 'refs/tags') + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a8512058..e1a96b12 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -34,9 +34,9 @@ jobs: - name: black python: "3.12" toxenv: black - - name: flake8 + - name: ruff python: "3.12" - toxenv: flake8 + toxenv: ruff steps: - uses: actions/checkout@v4 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..57a1e683 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,23 @@ +repos: + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.2.2 + hooks: + - id: ruff + args: [--fix] + + - repo: https://github.com/psf/black + rev: 24.2.0 + hooks: + - id: black + language_version: python3.12 + + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: end-of-file-fixer + - id: trailing-whitespace + + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v3.1.0 + hooks: + - id: prettier diff --git a/.readthedocs.yaml b/.readthedocs.yaml index ad133429..981cae46 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -13,4 +13,4 @@ sphinx: python: install: - - requirements: docs/requirements.txt + - requirements: docs/requirements.txt diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7fc28965..34f9a188 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,6 +3,7 @@ as possible. Here is a quick guide. It's useful to have a virtual environment to work in. I use commands like these: + ``` $ cd pyanalyze $ python3 -m venv .venv @@ -13,7 +14,7 @@ $ pip install -e . ## Black -The code is formatted using [*Black*](https://black.readthedocs.io). +The code is formatted using [_Black_](https://black.readthedocs.io). You can run the formatter with: ``` diff --git a/docs/conf.py b/docs/conf.py index f63cf715..355e81a3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -12,6 +12,7 @@ # import os import sys + from pkg_resources import get_distribution sys.path.insert(0, os.path.abspath("..")) diff --git a/pyanalyze/analysis_lib.py b/pyanalyze/analysis_lib.py index 9dfaf5aa..1bccedde 100644 --- a/pyanalyze/analysis_lib.py +++ b/pyanalyze/analysis_lib.py @@ -7,11 +7,11 @@ import ast import linecache import os -from pathlib import Path import secrets import sys import types from dataclasses import dataclass +from pathlib import Path from typing import Callable, List, Mapping, Optional, Set, Union diff --git a/pyanalyze/annotated_types.py b/pyanalyze/annotated_types.py index 92cb276d..45aaefe0 100644 --- a/pyanalyze/annotated_types.py +++ b/pyanalyze/annotated_types.py @@ -4,10 +4,10 @@ """ +import enum from dataclasses import dataclass from datetime import datetime, timezone -import enum -from typing import Any, Callable, Iterable, Optional, Union, Type +from typing import Any, Callable, Iterable, Optional, Type, Union from pyanalyze.value import CanAssign, CanAssignContext, Value, flatten_values diff --git a/pyanalyze/annotations.py b/pyanalyze/annotations.py index ab8714fd..00ceec18 100644 --- a/pyanalyze/annotations.py +++ b/pyanalyze/annotations.py @@ -29,10 +29,10 @@ import contextlib import typing from collections.abc import Callable, Hashable -from dataclasses import dataclass, field, InitVar +from dataclasses import InitVar, dataclass, field from typing import ( + TYPE_CHECKING, Any, - cast, Container, ContextManager, Generator, @@ -43,20 +43,18 @@ Sequence, Set, Tuple, - TYPE_CHECKING, TypeVar, Union, + cast, ) -import typing_extensions import qcore - -from typing_extensions import ParamSpec, TypedDict, get_origin, get_args +import typing_extensions +from typing_extensions import ParamSpec, TypedDict, get_args, get_origin from pyanalyze.annotated_types import get_annotated_types_extension from . import type_evaluation - from .error_code import ErrorCode from .extensions import ( AsynqCallable, @@ -81,25 +79,20 @@ SigParameter, ) from .value import ( - _HashableValue, - DictIncompleteValue, - KVPair, - TypeAlias, - TypeAliasValue, - TypeIsExtension, - annotate_value, + NO_RETURN_VALUE, AnnotatedValue, AnySource, AnyValue, CallableValue, CustomCheckExtension, + DictIncompleteValue, Extension, GenericValue, HasAttrGuardExtension, KnownValue, + KVPair, MultiValuedValue, NewTypeValue, - NO_RETURN_VALUE, NoReturnGuardExtension, ParameterTypeGuardExtension, ParamSpecArgsValue, @@ -107,14 +100,19 @@ SelfTVV, SequenceValue, SubclassValue, + TypeAlias, + TypeAliasValue, TypedDictValue, TypedValue, TypeGuardExtension, + TypeIsExtension, TypeVarLike, TypeVarValue, - unite_values, UnpackedValue, Value, + _HashableValue, + annotate_value, + unite_values, ) if TYPE_CHECKING: diff --git a/pyanalyze/arg_spec.py b/pyanalyze/arg_spec.py index f703621a..8b0ad514 100644 --- a/pyanalyze/arg_spec.py +++ b/pyanalyze/arg_spec.py @@ -11,9 +11,9 @@ import inspect import sys import textwrap +import typing from dataclasses import dataclass, replace from types import FunctionType, MethodType, ModuleType -import typing from typing import ( Any, Callable, @@ -37,15 +37,12 @@ from typing_extensions import is_typeddict import pyanalyze + from . import implementation from .analysis_lib import is_positional_only_arg_name from .annotations import Context, RuntimeEvaluator, type_from_runtime -from .extensions import ( - CustomCheck, - get_overloads as pyanalyze_get_overloads, - get_type_evaluations, - TypeGuard, -) +from .extensions import CustomCheck, TypeGuard, get_type_evaluations +from .extensions import get_overloads as pyanalyze_get_overloads from .find_unused import used from .functions import translate_vararg_type from .options import Options, PyObjectSequenceOption @@ -63,15 +60,15 @@ ) from .signature import ( ANY_SIGNATURE, - ConcreteSignature, ELLIPSIS_PARAM, + ConcreteSignature, Impl, - make_bound_method, MaybeSignature, OverloadedSignature, ParameterKind, Signature, SigParameter, + make_bound_method, ) from .stacked_scopes import Composite, uniq_chain from .typeshed import TypeshedFinder @@ -80,18 +77,18 @@ AnyValue, CanAssignContext, Extension, - extract_typevars, GenericBases, GenericValue, KnownValue, KVPair, - make_coro_type, NewTypeValue, SubclassValue, TypedDictValue, TypedValue, TypeVarValue, Value, + extract_typevars, + make_coro_type, ) _GET_OVERLOADS = [] @@ -306,8 +303,8 @@ def unwrap(cls, typ: type, options: Options) -> type: _BUILTIN_KNOWN_SIGNATURES = [] try: - import pytest import _pytest + import pytest except ImportError: # if pytest is not installed in this environment, don't use it pass diff --git a/pyanalyze/attributes.py b/pyanalyze/attributes.py index 5a142073..d50bd55c 100644 --- a/pyanalyze/attributes.py +++ b/pyanalyze/attributes.py @@ -22,6 +22,7 @@ from .signature import MaybeSignature from .stacked_scopes import Composite from .value import ( + UNINITIALIZED_VALUE, AnnotatedValue, AnySource, AnyValue, @@ -33,16 +34,15 @@ KnownValue, KnownValueWithTypeVars, MultiValuedValue, + SubclassValue, SyntheticModuleValue, TypeAliasValue, - annotate_value, - set_self, - SubclassValue, TypedValue, TypeVarValue, UnboundMethodValue, - UNINITIALIZED_VALUE, Value, + annotate_value, + set_self, ) # these don't appear to be in the standard types module diff --git a/pyanalyze/boolability.py b/pyanalyze/boolability.py index c9034c8c..4ff9f40b 100644 --- a/pyanalyze/boolability.py +++ b/pyanalyze/boolability.py @@ -15,19 +15,19 @@ from pyanalyze.safe import safe_getattr, safe_hasattr from .value import ( + KNOWN_MUTABLE_TYPES, AnnotatedValue, AnyValue, DictIncompleteValue, - KNOWN_MUTABLE_TYPES, KnownValue, MultiValuedValue, - replace_known_sequence_value, SequenceValue, SubclassValue, TypedDictValue, TypedValue, UnboundMethodValue, Value, + replace_known_sequence_value, ) diff --git a/pyanalyze/checker.py b/pyanalyze/checker.py index 20f1d89f..577bbb4b 100644 --- a/pyanalyze/checker.py +++ b/pyanalyze/checker.py @@ -9,7 +9,7 @@ import sys import types from contextlib import contextmanager -from dataclasses import dataclass, field, InitVar +from dataclasses import InitVar, dataclass, field from typing import ( Callable, ContextManager, @@ -29,7 +29,6 @@ from .arg_spec import ArgSpecCache, GenericBases from .attributes import AttrContext, get_attribute from .node_visitor import Failure - from .options import Options, PyObjectSequenceOption from .reexport import ImplicitReexportTracker from .safe import is_instance_of_typing_name, is_typing_name, safe_getattr @@ -38,33 +37,33 @@ ANY_SIGNATURE, BoundMethodSignature, ConcreteSignature, - make_bound_method, MaybeSignature, OverloadedSignature, Signature, + make_bound_method, ) from .stacked_scopes import Composite from .suggested_type import CallableTracker -from .type_object import get_mro, TypeObject +from .type_object import TypeObject, get_mro from .typeshed import TypeshedFinder from .value import ( + UNINITIALIZED_VALUE, AnnotatedValue, AnyValue, CallableValue, - TypeAlias, - flatten_values, - is_union, KnownValue, KnownValueWithTypeVars, MultiValuedValue, SubclassValue, + TypeAlias, TypedValue, TypeVarValue, UnboundMethodValue, - UNINITIALIZED_VALUE, - unite_values, Value, VariableNameValue, + flatten_values, + is_union, + unite_values, ) _BaseProvider = Callable[[Union[type, super]], Set[type]] diff --git a/pyanalyze/extensions.py b/pyanalyze/extensions.py index bc26459d..f5024eba 100644 --- a/pyanalyze/extensions.py +++ b/pyanalyze/extensions.py @@ -9,12 +9,13 @@ """ +import enum import typing from collections import defaultdict from contextlib import contextmanager from dataclasses import dataclass, field -import enum from typing import ( + TYPE_CHECKING, Any, Callable, Container, @@ -23,17 +24,16 @@ Iterator, List, Optional, - overload as real_overload, Sequence, Tuple, - TYPE_CHECKING, Type, TypeVar, Union, ) +from typing import overload as real_overload import typing_extensions -from typing_extensions import Literal, NoReturn, Annotated +from typing_extensions import Annotated, Literal, NoReturn import pyanalyze diff --git a/pyanalyze/find_unused.py b/pyanalyze/find_unused.py index 77a855e8..eecba425 100644 --- a/pyanalyze/find_unused.py +++ b/pyanalyze/find_unused.py @@ -16,6 +16,7 @@ import qcore import pyanalyze + from . import extensions from .safe import safe_in diff --git a/pyanalyze/format_strings.py b/pyanalyze/format_strings.py index 1a7550a4..8caeffa1 100644 --- a/pyanalyze/format_strings.py +++ b/pyanalyze/format_strings.py @@ -28,12 +28,12 @@ AnnotatedValue, CanAssignContext, DictIncompleteValue, - flatten_values, KnownValue, - replace_known_sequence_value, SequenceValue, TypedValue, Value, + flatten_values, + replace_known_sequence_value, ) # refer to https://docs.python.org/2/library/stdtypes.html#string-formatting-operations diff --git a/pyanalyze/functions.py b/pyanalyze/functions.py index 099e20ea..68448b39 100644 --- a/pyanalyze/functions.py +++ b/pyanalyze/functions.py @@ -29,17 +29,17 @@ CanAssignContext, CanAssignError, GenericValue, - get_tv_map, KnownValue, - is_async_iterable, - is_iterable, - make_coro_type, SubclassValue, TypedValue, TypeVarValue, - unite_values, UnpackedValue, Value, + get_tv_map, + is_async_iterable, + is_iterable, + make_coro_type, + unite_values, ) FunctionDefNode = Union[ast.FunctionDef, ast.AsyncFunctionDef] diff --git a/pyanalyze/implementation.py b/pyanalyze/implementation.py index f2c0e1b3..6fd695cd 100644 --- a/pyanalyze/implementation.py +++ b/pyanalyze/implementation.py @@ -6,21 +6,20 @@ from itertools import product from typing import ( Callable, - Type, - cast, Dict, NewType, Optional, Sequence, + Type, TypeVar, Union, + cast, ) -from .annotated_types import MaxLen, MinLen - import qcore import typing_extensions +from .annotated_types import MaxLen, MinLen from .annotations import type_from_value from .error_code import ErrorCode from .extensions import assert_type, reveal_locals, reveal_type @@ -37,57 +36,57 @@ SigParameter, ) from .stacked_scopes import ( + NULL_CONSTRAINT, AbstractConstraint, - annotate_with_constraint, Composite, Constraint, ConstraintType, - NULL_CONSTRAINT, OrConstraint, PredicateProvider, VarnameWithOrigin, + annotate_with_constraint, ) from .value import ( + KNOWN_MUTABLE_TYPES, + NO_RETURN_VALUE, + UNINITIALIZED_VALUE, AnnotatedValue, AnySource, AnyValue, - CustomCheckExtension, - annotate_value, - assert_is_value, CallableValue, CanAssignContext, CanAssignError, - check_hashability, - concrete_values_from_iterable, + CustomCheckExtension, DictIncompleteValue, - dump_value, - flatten_values, GenericValue, HasAttrGuardExtension, - KNOWN_MUTABLE_TYPES, KnownValue, - kv_pairs_from_mapping, KVPair, MultiValuedValue, - NO_RETURN_VALUE, ParameterTypeGuardExtension, - replace_known_sequence_value, SequenceValue, SubclassValue, TypedDictValue, TypedValue, TypeVarValue, - UNINITIALIZED_VALUE, + Value, + annotate_value, + assert_is_value, + check_hashability, + concrete_values_from_iterable, + dump_value, + flatten_values, + kv_pairs_from_mapping, + replace_known_sequence_value, unite_values, unpack_values, - Value, ) _NO_ARG_SENTINEL = KnownValue(qcore.MarkerObject("no argument given")) def clean_up_implementation_fn_return( - return_value: Union[Value, ImplReturn] + return_value: Union[Value, ImplReturn], ) -> ImplReturn: if isinstance(return_value, Value): return ImplReturn(return_value) diff --git a/pyanalyze/importer.py b/pyanalyze/importer.py index cc7e637d..28a92d21 100644 --- a/pyanalyze/importer.py +++ b/pyanalyze/importer.py @@ -10,7 +10,7 @@ from functools import lru_cache from pathlib import Path from types import ModuleType -from typing import cast, Optional, Sequence, Tuple +from typing import Optional, Sequence, Tuple, cast @lru_cache() diff --git a/pyanalyze/name_check_visitor.py b/pyanalyze/name_check_visitor.py index 9bab457b..c6f17bdd 100644 --- a/pyanalyze/name_check_visitor.py +++ b/pyanalyze/name_check_visitor.py @@ -9,7 +9,6 @@ """ import abc -from abc import abstractmethod import ast import asyncio import collections @@ -26,6 +25,7 @@ import traceback import types import typing +from abc import abstractmethod from argparse import ArgumentParser from dataclasses import dataclass from itertools import chain @@ -56,50 +56,48 @@ import typeshed_client from typing_extensions import Annotated, Protocol, get_args, get_origin -from .annotated_types import Gt, Ge, Le, Lt - from . import attributes, format_strings, importer, node_visitor, type_evaluation from .analysis_lib import get_attribute_path +from .annotated_types import Ge, Gt, Le, Lt from .annotations import ( + SyntheticEvaluator, is_context_manager_type, is_instance_of_typing_name, is_typing_name, - SyntheticEvaluator, type_from_annotations, type_from_value, ) -from .arg_spec import ArgSpecCache, IgnoredCallees, is_dot_asynq_function, UnwrapClass +from .arg_spec import ArgSpecCache, IgnoredCallees, UnwrapClass, is_dot_asynq_function from .asynq_checker import AsynqChecker from .boolability import Boolability, get_boolability from .checker import Checker, CheckerAttrContext from .error_code import ERROR_DESCRIPTION, ErrorCode from .extensions import ( + ParameterTypeGuard, assert_error, evaluated, overload, - real_overload, - ParameterTypeGuard, patch_typing_overload, + real_overload, ) from .find_unused import UnusedObjectFinder, used from .functions import ( + IMPLICIT_CLASSMETHODS, AsyncFunctionKind, AsyncProxyDecorators, AsynqDecorators, - compute_parameters, - compute_value_of_function, FunctionDefNode, FunctionInfo, FunctionNode, FunctionResult, GeneratorValue, - IMPLICIT_CLASSMETHODS, ReturnT, SendT, YieldT, + compute_parameters, + compute_value_of_function, ) from .options import ( - add_arguments, BooleanOption, ConcatenatedOption, ConfigOption, @@ -108,6 +106,7 @@ Options, PyObjectSequenceOption, StringSequenceOption, + add_arguments, ) from .patma import PatmaVisitor from .predicates import EqualsPredicate, InPredicate @@ -125,8 +124,8 @@ from .signature import ( ANY_SIGNATURE, ARGS, - ConcreteSignature, KWARGS, + ConcreteSignature, MaybeSignature, OverloadedSignature, ParameterKind, @@ -134,32 +133,32 @@ SigParameter, ) from .stacked_scopes import ( + EMPTY_ORIGIN, + FALSY_CONSTRAINT, + LEAVES_LOOP, + LEAVES_SCOPE, + NULL_CONSTRAINT, + TRUTHY_CONSTRAINT, AbstractConstraint, AndConstraint, - annotate_with_constraint, Composite, CompositeIndex, - constrain_value, Constraint, ConstraintType, - EMPTY_ORIGIN, EquivalentConstraint, - extract_constraints, - FALSY_CONSTRAINT, FunctionScope, - LEAVES_LOOP, - LEAVES_SCOPE, - NULL_CONSTRAINT, OrConstraint, PredicateProvider, ScopeType, StackedScopes, SubScope, - TRUTHY_CONSTRAINT, Varname, VarnameOrigin, VarnameWithOrigin, VisitorState, + annotate_with_constraint, + constrain_value, + extract_constraints, ) from .suggested_type import ( CallArgs, @@ -167,21 +166,15 @@ prepare_type, should_suggest_type, ) -from .type_object import get_mro, TypeObject +from .type_object import TypeObject, get_mro from .typeshed import TypeshedFinder from .value import ( + NO_RETURN_VALUE, SYS_PLATFORM_EXTENSION, SYS_VERSION_INFO_EXTENSION, + UNINITIALIZED_VALUE, + VOID, AlwaysPresentExtension, - CustomCheckExtension, - DefiniteValueExtension, - DeprecatedExtension, - SkipDeprecatedExtension, - TypeAlias, - TypeAliasValue, - TypeGuardExtension, - TypeIsExtension, - annotate_value, AnnotatedValue, AnySource, AnyValue, @@ -190,44 +183,49 @@ CallableValue, CanAssign, CanAssignError, - check_hashability, - concrete_values_from_iterable, ConstraintExtension, + CustomCheckExtension, + DefiniteValueExtension, + DeprecatedExtension, DictIncompleteValue, - flatten_values, GenericBases, GenericValue, - get_tv_map, - is_async_iterable, - is_iterable, - is_union, KnownValue, - kv_pairs_from_mapping, KVPair, - make_coro_type, MultiValuedValue, - NO_RETURN_VALUE, NoReturnConstraintExtension, ReferencingValue, - replace_known_sequence_value, SequenceValue, - set_self, - stringify_object, + SkipDeprecatedExtension, SubclassValue, + TypeAlias, + TypeAliasValue, TypedValue, + TypeGuardExtension, + TypeIsExtension, TypeVarValue, - unannotate_value, UnboundMethodValue, - UNINITIALIZED_VALUE, + Value, + annotate_value, + check_hashability, + concrete_values_from_iterable, + flatten_values, + get_tv_map, + is_async_iterable, + is_iterable, + is_union, + kv_pairs_from_mapping, + make_coro_type, + replace_known_sequence_value, + set_self, + stringify_object, + unannotate_value, unite_and_simplify, unite_values, unpack_values, - Value, - VOID, ) from .yield_checker import YieldChecker - if sys.version_info >= (3, 11): TryNode = ast.Try | ast.TryStar else: @@ -3232,7 +3230,7 @@ def visit_Dict(self, node: ast.Dict) -> Value: try: already_exists = key in ret - except TypeError as e: + except TypeError: continue if already_exists: diff --git a/pyanalyze/node_visitor.py b/pyanalyze/node_visitor.py index 837b8056..fb8b15fc 100644 --- a/pyanalyze/node_visitor.py +++ b/pyanalyze/node_visitor.py @@ -14,7 +14,6 @@ import logging import os import os.path -from pathlib import Path import re import subprocess import sys @@ -23,6 +22,7 @@ from contextlib import contextmanager from dataclasses import dataclass from enum import Enum +from pathlib import Path from types import ModuleType from typing import ( Any, diff --git a/pyanalyze/options.py b/pyanalyze/options.py index 47b2fd1e..241a17af 100644 --- a/pyanalyze/options.py +++ b/pyanalyze/options.py @@ -32,7 +32,6 @@ import tomli from .error_code import ErrorCode - from .find_unused import used from .safe import safe_in diff --git a/pyanalyze/patma.py b/pyanalyze/patma.py index 343ad9a4..0ff4cf27 100644 --- a/pyanalyze/patma.py +++ b/pyanalyze/patma.py @@ -24,24 +24,25 @@ import qcore import pyanalyze + from .annotations import type_from_value from .error_code import ErrorCode from .extensions import CustomCheck - from .implementation import len_of_value from .predicates import EqualsPredicate, IsAssignablePredicate from .signature import MappingValue from .stacked_scopes import ( + NULL_CONSTRAINT, AbstractConstraint, AndConstraint, Composite, - constrain_value, Constraint, ConstraintType, - NULL_CONSTRAINT, OrConstraint, + constrain_value, ) from .value import ( + UNINITIALIZED_VALUE, AnnotatedValue, AnySource, AnyValue, @@ -50,20 +51,19 @@ CanAssignError, CustomCheckExtension, DictIncompleteValue, - flatten_values, - is_overlapping, KnownValue, - kv_pairs_from_mapping, KVPair, - replace_known_sequence_value, SequenceValue, SubclassValue, TypedValue, + Value, + flatten_values, + is_overlapping, + kv_pairs_from_mapping, + replace_known_sequence_value, unannotate, - UNINITIALIZED_VALUE, unite_values, unpack_values, - Value, ) try: diff --git a/pyanalyze/predicates.py b/pyanalyze/predicates.py index 32cde7d2..fc11f19f 100644 --- a/pyanalyze/predicates.py +++ b/pyanalyze/predicates.py @@ -11,19 +11,19 @@ from .safe import safe_issubclass from .value import ( + NO_RETURN_VALUE, AnnotatedValue, AnyValue, CanAssignContext, - is_overlapping, KnownValue, MultiValuedValue, - NO_RETURN_VALUE, SubclassValue, TypedValue, TypeVarValue, + Value, + is_overlapping, unannotate, unite_values, - Value, ) diff --git a/pyanalyze/reexport.py b/pyanalyze/reexport.py index a959e7e8..56b31c08 100644 --- a/pyanalyze/reexport.py +++ b/pyanalyze/reexport.py @@ -6,12 +6,11 @@ from ast import AST from collections import defaultdict -from dataclasses import dataclass, field, InitVar +from dataclasses import InitVar, dataclass, field from typing import Callable, Dict, List, Set, Tuple from .error_code import ErrorCode from .node_visitor import ErrorContext - from .options import Options, PyObjectSequenceOption _ReexportConfigProvider = Callable[["ImplicitReexportTracker"], None] diff --git a/pyanalyze/runtime.py b/pyanalyze/runtime.py index 6f1ec718..3ef2097d 100644 --- a/pyanalyze/runtime.py +++ b/pyanalyze/runtime.py @@ -4,13 +4,14 @@ """ +from functools import lru_cache from typing import Optional + import pyanalyze -from functools import lru_cache -from .value import CanAssignError, KnownValue from .annotations import type_from_runtime from .find_unused import used +from .value import CanAssignError, KnownValue @lru_cache(maxsize=None) diff --git a/pyanalyze/signature.py b/pyanalyze/signature.py index e54f7d35..5ac62970 100644 --- a/pyanalyze/signature.py +++ b/pyanalyze/signature.py @@ -14,6 +14,7 @@ from dataclasses import dataclass, field, replace from types import FunctionType, MethodType from typing import ( + TYPE_CHECKING, Any, Callable, ClassVar, @@ -26,7 +27,6 @@ Sequence, Set, Tuple, - TYPE_CHECKING, TypeVar, Union, ) @@ -34,82 +34,82 @@ import asynq import qcore from qcore.helpers import safe_str -from typing_extensions import assert_never, Literal, Protocol, Self +from typing_extensions import Literal, Protocol, Self, assert_never from pyanalyze.predicates import IsAssignablePredicate from .error_code import ErrorCode -from .safe import safe_getattr from .node_visitor import Replacement from .options import IntegerOption +from .safe import safe_getattr from .stacked_scopes import ( + NULL_CONSTRAINT, AbstractConstraint, AndConstraint, Composite, Constraint, ConstraintType, - NULL_CONSTRAINT, OrConstraint, VarnameWithOrigin, ) from .type_evaluation import ( ARGS, DEFAULT, + KWARGS, + UNKNOWN, EvalContext, Evaluator, - KWARGS, Position, - UNKNOWN, ) from .typevar import resolve_bounds_map from .value import ( - SelfT, - TypeIsExtension, - annotate_value, + NO_RETURN_VALUE, AnnotatedValue, AnySource, AnyValue, AsyncTaskIncompleteValue, BoundsMap, CallableValue, - can_assign_and_used_any, CanAssign, CanAssignContext, CanAssignError, - concrete_values_from_iterable, ConstraintExtension, DictIncompleteValue, - extract_typevars, - flatten_values, GenericValue, - get_tv_map, HasAttrExtension, HasAttrGuardExtension, KnownValue, KVPair, LowerBound, MultiValuedValue, - NO_RETURN_VALUE, NoReturnConstraintExtension, NoReturnGuardExtension, ParameterTypeGuardExtension, ParamSpecArgsValue, ParamSpecKwargsValue, - is_iterable, - replace_known_sequence_value, + SelfT, SequenceValue, - stringify_object, TypedDictValue, TypedValue, TypeGuardExtension, + TypeIsExtension, TypeVarLike, TypeVarMap, TypeVarValue, + Value, + annotate_value, + can_assign_and_used_any, + concrete_values_from_iterable, + extract_typevars, + flatten_values, + get_tv_map, + is_iterable, + replace_known_sequence_value, + stringify_object, unannotate, unannotate_value, unify_bounds_maps, unite_values, - Value, ) if TYPE_CHECKING: diff --git a/pyanalyze/stacked_scopes.py b/pyanalyze/stacked_scopes.py index a138f954..c3cc13cd 100644 --- a/pyanalyze/stacked_scopes.py +++ b/pyanalyze/stacked_scopes.py @@ -24,7 +24,7 @@ import contextlib import enum from ast import AST -from collections import defaultdict, OrderedDict +from collections import OrderedDict, defaultdict from dataclasses import dataclass, field, replace from itertools import chain from types import ModuleType @@ -53,23 +53,23 @@ from .extensions import reveal_type from .safe import safe_equals, safe_issubclass from .value import ( - annotate_value, + NO_RETURN_VALUE, + UNINITIALIZED_VALUE, AnnotatedValue, AnySource, AnyValue, ConstraintExtension, - flatten_values, KnownValue, MultiValuedValue, - NO_RETURN_VALUE, ReferencingValue, SubclassValue, TypedValue, TypeVarMap, - UNINITIALIZED_VALUE, + Value, + annotate_value, + flatten_values, unite_and_simplify, unite_values, - Value, ) T = TypeVar("T") diff --git a/pyanalyze/stubs/_pyanalyze_tests-stubs/callable.pyi b/pyanalyze/stubs/_pyanalyze_tests-stubs/callable.pyi index ab5fc195..bc7a0aa5 100644 --- a/pyanalyze/stubs/_pyanalyze_tests-stubs/callable.pyi +++ b/pyanalyze/stubs/_pyanalyze_tests-stubs/callable.pyi @@ -1,6 +1,4 @@ from typing import Any -from typing import Any - class StubCallable: def __call__(self, *args: Any, **kwds: Any) -> Any: ... diff --git a/pyanalyze/stubs/_pyanalyze_tests-stubs/deprecated.pyi b/pyanalyze/stubs/_pyanalyze_tests-stubs/deprecated.pyi index a289fd50..f03d6d4b 100644 --- a/pyanalyze/stubs/_pyanalyze_tests-stubs/deprecated.pyi +++ b/pyanalyze/stubs/_pyanalyze_tests-stubs/deprecated.pyi @@ -1,6 +1,7 @@ -from pyanalyze.extensions import deprecated from typing import overload +from pyanalyze.extensions import deprecated + @overload @deprecated("int support is deprecated") def deprecated_overload(x: int) -> int: ... diff --git a/pyanalyze/stubs/_pyanalyze_tests-stubs/evaluated.pyi b/pyanalyze/stubs/_pyanalyze_tests-stubs/evaluated.pyi index ac34c59c..5df642e1 100644 --- a/pyanalyze/stubs/_pyanalyze_tests-stubs/evaluated.pyi +++ b/pyanalyze/stubs/_pyanalyze_tests-stubs/evaluated.pyi @@ -1,4 +1,4 @@ -from typing import Any, BinaryIO, IO, TextIO +from typing import IO, Any, BinaryIO, TextIO from pyanalyze.extensions import evaluated diff --git a/pyanalyze/stubs/_pyanalyze_tests-stubs/initnew.pyi b/pyanalyze/stubs/_pyanalyze_tests-stubs/initnew.pyi index 037ea20d..fbcacd63 100644 --- a/pyanalyze/stubs/_pyanalyze_tests-stubs/initnew.pyi +++ b/pyanalyze/stubs/_pyanalyze_tests-stubs/initnew.pyi @@ -1,4 +1,4 @@ -from typing import Generic, Iterable, Iterator, overload, TypeVar +from typing import Generic, Iterable, Iterator, TypeVar, overload _T = TypeVar("_T") diff --git a/pyanalyze/stubs/_pyanalyze_tests-stubs/recursion.pyi b/pyanalyze/stubs/_pyanalyze_tests-stubs/recursion.pyi index 1e87d68b..43c99a4c 100644 --- a/pyanalyze/stubs/_pyanalyze_tests-stubs/recursion.pyi +++ b/pyanalyze/stubs/_pyanalyze_tests-stubs/recursion.pyi @@ -1,4 +1,5 @@ from typing import AnyStr, ContextManager, Dict, Union + from typing_extensions import TypeAlias class _ScandirIterator(ContextManager[_ScandirIterator[AnyStr]]): diff --git a/pyanalyze/suggested_type.py b/pyanalyze/suggested_type.py index 1e42f1cf..68adcfc2 100644 --- a/pyanalyze/suggested_type.py +++ b/pyanalyze/suggested_type.py @@ -12,10 +12,10 @@ from .error_code import ErrorCode from .node_visitor import ErrorContext, Failure - from .safe import safe_getattr, safe_isinstance from .signature import Signature from .value import ( + NO_RETURN_VALUE, AnnotatedValue, AnySource, AnyValue, @@ -24,16 +24,15 @@ GenericValue, KnownValue, MultiValuedValue, - NO_RETURN_VALUE, - replace_known_sequence_value, SequenceValue, - stringify_object, SubclassValue, TypedDictValue, TypedValue, - unite_values, Value, VariableNameValue, + replace_known_sequence_value, + stringify_object, + unite_values, ) CallArgs = Mapping[str, Value] diff --git a/pyanalyze/test.toml b/pyanalyze/test.toml index 22c456e8..f3281b61 100644 --- a/pyanalyze/test.toml +++ b/pyanalyze/test.toml @@ -20,4 +20,4 @@ disallowed_imports = [ "getopt", "email.quoprimime", "xml", -] \ No newline at end of file +] diff --git a/pyanalyze/test_annotated_types.py b/pyanalyze/test_annotated_types.py index 54485f5e..c7e58981 100644 --- a/pyanalyze/test_annotated_types.py +++ b/pyanalyze/test_annotated_types.py @@ -6,9 +6,10 @@ class TestAnnotatedTypesAnnotations(TestNameCheckVisitorBase): @assert_passes() def test_gt(self): - from typing_extensions import Annotated from typing import Any - from annotated_types import Gt, Ge + + from annotated_types import Ge, Gt + from typing_extensions import Annotated def takes_gt_5(x: Annotated[Any, Gt(5)]) -> None: pass @@ -35,9 +36,10 @@ def capybara( @assert_passes() def test_ge(self): - from typing_extensions import Annotated from typing import Any + from annotated_types import Ge, Gt + from typing_extensions import Annotated def takes_ge_5(x: Annotated[Any, Ge(5)]) -> None: pass @@ -65,9 +67,10 @@ def capybara( @assert_passes() def test_lt(self): - from typing_extensions import Annotated from typing import Any - from annotated_types import Lt, Le + + from annotated_types import Le, Lt + from typing_extensions import Annotated def takes_lt_5(x: Annotated[Any, Lt(5)]) -> None: pass @@ -93,9 +96,10 @@ def capybara( @assert_passes() def test_le(self): - from typing_extensions import Annotated from typing import Any + from annotated_types import Le, Lt + from typing_extensions import Annotated def takes_le_5(x: Annotated[Any, Le(5)]) -> None: pass @@ -123,8 +127,8 @@ def capybara( @assert_passes() def test_multiple_of(self): - from typing_extensions import Annotated from annotated_types import MultipleOf + from typing_extensions import Annotated def takes_multiple_of_10(x: Annotated[int, MultipleOf(10)]) -> None: pass @@ -147,8 +151,8 @@ def capybara( @assert_passes() def test_min_max_len(self): - from typing_extensions import Annotated, TypedDict, NotRequired - from annotated_types import MinLen, MaxLen, Len + from annotated_types import Len, MaxLen, MinLen + from typing_extensions import Annotated, NotRequired, TypedDict def takes_min_len_5(x: Annotated[object, MinLen(5)]) -> None: pass @@ -206,9 +210,10 @@ def capybara( @assert_passes() def test_timezone(self): - from typing_extensions import Annotated + from datetime import datetime, timedelta, timezone + from annotated_types import Timezone - from datetime import datetime, timezone, timedelta + from typing_extensions import Annotated def takes_naive(x: Annotated[datetime, Timezone(None)]) -> None: pass @@ -241,8 +246,8 @@ def capybara(dt: datetime) -> None: @assert_passes() def test_predicate(self): - from typing_extensions import Annotated from annotated_types import Predicate + from typing_extensions import Annotated def takes_upper(x: Annotated[str, Predicate(str.isupper)]) -> None: pass @@ -260,8 +265,8 @@ def capybara( class TestInferAnnotations(TestNameCheckVisitorBase): @assert_passes() def test_infer_gt(self): - from typing_extensions import Annotated from annotated_types import Gt + from typing_extensions import Annotated def takes_gt_5(x: Annotated[int, Gt(5)]) -> None: pass @@ -282,8 +287,8 @@ def capybara(i: int) -> None: @assert_passes() def test_len(self): + from annotated_types import Len, MaxLen, MinLen from typing_extensions import Annotated - from annotated_types import MinLen, MaxLen, Len def takes_len_5(x: Annotated[str, Len(5)]) -> None: pass diff --git a/pyanalyze/test_annotations.py b/pyanalyze/test_annotations.py index 657e4ecf..2a337245 100644 --- a/pyanalyze/test_annotations.py +++ b/pyanalyze/test_annotations.py @@ -408,7 +408,8 @@ def capybara( @skip_before((3, 9)) def test_builtin_tuples_string(self): - self.assert_passes(""" + self.assert_passes( + """ from __future__ import annotations from collections.abc import Iterable from typing import Union @@ -434,7 +435,8 @@ def capybara( assert_is_value(t, t_str_int) for elt in returner(): assert_is_value(elt, t_str_int) - """) + """ + ) @assert_passes() def test_invalid_annotation(self): @@ -490,14 +492,16 @@ def capybara(x: Pattern[str]): assert_is_value(x, GenericValue(_Pattern, [TypedValue(str)])) def test_future_annotations(self): - self.assert_passes(""" + self.assert_passes( + """ from __future__ import annotations from typing import List def f(x: int, y: List[str]): assert_is_value(x, TypedValue(int)) assert_is_value(y, GenericValue(list, [TypedValue(str)])) - """) + """ + ) @assert_passes() def test_final(self): @@ -556,7 +560,8 @@ def capybara(x: list[int], y: tuple[int, str], z: tuple[int, ...]) -> None: @skip_before((3, 9)) def test_pep604(self): - self.assert_passes(""" + self.assert_passes( + """ from __future__ import annotations def capybara(x: int | None, y: int | str) -> None: @@ -566,11 +571,13 @@ def capybara(x: int | None, y: int | str) -> None: def caller(): capybara(1, 2) capybara(None, "x") - """) + """ + ) @skip_before((3, 10)) def test_pep604_runtime(self): - self.assert_passes(""" + self.assert_passes( + """ def capybara(x: int | None, y: int | str) -> None: assert_is_value(x, MultiValuedValue([TypedValue(int), KnownValue(None)])) assert_is_value(y, MultiValuedValue([TypedValue(int), TypedValue(str)])) @@ -578,7 +585,8 @@ def capybara(x: int | None, y: int | str) -> None: def caller(): capybara(1, 2) capybara(None, "x") - """) + """ + ) @assert_passes() def test_stringified_ops(self): @@ -605,7 +613,7 @@ def capybara(x: "Union[List[T], Set[T]][int]"): @assert_passes() def test_initvar(self): - from dataclasses import dataclass, InitVar + from dataclasses import InitVar, dataclass @dataclass class Capybara: @@ -945,8 +953,8 @@ def caller(): @assert_passes() def test_bare_callable(self): - import typing import collections.abc + import typing def want_typing(c: typing.Callable) -> None: pass @@ -1267,8 +1275,8 @@ def test_reverse_direction(self): CanAssign, CanAssignContext, CanAssignError, - flatten_values, Value, + flatten_values, ) class DontAssignToAny(CustomCheck): @@ -1300,7 +1308,7 @@ def deep(x: Annotated[List[int], NoAny(deep=True)]) -> None: pass def none_at_all( - x: Annotated[List[int], NoAny(deep=True, allowed_sources=frozenset())] + x: Annotated[List[int], NoAny(deep=True, allowed_sources=frozenset())], ) -> None: pass @@ -1337,9 +1345,9 @@ def test_not_none(self) -> None: CanAssign, CanAssignContext, CanAssignError, - flatten_values, KnownValue, Value, + flatten_values, ) @dataclass(frozen=True) @@ -1374,11 +1382,11 @@ def test_greater_than(self) -> None: CanAssign, CanAssignContext, CanAssignError, - flatten_values, KnownValue, TypeVarMap, TypeVarValue, Value, + flatten_values, ) @dataclass(frozen=True) @@ -1685,8 +1693,9 @@ def capybara() -> None: @assert_passes() def test_concatenate(self): - from typing_extensions import ParamSpec, Concatenate - from typing import Callable, TypeVar, List + from typing import Callable, List, TypeVar + + from typing_extensions import Concatenate, ParamSpec P = ParamSpec("P") T = TypeVar("T") @@ -1861,7 +1870,7 @@ def capybara( class TestMissinGenericParameters(TestNameCheckVisitorBase): @assert_passes() def test(self): - from typing import List, Set, Dict + from typing import Dict, List, Set def capybara( x: list, # E: missing_generic_parameters diff --git a/pyanalyze/test_arg_spec.py b/pyanalyze/test_arg_spec.py index 2c70b418..a1c44a5a 100644 --- a/pyanalyze/test_arg_spec.py +++ b/pyanalyze/test_arg_spec.py @@ -6,7 +6,6 @@ from asynq import asynq from .arg_spec import is_dot_asynq_function - from .checker import Checker from .signature import BoundMethodSignature, ParameterKind, Signature, SigParameter from .stacked_scopes import Composite @@ -19,12 +18,12 @@ from .value import ( AnySource, AnyValue, - assert_is_value, GenericValue, KnownValue, MultiValuedValue, NewTypeValue, TypedValue, + assert_is_value, ) T = TypeVar("T") diff --git a/pyanalyze/test_ast_annotator.py b/pyanalyze/test_ast_annotator.py index 6fff4645..6f1a3e77 100644 --- a/pyanalyze/test_ast_annotator.py +++ b/pyanalyze/test_ast_annotator.py @@ -3,9 +3,8 @@ from typing import Callable, Type from .analysis_lib import files_with_extension_from_directory - from .ast_annotator import annotate_code, annotate_file -from .value import KnownValue, unannotate, Value +from .value import KnownValue, Value, unannotate def _check_inferred_value( @@ -25,23 +24,28 @@ def test_annotate_code() -> None: _check_inferred_value(tree, ast.Constant, KnownValue(1)) _check_inferred_value(tree, ast.Name, KnownValue(1)) - tree = annotate_code(""" + tree = annotate_code( + """ class X: def __init__(self): self.a = 1 - """) + """ + ) _check_inferred_value(tree, ast.Attribute, KnownValue(1)) - tree = annotate_code(""" + tree = annotate_code( + """ class X: def __init__(self): self.a = 1 x = X() x.a + 1 - """) + """ + ) _check_inferred_value(tree, ast.BinOp, KnownValue(2)) - tree = annotate_code(""" + tree = annotate_code( + """ class A: def __init__(self): self.a = 1 @@ -52,7 +56,8 @@ def bla(self): a = A() b = a.bla() - """) + """ + ) _check_inferred_value(tree, ast.Name, KnownValue(1), lambda node: node.id == "b") diff --git a/pyanalyze/test_async_await.py b/pyanalyze/test_async_await.py index b41343f2..98d06847 100644 --- a/pyanalyze/test_async_await.py +++ b/pyanalyze/test_async_await.py @@ -222,7 +222,7 @@ async def capybara(): @assert_passes() def test_async_def_from_typeshed(self): - from asyncio.streams import open_connection, StreamReader, StreamWriter + from asyncio.streams import StreamReader, StreamWriter, open_connection from pyanalyze.value import make_coro_type diff --git a/pyanalyze/test_asynq.py b/pyanalyze/test_asynq.py index b456dc3c..3c33208d 100644 --- a/pyanalyze/test_asynq.py +++ b/pyanalyze/test_asynq.py @@ -18,7 +18,7 @@ class TestBadAsyncYield(TestNameCheckVisitorBase): @assert_passes() def test_const_future(self): - from asynq import asynq, ConstFuture, FutureBase + from asynq import ConstFuture, FutureBase, asynq @asynq() def capybara(condition): @@ -110,7 +110,7 @@ class TestTaskNeedsYield(TestNameCheckVisitorBase): # constfuture, async, and yielded because changes between Python 3.7 and 3.8 @assert_fails(ErrorCode.task_needs_yield) def test_constfuture(self): - from asynq import asynq, ConstFuture + from asynq import ConstFuture, asynq @asynq() def bad_async_fn(): @@ -162,7 +162,7 @@ def capybara(oid): class TestReturn(TestNameCheckVisitorBase): @assert_passes() def test_type_inference(self): - from asynq import async_proxy, AsyncTask, asynq, ConstFuture, FutureBase + from asynq import AsyncTask, ConstFuture, FutureBase, async_proxy, asynq def returns_3(): return 3 diff --git a/pyanalyze/test_asynq_checker.py b/pyanalyze/test_asynq_checker.py index 6834e198..a3026207 100644 --- a/pyanalyze/test_asynq_checker.py +++ b/pyanalyze/test_asynq_checker.py @@ -8,13 +8,13 @@ from .test_name_check_visitor import TestNameCheckVisitorBase from .test_node_visitor import assert_passes from .tests import ( - async_fn, ASYNQ_METHOD_NAME, + PropertyObject, + Subclass, + async_fn, cached_fn, l0cached_async_fn, - PropertyObject, proxied_fn, - Subclass, ) from .value import KnownValue, TypedValue, UnboundMethodValue @@ -137,7 +137,7 @@ def capybara(): def test_pure_async_call(self): from asynq import asynq, result - from pyanalyze.tests import async_fn, CheckedForAsynq + from pyanalyze.tests import CheckedForAsynq, async_fn class Capybara(CheckedForAsynq): def init(self, qid): @@ -150,7 +150,7 @@ def tree(self): @assert_passes() def test_impure_async_call(self): - from pyanalyze.tests import async_fn, CheckedForAsynq + from pyanalyze.tests import CheckedForAsynq, async_fn class Capybara(CheckedForAsynq): def init(self, aid): @@ -162,7 +162,7 @@ def tree(self): @assert_passes() def test_impure_cached_call(self): - from pyanalyze.tests import cached_fn, CheckedForAsynq + from pyanalyze.tests import CheckedForAsynq, cached_fn class Capybara(CheckedForAsynq): def init(self, uid): @@ -176,7 +176,7 @@ def tree(self): def test_impure_async_call_in_component(self): from asynq import asynq - from pyanalyze.tests import cached_fn, CheckedForAsynq + from pyanalyze.tests import CheckedForAsynq, cached_fn class Capybara(CheckedForAsynq): def init(self, uid): @@ -261,7 +261,7 @@ def init(self, poid): @assert_passes() def test_no_error_in_classmethod(self): - from pyanalyze.tests import cached_fn, CheckedForAsynq + from pyanalyze.tests import CheckedForAsynq, cached_fn class Capybara(CheckedForAsynq): @classmethod diff --git a/pyanalyze/test_attributes.py b/pyanalyze/test_attributes.py index 9fb732b3..a2063cab 100644 --- a/pyanalyze/test_attributes.py +++ b/pyanalyze/test_attributes.py @@ -7,12 +7,12 @@ AnnotatedValue, AnySource, AnyValue, - assert_is_value, GenericValue, KnownValue, MultiValuedValue, TypedValue, UnboundMethodValue, + assert_is_value, ) _global_dict: Dict[Union[int, str], float] = {} @@ -165,9 +165,10 @@ def capybara(): @assert_passes() def test_only_known_attributes(self): from dataclasses import dataclass - from pydantic import BaseModel from typing import NamedTuple + from pydantic import BaseModel + @dataclass class DC: a: int @@ -207,9 +208,10 @@ def test(x: Union[Capybara, Paca]) -> None: @assert_passes() def test_annotated_known(self): + from typing import Any, cast from unittest.mock import ANY + from typing_extensions import Annotated, Literal - from typing import Any, cast from pyanalyze.extensions import LiteralOnly from pyanalyze.stacked_scopes import Composite, VarnameWithOrigin diff --git a/pyanalyze/test_boolability.py b/pyanalyze/test_boolability.py index 446afa90..8a38b222 100644 --- a/pyanalyze/test_boolability.py +++ b/pyanalyze/test_boolability.py @@ -6,13 +6,13 @@ from .test_name_check_visitor import TestNameCheckVisitorBase from .test_node_visitor import assert_passes from .value import ( + NO_RETURN_VALUE, AnnotatedValue, AnySource, AnyValue, DictIncompleteValue, KnownValue, KVPair, - NO_RETURN_VALUE, SequenceValue, TypedDictValue, TypedValue, diff --git a/pyanalyze/test_config.py b/pyanalyze/test_config.py index 669660e0..ad2a3fc6 100644 --- a/pyanalyze/test_config.py +++ b/pyanalyze/test_config.py @@ -11,7 +11,6 @@ from .arg_spec import ArgSpecCache from .error_code import ErrorCode, register_error_code from .find_unused import used - from .options import Options from .signature import ( CallContext, diff --git a/pyanalyze/test_definite_value.py b/pyanalyze/test_definite_value.py index 76562058..43d95525 100644 --- a/pyanalyze/test_definite_value.py +++ b/pyanalyze/test_definite_value.py @@ -8,6 +8,7 @@ class TestSysPlatform(TestNameCheckVisitorBase): def test(self): import os import sys + from typing_extensions import assert_type def capybara() -> None: @@ -22,6 +23,7 @@ class TestSysVersion(TestNameCheckVisitorBase): def test(self): import ast import sys + from typing_extensions import assert_type if sys.version_info >= (3, 10): diff --git a/pyanalyze/test_deprecated.py b/pyanalyze/test_deprecated.py index dab77dd5..afdd74c9 100644 --- a/pyanalyze/test_deprecated.py +++ b/pyanalyze/test_deprecated.py @@ -7,10 +7,15 @@ class TestStub(TestNameCheckVisitorBase): @assert_passes() def test(self): def capybara(): - from _pyanalyze_tests.deprecated import deprecated_overload - from _pyanalyze_tests.deprecated import deprecated_function # E: deprecated + print("keep") from _pyanalyze_tests.deprecated import DeprecatedCapybara # E: deprecated + print("these imports") + from _pyanalyze_tests.deprecated import deprecated_function # E: deprecated + + print("separate") + from _pyanalyze_tests.deprecated import deprecated_overload + deprecated_overload(1) # E: deprecated deprecated_overload("x") @@ -24,9 +29,9 @@ def capybara(): def test_multiline_import(self): def capybara(): from _pyanalyze_tests.deprecated import ( - deprecated_overload, - deprecated_function, # E: deprecated DeprecatedCapybara, # E: deprecated + deprecated_function, # E: deprecated + deprecated_overload, ) return [deprecated_function, deprecated_overload, DeprecatedCapybara] diff --git a/pyanalyze/test_enum.py b/pyanalyze/test_enum.py index 8938c833..f6b9850a 100644 --- a/pyanalyze/test_enum.py +++ b/pyanalyze/test_enum.py @@ -71,6 +71,7 @@ class TestNarrowing(TestNameCheckVisitorBase): @assert_passes() def test_exhaustive(self): from enum import Enum + from typing_extensions import assert_never class X(Enum): @@ -117,10 +118,12 @@ def whatever(x): class TestEnumName(TestNameCheckVisitorBase): @assert_passes() def test(self): - from pyanalyze.extensions import EnumName import enum + from typing_extensions import assert_type + from pyanalyze.extensions import EnumName + class Rodent(enum.IntEnum): capybara = 1 agouti = 2 diff --git a/pyanalyze/test_extensions.py b/pyanalyze/test_extensions.py index 46484fbf..8e7c5c6e 100644 --- a/pyanalyze/test_extensions.py +++ b/pyanalyze/test_extensions.py @@ -1,9 +1,9 @@ import sys from types import FunctionType from typing import List, Optional, TypeVar, Union -from typing_extensions import get_args from qcore.asserts import AssertRaises +from typing_extensions import get_args from .extensions import AsynqCallable, get_overloads, overload from .safe import all_of_type diff --git a/pyanalyze/test_format_strings.py b/pyanalyze/test_format_strings.py index edf95dfb..b9036926 100644 --- a/pyanalyze/test_format_strings.py +++ b/pyanalyze/test_format_strings.py @@ -4,10 +4,10 @@ ConversionSpecifier, FormatString, IndexOrAttribute, - parse_format_string, PercentFormatString, ReplacementField, StarConversionSpecifier, + parse_format_string, ) from .test_name_check_visitor import TestNameCheckVisitorBase from .test_node_visitor import assert_passes @@ -16,14 +16,13 @@ from .value import ( AnySource, AnyValue, - assert_is_value, DictIncompleteValue, KnownValue, KVPair, TypedValue, + assert_is_value, ) - PERCENT_TESTCASES = [ ("%(a)s", (ConversionSpecifier("s", mapping_key="a"),), ("", "")), # all the things diff --git a/pyanalyze/test_functions.py b/pyanalyze/test_functions.py index e0563754..d02c3bde 100644 --- a/pyanalyze/test_functions.py +++ b/pyanalyze/test_functions.py @@ -219,7 +219,8 @@ def caller() -> None: class TestGenericFunctions(TestNameCheckVisitorBase): @skip_before((3, 12)) def test_generic(self): - self.assert_passes(""" + self.assert_passes( + """ from typing_extensions import assert_type def func[T](x: T) -> T: @@ -227,11 +228,13 @@ def func[T](x: T) -> T: def capybara(i: int): assert_type(func(i), int) - """) + """ + ) @skip_before((3, 12)) def test_generic_with_bound(self): - self.assert_passes(""" + self.assert_passes( + """ from typing_extensions import assert_type def func[T: int](x: T) -> T: @@ -241,4 +244,5 @@ def capybara(i: int, s: str, b: bool): assert_type(func(i), int) assert_type(func(b), bool) func(s) # E: incompatible_argument - """) + """ + ) diff --git a/pyanalyze/test_implementation.py b/pyanalyze/test_implementation.py index 24e4e139..f056dc62 100644 --- a/pyanalyze/test_implementation.py +++ b/pyanalyze/test_implementation.py @@ -3,19 +3,19 @@ from .test_node_visitor import assert_passes from .tests import make_simple_sequence from .value import ( + NO_RETURN_VALUE, AnySource, AnyValue, - assert_is_value, CallableValue, DictIncompleteValue, GenericValue, KnownValue, KVPair, MultiValuedValue, - NO_RETURN_VALUE, SequenceValue, SubclassValue, TypedValue, + assert_is_value, ) @@ -351,7 +351,7 @@ def capybara(x: Optional[int]): class TestCast(TestNameCheckVisitorBase): @assert_passes() def test(self): - from typing import cast, List + from typing import List, cast def capybara(): assert_is_value(cast(str, 1), TypedValue(str)) @@ -360,7 +360,7 @@ def capybara(): @assert_passes() def test_undefined_name(self): - from typing import cast, List + from typing import List, cast def capybara(): cast("List[fail]", 1) # E: undefined_name @@ -1332,9 +1332,10 @@ def capybara(o: object) -> None: class TestAssertType(TestNameCheckVisitorBase): @assert_passes() def test_assert_type(self): - from typing_extensions import assert_type, Literal from typing import Any + from typing_extensions import Literal, assert_type + def capybara(x: object, unannotated, explicit_any: Any) -> None: assert_type(x, object) diff --git a/pyanalyze/test_import.py b/pyanalyze/test_import.py index 19be5642..fafbe383 100644 --- a/pyanalyze/test_import.py +++ b/pyanalyze/test_import.py @@ -32,7 +32,8 @@ def capybara(): assert_is_value(assert_error, KnownValue(P.extensions.assert_error)) def test_import_star(self): - self.assert_passes(""" + self.assert_passes( + """ import pyanalyze as P if False: @@ -40,7 +41,8 @@ def test_import_star(self): assert_is_value(extensions, KnownValue(P.extensions)) not_a_name # E: undefined_name - """) + """ + ) class TestDisallowedImport(TestNameCheckVisitorBase): @@ -48,30 +50,29 @@ class TestDisallowedImport(TestNameCheckVisitorBase): def test_top_level(self): import getopt # E: disallowed_import import xml.etree.ElementTree # E: disallowed_import - from getopt import GetoptError # E: disallowed_import print(getopt, GetoptError, xml) # shut up flake8 def capybara(): import getopt # E: disallowed_import - from getopt import GetoptError # E: disallowed_import import xml.etree.ElementTree # E: disallowed_import + from getopt import GetoptError # E: disallowed_import print(getopt, GetoptError, xml) @assert_passes() def test_nested(self): - import email.quoprimime # E: disallowed_import import email.base64mime # ok + import email.quoprimime # E: disallowed_import from email.quoprimime import unquote # E: disallowed_import from xml.etree import ElementTree # E: disallowed_import print(email, unquote, ElementTree) def capybara(): - import email.quoprimime # E: disallowed_import import email.base64mime # ok + import email.quoprimime # E: disallowed_import from email.quoprimime import unquote # E: disallowed_import from xml.etree import ElementTree # E: disallowed_import @@ -79,13 +80,11 @@ def capybara(): @assert_passes() def test_import_from(self): - from email import quoprimime # E: disallowed_import - from email import base64mime # ok + from email import base64mime, quoprimime # ok # E: disallowed_import print(quoprimime, base64mime) def capybara(): - from email import quoprimime # E: disallowed_import - from email import base64mime # ok + from email import base64mime, quoprimime # ok # E: disallowed_import print(quoprimime, base64mime) diff --git a/pyanalyze/test_name_check_visitor.py b/pyanalyze/test_name_check_visitor.py index 25fbd131..f3151dc9 100644 --- a/pyanalyze/test_name_check_visitor.py +++ b/pyanalyze/test_name_check_visitor.py @@ -12,21 +12,24 @@ from .error_code import DISABLED_IN_TESTS, ErrorCode from .implementation import assert_is_value, dump_value from .name_check_visitor import ( - _get_task_cls, - _static_hasattr, ClassAttributeChecker, NameCheckVisitor, + _get_task_cls, + _static_hasattr, ) from .test_config import CONFIG_PATH from .test_node_visitor import assert_fails, assert_passes from .tests import ( + PropertyObject, autogenerated, l0cached_async_fn, make_simple_sequence, - PropertyObject, proxied_fn, ) from .value import ( + NO_RETURN_VALUE, + UNINITIALIZED_VALUE, + UNRESOLVED_VALUE, AnnotatedValue, AnySource, AnyValue, @@ -38,7 +41,6 @@ KVPair, MultiValuedValue, NewTypeValue, - NO_RETURN_VALUE, ReferencingValue, SequenceValue, SubclassValue, @@ -46,12 +48,9 @@ TypedValue, TypeVarValue, UnboundMethodValue, - UNINITIALIZED_VALUE, - UNRESOLVED_VALUE, VariableNameValue, ) - # =================================================== # Base classes for test_scope tests. # @@ -845,7 +844,7 @@ class TestBadRaise(TestNameCheckVisitorBase): @assert_passes() def test_raise(self): def bad_value(): - raise NotImplemented # E: bad_exception + raise 42 # E: bad_exception def bad_type(): # make sure this isn't inferenced to KnownValue, so this tests what it's supposed to @@ -908,11 +907,13 @@ def test(self, uid: Uid): class TestImports(TestNameCheckVisitorBase): def test_star_import(self): - self.assert_passes(""" + self.assert_passes( + """ from qcore.asserts import * assert_eq(1, 1) - """) + """ + ) @assert_passes() def test_local_import(self): @@ -1229,6 +1230,7 @@ def capybara(oid): def test_metaclass_super(self): from typing import Any, cast from unittest.mock import ANY + from pyanalyze.stacked_scopes import Composite, VarnameWithOrigin varname = VarnameWithOrigin("self", cast(Any, ANY)) @@ -1377,7 +1379,8 @@ def run_and_get_call_map(self, code_str, **kwargs): return collector.map def test_member_function_call(self): - call_map = self.run_and_get_call_map(""" + call_map = self.run_and_get_call_map( + """ class TestClass(object): def __init__(self): self.first_function(5) @@ -1388,7 +1391,8 @@ def first_function(self, x): def second_function(self, y, z): print(y + z) - """) + """ + ) assert "TestClass.first_function" in call_map["TestClass.second_function"] assert "TestClass.__init__" in call_map["TestClass.first_function"] @@ -2001,7 +2005,8 @@ def f(self, value: bool) -> None: # E: incompatible_override class TestWalrus(TestNameCheckVisitorBase): def test(self): - self.assert_passes(""" + self.assert_passes( + """ from typing import Optional def opt() -> Optional[int]: @@ -2015,10 +2020,12 @@ def capybara(): if (y := opt()) is not None: assert_is_value(y, TypedValue(int)) assert_is_value(y, TypedValue(int) | KnownValue(None)) - """) + """ + ) def test_and(self): - self.assert_passes(""" + self.assert_passes( + """ from typing import Optional def opt() -> Optional[int]: @@ -2028,31 +2035,38 @@ def capybara(cond): if (x := opt()) and cond: assert_is_value(x, TypedValue(int)) assert_is_value(x, TypedValue(int) | KnownValue(None)) - """) - self.assert_passes(""" + """ + ) + self.assert_passes( + """ from typing import Set def func(myvar: str, strset: Set[str]) -> None: if (encoder_type := myvar) and myvar in strset: print(encoder_type) - """) + """ + ) def test_if_exp(self): - self.assert_passes(""" + self.assert_passes( + """ def capybara(cond): (x := 2) if cond else (x := 1) assert_is_value(x, KnownValue(2) | KnownValue(1)) - """) + """ + ) def test_comprehension_scope(self): - self.assert_passes(""" + self.assert_passes( + """ from typing import List, Optional def capybara(elts: List[Optional[int]]) -> None: if any((x := i) is not None for i in elts): assert_is_value(x, TypedValue(int) | KnownValue(None)) print(i) # E: undefined_name - """) + """ + ) class TestUnion(TestNameCheckVisitorBase): diff --git a/pyanalyze/test_never.py b/pyanalyze/test_never.py index 46c8fdda..352e878d 100644 --- a/pyanalyze/test_never.py +++ b/pyanalyze/test_never.py @@ -82,9 +82,10 @@ def capybara(x: Union[int, str]) -> None: @assert_passes() def test_enum(self): - from typing_extensions import assert_never import enum + from typing_extensions import assert_never + class Capybara(enum.Enum): hydrochaeris = 1 isthmius = 2 diff --git a/pyanalyze/test_node_visitor.py b/pyanalyze/test_node_visitor.py index f3187fc8..9c607a69 100644 --- a/pyanalyze/test_node_visitor.py +++ b/pyanalyze/test_node_visitor.py @@ -407,7 +407,11 @@ def assert_code_equal(expected, actual): %s >>> diff: %s -""" % (expected, actual, diff) +""" % ( + expected, + actual, + diff, + ) assert False, message diff --git a/pyanalyze/test_operations.py b/pyanalyze/test_operations.py index 80c06533..0df5a0cc 100644 --- a/pyanalyze/test_operations.py +++ b/pyanalyze/test_operations.py @@ -233,7 +233,7 @@ def comparison(i: int, f: float, s: str, os: Optional[str]): @assert_passes() def test_contains(self): - from typing import Iterator, Iterable + from typing import Iterable, Iterator class OnlyGetitem: def __getitem__(self, x: int) -> int: diff --git a/pyanalyze/test_patma.py b/pyanalyze/test_patma.py index eb31edeb..e8d3b1f9 100644 --- a/pyanalyze/test_patma.py +++ b/pyanalyze/test_patma.py @@ -6,7 +6,8 @@ class TestPatma(TestNameCheckVisitorBase): @skip_before((3, 10)) def test_singletons(self): - self.assert_passes(""" + self.assert_passes( + """ from typing import Literal def capybara(x: Literal[True, False, None]): match x: @@ -14,11 +15,13 @@ def capybara(x: Literal[True, False, None]): assert_is_value(x, KnownValue(True)) case _: assert_is_value(x, KnownValue(False) | KnownValue(None)) - """) + """ + ) @skip_before((3, 10)) def test_value(self): - self.assert_passes(""" + self.assert_passes( + """ from typing import Literal from pyanalyze.tests import assert_never @@ -35,11 +38,13 @@ def capybara(x: int): assert_is_value(x, KnownValue(4)) case _: assert_is_value(x, TypedValue(int)) - """) + """ + ) @skip_before((3, 10)) def test_sequence(self): - self.assert_passes(""" + self.assert_passes( + """ import collections.abc from typing import Tuple @@ -72,11 +77,13 @@ def capybara(seq: Tuple[int, ...], obj: object): match seq[0]: case [1, 2, 3]: # E: impossible_pattern pass - """) + """ + ) @skip_before((3, 10)) def test_or(self): - self.assert_passes(""" + self.assert_passes( + """ import collections.abc from typing import Tuple @@ -86,11 +93,13 @@ def capybara(obj: object): assert_is_value(obj, KnownValue(1) | KnownValue(2)) case (3 as x) | (4 as x): assert_is_value(x, KnownValue(3) | KnownValue(4)) - """) + """ + ) @skip_before((3, 10)) def test_mapping(self): - self.assert_passes(""" + self.assert_passes( + """ import collections.abc from typing import Tuple @@ -105,11 +114,13 @@ def capybara(obj: object): KVPair(KnownValue(5), KnownValue(6)), ] )) - """) + """ + ) @skip_before((3, 10)) def test_class_pattern(self): - self.assert_passes(""" + self.assert_passes( + """ import collections.abc from typing import Tuple @@ -147,11 +158,13 @@ def capybara(obj: object): pass case MatchArgs(1, 2, 3): # E: bad_match pass - """) + """ + ) @skip_before((3, 10)) def test_bool_narrowing(self): - self.assert_passes(""" + self.assert_passes( + """ class X: true = True @@ -163,8 +176,10 @@ def capybara(b: bool): case _ as b2: assert_is_value(b, KnownValue(False)) assert_is_value(b2, KnownValue(False)) - """) - self.assert_passes(""" + """ + ) + self.assert_passes( + """ def capybara(b: bool): match b: case True: @@ -172,11 +187,13 @@ def capybara(b: bool): case _ as b2: assert_is_value(b, KnownValue(False)) assert_is_value(b2, KnownValue(False)) - """) + """ + ) @skip_before((3, 10)) def test_enum_narrowing(self): - self.assert_passes(""" + self.assert_passes( + """ from enum import Enum class Planet(Enum): @@ -193,4 +210,5 @@ def capybara(p: Planet): case _ as p2: assert_is_value(p2, KnownValue(Planet.earth)) assert_is_value(p, KnownValue(Planet.earth)) - """) + """ + ) diff --git a/pyanalyze/test_pep673.py b/pyanalyze/test_pep673.py index 563daf01..bd7f6171 100644 --- a/pyanalyze/test_pep673.py +++ b/pyanalyze/test_pep673.py @@ -152,8 +152,8 @@ def capybara(): @assert_passes() def test_stub(self): def capybara(): - from typing_extensions import assert_type from _pyanalyze_tests.self import X, Y + from typing_extensions import assert_type x = X() y = Y() @@ -175,8 +175,8 @@ def want_y(y: Y): @assert_passes() def test_typeshed_self(self): def capybara(): - from typing_extensions import assert_type from _pyanalyze_tests.tsself import X + from typing_extensions import assert_type x = X() assert_type(x, X) diff --git a/pyanalyze/test_runtime.py b/pyanalyze/test_runtime.py index 92c661e6..5b0b0c11 100644 --- a/pyanalyze/test_runtime.py +++ b/pyanalyze/test_runtime.py @@ -1,7 +1,7 @@ # static analysis: ignore from typing import List -from .runtime import is_compatible, get_compatibility_error +from .runtime import get_compatibility_error, is_compatible from .test_name_check_visitor import TestNameCheckVisitorBase from .test_node_visitor import assert_passes @@ -28,8 +28,9 @@ def test_get_compatibility_error() -> None: class TestRuntimeTypeGuard(TestNameCheckVisitorBase): @assert_passes() def test_runtime(self): - from typing_extensions import Annotated from annotated_types import Predicate + from typing_extensions import Annotated + from pyanalyze.runtime import is_compatible IsLower = Annotated[str, Predicate(str.islower)] diff --git a/pyanalyze/test_signature.py b/pyanalyze/test_signature.py index 17824d9e..72a8d85b 100644 --- a/pyanalyze/test_signature.py +++ b/pyanalyze/test_signature.py @@ -2,19 +2,13 @@ from collections.abc import Sequence from .implementation import assert_is_value -from .signature import ( - ConcreteSignature, - ELLIPSIS_PARAM, - OverloadedSignature, - ParameterKind as K, - Signature, - SigParameter as P, -) +from .signature import ELLIPSIS_PARAM, ConcreteSignature, OverloadedSignature, Signature +from .signature import ParameterKind as K +from .signature import SigParameter as P from .test_name_check_visitor import TestNameCheckVisitorBase from .test_node_visitor import assert_passes from .test_value import CTX from .tests import make_simple_sequence - from .value import ( AnnotatedValue, AnySource, @@ -668,7 +662,6 @@ def run(): def test_hasattr(self): from dataclasses import dataclass from typing import Any, cast - from unittest.mock import ANY @dataclass @@ -862,7 +855,8 @@ def capybara(arg): many_args(**typed_int_kwargs) # E: incompatible_call def test_pos_only(self): - self.assert_passes(""" + self.assert_passes( + """ from typing import Sequence def pos_only(pos: int, /) -> None: @@ -875,7 +869,8 @@ def capybara(ints: Sequence[int], strs: Sequence[str]) -> None: pos_only(pos=1) # E: incompatible_call pos_only() # E: incompatible_call pos_only(1, 2) # E: incompatible_call - """) + """ + ) @assert_passes() def test_kw_only(self): @@ -1136,10 +1131,8 @@ def pacarana(f: float): @assert_passes() def test_runtime(self): - from pyanalyze.extensions import ( - overload as extension_overload, - patch_typing_overload, - ) + from pyanalyze.extensions import overload as extension_overload + from pyanalyze.extensions import patch_typing_overload patch_typing_overload() from typing import overload diff --git a/pyanalyze/test_stacked_scopes.py b/pyanalyze/test_stacked_scopes.py index df99da15..e04e99f9 100644 --- a/pyanalyze/test_stacked_scopes.py +++ b/pyanalyze/test_stacked_scopes.py @@ -5,19 +5,19 @@ from .test_name_check_visitor import TestNameCheckVisitorBase from .test_node_visitor import assert_passes from .value import ( + NO_RETURN_VALUE, + UNINITIALIZED_VALUE, AnnotatedValue, AnySource, AnyValue, - assert_is_value, DictIncompleteValue, GenericValue, KnownValue, MultiValuedValue, - NO_RETURN_VALUE, ReferencingValue, SequenceValue, TypedValue, - UNINITIALIZED_VALUE, + assert_is_value, ) @@ -1507,8 +1507,8 @@ def capybara(x: int) -> None: @assert_passes() def test_gt_annotated_unification(self): - from pyanalyze.value import CustomCheckExtension from pyanalyze.annotated_types import Gt + from pyanalyze.value import CustomCheckExtension ext = CustomCheckExtension(Gt(5)) diff --git a/pyanalyze/test_thrift_enum.py b/pyanalyze/test_thrift_enum.py index a09ef3d4..9eed3eba 100644 --- a/pyanalyze/test_thrift_enum.py +++ b/pyanalyze/test_thrift_enum.py @@ -2,7 +2,7 @@ from .test_name_check_visitor import TestNameCheckVisitorBase from .test_node_visitor import assert_passes -from .value import assert_is_value, KnownValue, TypedValue +from .value import KnownValue, TypedValue, assert_is_value class TestThriftEnum(TestNameCheckVisitorBase): diff --git a/pyanalyze/test_try.py b/pyanalyze/test_try.py index 4d71ed9a..c73b3ad8 100644 --- a/pyanalyze/test_try.py +++ b/pyanalyze/test_try.py @@ -1,12 +1,13 @@ # static analysis: ignore from .test_name_check_visitor import TestNameCheckVisitorBase -from .test_node_visitor import skip_before, assert_passes +from .test_node_visitor import assert_passes, skip_before class TestExoticTry(TestNameCheckVisitorBase): @assert_passes() def test_except_everything(self): - from typing import Union, Tuple, Type + from typing import Tuple, Type, Union + from typing_extensions import Literal, assert_type def capybara( @@ -37,7 +38,8 @@ def capybara( class TestTryStar(TestNameCheckVisitorBase): @skip_before((3, 11)) def test_eg_types(self): - self.assert_passes(""" + self.assert_passes( + """ from typing import assert_type def capybara(): @@ -53,11 +55,13 @@ def capybara(): pass except *int as eg: # E: bad_except_handler pass - """) + """ + ) @skip_before((3, 11)) def test_variable_scope(self): - self.assert_passes(""" + self.assert_passes( + """ from typing import assert_type, Literal def capybara(): @@ -72,11 +76,13 @@ def capybara(): assert_type(x, Literal[0, 1, 2]) x = 3 assert_type(x, Literal[1, 2, 3]) - """) + """ + ) @skip_before((3, 11)) def test_try_else(self): - self.assert_passes(""" + self.assert_passes( + """ from typing import assert_type, Literal def capybara(): @@ -94,11 +100,13 @@ def capybara(): assert_type(x, Literal[1]) x = 4 assert_type(x, Literal[2, 3, 4]) - """) + """ + ) @skip_before((3, 11)) def test_try_finally(self): - self.assert_passes(""" + self.assert_passes( + """ from typing import assert_type, Literal def capybara(): @@ -116,4 +124,5 @@ def capybara(): assert_type(x, Literal[0, 1, 2, 3]) x = 4 assert_type(x, Literal[4]) - """) + """ + ) diff --git a/pyanalyze/test_type_aliases.py b/pyanalyze/test_type_aliases.py index 0411f7a5..816127fa 100644 --- a/pyanalyze/test_type_aliases.py +++ b/pyanalyze/test_type_aliases.py @@ -36,8 +36,9 @@ def capybara(i: int, s: str): @assert_passes() def test_typing_extensions_generic(self): + from typing import List, Set, TypeVar, Union + from typing_extensions import TypeAliasType, assert_type - from typing import TypeVar, Union, List, Set T = TypeVar("T") MyType = TypeAliasType("MyType", Union[List[T], Set[T]], type_params=(T,)) @@ -52,7 +53,8 @@ def capybara(i: int, s: str): @skip_before((3, 12)) def test_312(self): - self.assert_passes(""" + self.assert_passes( + """ from typing_extensions import assert_type type MyType = int @@ -63,11 +65,13 @@ def f(x: MyType): def capybara(i: int, s: str): f(i) f(s) # E: incompatible_argument - """) + """ + ) @skip_before((3, 12)) def test_312_generic(self): - self.assert_passes(""" + self.assert_passes( + """ from typing_extensions import assert_type type MyType[T] = list[T] | set[T] @@ -78,11 +82,13 @@ def f(x: MyType[int]): def capybara(i: int, s: str): f([i]) f([s]) # E: incompatible_argument - """) + """ + ) @skip_before((3, 12)) def test_312_local_alias(self): - self.assert_passes(""" + self.assert_passes( + """ from typing_extensions import assert_type def capybara(): @@ -93,4 +99,5 @@ def f(x: MyType): f(1) f("x") # E: incompatible_argument - """) + """ + ) diff --git a/pyanalyze/test_type_evaluation.py b/pyanalyze/test_type_evaluation.py index bd9df160..b3a09523 100644 --- a/pyanalyze/test_type_evaluation.py +++ b/pyanalyze/test_type_evaluation.py @@ -2,7 +2,7 @@ from .extensions import is_keyword, is_of_type, is_positional, is_provided, show_error from .test_name_check_visitor import TestNameCheckVisitorBase from .test_node_visitor import assert_passes -from .value import AnySource, AnyValue, assert_is_value, KnownValue, TypedValue +from .value import AnySource, AnyValue, KnownValue, TypedValue, assert_is_value class TestTypeEvaluation(TestNameCheckVisitorBase): @@ -474,7 +474,7 @@ def test_open(self): FileIO, TextIOWrapper, ) - from typing import Any, BinaryIO, Callable, IO, Optional, Union + from typing import IO, Any, BinaryIO, Callable, Optional, Union from typing_extensions import Literal diff --git a/pyanalyze/test_type_object.py b/pyanalyze/test_type_object.py index f0967732..0489ba85 100644 --- a/pyanalyze/test_type_object.py +++ b/pyanalyze/test_type_object.py @@ -5,11 +5,11 @@ from .value import ( AnySource, AnyValue, - assert_is_value, CallableValue, GenericValue, KnownValue, TypedValue, + assert_is_value, ) @@ -384,9 +384,10 @@ def capybara(t1: Type[int], t2: type): class TestIO(TestNameCheckVisitorBase): @assert_passes() def test_text(self): + import io from typing import TextIO + from typing_extensions import assert_type - import io def want_io(x: TextIO): x.write("hello") @@ -398,9 +399,10 @@ def capybara(): @assert_passes() def test_binary(self): + import io from typing import BinaryIO + from typing_extensions import assert_type - import io def want_io(x: BinaryIO): x.write(b"hello") diff --git a/pyanalyze/test_typeddict.py b/pyanalyze/test_typeddict.py index 547d0468..db71c9aa 100644 --- a/pyanalyze/test_typeddict.py +++ b/pyanalyze/test_typeddict.py @@ -2,15 +2,16 @@ from .implementation import assert_is_value from .test_name_check_visitor import TestNameCheckVisitorBase from .test_node_visitor import assert_passes -from .value import TypedDictValue, TypedValue, AnyValue, AnySource +from .value import AnySource, AnyValue, TypedDictValue, TypedValue class TestExtraKeys(TestNameCheckVisitorBase): @assert_passes() def test_signature(self): - from pyanalyze.extensions import has_extra_keys from typing_extensions import TypedDict + from pyanalyze.extensions import has_extra_keys + @has_extra_keys(int) class TD(TypedDict): a: str @@ -28,10 +29,12 @@ def capybara() -> None: @assert_passes() def test_methods(self): - from pyanalyze.extensions import has_extra_keys - from typing_extensions import TypedDict, assert_type, Literal from typing import Union + from typing_extensions import Literal, TypedDict, assert_type + + from pyanalyze.extensions import has_extra_keys + @has_extra_keys(int) class TD(TypedDict): a: str @@ -57,9 +60,10 @@ def setdefault(td: TD) -> None: @assert_passes() def test_kwargs_annotation(self): - from pyanalyze.extensions import has_extra_keys from typing_extensions import TypedDict, Unpack, assert_type + from pyanalyze.extensions import has_extra_keys + @has_extra_keys(int) class TD(TypedDict): a: str @@ -73,10 +77,12 @@ def capybara() -> None: @assert_passes() def test_compatibility(self): - from pyanalyze.extensions import has_extra_keys - from typing_extensions import TypedDict from typing import Any, Dict + from typing_extensions import TypedDict + + from pyanalyze.extensions import has_extra_keys + @has_extra_keys(int) class TD(TypedDict): a: str @@ -100,10 +106,12 @@ def capybara(td: TD, td2: TD2, td3: TD3, anydict: Dict[str, Any]) -> None: @assert_passes() def test_iteration(self): - from pyanalyze.extensions import has_extra_keys - from typing_extensions import TypedDict, assert_type, Literal from typing import Union + from typing_extensions import Literal, TypedDict, assert_type + + from pyanalyze.extensions import has_extra_keys + @has_extra_keys(int) class TD(TypedDict): a: str diff --git a/pyanalyze/test_typeis.py b/pyanalyze/test_typeis.py index 2b3adb47..da4d6e80 100644 --- a/pyanalyze/test_typeis.py +++ b/pyanalyze/test_typeis.py @@ -72,7 +72,8 @@ def main(a: object, b: object) -> None: @assert_passes() def testTypeIsWithTypeVar(self): - from typing import TypeVar, Tuple, Type + from typing import Tuple, Type, TypeVar + from typing_extensions import TypeIs, assert_type T = TypeVar("T") @@ -89,6 +90,7 @@ def main(a: Tuple[object, ...]): @assert_passes() def testTypeIsUnionIn(self): from typing import Union + from typing_extensions import TypeIs, assert_type def is_foo(a: Union[int, str]) -> TypeIs[str]: @@ -104,6 +106,7 @@ def main(a: Union[str, int]) -> None: @assert_passes() def testTypeIsUnionOut(self): from typing import Union + from typing_extensions import TypeIs, assert_type def is_foo(a: object) -> TypeIs[Union[int, str]]: @@ -126,7 +129,8 @@ def main(a: int): @assert_passes() def testTypeIsHigherOrder(self): - from typing import Callable, TypeVar, Iterable, List + from typing import Callable, Iterable, List, TypeVar + from typing_extensions import TypeIs, assert_type T = TypeVar("T") @@ -166,6 +170,7 @@ def is_float(a: object) -> TypeIs[float]: @assert_passes() def testTypeIsNarrowToTypedDict(self): from typing import Mapping, TypedDict + from typing_extensions import TypeIs, assert_type class User(TypedDict): @@ -193,6 +198,7 @@ def main(a: object) -> None: @assert_passes() def testTypeIsFromAny(self): from typing import Any + from typing_extensions import TypeIs, assert_type def is_objfloat(a: object) -> TypeIs[float]: @@ -216,6 +222,7 @@ def anymain(a: Any) -> None: @assert_passes() def testTypeIsNegatedAndElse(self): from typing import Union + from typing_extensions import TypeIs, assert_type def is_int(a: object) -> TypeIs[int]: @@ -270,7 +277,8 @@ def main1(a: object) -> None: @assert_passes() def testTypeIsOverload(self): from typing import Callable, Iterable, Iterator, List, Optional, TypeVar - from typing_extensions import TypeIs, overload, assert_type + + from typing_extensions import TypeIs, assert_type, overload T = TypeVar("T") R = TypeVar("R") @@ -303,6 +311,7 @@ def main(a: List[Optional[int]]) -> None: @assert_passes() def testTypeIsDecorated(self): from typing import TypeVar + from typing_extensions import TypeIs, assert_type T = TypeVar("T") @@ -333,6 +342,7 @@ def is_float(self, a: object) -> bool: # E: incompatible_override @assert_passes() def testTypeIsInAnd(self): from typing import Any + from typing_extensions import TypeIs def isclass(a: object) -> bool: @@ -399,7 +409,7 @@ def capybara() -> None: @assert_passes() def testAssignToTypeIsedVariable3(self): - from typing_extensions import TypeIs, assert_type, Never + from typing_extensions import Never, TypeIs, assert_type class A: pass @@ -422,9 +432,10 @@ def capybara() -> None: @assert_passes() def testTypeIsNestedRestrictionAny(self): - from typing_extensions import TypeIs, assert_type from typing import Any, Union + from typing_extensions import TypeIs, assert_type + class A: ... def f(x: object) -> TypeIs[A]: @@ -439,9 +450,10 @@ def test(x: Any) -> None: @assert_passes() def testTypeIsNestedRestrictionUnionOther(self): - from typing_extensions import TypeIs, assert_type from typing import Union + from typing_extensions import TypeIs, assert_type + class A: ... class B: ... @@ -460,6 +472,7 @@ def test(x: object) -> None: @assert_passes() def testTypeIsComprehensionSubtype(self): from typing import List + from typing_extensions import TypeIs class Base: ... @@ -482,9 +495,10 @@ def foobar(items: List[object]) -> object: @assert_passes() def testTypeIsNestedRestrictionUnionIsInstance(self): - from typing_extensions import TypeIs, assert_type from typing import Any, List + from typing_extensions import TypeIs, assert_type + class A: ... def f(x: List[Any]) -> TypeIs[List[str]]: @@ -497,7 +511,7 @@ def test(x: List[Any]) -> None: @assert_passes() def testTypeIsMultipleCondition(self): - from typing_extensions import TypeIs, assert_type, Never + from typing_extensions import Never, TypeIs, assert_type class Foo: ... @@ -522,6 +536,7 @@ def foobar_typeguard(x: object): @assert_passes() def testTypeIsAsFunctionArgAsBoolSubtype(self): from typing import Callable + from typing_extensions import TypeIs def accepts_bool(f: Callable[[object], bool]) -> None: @@ -543,6 +558,7 @@ def with_bool(o: object) -> bool: @assert_passes() def testTypeIsAsFunctionArg(self): from typing import Callable + from typing_extensions import TypeIs def accepts_typeguard(f: Callable[[object], TypeIs[bool]]) -> None: @@ -566,6 +582,7 @@ def with_bool(o: object) -> bool: @assert_passes() def testTypeIsAsGenericFunctionArg(self): from typing import Callable, TypeVar + from typing_extensions import TypeIs T = TypeVar("T") @@ -589,7 +606,8 @@ def with_bool(o: object) -> bool: @assert_passes() def testTypeIsAsOverloadedFunctionArg(self): # https://github.com/python/mypy/issues/11307 - from typing import Callable, TypeVar, Generic, Any, overload + from typing import Any, Callable, Generic, TypeVar, overload + from typing_extensions import TypeIs _T = TypeVar("_T") @@ -621,6 +639,7 @@ def capybara() -> None: @assert_passes() def testTypeIsSubtypingVariance(self): from typing import Callable + from typing_extensions import TypeIs class A: @@ -651,6 +670,7 @@ def with_typeguard_c(o: object) -> TypeIs[C]: @assert_passes() def testTypeIsWithIdentityGeneric(self): from typing import TypeVar + from typing_extensions import TypeIs, assert_type _T = TypeVar("_T") @@ -670,7 +690,8 @@ def func2(name: str): @assert_passes() def testTypeIsWithGenericInstance(self): - from typing import TypeVar, List, Iterable + from typing import Iterable, List, TypeVar + from typing_extensions import TypeIs, assert_type _T = TypeVar("_T") @@ -685,7 +706,8 @@ def func(name: Iterable[str]): @assert_passes() def testTypeIsWithTupleGeneric(self): - from typing import TypeVar, Tuple + from typing import Tuple, TypeVar + from typing_extensions import TypeIs, assert_type _T = TypeVar("_T") @@ -759,7 +781,8 @@ def capybara(x: object): @assert_passes() def testTypeIsKwargFollowingThroughOverloaded(self): - from typing import overload, Union + from typing import Union, overload + from typing_extensions import TypeIs, assert_type @overload @@ -787,6 +810,7 @@ def capybara(x: object) -> None: @assert_passes() def testGenericAliasWithTypeIs(self): from typing import Callable, List, TypeVar + from typing_extensions import TypeIs, assert_type T = TypeVar("T") @@ -818,9 +842,10 @@ def capybara(a: A, x: object) -> None: @assert_passes() def testTypeIsMustBeSubtypeFunctions(self): - from typing_extensions import TypeIs from typing import List, Sequence, TypeVar + from typing_extensions import TypeIs + def f(x: str) -> TypeIs[int]: # E: typeis_must_be_subtype return False diff --git a/pyanalyze/test_typeshed.py b/pyanalyze/test_typeshed.py index dc78f3fa..2a5bb9f5 100644 --- a/pyanalyze/test_typeshed.py +++ b/pyanalyze/test_typeshed.py @@ -12,10 +12,10 @@ from collections.abc import Collection, MutableSequence, Reversible, Sequence, Set from pathlib import Path from typing import Dict, Generic, List, NewType, TypeVar, Union +from unittest.mock import ANY from urllib.error import HTTPError -from unittest.mock import ANY -from typeshed_client import get_search_context, Resolver +from typeshed_client import Resolver, get_search_context from .checker import Checker from .extensions import evaluated @@ -27,22 +27,22 @@ from .tests import make_simple_sequence from .typeshed import TypeshedFinder from .value import ( + UNINITIALIZED_VALUE, AnySource, AnyValue, - SequenceValue, - assert_is_value, CallableValue, DictIncompleteValue, GenericValue, KnownValue, KVPair, NewTypeValue, + SequenceValue, SubclassValue, TypedDictValue, TypedValue, TypeVarValue, - UNINITIALIZED_VALUE, Value, + assert_is_value, ) T = TypeVar("T") @@ -84,7 +84,9 @@ def test_newtype(self): with tempfile.TemporaryDirectory() as temp_dir_str: temp_dir = Path(temp_dir_str) (temp_dir / "typing.pyi").write_text("def NewType(a, b): pass\n") - (temp_dir / "newt.pyi").write_text(textwrap.dedent(""" + (temp_dir / "newt.pyi").write_text( + textwrap.dedent( + """ from typing import NewType NT = NewType("NT", int) @@ -92,7 +94,9 @@ def test_newtype(self): def f(x: NT, y: Alias) -> None: pass - """)) + """ + ) + ) (temp_dir / "VERSIONS").write_text("newt: 3.5\ntyping: 3.5\n") (temp_dir / "@python2").mkdir() tsf = TypeshedFinder(Checker(), verbose=True) @@ -156,6 +160,7 @@ def capybara(i: int) -> None: @assert_passes() def test_datetime(self): from datetime import datetime + from typing_extensions import assert_type def capybara(i: int): @@ -198,9 +203,9 @@ class TestBundledStubs(TestNameCheckVisitorBase): def test_import_aliases(self): def capybara(): from _pyanalyze_tests.aliases import ( + ExplicitAlias, aliased_constant, constant, - ExplicitAlias, explicitly_aliased_constant, ) @@ -271,7 +276,7 @@ def capybara(x: ast.Yield): @assert_passes() def test_import_typeddicts(self): def capybara(): - from _pyanalyze_tests.typeddict import Inherited, PEP655, TD1, TD2 + from _pyanalyze_tests.typeddict import PEP655, TD1, TD2, Inherited from pyanalyze.test_typeshed import _EXPECTED_TYPED_DICTS @@ -289,7 +294,7 @@ def test_evaluated(self): @assert_passes() def test_evaluated_import(self): def capybara(unannotated): - from typing import BinaryIO, IO, TextIO + from typing import IO, BinaryIO, TextIO from _pyanalyze_tests.evaluated import open, open2 @@ -344,7 +349,7 @@ def capybara(): @assert_passes() def test_stub_context_manager(self): - from typing_extensions import assert_type, Literal + from typing_extensions import Literal, assert_type def capybara(): from _pyanalyze_tests.contextmanager import cm @@ -747,7 +752,7 @@ class TestIntegration(TestNameCheckVisitorBase): @assert_passes() def test_open(self): import io - from typing import Any, BinaryIO, IO + from typing import IO, Any, BinaryIO from pyanalyze.extensions import assert_type diff --git a/pyanalyze/test_typevar.py b/pyanalyze/test_typevar.py index 84d11264..cf32730a 100644 --- a/pyanalyze/test_typevar.py +++ b/pyanalyze/test_typevar.py @@ -380,6 +380,7 @@ class TestDunder(TestNameCheckVisitorBase): @assert_passes() def test_sequence(self): from typing import Sequence + from typing_extensions import assert_type def capybara(s: Sequence[int], t: str): @@ -389,7 +390,8 @@ def capybara(s: Sequence[int], t: str): class TestGenericClasses(TestNameCheckVisitorBase): @skip_before((3, 12)) def test_generic(self): - self.assert_passes(""" + self.assert_passes( + """ from typing_extensions import assert_type class C[T]: @@ -400,11 +402,13 @@ def __init__(self, x: T) -> None: def capybara(i: int): assert_type(C(i).x, int) - """) + """ + ) @skip_before((3, 12)) def test_generic_with_bound(self): - self.assert_passes(""" + self.assert_passes( + """ from typing_extensions import assert_type class C[T: int]: @@ -417,4 +421,5 @@ def capybara(i: int, s: str, b: bool): assert_type(C(i).x, int) assert_type(C(b).x, bool) C(s) # E: incompatible_argument - """) + """ + ) diff --git a/pyanalyze/test_value.py b/pyanalyze/test_value.py index 5f132318..7f681e3d 100644 --- a/pyanalyze/test_value.py +++ b/pyanalyze/test_value.py @@ -21,7 +21,6 @@ AnyValue, CallableValue, CanAssignError, - concrete_values_from_iterable, GenericValue, KnownValue, KVPair, @@ -30,9 +29,10 @@ SubclassValue, TypedValue, TypeVarMap, + Value, + concrete_values_from_iterable, unite_and_simplify, unpack_values, - Value, ) _checker = Checker() diff --git a/pyanalyze/test_yield_checker.py b/pyanalyze/test_yield_checker.py index d557ee25..3bec4a70 100644 --- a/pyanalyze/test_yield_checker.py +++ b/pyanalyze/test_yield_checker.py @@ -3,8 +3,7 @@ from .test_name_check_visitor import TestNameCheckVisitorBase from .test_node_visitor import assert_passes - -from .yield_checker import _camel_case_to_snake_case, VarnameGenerator +from .yield_checker import VarnameGenerator, _camel_case_to_snake_case class TestUnnecessaryYield(TestNameCheckVisitorBase): @@ -77,7 +76,7 @@ def test_nested(self): from asynq import asynq, result from asynq.tools import afilter - from pyanalyze.tests import async_fn, PropertyObject + from pyanalyze.tests import PropertyObject, async_fn @asynq() def capybara(qids, t): diff --git a/pyanalyze/tests.py b/pyanalyze/tests.py index ebb1c2dc..e2f81b4b 100644 --- a/pyanalyze/tests.py +++ b/pyanalyze/tests.py @@ -5,10 +5,10 @@ """ -from typing import ClassVar, NoReturn, overload, Sequence, Union +from typing import ClassVar, NoReturn, Sequence, Union, overload import qcore -from asynq import async_proxy, AsyncTask, asynq, ConstFuture, get_async_fn, result +from asynq import AsyncTask, ConstFuture, async_proxy, asynq, get_async_fn, result from asynq.decorators import AsyncDecorator from .value import SequenceValue, Value, VariableNameValue diff --git a/pyanalyze/type_evaluation.py b/pyanalyze/type_evaluation.py index b72f6980..33af51ce 100644 --- a/pyanalyze/type_evaluation.py +++ b/pyanalyze/type_evaluation.py @@ -29,26 +29,26 @@ from .predicates import IsAssignablePredicate from .stacked_scopes import ( - constrain_value, Constraint, ConstraintType, VarnameWithOrigin, + constrain_value, ) from .value import ( + NO_RETURN_VALUE, BoundsMap, CanAssign, CanAssignContext, CanAssignError, - flatten_values, KnownValue, MultiValuedValue, - NO_RETURN_VALUE, SequenceValue, TypeVarMap, + Value, + flatten_values, unannotate, unify_bounds_maps, unite_values, - Value, ) ARGS = qcore.MarkerObject("*args") diff --git a/pyanalyze/type_object.py b/pyanalyze/type_object.py index 0438b0d1..edff8faa 100644 --- a/pyanalyze/type_object.py +++ b/pyanalyze/type_object.py @@ -11,6 +11,7 @@ from .safe import safe_in, safe_isinstance, safe_issubclass from .value import ( + UNINITIALIZED_VALUE, AnnotatedValue, AnySource, AnyValue, @@ -19,12 +20,11 @@ CanAssignContext, CanAssignError, KnownValue, - stringify_object, SubclassValue, TypedValue, - unify_bounds_maps, - UNINITIALIZED_VALUE, Value, + stringify_object, + unify_bounds_maps, ) diff --git a/pyanalyze/typeshed.py b/pyanalyze/typeshed.py index b2355ecf..74bcb8ea 100644 --- a/pyanalyze/typeshed.py +++ b/pyanalyze/typeshed.py @@ -10,13 +10,13 @@ import enum import inspect import sys - +import types from abc import abstractmethod -from collections.abc import Collection, MutableMapping, Set as AbstractSet +from collections.abc import Collection, MutableMapping +from collections.abc import Set as AbstractSet from dataclasses import dataclass, field, replace from enum import Enum, EnumMeta from types import GeneratorType, MethodDescriptorType, ModuleType -import types from typing import ( Any, Callable, @@ -37,54 +37,51 @@ from typing_extensions import Protocol, TypedDict from pyanalyze.functions import translate_vararg_type + from .analysis_lib import is_positional_only_arg_name from .annotations import ( Context, - make_type_var_value, DecoratorValue, Pep655Value, SyntheticEvaluator, + make_type_var_value, type_from_value, value_from_ast, ) from .error_code import ErrorCode -from .extensions import ( - evaluated, - overload, - real_overload, - deprecated as deprecated_decorator, -) +from .extensions import deprecated as deprecated_decorator +from .extensions import evaluated, overload, real_overload from .node_visitor import Failure from .options import Options, PathSequenceOption from .safe import all_of_type, hasattr_static, is_typing_name, safe_isinstance from .signature import ( ConcreteSignature, - make_bound_method, OverloadedSignature, ParameterKind, Signature, SigParameter, + make_bound_method, ) from .stacked_scopes import Composite, uniq_chain from .value import ( + UNINITIALIZED_VALUE, AnySource, AnyValue, CallableValue, CanAssignContext, DeprecatedExtension, Extension, - SyntheticModuleValue, - annotate_value, - extract_typevars, GenericValue, KnownValue, - make_coro_type, SubclassValue, + SyntheticModuleValue, TypedDictValue, TypedValue, TypeVarValue, - UNINITIALIZED_VALUE, Value, + annotate_value, + extract_typevars, + make_coro_type, ) PROPERTY_LIKE = {KnownValue(property), KnownValue(types.DynamicClassAttribute)} diff --git a/pyanalyze/typevar.py b/pyanalyze/typevar.py index 4eb46f89..769e0493 100644 --- a/pyanalyze/typevar.py +++ b/pyanalyze/typevar.py @@ -21,12 +21,11 @@ OrBound, TypeVarLike, TypeVarMap, - unite_values, UpperBound, Value, + unite_values, ) - BOTTOM = qcore.MarkerObject("") TOP = qcore.MarkerObject("") diff --git a/pyanalyze/value.py b/pyanalyze/value.py index 636588ef..4b8a9df9 100644 --- a/pyanalyze/value.py +++ b/pyanalyze/value.py @@ -21,16 +21,15 @@ def function(x: int, y: list[int], z: Any): import collections.abc import enum +import sys import textwrap from collections import deque -from dataclasses import dataclass, field, InitVar +from dataclasses import InitVar, dataclass, field from itertools import chain -import sys from types import FunctionType from typing import ( Any, Callable, - cast, ContextManager, Dict, Iterable, @@ -44,6 +43,7 @@ def function(x: int, y: list[int], z: Any): Type, TypeVar, Union, + cast, ) import qcore diff --git a/pyanalyze/yield_checker.py b/pyanalyze/yield_checker.py index d07c2232..5ce093aa 100644 --- a/pyanalyze/yield_checker.py +++ b/pyanalyze/yield_checker.py @@ -32,14 +32,14 @@ from ast_decompiler import decompile import pyanalyze -from .analysis_lib import get_indentation, get_line_range_for_node +from .analysis_lib import get_indentation, get_line_range_for_node from .asynq_checker import AsyncFunctionKind from .error_code import ErrorCode from .functions import FunctionNode from .node_visitor import Replacement from .stacked_scopes import VisitorState -from .value import KnownValue, UnboundMethodValue, UNINITIALIZED_VALUE, Value +from .value import UNINITIALIZED_VALUE, KnownValue, UnboundMethodValue, Value @dataclass diff --git a/pyproject.toml b/pyproject.toml index 5e03ca84..b5a4de5f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,13 +1,8 @@ [tool.black] -target_version = ['py36'] +target_version = ['py38'] include = '\.pyi?$' skip-magic-trailing-comma = true preview = true - -# README -# The first section is for directories -# The second section is for specific files - exclude = ''' /( \.git @@ -46,3 +41,32 @@ implicit_any = true [[tool.pyanalyze.overrides]] module = "pyanalyze.yield_checker" implicit_any = true + +[tool.ruff] +line-length = 100 +target-version = "py38" + +[tool.ruff.lint] +select = [ + "F", + "E", + "I", # import sorting +] + +ignore = [ + "B008", # do not perform function calls in argument defaults + "F811", # redefinition of unused '...' + "F821", # undefined name + "F505", # .format() stuff + "F507", # .format() stuff + "F522", # .format() stuff + "F523", # .format() stuff + "F524", # .format() stuff + "F823", # local variable referenced before assignment + "F601", # dictionary key name repeated with different values + "E721", # do not compare types, use 'isinstance()' + "F841", # local variable is assigned to but never used + "E742", # Ambiguous class name + "E731", # do not assign a lambda expression, use a def + "E741", # ambiguous variable name +] diff --git a/setup.py b/setup.py index dd02fa07..ee7d6ec8 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ from pathlib import Path -from setuptools import setup +from setuptools import setup version = "0.11.0" package_data = ["test.toml", "stubs/*/*.pyi"] diff --git a/tox.ini b/tox.ini index b51b1afa..a1716457 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] envlist = - py38,py39,py310,py311,py312,black,flake8 + py38,py39,py310,py311,py312,black,ruff skip_missing_interpreters = True [testenv] @@ -13,60 +13,14 @@ commands = [testenv:black] deps = - black==23.10.1 + black==24.2.0 commands = black --check pyanalyze/ -[testenv:flake8] +[testenv:ruff] deps = - flake8==6.1.0 + ruff==0.2.2 commands = - flake8 pyanalyze/ - -[testenv:usort] -deps = - usort==1.0.7 - -commands = - usort check pyanalyze/ - -[flake8] -max-line-length = 100 -ignore = - # Sometimes comparing types is necessary - E721, - # ambiguous class definition - E742, - # ambiguous variable name - E741, - # formatting stuff where Black takes the decisions - E701, - E704, - # undefined name - F821, - # local variable 'x' is assigned to but never used - F841, - # do not assign a lambda expression, use a def - E731, - # redefinition of unused - F811, - # dictionary key repeated with different values - F601, - # 'raise NotImplemented' should be 'raise NotImplementedError' - F901, - # Formatting stuff that black handles for us - # expected 1 blank line before a nested definition - E306 - # line break before binary operator - W503, - # whitespace before ':' - E203, - # .format() stuff we handle ourselves - F522, - F523, - F524, - F525, - F505, - F507 + ruff check pyanalyze/