@@ -1817,6 +1817,172 @@ def _verify_node_has_expected_attr(self, node: nodes.NodeNG) -> None:
1817
1817
with self .assertRaises (AttributeInferenceError ):
1818
1818
inferred .getattr ("bad_attr" )
1819
1819
1820
+ def test_typing_newtype_forward_reference_imported (self ) -> None :
1821
+ all_ast_nodes = builder .extract_node (
1822
+ """
1823
+ from typing import NewType
1824
+
1825
+ A = NewType("A", "decimal.Decimal")
1826
+ B = NewType("B", "decimal_mod_alias.Decimal")
1827
+ C = NewType("C", "Decimal")
1828
+ D = NewType("D", "DecimalAlias")
1829
+
1830
+ import decimal
1831
+ import decimal as decimal_mod_alias
1832
+ from decimal import Decimal
1833
+ from decimal import Decimal as DecimalAlias
1834
+
1835
+ Decimal #@
1836
+
1837
+ a = A(decimal.Decimal(2))
1838
+ a #@
1839
+ b = B(decimal_mod_alias.Decimal(2))
1840
+ b #@
1841
+ c = C(Decimal(2))
1842
+ c #@
1843
+ d = D(DecimalAlias(2))
1844
+ d #@
1845
+ """
1846
+ )
1847
+ assert isinstance (all_ast_nodes , list )
1848
+
1849
+ real_dec , * ast_nodes = all_ast_nodes
1850
+
1851
+ real_quantize = next (real_dec .infer ()).getattr ("quantize" )
1852
+
1853
+ for node in ast_nodes :
1854
+ all_inferred = list (node .infer ())
1855
+ assert len (all_inferred ) == 1
1856
+ inferred = all_inferred [0 ]
1857
+ self .assertIsInstance (inferred , astroid .Instance )
1858
+
1859
+ assert inferred .getattr ("quantize" ) == real_quantize
1860
+
1861
+ def test_typing_newtype_forward_ref_bad_base (self ) -> None :
1862
+ ast_nodes = builder .extract_node (
1863
+ """
1864
+ from typing import NewType
1865
+
1866
+ A = NewType("A", "DoesntExist")
1867
+
1868
+ a = A()
1869
+ a #@
1870
+
1871
+ # Valid name, but not actually imported
1872
+ B = NewType("B", "decimal.Decimal")
1873
+
1874
+ b = B()
1875
+ b #@
1876
+
1877
+ # AST works out, but can't import the module
1878
+ import not_a_real_module
1879
+
1880
+ C = NewType("C", "not_a_real_module.SomeClass")
1881
+ c = C()
1882
+ c #@
1883
+
1884
+ # Real module, fake base class name
1885
+ import email.charset
1886
+
1887
+ D = NewType("D", "email.charset.BadClassRef")
1888
+ d = D()
1889
+ d #@
1890
+
1891
+ # Real module, but aliased differently than used
1892
+ import email.header as header_mod
1893
+
1894
+ E = NewType("E", "email.header.Header")
1895
+ e = E(header_mod.Header())
1896
+ e #@
1897
+ """
1898
+ )
1899
+ assert isinstance (ast_nodes , list )
1900
+
1901
+ for ast_node in ast_nodes :
1902
+ inferred = next (ast_node .infer ())
1903
+
1904
+ with self .assertRaises (astroid .AttributeInferenceError ):
1905
+ inferred .getattr ("value" )
1906
+
1907
+ def test_typing_newtype_forward_ref_nested_module (self ) -> None :
1908
+ ast_nodes = builder .extract_node (
1909
+ """
1910
+ from typing import NewType
1911
+
1912
+ A = NewType("A", "email.charset.Charset")
1913
+ B = NewType("B", "charset.Charset")
1914
+
1915
+ # header is unused in both cases, but verifies that module name is properly checked
1916
+ import email.header, email.charset
1917
+ from email import header, charset
1918
+
1919
+ real = charset.Charset()
1920
+ real #@
1921
+
1922
+ a = A(email.charset.Charset())
1923
+ a #@
1924
+
1925
+ b = B(charset.Charset())
1926
+ """
1927
+ )
1928
+ assert isinstance (ast_nodes , list )
1929
+
1930
+ real , * newtypes = ast_nodes
1931
+
1932
+ real_inferred_all = list (real .infer ())
1933
+ assert len (real_inferred_all ) == 1
1934
+ real_inferred = real_inferred_all [0 ]
1935
+
1936
+ real_method = real_inferred .getattr ("get_body_encoding" )
1937
+
1938
+ for newtype_node in newtypes :
1939
+ newtype_inferred_all = list (newtype_node .infer ())
1940
+ assert len (newtype_inferred_all ) == 1
1941
+ newtype_inferred = newtype_inferred_all [0 ]
1942
+
1943
+ newtype_method = newtype_inferred .getattr ("get_body_encoding" )
1944
+
1945
+ assert real_method == newtype_method
1946
+
1947
+ def test_typing_newtype_forward_ref_nested_class (self ) -> None :
1948
+ ast_nodes = builder .extract_node (
1949
+ """
1950
+ from typing import NewType
1951
+
1952
+ A = NewType("A", "SomeClass.Nested")
1953
+
1954
+ class SomeClass:
1955
+ class Nested:
1956
+ def method(self) -> None:
1957
+ pass
1958
+
1959
+ real = SomeClass.Nested()
1960
+ real #@
1961
+
1962
+ a = A(SomeClass.Nested())
1963
+ a #@
1964
+ """
1965
+ )
1966
+ assert isinstance (ast_nodes , list )
1967
+
1968
+ real , newtype = ast_nodes
1969
+
1970
+ real_all_inferred = list (real .infer ())
1971
+ assert len (real_all_inferred ) == 1
1972
+ real_inferred = real_all_inferred [0 ]
1973
+ real_method = real_inferred .getattr ("method" )
1974
+
1975
+ newtype_all_inferred = list (newtype .infer ())
1976
+ assert len (newtype_all_inferred ) == 1
1977
+ newtype_inferred = newtype_all_inferred [0 ]
1978
+
1979
+ # This could theoretically work, but for now just here to check that
1980
+ # the "forward-declared module" inference doesn't totally break things
1981
+ with self .assertRaises (astroid .AttributeInferenceError ):
1982
+ newtype_method = newtype_inferred .getattr ("method" )
1983
+
1984
+ assert real_method == newtype_method
1985
+
1820
1986
def test_namedtuple_nested_class (self ):
1821
1987
result = builder .extract_node (
1822
1988
"""
0 commit comments