|
29 | 29 |
|
30 | 30 | def missing_exports(internal_obj, wrapped_obj) -> None: |
31 | 31 | """ |
| 32 | + Identify if any of the rust exposted structs or functions do not have wrappers. |
| 33 | +
|
32 | 34 | Special handling for: |
33 | 35 | - Raw* classes: Internal implementation details that shouldn't be exposed |
34 | 36 | - _global_ctx: Internal implementation detail |
35 | 37 | - __self__, __class__: Python special attributes |
36 | 38 | """ |
37 | | - # Special case enums - just make sure they exist since dir() |
38 | | - # and other functions get overridden. |
| 39 | + # Special case enums - EnumType overrides a some of the internal functions, |
| 40 | + # so check all of the values exist and move on |
39 | 41 | if isinstance(wrapped_obj, EnumType): |
| 42 | + expected_values = [v for v in dir(internal_obj) if not v.startswith("__")] |
| 43 | + for value in expected_values: |
| 44 | + assert value in dir(wrapped_obj) |
40 | 45 | return |
41 | 46 |
|
42 | | - # iterate through all the classes in datafusion._internal |
43 | | - for attr in dir(internal_obj): |
| 47 | + for internal_attr_name in dir(internal_obj): |
44 | 48 | # Skip internal implementation details that shouldn't be exposed in public API |
45 | | - if attr in ["_global_ctx"] or attr.startswith("Raw"): |
| 49 | + if internal_attr_name in ["_global_ctx"]: |
46 | 50 | continue |
47 | 51 |
|
48 | | - assert attr in dir(wrapped_obj) |
| 52 | + wrapped_attr_name = ( |
| 53 | + internal_attr_name[3:] |
| 54 | + if internal_attr_name.startswith("Raw") |
| 55 | + else internal_attr_name |
| 56 | + ) |
| 57 | + assert wrapped_attr_name in dir(wrapped_obj) |
49 | 58 |
|
50 | | - internal_attr = getattr(internal_obj, attr) |
51 | | - wrapped_attr = getattr(wrapped_obj, attr) |
| 59 | + internal_attr = getattr(internal_obj, internal_attr_name) |
| 60 | + wrapped_attr = getattr(wrapped_obj, wrapped_attr_name) |
52 | 61 |
|
| 62 | + # There are some auto generated attributes that can be None, such as |
| 63 | + # __kwdefaults__ and __doc__. As long as these are None on the internal |
| 64 | + # object, it's okay to skip them. However if they do exist on the internal |
| 65 | + # object they must also exist on the wrapped object. |
53 | 66 | if internal_attr is not None: |
54 | 67 | if wrapped_attr is None: |
55 | | - print("Missing attribute: ", attr) |
| 68 | + print("Missing attribute: ", internal_attr_name) |
56 | 69 | assert False |
57 | 70 |
|
58 | | - if attr in ["__self__", "__class__"]: |
| 71 | + if internal_attr_name in ["__self__", "__class__"]: |
59 | 72 | continue |
60 | 73 |
|
61 | | - # check if the class found in the internal module has a |
62 | | - # wrapper exposed in the public module, datafusion |
63 | 74 | if isinstance(internal_attr, list): |
64 | 75 | assert isinstance(wrapped_attr, list) |
| 76 | + |
| 77 | + # We have cases like __all__ that are a list and we want to be certain that |
| 78 | + # every value in the list in the internal object is also in the wrapper list |
65 | 79 | for val in internal_attr: |
66 | | - # Skip Raw* classes as they are internal |
67 | 80 | if isinstance(val, str) and val.startswith("Raw"): |
68 | | - print("Skipping Raw* class: ", val) |
69 | | - continue |
70 | | - |
71 | | - assert val in wrapped_attr |
| 81 | + assert val[3:] in wrapped_attr |
| 82 | + else: |
| 83 | + assert val in wrapped_attr |
72 | 84 | elif hasattr(internal_attr, "__dict__"): |
| 85 | + # Check all submodules recursively |
73 | 86 | missing_exports(internal_attr, wrapped_attr) |
74 | 87 |
|
75 | 88 |
|
|
0 commit comments