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

Python 3.9 AttributeError: __args__ #231

Closed
GameDungeon opened this issue May 21, 2021 · 28 comments
Closed

Python 3.9 AttributeError: __args__ #231

GameDungeon opened this issue May 21, 2021 · 28 comments

Comments

@GameDungeon
Copy link

I honestly cannot parse this error message.

I'm trying to run monkeytype on manim's mobject.py

monkeytype stub manim.mobject.mobject

Traceback (most recent call last):
  File "C:\Python39\lib\runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Python39\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\Users\ethan\AppData\Local\pypoetry\Cache\virtualenvs\manim-ob3XvX2_-py3.9\Scripts\monkeytype.exe\__main__.py", line 7, in <module>
  File "c:\users\ethan\appdata\local\pypoetry\cache\virtualenvs\manim-ob3xvx2_-py3.9\lib\site-packages\monkeytype\cli.py", line 396, in entry_point_main
    sys.exit(main(sys.argv[1:], sys.stdout, sys.stderr))
  File "c:\users\ethan\appdata\local\pypoetry\cache\virtualenvs\manim-ob3xvx2_-py3.9\lib\site-packages\monkeytype\cli.py", line 381, in main
    handler(args, stdout, stderr)
  File "c:\users\ethan\appdata\local\pypoetry\cache\virtualenvs\manim-ob3xvx2_-py3.9\lib\site-packages\monkeytype\cli.py", line 199, in print_stub_handler
    stub = get_stub(args, stdout, stderr)
  File "c:\users\ethan\appdata\local\pypoetry\cache\virtualenvs\manim-ob3xvx2_-py3.9\lib\site-packages\monkeytype\cli.py", line 126, in get_stub
    stubs = build_module_stubs_from_traces(
  File "c:\users\ethan\appdata\local\pypoetry\cache\virtualenvs\manim-ob3xvx2_-py3.9\lib\site-packages\monkeytype\stubs.py", line 819, in build_module_stubs_from_traces
    return build_module_stubs(defns)
  File "c:\users\ethan\appdata\local\pypoetry\cache\virtualenvs\manim-ob3xvx2_-py3.9\lib\site-packages\monkeytype\stubs.py", line 784, in build_module_stubs
    imports = get_imports_for_signature(entry.signature)
  File "c:\users\ethan\appdata\local\pypoetry\cache\virtualenvs\manim-ob3xvx2_-py3.9\lib\site-packages\monkeytype\stubs.py", line 157, in get_imports_for_signature
    param_imports = get_imports_for_annotation(param.annotation)
  File "c:\users\ethan\appdata\local\pypoetry\cache\virtualenvs\manim-ob3xvx2_-py3.9\lib\site-packages\monkeytype\stubs.py", line 143, in get_imports_for_annotation
    elem_types = anno.__args__ or []
  File "C:\Python39\lib\typing.py", line 694, in __getattr__
    raise AttributeError(attr)
AttributeError: __args__
@GameDungeon
Copy link
Author

Version 21.5.0 for MonkeyType

@GameDungeon
Copy link
Author

@carljm This is becoming quite an issue for me as it chooses seemingly random files that I am completely unable to stub with monkeytype. Can you offer any advice?

@GameDungeon
Copy link
Author

GameDungeon commented May 24, 2021

this seems quite similar to #122. The main difference is the error is deterministic.

@carljm
Copy link
Contributor

carljm commented May 24, 2021

@GameDungeon There is some kind of type present in your annotations that passes the is_generic() test at https://github.com/Instagram/MonkeyType/blob/master/monkeytype/stubs.py#L137 but yet doesn't have an __args__ attribute, which most generic types should have, and so fails at https://github.com/Instagram/MonkeyType/blob/master/monkeytype/stubs.py#L143

It would be useful to know what type this is; probably once we know it won't be hard to add support for it. If you are able to temporarily add a try: ... except AttributeError: import pdb; pdb.set_trace() around line 143 locally, it will drop you into pdb (the Python debugger) when the error is hit, which should allow you to explore what value the anno name references. If you have trouble with this, if you can provide a precise set of instructions to reproduce the problem using publicly-available code, I will look into it when I can.

@GameDungeon
Copy link
Author

The error comes up when trying to stub camera.py and mobject.py both are untyped as of now. I'll try the except.

@GameDungeon
Copy link
Author

GameDungeon commented May 24, 2021

Ok, I think I found it:
WARNING: Failed decoding trace: Attribute specified by 'Callable' in module 'typing' is of type <class 'typing._CallableType'>, not type. When opening the terminal in admin it works but tells me traces failed to decode. Verbose output gives me the above.

@GameDungeon
Copy link
Author

Also if you see this later, quick question. Does MonkeyType allow for custom generics?

@carljm
Copy link
Contributor

carljm commented May 24, 2021

@GameDungeon The Callable trace decoding failure doesn't seem clearly related to the __args__ AttributeError.

If you want me to repro I'll need more detailed instructions; in particular the key missing step is how you are collecting the traces in the first place.

MonkeyType doesn't record generic arg types for custom generics; it has no way to know how to introspect an instance of an arbitrary generic type to find the right types for its type args.

@GameDungeon
Copy link
Author

GameDungeon commented May 24, 2021

I'm currently calling monkeytype run on this.

from collections import Counter
import importlib
import warnings
from manim.utils.color import Colors
import manim
import os
import sys
import inspect
from manim import *
import re

from typing import List, Callable, Dict, Any, Tuple

config.verbosity = "ERROR"
warnings.filterwarnings("ignore")

errors = 0
all_errors: List[Any] = list()


class arg_generator:
    def __init__(self) -> None:
        func = lambda *args : args[0]

        self.end_args: Dict[str, Any] = dict()

        self.checks = {
            "mobject": Mobject,
            "vmobject": VMobject(),
            "t": 0,
            "animation": Animation(Mobject()),
            "text": "Hello",
            "angle": 100,
            "function": func,
            "func": func,
            "name": "Fred",
            "vmob": VMobject(),
            "color": Colors.black.value,
            "matrix": Matrix([[2, 2], [2, 2]]),
            "n": 0,
            "obj": "obj",
            "line1": Line(),
            "line2": Line(),
            "method": Line().add_tip(),
            "points": [(1, 1), (2, 2)],
            "camera": Camera(),
            "a": 1.0,
            "b": 1.0,
            "start": (1, 1),
            "end": (2, 2),
        }

    def arg_check(self, sig: List[Any], check: str, final: Any) -> None:
        if check in sig:
            self.end_args[check] = final

    def generate_args(self, sig: List[Any]) -> Dict[str, Any]:
        self.end_args = dict()

        for key in self.checks.keys():
            self.arg_check(sig, key, self.checks[key])

        return self.end_args


def run_function(obj, end_args: Dict[str, Any], kill: bool = False) -> bool:
    global errors
    global all_errors
    try:
        obj(**end_args)

    except TypeError as e:
        sig = inspect.signature(obj)
        need_sig = list({k: v.default for k, v in sig.parameters.items()}.keys())
        arg_gen = arg_generator()

        x = tuple(re.findall(r"\'([^\']*)\'", str(e)))

        if x == ():
            print(f"{obj.__name__}, Error: {e}")
            return False

        if kill:
            # print(f"{obj.__name__}, Failed: {x}")
            all_errors.append(x)
            errors += 1
            return False

        if need_sig == [
            "mobject",
            "args",
            "use_override",
            "kwargs",
        ]:  # Needed due to strange bug. Might effect animation typings.
            return False

        run_function(obj, arg_gen.generate_args(need_sig), True)

    except Exception as e:
        # print(f"Error: {e} from {obj.__name__}")
        return False

    return True


def all_tests(start: str = "tests") -> None:
    sys.path.append(start)

    for file in os.listdir(start):
        if file.startswith("test_"):
            try:
                importlib.import_module(file[:-3])
            except ImportError as e:
                struct = f"{start}//{file}"
                if os.path.isdir(struct):
                    all_tests(struct)
            except Exception as e:
                print("Can't run this test: " + file)
                print(e)


def all_classes() -> None:
    for name, obj in inspect.getmembers(manim):
        if callable(obj):
            run_function(obj, dict())


all_tests()
all_classes()

The above is designed to give monkeytype as much info as possible for its typings as everything else barely touches anything. (are tests are at 50% coverage)

Download the manim git, pop that file at the git's root and the monkey type run it. After that try to call monkeytype stub on camera.

@GameDungeon
Copy link
Author

I think this error might be the missing piece in the puzzle:

Failed to serialize trace
Traceback (most recent call last):
  File "c:\python39\lib\site-packages\monkeytype\encoding.py", line 249, in serialize_traces
    yield CallTraceRow.from_trace(trace)
  File "c:\python39\lib\site-packages\monkeytype\encoding.py", line 211, in from_trace
    return_type = maybe_encode_type(type_to_json, trace.return_type)
  File "c:\python39\lib\site-packages\monkeytype\encoding.py", line 174, in maybe_encode_type
    return encode(typ)
  File "c:\python39\lib\site-packages\monkeytype\encoding.py", line 146, in type_to_json
    type_dict = type_to_dict(typ)
  File "c:\python39\lib\site-packages\monkeytype\encoding.py", line 82, in type_to_dict
    qualname = typ.__qualname__
  File "c:\python39\lib\typing.py", line 694, in __getattr__
    raise AttributeError(attr)
AttributeError: __qualname__

I get a ton of those when running MonkeyType run on the above. Need anything else @carljm?

@GameDungeon
Copy link
Author

GameDungeon commented May 24, 2021

I have to believe the above error is directly causing:

WARNING: Failed decoding trace: Attribute specified by 'Callable' in module 'typing' is of type <class 'typing._CallableType'>, not type

Still see no clear connection between that and the original error.

@carljm
Copy link
Contributor

carljm commented May 27, 2021

I'm having trouble even getting types collected. After a bunch of work to install all the manim dependencies, I'm now getting this error:

➜ monkeytype run collect.py
Manim Community v0.6.0

[05/27/21 11:04:24] ERROR    LaTeX compilation error! LaTeX reports:                                                                                          tex_file_writing.py:180
Traceback (most recent call last):
  File "collect.py", line 70, in run_function
    obj(**end_args)
TypeError: __init__() missing 1 required positional argument: 'scale_to_resolution'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/carljm/Library/Caches/pypoetry/virtualenvs/manim-RhTJCDRG-py3.8/bin/monkeytype", line 33, in <module>
    sys.exit(load_entry_point('MonkeyType', 'console_scripts', 'monkeytype')())
  File "/Users/carljm/projects/monkeytype/monkeytype/cli.py", line 396, in entry_point_main
    sys.exit(main(sys.argv[1:], sys.stdout, sys.stderr))
  File "/Users/carljm/projects/monkeytype/monkeytype/cli.py", line 381, in main
    handler(args, stdout, stderr)
  File "/Users/carljm/projects/monkeytype/monkeytype/cli.py", line 224, in run_handler
    runpy.run_path(args.script_path, run_name='__main__')
  File "/Users/carljm/.pythonz/pythons/CPython-3.8.7/lib/python3.8/runpy.py", line 265, in run_path
    return _run_module_code(code, init_globals, run_name,
  File "/Users/carljm/.pythonz/pythons/CPython-3.8.7/lib/python3.8/runpy.py", line 97, in _run_module_code
    _run_code(code, mod_globals, init_globals,
  File "/Users/carljm/.pythonz/pythons/CPython-3.8.7/lib/python3.8/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "collect.py", line 129, in <module>
    all_classes()
  File "collect.py", line 125, in all_classes
    run_function(obj, dict())
  File "collect.py", line 75, in run_function
    arg_gen = arg_generator()
  File "collect.py", line 39, in __init__
    "matrix": Matrix([[2, 2], [2, 2]]),
  File "/Users/carljm/projects/manim/manim/manim/mobject/matrix.py", line 130, in __init__
    mob_matrix = self.matrix_to_mob_matrix(matrix)
  File "/Users/carljm/projects/manim/manim/manim/mobject/matrix.py", line 144, in matrix_to_mob_matrix
    return np.vectorize(self.element_to_mobject)(
  File "/Users/carljm/Library/Caches/pypoetry/virtualenvs/manim-RhTJCDRG-py3.8/lib/python3.8/site-packages/numpy/lib/function_base.py", line 2113, in __call__
    return self._vectorize_call(func=func, args=vargs)
  File "/Users/carljm/Library/Caches/pypoetry/virtualenvs/manim-RhTJCDRG-py3.8/lib/python3.8/site-packages/numpy/lib/function_base.py", line 2191, in _vectorize_call
    ufunc, otypes = self._get_ufunc_and_otypes(func=func, args=args)
  File "/Users/carljm/Library/Caches/pypoetry/virtualenvs/manim-RhTJCDRG-py3.8/lib/python3.8/site-packages/numpy/lib/function_base.py", line 2151, in _get_ufunc_and_otypes
    outputs = func(*inputs)
  File "/Users/carljm/projects/manim/manim/manim/mobject/svg/tex_mobject.py", line 432, in __init__
    SingleStringMathTex.__init__(
  File "/Users/carljm/projects/manim/manim/manim/mobject/svg/tex_mobject.py", line 259, in __init__
    file_name = tex_to_svg_file(
  File "/Users/carljm/projects/manim/manim/manim/utils/tex_file_writing.py", line 44, in tex_to_svg_file
    dvi_file = compile_tex(
  File "/Users/carljm/projects/manim/manim/manim/utils/tex_file_writing.py", line 202, in compile_tex
    while not tex_lines[environment - 1].startswith("\\end"):
NameError: name 'tex_lines' is not defined

@GameDungeon
Copy link
Author

That is strange. It seems you got the github version too. I'll see if I can replicate the error.

@carljm
Copy link
Contributor

carljm commented May 27, 2021

FWIW I'm on OS X and installed latex via brew install basictex. FWIW it looks like that tex_lines variable really is not defined, so I'm guessing you must be somehow avoiding that codepath altogether.

@GameDungeon
Copy link
Author

Is running every function with the right parameters a healthy way to use monkeytype?

@carljm
Copy link
Contributor

carljm commented May 27, 2021

Is running every function with the right parameters a healthy way to use monkeytype?

It's not an approach I've seen before. It should work, but the types you get out will be only as good as what you put in. Typically you'd run MonkeyType with a more realistic workload (test suite and/or some kind of "production" workload), and for stuff you can't get covered that way, you'd add types a different way. E.g. if you can reliably predict the types of args based on their name, then you could write a LibCST transform (even based on MonkeyType's) to just add those types to args with those names if not already annotated, without going through MonkeyType for it.

@GameDungeon
Copy link
Author

"but the types you get out will be only as good as what you put in" If I put in a bad type and it errors will monkey type still log it?

@carljm
Copy link
Contributor

carljm commented May 27, 2021

Yeah if a function raises an exception, MonkeyType will still log the argument types, just no return type for that particular execution.

@GameDungeon
Copy link
Author

While I believe that any function that raises an exception shouldn't be logged, I'll keep that in mind. I went this route as the test suite for manim is lacking.

@carljm
Copy link
Contributor

carljm commented May 27, 2021

While I believe that any function that raises an exception shouldn't be logged

There are plenty of cases where functions raise exceptions that are not related to a bad type of argument being passed in. There could even be cases where a certain type of argument always results in an exception in practice, but this is part of the contract of the function and that type should still be annotated as valid for that argument!

MonkeyType's job is to record what happens at runtime and tell you about the types it saw, not to make judgements (which will inevitably not be right for all cases) about which executions were valid or invalid.

@GameDungeon
Copy link
Author

GameDungeon commented May 27, 2021

Ok I see your point, I'll just have to be careful then.
I ran it again and got instead of the normal error:
WARNING: Failed decoding trace: Attribute specified by 'Type' in module 'typing' is of type <class 'typing._SpecialGenericAlias'>, not type.
WARNING: Failed decoding trace: Module 'builtins' has no attribute 'list_iterator'
WARNING: Failed decoding trace: Attribute specified by 'List' in module 'typing' is of type <class 'typing._SpecialGenericAlias'>, not type.

@GameDungeon
Copy link
Author

@carljm Soon I'm just going to move on from this issue, as it has taken a lot of time, but let me know if you need my help.

@GameDungeon
Copy link
Author

GameDungeon commented May 31, 2021

Now I'm getting this lovely error: AttributeError: '_SpecialForm' object has no attribute '__name__'. This has been a fun time.

@ntjess
Copy link

ntjess commented Jun 3, 2021

I reproduced the __args__ error with a much easier setup:

# monkeymodule/file1.py
def to_str(func):
  def wrapper(*args):
    newArgs = tuple(map(str, args))
    return func(*newArgs)
  return wrapper

@to_str
def add(a, b):
  return a + b
# monkeymodule/file2.py
from monkeymodule.file1 import add
add(1,2)

Terminal script:

monkeytype.exe run .\monkeymodule\file2.py
monkeytype.exe stub monkeymodule.file1

Trace:

Traceback (most recent call last):
  File "<userpath>\miniconda3\envs\py39\lib\runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "<userpath>\miniconda3\envs\py39\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "<userpath>\Miniconda3\envs\py39\Scripts\monkeytype.exe\__main__.py", line 7, in <module>
  File "<userpath>\miniconda3\envs\py39\lib\site-packages\monkeytype\cli.py", line 396, in entry_point_main
    sys.exit(main(sys.argv[1:], sys.stdout, sys.stderr))
  File "<userpath>\miniconda3\envs\py39\lib\site-packages\monkeytype\cli.py", line 381, in main
    handler(args, stdout, stderr)
  File "<userpath>\miniconda3\envs\py39\lib\site-packages\monkeytype\cli.py", line 199, in print_stub_handler
    stub = get_stub(args, stdout, stderr)
  File "<userpath>\miniconda3\envs\py39\lib\site-packages\monkeytype\cli.py", line 126, in get_stub
    stubs = build_module_stubs_from_traces(
  File "<userpath>\miniconda3\envs\py39\lib\site-packages\monkeytype\stubs.py", line 819, in build_module_stubs_from_traces
    return build_module_stubs(defns)
  File "<userpath>\miniconda3\envs\py39\lib\site-packages\monkeytype\stubs.py", line 784, in build_module_stubs
    imports = get_imports_for_signature(entry.signature)
  File "<userpath>\miniconda3\envs\py39\lib\site-packages\monkeytype\stubs.py", line 157, in get_imports_for_signature
    param_imports = get_imports_for_annotation(param.annotation)
  File "<userpath>\miniconda3\envs\py39\lib\site-packages\monkeytype\stubs.py", line 143, in get_imports_for_annotation
    elem_types = anno.__args__ or []
  File "<userpath>\miniconda3\envs\py39\lib\typing.py", line 694, in __getattr__
    raise AttributeError(attr)
AttributeError: __args__

@GameDungeon
Copy link
Author

ok, it seems to break on decorators? still wondering on the "AttributeError: '_SpecialForm' object has no attribute 'name'"

@carljm
Copy link
Contributor

carljm commented Jun 5, 2021

Thanks @ntjess for the simple repro! It looks like in Python 3.9 unbound typing.Callable has no __args__ attribute, whereas in previous Python versions it had __args__ of empty tuple. Should be a pretty easy fix.

@carljm
Copy link
Contributor

carljm commented Jun 5, 2021

@GameDungeon

Now I'm getting this lovely error: AttributeError: '_SpecialForm' object has no attribute 'name'. This has been a fun time.

Sorry for the unpleasant experience. MonkeyType uses internal API of the typing module that changes on every Python release, and the 3.9 support is not very well exercised yet. If you have the option of using Python 3.8 instead, I expect you might have a better experience. But thanks for helping flush out bugs in the 3.9 support!

If you want to file a separate issue with a full traceback for the SpecialForm has no attribute __name__ I can see if I can repro it.

@carljm
Copy link
Contributor

carljm commented Jun 5, 2021

Fixed with merge of #237.

@carljm carljm closed this as completed Jun 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants