Skip to content

Commit

Permalink
wrap GeneratorModel methods into BoundMethod; remove redundant test (#…
Browse files Browse the repository at this point in the history
…2584)

The LookupTest.test_generator_attributes contains outdated Python 2
   code (doesn't run on Python 3). The test is superceded by
   GeneratorModelTest.test_model.

Fix AsyncGenerator test and model, they just weren't used before
  • Loading branch information
temyurchenko authored Sep 25, 2024
1 parent eb88dfe commit a3f5c4a
Show file tree
Hide file tree
Showing 5 changed files with 18 additions and 55 deletions.
4 changes: 4 additions & 0 deletions astroid/bases.py
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,10 @@ def __str__(self) -> str:
class AsyncGenerator(Generator):
"""Special node representing an async generator."""

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
AsyncGenerator.special_attributes = objectmodel.AsyncGeneratorModel()

def pytype(self) -> Literal["builtins.async_generator"]:
return "builtins.async_generator"

Expand Down
26 changes: 11 additions & 15 deletions astroid/interpreter/objectmodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -695,19 +695,19 @@ def attr___self__(self):


class GeneratorModel(FunctionModel, ContextManagerModel):
def __new__(cls, *args, **kwargs):
def __init__(self):
# Append the values from the GeneratorType unto this object.
ret = super().__new__(cls, *args, **kwargs)
super().__init__()
generator = AstroidManager().builtins_module["generator"]
for name, values in generator.locals.items():
method = values[0]
if isinstance(method, nodes.FunctionDef):
method = bases.BoundMethod(method, _get_bound_node(self))

def patched(cls, meth=method):
return meth

setattr(type(ret), IMPL_PREFIX + name, property(patched))

return ret
setattr(type(self), IMPL_PREFIX + name, property(patched))

@property
def attr___name__(self):
Expand All @@ -724,24 +724,20 @@ def attr___doc__(self):


class AsyncGeneratorModel(GeneratorModel):
def __new__(cls, *args, **kwargs):
def __init__(self):
# Append the values from the AGeneratorType unto this object.
ret = super().__new__(cls, *args, **kwargs)
super().__init__()
astroid_builtins = AstroidManager().builtins_module
generator = astroid_builtins.get("async_generator")
if generator is None:
# Make it backward compatible.
generator = astroid_builtins.get("generator")

generator = astroid_builtins["async_generator"]
for name, values in generator.locals.items():
method = values[0]
if isinstance(method, nodes.FunctionDef):
method = bases.BoundMethod(method, _get_bound_node(self))

def patched(cls, meth=method):
return meth

setattr(type(ret), IMPL_PREFIX + name, property(patched))

return ret
setattr(type(self), IMPL_PREFIX + name, property(patched))


class InstanceModel(ObjectModel):
Expand Down
6 changes: 2 additions & 4 deletions astroid/raw_building.py
Original file line number Diff line number Diff line change
Expand Up @@ -627,9 +627,8 @@ def _astroid_bootstrapping() -> None:
col_offset=0,
end_lineno=0,
end_col_offset=0,
parent=nodes.Unknown(),
parent=astroid_builtin,
)
_GeneratorType.parent = astroid_builtin
generator_doc_node = (
nodes.Const(value=types.GeneratorType.__doc__)
if types.GeneratorType.__doc__
Expand All @@ -651,9 +650,8 @@ def _astroid_bootstrapping() -> None:
col_offset=0,
end_lineno=0,
end_col_offset=0,
parent=nodes.Unknown(),
parent=astroid_builtin,
)
_AsyncGeneratorType.parent = astroid_builtin
async_generator_doc_node = (
nodes.Const(value=types.AsyncGeneratorType.__doc__)
if types.AsyncGeneratorType.__doc__
Expand Down
18 changes: 0 additions & 18 deletions tests/test_lookup.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,24 +322,6 @@ class _Inner:
self.assertEqual(len(name.lookup("x")[1]), 1, repr(name))
self.assertEqual(name.lookup("x")[1][0].lineno, 3, repr(name))

def test_generator_attributes(self) -> None:
tree = builder.parse(
"""
def count():
"test"
yield 0
iterer = count()
num = iterer.next()
"""
)
next_node = tree.body[2].value.func
gener = next_node.expr.inferred()[0]
self.assertIsInstance(gener.getattr("__next__")[0], nodes.FunctionDef)
self.assertIsInstance(gener.getattr("send")[0], nodes.FunctionDef)
self.assertIsInstance(gener.getattr("throw")[0], nodes.FunctionDef)
self.assertIsInstance(gener.getattr("close")[0], nodes.FunctionDef)

def test_explicit___name__(self) -> None:
code = """
class Pouet:
Expand Down
19 changes: 1 addition & 18 deletions tests/test_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1454,7 +1454,7 @@ def test(self):
assert bool(inferred.is_generator())


class AsyncGeneratorTest:
class AsyncGeneratorTest(unittest.TestCase):
def test_async_generator(self):
node = astroid.extract_node(
"""
Expand All @@ -1472,23 +1472,6 @@ async def a_iter(n):
assert inferred.pytype() == "builtins.async_generator"
assert inferred.display_type() == "AsyncGenerator"

def test_async_generator_is_generator_on_older_python(self):
node = astroid.extract_node(
"""
async def a_iter(n):
for i in range(1, n + 1):
yield i
await asyncio.sleep(1)
a_iter(2) #@
"""
)
inferred = next(node.infer())
assert isinstance(inferred, bases.Generator)
assert inferred.getattr("__iter__")
assert inferred.getattr("__next__")
assert inferred.pytype() == "builtins.generator"
assert inferred.display_type() == "Generator"


def test_f_string_correct_line_numbering() -> None:
"""Test that we generate correct line numbers for f-strings."""
Expand Down

0 comments on commit a3f5c4a

Please sign in to comment.