diff options
author | Pierre Sassoulas <pierre.sassoulas@gmail.com> | 2023-02-09 22:34:26 +0100 |
---|---|---|
committer | Pierre Sassoulas <pierre.sassoulas@gmail.com> | 2023-02-09 23:53:46 +0100 |
commit | 90f456fd12f6e1d3415b24831093a7abaa3cac64 (patch) | |
tree | 5e855770e2c92237266cf066169d0df1107346ab /tests | |
parent | 6fb696561d1ad580f5ee7349df2f6a2bdbc4af64 (diff) | |
download | astroid-git-90f456fd12f6e1d3415b24831093a7abaa3cac64.tar.gz |
[brain tests] Burst named tuple from the main file
Diffstat (limited to 'tests')
-rw-r--r-- | tests/brain/test_brain.py | 300 | ||||
-rw-r--r-- | tests/brain/test_named_tuple.py | 311 |
2 files changed, 311 insertions, 300 deletions
diff --git a/tests/brain/test_brain.py b/tests/brain/test_brain.py index 839d1fb4..43a06e6a 100644 --- a/tests/brain/test_brain.py +++ b/tests/brain/test_brain.py @@ -127,306 +127,6 @@ class OrderedDictTest(unittest.TestCase): self.assertIn("move_to_end", inferred.locals) -class NamedTupleTest(unittest.TestCase): - def test_namedtuple_base(self) -> None: - klass = builder.extract_node( - """ - from collections import namedtuple - - class X(namedtuple("X", ["a", "b", "c"])): - pass - """ - ) - assert isinstance(klass, nodes.ClassDef) - self.assertEqual( - [anc.name for anc in klass.ancestors()], ["X", "tuple", "object"] - ) - # See: https://github.com/PyCQA/pylint/issues/5982 - self.assertNotIn("X", klass.locals) - for anc in klass.ancestors(): - self.assertFalse(anc.parent is None) - - def test_namedtuple_inference(self) -> None: - klass = builder.extract_node( - """ - from collections import namedtuple - - name = "X" - fields = ["a", "b", "c"] - class X(namedtuple(name, fields)): - pass - """ - ) - assert isinstance(klass, nodes.ClassDef) - base = next(base for base in klass.ancestors() if base.name == "X") - self.assertSetEqual({"a", "b", "c"}, set(base.instance_attrs)) - - def test_namedtuple_inference_failure(self) -> None: - klass = builder.extract_node( - """ - from collections import namedtuple - - def foo(fields): - return __(namedtuple("foo", fields)) - """ - ) - self.assertIs(util.Uninferable, next(klass.infer())) - - def test_namedtuple_advanced_inference(self) -> None: - # urlparse return an object of class ParseResult, which has a - # namedtuple call and a mixin as base classes - result = builder.extract_node( - """ - from urllib.parse import urlparse - - result = __(urlparse('gopher://')) - """ - ) - instance = next(result.infer()) - self.assertGreaterEqual(len(instance.getattr("scheme")), 1) - self.assertGreaterEqual(len(instance.getattr("port")), 1) - with self.assertRaises(AttributeInferenceError): - instance.getattr("foo") - self.assertGreaterEqual(len(instance.getattr("geturl")), 1) - self.assertEqual(instance.name, "ParseResult") - - def test_namedtuple_instance_attrs(self) -> None: - result = builder.extract_node( - """ - from collections import namedtuple - namedtuple('a', 'a b c')(1, 2, 3) #@ - """ - ) - inferred = next(result.infer()) - for name, attr in inferred.instance_attrs.items(): - self.assertEqual(attr[0].attrname, name) - - def test_namedtuple_uninferable_fields(self) -> None: - node = builder.extract_node( - """ - x = [A] * 2 - from collections import namedtuple - l = namedtuple('a', x) - l(1) - """ - ) - inferred = next(node.infer()) - self.assertIs(util.Uninferable, inferred) - - def test_namedtuple_access_class_fields(self) -> None: - node = builder.extract_node( - """ - from collections import namedtuple - Tuple = namedtuple("Tuple", "field other") - Tuple #@ - """ - ) - inferred = next(node.infer()) - self.assertIn("field", inferred.locals) - self.assertIn("other", inferred.locals) - - def test_namedtuple_rename_keywords(self) -> None: - node = builder.extract_node( - """ - from collections import namedtuple - Tuple = namedtuple("Tuple", "abc def", rename=True) - Tuple #@ - """ - ) - inferred = next(node.infer()) - self.assertIn("abc", inferred.locals) - self.assertIn("_1", inferred.locals) - - def test_namedtuple_rename_duplicates(self) -> None: - node = builder.extract_node( - """ - from collections import namedtuple - Tuple = namedtuple("Tuple", "abc abc abc", rename=True) - Tuple #@ - """ - ) - inferred = next(node.infer()) - self.assertIn("abc", inferred.locals) - self.assertIn("_1", inferred.locals) - self.assertIn("_2", inferred.locals) - - def test_namedtuple_rename_uninferable(self) -> None: - node = builder.extract_node( - """ - from collections import namedtuple - Tuple = namedtuple("Tuple", "a b c", rename=UNINFERABLE) - Tuple #@ - """ - ) - inferred = next(node.infer()) - self.assertIn("a", inferred.locals) - self.assertIn("b", inferred.locals) - self.assertIn("c", inferred.locals) - - def test_namedtuple_func_form(self) -> None: - node = builder.extract_node( - """ - from collections import namedtuple - Tuple = namedtuple(typename="Tuple", field_names="a b c", rename=UNINFERABLE) - Tuple #@ - """ - ) - inferred = next(node.infer()) - self.assertEqual(inferred.name, "Tuple") - self.assertIn("a", inferred.locals) - self.assertIn("b", inferred.locals) - self.assertIn("c", inferred.locals) - - def test_namedtuple_func_form_args_and_kwargs(self) -> None: - node = builder.extract_node( - """ - from collections import namedtuple - Tuple = namedtuple("Tuple", field_names="a b c", rename=UNINFERABLE) - Tuple #@ - """ - ) - inferred = next(node.infer()) - self.assertEqual(inferred.name, "Tuple") - self.assertIn("a", inferred.locals) - self.assertIn("b", inferred.locals) - self.assertIn("c", inferred.locals) - - def test_namedtuple_bases_are_actually_names_not_nodes(self) -> None: - node = builder.extract_node( - """ - from collections import namedtuple - Tuple = namedtuple("Tuple", field_names="a b c", rename=UNINFERABLE) - Tuple #@ - """ - ) - inferred = next(node.infer()) - self.assertIsInstance(inferred, astroid.ClassDef) - self.assertIsInstance(inferred.bases[0], astroid.Name) - self.assertEqual(inferred.bases[0].name, "tuple") - - def test_invalid_label_does_not_crash_inference(self) -> None: - code = """ - import collections - a = collections.namedtuple( 'a', ['b c'] ) - a - """ - node = builder.extract_node(code) - inferred = next(node.infer()) - assert isinstance(inferred, astroid.ClassDef) - assert "b" not in inferred.locals - assert "c" not in inferred.locals - - def test_no_rename_duplicates_does_not_crash_inference(self) -> None: - node = builder.extract_node( - """ - from collections import namedtuple - Tuple = namedtuple("Tuple", "abc abc") - Tuple #@ - """ - ) - inferred = next(node.infer()) - self.assertIs(util.Uninferable, inferred) # would raise ValueError - - def test_no_rename_keywords_does_not_crash_inference(self) -> None: - node = builder.extract_node( - """ - from collections import namedtuple - Tuple = namedtuple("Tuple", "abc def") - Tuple #@ - """ - ) - inferred = next(node.infer()) - self.assertIs(util.Uninferable, inferred) # would raise ValueError - - def test_no_rename_nonident_does_not_crash_inference(self) -> None: - node = builder.extract_node( - """ - from collections import namedtuple - Tuple = namedtuple("Tuple", "123 456") - Tuple #@ - """ - ) - inferred = next(node.infer()) - self.assertIs(util.Uninferable, inferred) # would raise ValueError - - def test_no_rename_underscore_does_not_crash_inference(self) -> None: - node = builder.extract_node( - """ - from collections import namedtuple - Tuple = namedtuple("Tuple", "_1") - Tuple #@ - """ - ) - inferred = next(node.infer()) - self.assertIs(util.Uninferable, inferred) # would raise ValueError - - def test_invalid_typename_does_not_crash_inference(self) -> None: - node = builder.extract_node( - """ - from collections import namedtuple - Tuple = namedtuple("123", "abc") - Tuple #@ - """ - ) - inferred = next(node.infer()) - self.assertIs(util.Uninferable, inferred) # would raise ValueError - - def test_keyword_typename_does_not_crash_inference(self) -> None: - node = builder.extract_node( - """ - from collections import namedtuple - Tuple = namedtuple("while", "abc") - Tuple #@ - """ - ) - inferred = next(node.infer()) - self.assertIs(util.Uninferable, inferred) # would raise ValueError - - def test_typeerror_does_not_crash_inference(self) -> None: - node = builder.extract_node( - """ - from collections import namedtuple - Tuple = namedtuple("Tuple", [123, 456]) - Tuple #@ - """ - ) - inferred = next(node.infer()) - # namedtuple converts all arguments to strings so these should be too - # and catch on the isidentifier() check - self.assertIs(util.Uninferable, inferred) - - def test_pathological_str_does_not_crash_inference(self) -> None: - node = builder.extract_node( - """ - from collections import namedtuple - class Invalid: - def __str__(self): - return 123 # will raise TypeError - Tuple = namedtuple("Tuple", [Invalid()]) - Tuple #@ - """ - ) - inferred = next(node.infer()) - self.assertIs(util.Uninferable, inferred) - - def test_name_as_typename(self) -> None: - """Reported in https://github.com/PyCQA/pylint/issues/7429 as a crash.""" - good_node, good_node_two, bad_node = builder.extract_node( - """ - import collections - collections.namedtuple(typename="MyTuple", field_names=["birth_date", "city"]) #@ - collections.namedtuple("MyTuple", field_names=["birth_date", "city"]) #@ - collections.namedtuple(["birth_date", "city"], typename="MyTuple") #@ - """ - ) - good_inferred = next(good_node.infer()) - assert isinstance(good_inferred, nodes.ClassDef) - good_node_two_inferred = next(good_node_two.infer()) - assert isinstance(good_node_two_inferred, nodes.ClassDef) - bad_node_inferred = next(bad_node.infer()) - assert bad_node_inferred == util.Uninferable - - class DefaultDictTest(unittest.TestCase): def test_1(self) -> None: node = builder.extract_node( diff --git a/tests/brain/test_named_tuple.py b/tests/brain/test_named_tuple.py new file mode 100644 index 00000000..dff042e6 --- /dev/null +++ b/tests/brain/test_named_tuple.py @@ -0,0 +1,311 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +from __future__ import annotations + +import unittest + +import astroid +from astroid import builder, nodes, util +from astroid.exceptions import AttributeInferenceError + + +class NamedTupleTest(unittest.TestCase): + def test_namedtuple_base(self) -> None: + klass = builder.extract_node( + """ + from collections import namedtuple + + class X(namedtuple("X", ["a", "b", "c"])): + pass + """ + ) + assert isinstance(klass, nodes.ClassDef) + self.assertEqual( + [anc.name for anc in klass.ancestors()], ["X", "tuple", "object"] + ) + # See: https://github.com/PyCQA/pylint/issues/5982 + self.assertNotIn("X", klass.locals) + for anc in klass.ancestors(): + self.assertFalse(anc.parent is None) + + def test_namedtuple_inference(self) -> None: + klass = builder.extract_node( + """ + from collections import namedtuple + + name = "X" + fields = ["a", "b", "c"] + class X(namedtuple(name, fields)): + pass + """ + ) + assert isinstance(klass, nodes.ClassDef) + base = next(base for base in klass.ancestors() if base.name == "X") + self.assertSetEqual({"a", "b", "c"}, set(base.instance_attrs)) + + def test_namedtuple_inference_failure(self) -> None: + klass = builder.extract_node( + """ + from collections import namedtuple + + def foo(fields): + return __(namedtuple("foo", fields)) + """ + ) + self.assertIs(util.Uninferable, next(klass.infer())) + + def test_namedtuple_advanced_inference(self) -> None: + # urlparse return an object of class ParseResult, which has a + # namedtuple call and a mixin as base classes + result = builder.extract_node( + """ + from urllib.parse import urlparse + + result = __(urlparse('gopher://')) + """ + ) + instance = next(result.infer()) + self.assertGreaterEqual(len(instance.getattr("scheme")), 1) + self.assertGreaterEqual(len(instance.getattr("port")), 1) + with self.assertRaises(AttributeInferenceError): + instance.getattr("foo") + self.assertGreaterEqual(len(instance.getattr("geturl")), 1) + self.assertEqual(instance.name, "ParseResult") + + def test_namedtuple_instance_attrs(self) -> None: + result = builder.extract_node( + """ + from collections import namedtuple + namedtuple('a', 'a b c')(1, 2, 3) #@ + """ + ) + inferred = next(result.infer()) + for name, attr in inferred.instance_attrs.items(): + self.assertEqual(attr[0].attrname, name) + + def test_namedtuple_uninferable_fields(self) -> None: + node = builder.extract_node( + """ + x = [A] * 2 + from collections import namedtuple + l = namedtuple('a', x) + l(1) + """ + ) + inferred = next(node.infer()) + self.assertIs(util.Uninferable, inferred) + + def test_namedtuple_access_class_fields(self) -> None: + node = builder.extract_node( + """ + from collections import namedtuple + Tuple = namedtuple("Tuple", "field other") + Tuple #@ + """ + ) + inferred = next(node.infer()) + self.assertIn("field", inferred.locals) + self.assertIn("other", inferred.locals) + + def test_namedtuple_rename_keywords(self) -> None: + node = builder.extract_node( + """ + from collections import namedtuple + Tuple = namedtuple("Tuple", "abc def", rename=True) + Tuple #@ + """ + ) + inferred = next(node.infer()) + self.assertIn("abc", inferred.locals) + self.assertIn("_1", inferred.locals) + + def test_namedtuple_rename_duplicates(self) -> None: + node = builder.extract_node( + """ + from collections import namedtuple + Tuple = namedtuple("Tuple", "abc abc abc", rename=True) + Tuple #@ + """ + ) + inferred = next(node.infer()) + self.assertIn("abc", inferred.locals) + self.assertIn("_1", inferred.locals) + self.assertIn("_2", inferred.locals) + + def test_namedtuple_rename_uninferable(self) -> None: + node = builder.extract_node( + """ + from collections import namedtuple + Tuple = namedtuple("Tuple", "a b c", rename=UNINFERABLE) + Tuple #@ + """ + ) + inferred = next(node.infer()) + self.assertIn("a", inferred.locals) + self.assertIn("b", inferred.locals) + self.assertIn("c", inferred.locals) + + def test_namedtuple_func_form(self) -> None: + node = builder.extract_node( + """ + from collections import namedtuple + Tuple = namedtuple(typename="Tuple", field_names="a b c", rename=UNINFERABLE) + Tuple #@ + """ + ) + inferred = next(node.infer()) + self.assertEqual(inferred.name, "Tuple") + self.assertIn("a", inferred.locals) + self.assertIn("b", inferred.locals) + self.assertIn("c", inferred.locals) + + def test_namedtuple_func_form_args_and_kwargs(self) -> None: + node = builder.extract_node( + """ + from collections import namedtuple + Tuple = namedtuple("Tuple", field_names="a b c", rename=UNINFERABLE) + Tuple #@ + """ + ) + inferred = next(node.infer()) + self.assertEqual(inferred.name, "Tuple") + self.assertIn("a", inferred.locals) + self.assertIn("b", inferred.locals) + self.assertIn("c", inferred.locals) + + def test_namedtuple_bases_are_actually_names_not_nodes(self) -> None: + node = builder.extract_node( + """ + from collections import namedtuple + Tuple = namedtuple("Tuple", field_names="a b c", rename=UNINFERABLE) + Tuple #@ + """ + ) + inferred = next(node.infer()) + self.assertIsInstance(inferred, astroid.ClassDef) + self.assertIsInstance(inferred.bases[0], astroid.Name) + self.assertEqual(inferred.bases[0].name, "tuple") + + def test_invalid_label_does_not_crash_inference(self) -> None: + code = """ + import collections + a = collections.namedtuple( 'a', ['b c'] ) + a + """ + node = builder.extract_node(code) + inferred = next(node.infer()) + assert isinstance(inferred, astroid.ClassDef) + assert "b" not in inferred.locals + assert "c" not in inferred.locals + + def test_no_rename_duplicates_does_not_crash_inference(self) -> None: + node = builder.extract_node( + """ + from collections import namedtuple + Tuple = namedtuple("Tuple", "abc abc") + Tuple #@ + """ + ) + inferred = next(node.infer()) + self.assertIs(util.Uninferable, inferred) # would raise ValueError + + def test_no_rename_keywords_does_not_crash_inference(self) -> None: + node = builder.extract_node( + """ + from collections import namedtuple + Tuple = namedtuple("Tuple", "abc def") + Tuple #@ + """ + ) + inferred = next(node.infer()) + self.assertIs(util.Uninferable, inferred) # would raise ValueError + + def test_no_rename_nonident_does_not_crash_inference(self) -> None: + node = builder.extract_node( + """ + from collections import namedtuple + Tuple = namedtuple("Tuple", "123 456") + Tuple #@ + """ + ) + inferred = next(node.infer()) + self.assertIs(util.Uninferable, inferred) # would raise ValueError + + def test_no_rename_underscore_does_not_crash_inference(self) -> None: + node = builder.extract_node( + """ + from collections import namedtuple + Tuple = namedtuple("Tuple", "_1") + Tuple #@ + """ + ) + inferred = next(node.infer()) + self.assertIs(util.Uninferable, inferred) # would raise ValueError + + def test_invalid_typename_does_not_crash_inference(self) -> None: + node = builder.extract_node( + """ + from collections import namedtuple + Tuple = namedtuple("123", "abc") + Tuple #@ + """ + ) + inferred = next(node.infer()) + self.assertIs(util.Uninferable, inferred) # would raise ValueError + + def test_keyword_typename_does_not_crash_inference(self) -> None: + node = builder.extract_node( + """ + from collections import namedtuple + Tuple = namedtuple("while", "abc") + Tuple #@ + """ + ) + inferred = next(node.infer()) + self.assertIs(util.Uninferable, inferred) # would raise ValueError + + def test_typeerror_does_not_crash_inference(self) -> None: + node = builder.extract_node( + """ + from collections import namedtuple + Tuple = namedtuple("Tuple", [123, 456]) + Tuple #@ + """ + ) + inferred = next(node.infer()) + # namedtuple converts all arguments to strings so these should be too + # and catch on the isidentifier() check + self.assertIs(util.Uninferable, inferred) + + def test_pathological_str_does_not_crash_inference(self) -> None: + node = builder.extract_node( + """ + from collections import namedtuple + class Invalid: + def __str__(self): + return 123 # will raise TypeError + Tuple = namedtuple("Tuple", [Invalid()]) + Tuple #@ + """ + ) + inferred = next(node.infer()) + self.assertIs(util.Uninferable, inferred) + + def test_name_as_typename(self) -> None: + """Reported in https://github.com/PyCQA/pylint/issues/7429 as a crash.""" + good_node, good_node_two, bad_node = builder.extract_node( + """ + import collections + collections.namedtuple(typename="MyTuple", field_names=["birth_date", "city"]) #@ + collections.namedtuple("MyTuple", field_names=["birth_date", "city"]) #@ + collections.namedtuple(["birth_date", "city"], typename="MyTuple") #@ + """ + ) + good_inferred = next(good_node.infer()) + assert isinstance(good_inferred, nodes.ClassDef) + good_node_two_inferred = next(good_node_two.infer()) + assert isinstance(good_node_two_inferred, nodes.ClassDef) + bad_node_inferred = next(bad_node.infer()) + assert bad_node_inferred == util.Uninferable |