Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Support name mangling #16715

Open
wants to merge 27 commits into
base: master
Choose a base branch
from
Open

Conversation

tyralla
Copy link
Collaborator

@tyralla tyralla commented Dec 29, 2023

Fixes #8267

After some playing around, I found it cleaner to separate the name mangling from the type-checking logic and to modify the abstract syntax trees of all class definitions instead, for which I implemented the node transformer NameMangler.

NameMangler is simpler than I expected because Python's mangling routine is coarser than I knew. Two runtime error examples. The first one shows why I adjusted the testSelfTypeReallyTrickyExample test case:

__y = int
class A:
    def f(self, x: __y):  # NameError: name '_A__y' is not defined
        pass

The second example shows that Python does not only suggest the "direct" fields of a type but also those of its ancestors. I extended the suggestion algorithm of method MessageBuilder.has_no_attr accordingly so that Mypy's error messages should be equally easy to understand:

class A:
    __x: int = 1
class B(A):
    pass
class C:
    def f(self, b):
        b.__x
B().f(B())  # AttributeError: 'B' object has no attribute '_C__x'. Did you mean: '_A__x'?

I hoped I could remove function is_private and all its usages because, during type checking, all __attr field names should already be mangled to _class__attr. Unfortunately, Mypy introduces some special names for internal reasons. My first idea was to replace is_private(str) with not str.isidentifier() to filter out names like __mypy-replace and __mypy-post_init. But then I encountered <lambda>, which neither looks private nor like a valid identifier. As I am not aware if there are similar pitfalls (not covered by the test suites), I decided to leave is_private as is but added a note.

A case where is_private does not work is covered by the testFinalWithPrivateAssignment. One can only subclass an enumeration if all its members are private. As a surrogate, method TypeChecker.is_final_enum_value now checks if the member's name looks mangled.

The possibly most controversial change is that one cannot prepend double underscores to mark method parameters as positional-only. This change seems to comply with a decision mentioned in PEP 570, but it may affect too many libraries. On the contrary, when not accepting double underscores as positional-only markers in methods, one should likely do the same for pure functions.

After writing the last paragraph, I realised that even stubs like builtins.pyi rely on the double underscore style. So, now it's clear this is something one should not change ad hoc. But I leave it for a first discussion and to see the results of the Mypy primer.

This comment has been minimized.

This comment has been minimized.

@tyralla
Copy link
Collaborator Author

tyralla commented Dec 30, 2023

The first Mypy primer diff was much too long, so I made the very first steps to introduce a flag to avoid the mangling of method parameters.

This comment has been minimized.

@tyralla
Copy link
Collaborator Author

tyralla commented Jan 2, 2024

At least two libraries combine private members with the TypedDict class syntax. Hence, they become "mangled keys". This appears a little strange at first glance but is consistent with Python's runtime behaviour:

from typing import TypedDict

class A(TypedDict):
    __x: str
A.__required_keys__  # frozenset({'_A__x'})

One can use the alternative syntax to avoid the mangling:

B = TypedDict('B', {'__y': str})
B.__required_keys__  # frozenset({'__y'})

@tyralla
Copy link
Collaborator Author

tyralla commented Jan 2, 2024

A preliminary thought on the problems with __slots__.

I need to fix my implementation, and I will try by mangling the strings within __slots__, even if this does not happen at runtime:

class A:
    __slots__ = ["__x",]

A.__slots__  # ['__x']

I think Mypy never exposes the strings within __slots__ in error messages, so this should be okay. Also, this should fix the current limitation of Mypy not to detect the following runtime error:

class A:
    __slots__ = ["__x"]

class B(A):
    __slots__ = []

    def __init__(self) -> None:
        self.__x = 1

b = B()  # AttributeError: 'B' object has no attribute '_B__x'

@tyralla
Copy link
Collaborator Author

tyralla commented Jan 2, 2024

Mypy also does not protect from the following runtime error:

class A:
    __slots__, b = ["__x"], None

    def __init__(self) -> None:
        self.__x = 1
        self.__y = 1

A()  # AttributeError: 'A' object has no attribute '_A__y'

This is neither an everyday pattern nor easily readable. So, for now, I see no reason to complicate the name mangling for such multiple assignments.

This comment has been minimized.

@tyralla
Copy link
Collaborator Author

tyralla commented Jan 2, 2024

The primer differences for speedrun.com_global_scoreboard_webapp let me overthink the case of annotations starting with "__", and there is more trouble than expected.

"Normally", Python mangles such annotations:

__y = int

class A:
    def f(self, x: __y):  # NameError: name '_A__y' is not defined
        pass

However, when using the mechanism introduced in PEP 563, this doesn't seem to be the case:

from __future__ import annotations
import typing

__y = int
class A:
    def f(self, x: __y):
        pass

A.f.__annotations__  # {'x': '__y'}
typing.get_type_hints(A.f, globalns=None, localns=None)  # {'x': <class 'int'>}

The same when using strings:

import typing

__y = int
class A:
    def f(self, x: "__y"):
        pass

A.f.__annotations__  # {'x': '__y'}  # {'x': "'__y'"}
typing.get_type_hints(A.f, globalns=None, localns=None)  # {'x': <class 'int'>}

No idea what PEP 649 will bring.

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.

@tyralla
Copy link
Collaborator Author

tyralla commented Jan 4, 2024

There were some additional error messages for Tanjun, which were due to the (numerous) uses of private identifiers in the stub files of the underlying Hikari library. A section from a relevant file:

class UndefinedType(__enum.Enum):
    def __bool__(self) -> __Literal[False]: ...
    UNDEFINED = __enum.auto()

This would never work at runtime because __enum would be mangled to _UndefinedType__enum. __Literal would only work when using from __future__ import annotations, but no one would write this import line in a stub file. So, I decided also to skip the mangling of annotations when analysing a stub file, which removed all remaining primer differences for Tanjun.

@ikonst
Copy link
Contributor

ikonst commented Jan 4, 2024

I need to have a deeper look at all this, but just wondering why __mypy-replace etc. need to be special-cased? We do want class-private semantics for them.

@tyralla
Copy link
Collaborator Author

tyralla commented Jan 5, 2024

@JukkaL

I think the remaining differences are okay for now. Most are due to the extended suggestion mechanism. The unused-ignore notes are due to accessing the private attributes of base classes via their mangled names.

The issue of mangled keywords in typed dictionaries is unfortunate, but to not mangle them seems like an inconsistency and unnecessary complication. Of course, I am open to other opinions.

The issues of handling "private" method parameters and annotations are likely the most debatable.

This comment has been minimized.

@tyralla
Copy link
Collaborator Author

tyralla commented Jan 5, 2024

@ikonst

I did not investigate the reason for introducing __mypy-replace etc. Can you give me some information on this? And on <lambda> and if Mypy uses other special names internally?

Do you suggest using mangled versions of __mypy-replace etc. to get rid of is_private?

This comment has been minimized.

@tyralla
Copy link
Collaborator Author

tyralla commented Jan 5, 2024

Do you suggest using mangled versions of __mypy-replace etc. to get rid of is_private?

I tried it, and, according to the test suite and the Mypy primer, it works, and it removes many branches that are not required anymore. The only introduced hack is a "mypy-" not in defn.name check to avoid unnecessary error messages on the variance of type variables.

This comment has been minimized.

@ikonst
Copy link
Contributor

ikonst commented Jan 5, 2024

What I'm saying is that this symbol has a dunder on one side exactly so it becomes private to a class and not overridden in derived classes.

For example, if A is base and B is derived, and both are attrs classes, then there's A.__mypy-replace and B.__mypy-replace, and due to mangling they're actually different symbols and not subject to LSP.

@tyralla
Copy link
Collaborator Author

tyralla commented Jan 5, 2024

@ikonst: __mypy-replace is special because it does not directly stem from Python code (or stub files). The data classes plugin creates and uses it for type checking the dataclasses.replace function. In commit e37398b, I changed the plugin to using mangled names (e.g. A._A__mypy-replace) so that the additional checks of the (removed) function is_private become obsolete. I extended a test case in the same commit to ensure it works. (Similar for __mypy-post_init, but enough tests dealing with subclassing were already available.)

If other plugins introduce non-mangled private attribute names, we might have to revive is_private.

# Conflicts:
#	mypy/typeanal.py
Copy link
Contributor

Diff from mypy_primer, showing the effect of this PR on open source code:

comtypes (https://github.com/enthought/comtypes)
+ comtypes/automation.py:163: error: Name "U_VARIANT1.__tagVARIANT.U_VARIANT2" is not defined  [name-defined]
+ comtypes/__init__.py:828: error: "IUnknown" has no attribute "_IUnknown__com_QueryInterface"; maybe "_IUnknown_Base__com_QueryInterface"?  [attr-defined]
+ comtypes/__init__.py:838: error: "IUnknown" has no attribute "_IUnknown__com_AddRef"; maybe "_IUnknown_Base__com_AddRef"?  [attr-defined]
+ comtypes/__init__.py:842: error: "IUnknown" has no attribute "_IUnknown__com_Release"; maybe "_IUnknown_Base__com_Release"?  [attr-defined]

dragonchain (https://github.com/dragonchain/dragonchain)
- dragonchain/lib/authorization_utest.py:35:13: error: "TestAuthorization" has no attribute "assertFail"  [attr-defined]
+ dragonchain/lib/authorization_utest.py:35:13: error: "TestAuthorization" has no attribute "assertFail"; maybe "assertFalse" or "assertEqual"?  [attr-defined]
- dragonchain/lib/dto/models_utest.py:185:9: error: "TestSmartContract" has no attribute "assertFail"  [attr-defined]
+ dragonchain/lib/dto/models_utest.py:185:9: error: "TestSmartContract" has no attribute "assertFail"; maybe "assertFalse" or "assertEqual"?  [attr-defined]
- dragonchain/lib/dto/models_utest.py:204:9: error: "TestSmartContract" has no attribute "assertFail"  [attr-defined]
+ dragonchain/lib/dto/models_utest.py:204:9: error: "TestSmartContract" has no attribute "assertFail"; maybe "assertFalse" or "assertEqual"?  [attr-defined]
- dragonchain/lib/dto/bnb_utest.py:42:13: error: "TestBinanceMethods" has no attribute "assertFail"  [attr-defined]
+ dragonchain/lib/dto/bnb_utest.py:42:13: error: "TestBinanceMethods" has no attribute "assertFail"; maybe "assertFalse" or "assertEqual"?  [attr-defined]

steam.py (https://github.com/Gobot1234/steam.py)
- steam/ext/csgo/state.py:216: error: "ClientUser" has no attribute "_profile_info_msg"  [attr-defined]
+ steam/ext/csgo/state.py:216: error: "ClientUser" has no attribute "_profile_info_msg"; maybe "profile_info"?  [attr-defined]

antidote (https://github.com/Finistere/antidote)
+ src/antidote/core/_catalog.py:541: error: Name "_CatalogOverrideImpl__dependency" is not defined  [name-defined]
+ src/antidote/core/_catalog.py:542: error: Name "_CatalogOverrideImpl__dependency" is not defined  [name-defined]
+ src/antidote/core/_catalog.py:543: error: Name "_CatalogOverrideImpl__dependency" is not defined  [name-defined]
+ src/antidote/lib/interface_ext/_interface.py:487: error: Name "_ImplementsImpl__existing_implementation" is not defined  [name-defined]
+ src/antidote/lib/interface_ext/_interface.py:493: error: Name "_ImplementsImpl__existing_implementation" is not defined  [name-defined]
+ tests/core/test_wiring.py:152: error: Unused "type: ignore" comment  [unused-ignore]

prefect (https://github.com/PrefectHQ/prefect)
- src/prefect/deployments/runner.py:550: error: "Flow[Any, Any]" has no attribute "__name__"  [attr-defined]
+ src/prefect/deployments/runner.py:550: error: "Flow[Any, Any]" has no attribute "__name__"; maybe "__ne__" or "__new__"?  [attr-defined]
- src/prefect/server/models/block_registration.py:137: error: "SessionTransaction" has no attribute "__aenter__"  [attr-defined]
+ src/prefect/server/models/block_registration.py:137: error: "SessionTransaction" has no attribute "__aenter__"; maybe "__enter__"?  [attr-defined]
- src/prefect/server/models/block_registration.py:137: error: "SessionTransaction" has no attribute "__aexit__"  [attr-defined]
+ src/prefect/server/models/block_registration.py:137: error: "SessionTransaction" has no attribute "__aexit__"; maybe "__exit__"?  [attr-defined]
- src/prefect/server/models/block_registration.py:159: error: "SessionTransaction" has no attribute "__aenter__"  [attr-defined]
+ src/prefect/server/models/block_registration.py:159: error: "SessionTransaction" has no attribute "__aenter__"; maybe "__enter__"?  [attr-defined]
- src/prefect/server/models/block_registration.py:159: error: "SessionTransaction" has no attribute "__aexit__"  [attr-defined]
+ src/prefect/server/models/block_registration.py:159: error: "SessionTransaction" has no attribute "__aexit__"; maybe "__exit__"?  [attr-defined]
- src/prefect/server/database/interface.py:116: error: "Coroutine[Any, Any, Any]" has no attribute "__aexit__"  [attr-defined]
+ src/prefect/server/database/interface.py:116: error: "Coroutine[Any, Any, Any]" has no attribute "__aexit__"; maybe "__await__"?  [attr-defined]

apprise (https://github.com/caronc/apprise)
- test/helpers/rest.py:72: error: Need type annotation for "__tests" (hint: "__tests: list[<type>] = ...")  [var-annotated]
+ test/helpers/rest.py:72: error: Need type annotation for "_AppriseURLTester__tests" (hint: "_AppriseURLTester__tests: list[<type>] = ...")  [var-annotated]
- apprise/plugins/NotifyTelegram.py:205: error: Need type annotation for "__telegram_escape_html_entries"  [var-annotated]
+ apprise/plugins/NotifyTelegram.py:205: error: Need type annotation for "_NotifyTelegram__telegram_escape_html_entries"  [var-annotated]

graphql-core (https://github.com/graphql-python/graphql-core)
+ src/graphql/utilities/build_client_schema.py:80: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:676: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:678: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:700: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:702: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:717: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:730: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:750: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:772: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:789: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:811: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:833: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:857: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:881: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:905: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:926: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:947: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:964: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:968: error: Unused "type: ignore" comment  [unused-ignore]
+ tests/utilities/test_build_client_schema.py:979: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:983: error: Unused "type: ignore" comment  [unused-ignore]
+ tests/utilities/test_build_client_schema.py:1060: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:1090: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]

schemathesis (https://github.com/schemathesis/schemathesis)
+ src/schemathesis/runner/impl/core.py: note: In function "_generate_events":
+ src/schemathesis/runner/impl/core.py:142: error: No binding for nonlocal "__probes" found  [misc]
+ src/schemathesis/runner/impl/core.py:154: error: No binding for nonlocal "__analysis" found  [misc]
+ src/schemathesis/runner/impl/core.py:154: error: No binding for nonlocal "__probes" found  [misc]
+ src/schemathesis/runner/impl/core.py:164: error: Incompatible types in assignment (expression has type "Err[Exception]", variable has type "Ok[Union[AnalysisSuccess, AnalysisError]]")  [assignment]

PyGithub (https://github.com/PyGithub/PyGithub)
+ github/GithubObject.py:448: error: Unused "type: ignore" comment  [unused-ignore]

ibis (https://github.com/ibis-project/ibis)
- ibis/common/graph.py:255: error: "Node" has no attribute "__iter__" (not iterable)  [attr-defined]
+ ibis/common/graph.py:255: error: "Node" has no attribute "__iter__"; maybe "__dir__" or "__str__"? (not iterable)  [attr-defined]
- ibis/expr/datatypes/cast.py:119: error: "DataType" has no attribute "names"; maybe "name"?  [attr-defined]
+ ibis/expr/datatypes/cast.py:119: error: "DataType" has no attribute "names"; maybe "name" or "argnames"?  [attr-defined]
- ibis/expr/types/structs.py:147: error: "DataType" has no attribute "names"; maybe "name"?  [attr-defined]
+ ibis/expr/types/structs.py:147: error: "DataType" has no attribute "names"; maybe "name" or "argnames"?  [attr-defined]
- ibis/expr/types/structs.py:270: error: "DataType" has no attribute "names"; maybe "name"?  [attr-defined]
+ ibis/expr/types/structs.py:270: error: "DataType" has no attribute "names"; maybe "name" or "argnames"?  [attr-defined]
- ibis/expr/types/structs.py:387: error: "DataType" has no attribute "names"; maybe "name"?  [attr-defined]
+ ibis/expr/types/structs.py:387: error: "DataType" has no attribute "names"; maybe "name" or "argnames"?  [attr-defined]

discord.py (https://github.com/Rapptz/discord.py)
- discord/shard.py:354: error: Need type annotation for "__shards" (hint: "__shards: dict[<type>, <type>] = ...")  [var-annotated]
+ discord/shard.py:354: error: Need type annotation for "_AutoShardedClient__shards" (hint: "_AutoShardedClient__shards: dict[<type>, <type>] = ...")  [var-annotated]
- discord/shard.py:453: error: Need type annotation for "__queue"  [var-annotated]
+ discord/shard.py:453: error: Need type annotation for "_AutoShardedClient__queue"  [var-annotated]
+ discord/interactions.py:177: error: Unused "type: ignore" comment  [unused-ignore]
+ discord/webhook/async_.py:1222: error: Unused "type: ignore" comment  [unused-ignore]
+ discord/webhook/async_.py:1287: error: Unused "type: ignore" comment  [unused-ignore]
+ discord/webhook/async_.py:1325: error: Unused "type: ignore" comment  [unused-ignore]

hydra-zen (https://github.com/mit-ll-responsible-ai/hydra-zen)
+ src/hydra_zen/wrapper/_implementations.py:961: error: Missing key "_StoreCallSig__kw" for TypedDict "_StoreCallSig"  [typeddict-item]
+ src/hydra_zen/wrapper/_implementations.py:961: error: Extra key "__kw" for TypedDict "_StoreCallSig"  [typeddict-unknown-key]
+ src/hydra_zen/wrapper/_implementations.py:1546: error: TypedDict "_StoreCallSig" has no key "__kw"  [typeddict-unknown-key]
+ src/hydra_zen/wrapper/_implementations.py:1547: error: TypedDict "_StoreCallSig" has no key "__kw"  [typeddict-item]
+ src/hydra_zen/wrapper/_implementations.py:1589: error: TypedDict "_StoreCallSig" has no key "__kw"  [typeddict-item]

@tyralla
Copy link
Collaborator Author

tyralla commented Mar 28, 2024

Shortly after starting this pull request, @srittau opened python/typeshed#11237, and @hauntsaninja seems to have implemented most of it. Thanks!

So, prefixing parameters with two underscores to indicate privateness seems history. Should I then set the _MANGLE_ARGS option to True (or delete it)?

@tyralla
Copy link
Collaborator Author

tyralla commented Apr 4, 2024

So, prefixing parameters with two underscores to indicate privateness seems history. Should I then set the _MANGLE_ARGS option to True (or delete it)?

Maybe not

Copy link
Contributor

github-actions bot commented Nov 3, 2024

Diff from mypy_primer, showing the effect of this PR on open source code:

setuptools (https://github.com/pypa/setuptools)
+ pkg_resources/__init__.py:3412: error: Attribute "_DistInfoDistribution__dep_map" already defined on line 3407  [no-redef]

psycopg (https://github.com/psycopg/psycopg)
- tests/dbapi20_tpc.py:36: error: "TwoPhaseCommitTests" has no attribute "assertEquals"  [attr-defined]
+ tests/dbapi20_tpc.py:36: error: "TwoPhaseCommitTests" has no attribute "assertEquals"; maybe "assertEqual" or "assertFalse"?  [attr-defined]
- tests/dbapi20_tpc.py:37: error: "TwoPhaseCommitTests" has no attribute "assertEquals"  [attr-defined]
+ tests/dbapi20_tpc.py:37: error: "TwoPhaseCommitTests" has no attribute "assertEquals"; maybe "assertEqual" or "assertFalse"?  [attr-defined]
- tests/dbapi20_tpc.py:38: error: "TwoPhaseCommitTests" has no attribute "assertEquals"  [attr-defined]
+ tests/dbapi20_tpc.py:38: error: "TwoPhaseCommitTests" has no attribute "assertEquals"; maybe "assertEqual" or "assertFalse"?  [attr-defined]
- tests/dbapi20_tpc.py:42: error: "TwoPhaseCommitTests" has no attribute "assertEquals"  [attr-defined]
+ tests/dbapi20_tpc.py:42: error: "TwoPhaseCommitTests" has no attribute "assertEquals"; maybe "assertEqual" or "assertFalse"?  [attr-defined]
- tests/dbapi20_tpc.py:44: error: "TwoPhaseCommitTests" has no attribute "assertEquals"  [attr-defined]
+ tests/dbapi20_tpc.py:44: error: "TwoPhaseCommitTests" has no attribute "assertEquals"; maybe "assertEqual" or "assertFalse"?  [attr-defined]

prefect (https://github.com/PrefectHQ/prefect)
- src/prefect/server/database/interface.py:112: error: "Coroutine[Any, Any, Any]" has no attribute "__aexit__"  [attr-defined]
+ src/prefect/server/database/interface.py:112: error: "Coroutine[Any, Any, Any]" has no attribute "__aexit__"; maybe "__await__"?  [attr-defined]
- src/prefect/deployments/runner.py:538: error: "Flow[Any, Any]" has no attribute "__name__"  [attr-defined]
+ src/prefect/deployments/runner.py:538: error: "Flow[Any, Any]" has no attribute "__name__"; maybe "__ne__" or "__new__"?  [attr-defined]

colour (https://github.com/colour-science/colour)
- colour/plotting/common.py:828: error: "Patch" has no attribute "get_width"; maybe "get_linewidth"?  [attr-defined]
+ colour/plotting/common.py:828: error: "Patch" has no attribute "get_width"  [attr-defined]
- colour/plotting/common.py:834: error: "Patch" has no attribute "get_width"; maybe "get_linewidth"?  [attr-defined]
+ colour/plotting/common.py:834: error: "Patch" has no attribute "get_width"  [attr-defined]

comtypes (https://github.com/enthought/comtypes)
+ comtypes/automation.py:153: error: Name "U_VARIANT1.__tagVARIANT.U_VARIANT2" is not defined  [name-defined]

hydra-zen (https://github.com/mit-ll-responsible-ai/hydra-zen)
+ src/hydra_zen/wrapper/_implementations.py:994: error: Missing key "_StoreCallSig__kw" for TypedDict "_StoreCallSig"  [typeddict-item]
+ src/hydra_zen/wrapper/_implementations.py:994: error: Extra key "__kw" for TypedDict "_StoreCallSig"  [typeddict-unknown-key]
+ src/hydra_zen/wrapper/_implementations.py:1579: error: TypedDict "_StoreCallSig" has no key "__kw"  [typeddict-unknown-key]
+ src/hydra_zen/wrapper/_implementations.py:1580: error: TypedDict "_StoreCallSig" has no key "__kw"  [typeddict-item]
+ src/hydra_zen/wrapper/_implementations.py:1622: error: TypedDict "_StoreCallSig" has no key "__kw"  [typeddict-item]

dragonchain (https://github.com/dragonchain/dragonchain)
- dragonchain/lib/authorization_utest.py:35:13: error: "TestAuthorization" has no attribute "assertFail"  [attr-defined]
+ dragonchain/lib/authorization_utest.py:35:13: error: "TestAuthorization" has no attribute "assertFail"; maybe "assertFalse" or "assertEqual"?  [attr-defined]
- dragonchain/lib/dto/models_utest.py:185:9: error: "TestSmartContract" has no attribute "assertFail"  [attr-defined]
+ dragonchain/lib/dto/models_utest.py:185:9: error: "TestSmartContract" has no attribute "assertFail"; maybe "assertFalse" or "assertEqual"?  [attr-defined]
- dragonchain/lib/dto/models_utest.py:204:9: error: "TestSmartContract" has no attribute "assertFail"  [attr-defined]
+ dragonchain/lib/dto/models_utest.py:204:9: error: "TestSmartContract" has no attribute "assertFail"; maybe "assertFalse" or "assertEqual"?  [attr-defined]
- dragonchain/lib/dto/bnb_utest.py:42:13: error: "TestBinanceMethods" has no attribute "assertFail"  [attr-defined]
+ dragonchain/lib/dto/bnb_utest.py:42:13: error: "TestBinanceMethods" has no attribute "assertFail"; maybe "assertFalse" or "assertEqual"?  [attr-defined]

PyGithub (https://github.com/PyGithub/PyGithub)
+ github/GithubObject.py:530: error: Unused "type: ignore" comment  [unused-ignore]

steam.py (https://github.com/Gobot1234/steam.py)
- steam/ext/csgo/state.py:220: error: "ClientUser" has no attribute "_profile_info_msg"  [attr-defined]
+ steam/ext/csgo/state.py:220: error: "ClientUser" has no attribute "_profile_info_msg"; maybe "profile_info"?  [attr-defined]

discord.py (https://github.com/Rapptz/discord.py)
- discord/shard.py:354: error: Need type annotation for "__shards" (hint: "__shards: dict[<type>, <type>] = ...")  [var-annotated]
+ discord/shard.py:354: error: Need type annotation for "_AutoShardedClient__shards" (hint: "_AutoShardedClient__shards: dict[<type>, <type>] = ...")  [var-annotated]
- discord/shard.py:453: error: Need type annotation for "__queue"  [var-annotated]
+ discord/shard.py:453: error: Need type annotation for "_AutoShardedClient__queue"  [var-annotated]
+ discord/interactions.py:186: error: Unused "type: ignore" comment  [unused-ignore]
+ discord/webhook/async_.py:1226: error: Unused "type: ignore" comment  [unused-ignore]
+ discord/webhook/async_.py:1291: error: Unused "type: ignore" comment  [unused-ignore]
+ discord/webhook/async_.py:1329: error: Unused "type: ignore" comment  [unused-ignore]

ibis (https://github.com/ibis-project/ibis)
- ibis/common/graph.py:299: error: "Node" has no attribute "__iter__" (not iterable)  [attr-defined]
+ ibis/common/graph.py:299: error: "Node" has no attribute "__iter__"; maybe "__dir__" or "__str__"? (not iterable)  [attr-defined]
- ibis/common/graph.py:514: error: "Node" has no attribute "__iter__" (not iterable)  [attr-defined]
+ ibis/common/graph.py:514: error: "Node" has no attribute "__iter__"; maybe "__dir__" or "__str__"? (not iterable)  [attr-defined]
- ibis/expr/datatypes/cast.py:120: error: "DataType" has no attribute "names"; maybe "name"?  [attr-defined]
+ ibis/expr/datatypes/cast.py:120: error: "DataType" has no attribute "names"; maybe "name" or "argnames"?  [attr-defined]
- ibis/expr/types/structs.py:152: error: "DataType" has no attribute "names"; maybe "name"?  [attr-defined]
+ ibis/expr/types/structs.py:152: error: "DataType" has no attribute "names"; maybe "name" or "argnames"?  [attr-defined]
- ibis/expr/types/structs.py:275: error: "DataType" has no attribute "names"; maybe "name"?  [attr-defined]
+ ibis/expr/types/structs.py:275: error: "DataType" has no attribute "names"; maybe "name" or "argnames"?  [attr-defined]
- ibis/expr/types/structs.py:393: error: "DataType" has no attribute "names"; maybe "name"?  [attr-defined]
+ ibis/expr/types/structs.py:393: error: "DataType" has no attribute "names"; maybe "name" or "argnames"?  [attr-defined]

core (https://github.com/home-assistant/core)
+ homeassistant/components/onkyo/const.py:129: error: Unsupported target for indexed assignment ("InputSource")  [index]
+ homeassistant/components/onkyo/const.py:136: error: Returning Any from function declared to return "Self"  [no-any-return]
+ homeassistant/components/onkyo/const.py:136: error: Value of type "InputSource" is not indexable  [index]
+ homeassistant/components/sun/entity.py:128: error: Unused "type: ignore" comment  [unused-ignore]
+ homeassistant/components/fjaraskupan/binary_sensor.py:27: error: Signature of "_EntityDescription__mypy-replace" incompatible with supertype "EntityDescription"  [override]
+ homeassistant/components/fjaraskupan/binary_sensor.py:27: note:      Superclass:
+ homeassistant/components/fjaraskupan/binary_sensor.py:27: note:          def _EntityDescription__mypy-replace(*, key: str = ..., device_class: str | None = ..., entity_category: EntityCategory | None = ..., entity_registry_enabled_default: bool = ..., entity_registry_visible_default: bool = ..., force_update: bool = ..., icon: str | None = ..., has_entity_name: bool = ..., name: str | UndefinedType | None = ..., translation_key: str | None = ..., translation_placeholders: Mapping[str, str] | None = ..., unit_of_measurement: str | None = ...) -> None
+ homeassistant/components/fjaraskupan/binary_sensor.py:27: note:      Subclass:
+ homeassistant/components/fjaraskupan/binary_sensor.py:27: note:          def _EntityDescription__mypy-replace(*, is_on: Callable[..., Any] = ..., key: str = ..., device_class: BinarySensorDeviceClass | None = ..., entity_category: EntityCategory | None = ..., entity_registry_enabled_default: bool = ..., entity_registry_visible_default: bool = ..., force_update: bool = ..., icon: str | None = ..., has_entity_name: bool = ..., name: str | UndefinedType | None = ..., translation_key: str | None = ..., translation_placeholders: Mapping[str, str] | None = ..., unit_of_measurement: str | None = ...) -> None
+ homeassistant/components/fjaraskupan/binary_sensor.py:27: note:      Superclass:
+ homeassistant/components/fjaraskupan/binary_sensor.py:27: note:          def _EntityDescription__mypy-replace(*, key: str = ..., device_class: str | None = ..., entity_category: EntityCategory | None = ..., entity_registry_enabled_default: bool = ..., entity_registry_visible_default: bool = ..., force_update: bool = ..., icon: str | None = ..., has_entity_name: bool = ..., name: str | UndefinedType | None = ..., translation_key: str | None = ..., translation_placeholders: Mapping[str, str] | None = ..., unit_of_measurement: str | None = ...) -> None
+ homeassistant/components/fjaraskupan/binary_sensor.py:27: note:      Subclass:
+ homeassistant/components/fjaraskupan/binary_sensor.py:27: note:          def _EntityDescription__mypy-replace(*, key: str = ..., device_class: BinarySensorDeviceClass | None = ..., entity_category: EntityCategory | None = ..., entity_registry_enabled_default: bool = ..., entity_registry_visible_default: bool = ..., force_update: bool = ..., icon: str | None = ..., has_entity_name: bool = ..., name: str | UndefinedType | None = ..., translation_key: str | None = ..., translation_placeholders: Mapping[str, str] | None = ..., unit_of_measurement: str | None = ..., is_on: Callable[..., Any] = ...) -> None

apprise (https://github.com/caronc/apprise)
- apprise/plugins/telegram.py:238: error: Need type annotation for "__telegram_escape_html_entries"  [var-annotated]
+ apprise/plugins/telegram.py:238: error: Need type annotation for "_NotifyTelegram__telegram_escape_html_entries"  [var-annotated]
- test/helpers/rest.py:73: error: Need type annotation for "__tests" (hint: "__tests: list[<type>] = ...")  [var-annotated]
+ test/helpers/rest.py:73: error: Need type annotation for "_AppriseURLTester__tests" (hint: "_AppriseURLTester__tests: list[<type>] = ...")  [var-annotated]

graphql-core (https://github.com/graphql-python/graphql-core)
+ src/graphql/utilities/build_client_schema.py:82: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:677: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:679: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:701: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:703: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:718: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:731: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:751: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:773: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:790: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:812: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:834: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:858: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:882: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:906: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:927: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:948: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:965: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:969: error: Unused "type: ignore" comment  [unused-ignore]
+ tests/utilities/test_build_client_schema.py:980: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:984: error: Unused "type: ignore" comment  [unused-ignore]
+ tests/utilities/test_build_client_schema.py:1061: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]
+ tests/utilities/test_build_client_schema.py:1091: error: TypedDict "IntrospectionQuery" has no key "__schema"  [typeddict-item]

schemathesis (https://github.com/schemathesis/schemathesis)
+ src/schemathesis/runner/impl/core.py: note: In function "_generate_events":
+ src/schemathesis/runner/impl/core.py:169: error: No binding for nonlocal "__probes" found  [misc]
+ src/schemathesis/runner/impl/core.py:181: error: No binding for nonlocal "__analysis" found  [misc]
+ src/schemathesis/runner/impl/core.py:181: error: No binding for nonlocal "__probes" found  [misc]
+ src/schemathesis/runner/impl/core.py:191: error: Incompatible types in assignment (expression has type "Err[Exception]", variable has type "Ok[Union[AnalysisSuccess, AnalysisError]]")  [assignment]

antidote (https://github.com/Finistere/antidote)
+ src/antidote/core/_catalog.py:541: error: Name "_CatalogOverrideImpl__dependency" is not defined  [name-defined]
+ src/antidote/core/_catalog.py:542: error: Name "_CatalogOverrideImpl__dependency" is not defined  [name-defined]
+ src/antidote/core/_catalog.py:543: error: Name "_CatalogOverrideImpl__dependency" is not defined  [name-defined]
+ src/antidote/lib/interface_ext/_interface.py:487: error: Name "_ImplementsImpl__existing_implementation" is not defined  [name-defined]
+ src/antidote/lib/interface_ext/_interface.py:493: error: Name "_ImplementsImpl__existing_implementation" is not defined  [name-defined]
+ tests/core/test_wiring.py:152: error: Unused "type: ignore" comment  [unused-ignore]

Copy link

@davidhalter davidhalter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally feel like name mangling should not be supported and mangled names should stay private and filtered as such. People accessing symbols such as _Foo__bar should not be able to do that in Mypy.

@@ -2994,7 +2994,7 @@ from typing import TypeVar, Protocol, Generic, Optional
T = TypeVar('T')

class F(Protocol[T]):
def __call__(self, __x: T) -> T: ...

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally don't think these should be renamed. These also work fine with inspect.signature.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure what you mean:

>>> import inspect
>>> class C:
...     def f(self, __x: int) -> str: ...
>>> print(inspect.signature(C.f))
(self, _C__x: int) -> str
>>> print(inspect.signature(C().f))
(_C__x: int) -> str

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh wow, sorry that was really my bad.

@tyralla
Copy link
Collaborator Author

tyralla commented Nov 3, 2024

I personally feel like name mangling should not be supported and mangled names should stay private and filtered as such. People accessing symbols such as _Foo__bar should not be able to do that in Mypy.

General topic "type vs. style checker". If this needs further discussion, probably better in #8267?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

mypy fails to report missing "private" __x attribute
4 participants