46
46
import zmq .asyncio
47
47
from packaging .version import Version
48
48
from torch .library import Library
49
- from typing_extensions import ParamSpec , TypeIs , assert_never
49
+ from typing_extensions import Never , ParamSpec , TypeIs , assert_never
50
50
51
51
import vllm .envs as envs
52
52
from vllm .logger import enable_trace_function_call , init_logger
@@ -1627,24 +1627,183 @@ def get_vllm_optional_dependencies():
1627
1627
}
1628
1628
1629
1629
1630
- @dataclass (frozen = True )
1631
- class PlaceholderModule :
1630
+ class _PlaceholderBase :
1631
+ """
1632
+ Disallows downstream usage of placeholder modules.
1633
+
1634
+ We need to explicitly override each dunder method because
1635
+ :meth:`__getattr__` is not called when they are accessed.
1636
+
1637
+ See also:
1638
+ [Special method lookup](https://docs.python.org/3/reference/datamodel.html#special-lookup)
1639
+ """
1640
+
1641
+ def __getattr__ (self , key : str ) -> Never :
1642
+ """
1643
+ The main class should implement this to throw an error
1644
+ for attribute accesses representing downstream usage.
1645
+ """
1646
+ raise NotImplementedError
1647
+
1648
+ # [Basic customization]
1649
+
1650
+ def __lt__ (self , other : object ):
1651
+ return self .__getattr__ ("__lt__" )
1652
+
1653
+ def __le__ (self , other : object ):
1654
+ return self .__getattr__ ("__le__" )
1655
+
1656
+ def __eq__ (self , other : object ):
1657
+ return self .__getattr__ ("__eq__" )
1658
+
1659
+ def __ne__ (self , other : object ):
1660
+ return self .__getattr__ ("__ne__" )
1661
+
1662
+ def __gt__ (self , other : object ):
1663
+ return self .__getattr__ ("__gt__" )
1664
+
1665
+ def __ge__ (self , other : object ):
1666
+ return self .__getattr__ ("__ge__" )
1667
+
1668
+ def __hash__ (self ):
1669
+ return self .__getattr__ ("__hash__" )
1670
+
1671
+ def __bool__ (self ):
1672
+ return self .__getattr__ ("__bool__" )
1673
+
1674
+ # [Callable objects]
1675
+
1676
+ def __call__ (self , * args : object , ** kwargs : object ):
1677
+ return self .__getattr__ ("__call__" )
1678
+
1679
+ # [Container types]
1680
+
1681
+ def __len__ (self ):
1682
+ return self .__getattr__ ("__len__" )
1683
+
1684
+ def __getitem__ (self , key : object ):
1685
+ return self .__getattr__ ("__getitem__" )
1686
+
1687
+ def __setitem__ (self , key : object , value : object ):
1688
+ return self .__getattr__ ("__setitem__" )
1689
+
1690
+ def __delitem__ (self , key : object ):
1691
+ return self .__getattr__ ("__delitem__" )
1692
+
1693
+ # __missing__ is optional according to __getitem__ specification,
1694
+ # so it is skipped
1695
+
1696
+ # __iter__ and __reversed__ have a default implementation
1697
+ # based on __len__ and __getitem__, so they are skipped.
1698
+
1699
+ # [Numeric Types]
1700
+
1701
+ def __add__ (self , other : object ):
1702
+ return self .__getattr__ ("__add__" )
1703
+
1704
+ def __sub__ (self , other : object ):
1705
+ return self .__getattr__ ("__sub__" )
1706
+
1707
+ def __mul__ (self , other : object ):
1708
+ return self .__getattr__ ("__mul__" )
1709
+
1710
+ def __matmul__ (self , other : object ):
1711
+ return self .__getattr__ ("__matmul__" )
1712
+
1713
+ def __truediv__ (self , other : object ):
1714
+ return self .__getattr__ ("__truediv__" )
1715
+
1716
+ def __floordiv__ (self , other : object ):
1717
+ return self .__getattr__ ("__floordiv__" )
1718
+
1719
+ def __mod__ (self , other : object ):
1720
+ return self .__getattr__ ("__mod__" )
1721
+
1722
+ def __divmod__ (self , other : object ):
1723
+ return self .__getattr__ ("__divmod__" )
1724
+
1725
+ def __pow__ (self , other : object , modulo : object = ...):
1726
+ return self .__getattr__ ("__pow__" )
1727
+
1728
+ def __lshift__ (self , other : object ):
1729
+ return self .__getattr__ ("__lshift__" )
1730
+
1731
+ def __rshift__ (self , other : object ):
1732
+ return self .__getattr__ ("__rshift__" )
1733
+
1734
+ def __and__ (self , other : object ):
1735
+ return self .__getattr__ ("__and__" )
1736
+
1737
+ def __xor__ (self , other : object ):
1738
+ return self .__getattr__ ("__xor__" )
1739
+
1740
+ def __or__ (self , other : object ):
1741
+ return self .__getattr__ ("__or__" )
1742
+
1743
+ # r* and i* methods have lower priority than
1744
+ # the methods for left operand so they are skipped
1745
+
1746
+ def __neg__ (self ):
1747
+ return self .__getattr__ ("__neg__" )
1748
+
1749
+ def __pos__ (self ):
1750
+ return self .__getattr__ ("__pos__" )
1751
+
1752
+ def __abs__ (self ):
1753
+ return self .__getattr__ ("__abs__" )
1754
+
1755
+ def __invert__ (self ):
1756
+ return self .__getattr__ ("__invert__" )
1757
+
1758
+ # __complex__, __int__ and __float__ have a default implementation
1759
+ # based on __index__, so they are skipped.
1760
+
1761
+ def __index__ (self ):
1762
+ return self .__getattr__ ("__index__" )
1763
+
1764
+ def __round__ (self , ndigits : object = ...):
1765
+ return self .__getattr__ ("__round__" )
1766
+
1767
+ def __trunc__ (self ):
1768
+ return self .__getattr__ ("__trunc__" )
1769
+
1770
+ def __floor__ (self ):
1771
+ return self .__getattr__ ("__floor__" )
1772
+
1773
+ def __ceil__ (self ):
1774
+ return self .__getattr__ ("__ceil__" )
1775
+
1776
+ # [Context managers]
1777
+
1778
+ def __enter__ (self ):
1779
+ return self .__getattr__ ("__enter__" )
1780
+
1781
+ def __exit__ (self , * args : object , ** kwargs : object ):
1782
+ return self .__getattr__ ("__exit__" )
1783
+
1784
+
1785
+ class PlaceholderModule (_PlaceholderBase ):
1632
1786
"""
1633
1787
A placeholder object to use when a module does not exist.
1634
1788
1635
1789
This enables more informative errors when trying to access attributes
1636
1790
of a module that does not exists.
1637
1791
"""
1638
- name : str
1792
+
1793
+ def __init__ (self , name : str ) -> None :
1794
+ super ().__init__ ()
1795
+
1796
+ # Apply name mangling to avoid conflicting with module attributes
1797
+ self .__name = name
1639
1798
1640
1799
def placeholder_attr (self , attr_path : str ):
1641
1800
return _PlaceholderModuleAttr (self , attr_path )
1642
1801
1643
1802
def __getattr__ (self , key : str ):
1644
- name = self .name
1803
+ name = self .__name
1645
1804
1646
1805
try :
1647
- importlib .import_module (self . name )
1806
+ importlib .import_module (name )
1648
1807
except ImportError as exc :
1649
1808
for extra , names in get_vllm_optional_dependencies ().items ():
1650
1809
if name in names :
@@ -1657,17 +1816,21 @@ def __getattr__(self, key: str):
1657
1816
"when the original module can be imported" )
1658
1817
1659
1818
1660
- @dataclass (frozen = True )
1661
- class _PlaceholderModuleAttr :
1662
- module : PlaceholderModule
1663
- attr_path : str
1819
+ class _PlaceholderModuleAttr (_PlaceholderBase ):
1820
+
1821
+ def __init__ (self , module : PlaceholderModule , attr_path : str ) -> None :
1822
+ super ().__init__ ()
1823
+
1824
+ # Apply name mangling to avoid conflicting with module attributes
1825
+ self .__module = module
1826
+ self .__attr_path = attr_path
1664
1827
1665
1828
def placeholder_attr (self , attr_path : str ):
1666
- return _PlaceholderModuleAttr (self .module ,
1667
- f"{ self .attr_path } .{ attr_path } " )
1829
+ return _PlaceholderModuleAttr (self .__module ,
1830
+ f"{ self .__attr_path } .{ attr_path } " )
1668
1831
1669
1832
def __getattr__ (self , key : str ):
1670
- getattr (self .module , f"{ self .attr_path } .{ key } " )
1833
+ getattr (self .__module , f"{ self .__attr_path } .{ key } " )
1671
1834
1672
1835
raise AssertionError ("PlaceholderModule should not be used "
1673
1836
"when the original module can be imported" )
0 commit comments