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