| 93 | |
| 94 | |
| 95 | class Error: |
| 96 | def __init__( |
| 97 | self, |
| 98 | object_path: list[str], |
| 99 | message: str, |
| 100 | stub_object: MaybeMissing[nodes.Node], |
| 101 | runtime_object: MaybeMissing[Any], |
| 102 | *, |
| 103 | stub_desc: str | None = None, |
| 104 | runtime_desc: str | None = None, |
| 105 | ) -> None: |
| 106 | """Represents an error found by stubtest. |
| 107 | |
| 108 | :param object_path: Location of the object with the error, |
| 109 | e.g. ``["module", "Class", "method"]`` |
| 110 | :param message: Error message |
| 111 | :param stub_object: The mypy node representing the stub |
| 112 | :param runtime_object: Actual object obtained from the runtime |
| 113 | :param stub_desc: Specialised description for the stub object, should you wish |
| 114 | :param runtime_desc: Specialised description for the runtime object, should you wish |
| 115 | |
| 116 | """ |
| 117 | self.object_path = object_path |
| 118 | self.object_desc = ".".join(object_path) |
| 119 | self.message = message |
| 120 | self.stub_object = stub_object |
| 121 | self.runtime_object = runtime_object |
| 122 | self.stub_desc = stub_desc or str(getattr(stub_object, "type", stub_object)) |
| 123 | |
| 124 | if runtime_desc is None: |
| 125 | runtime_sig = safe_inspect_signature(runtime_object) |
| 126 | if runtime_sig is None: |
| 127 | self.runtime_desc = _truncate(repr(runtime_object), 100) |
| 128 | else: |
| 129 | runtime_is_async = inspect.iscoroutinefunction(runtime_object) |
| 130 | description = describe_runtime_callable(runtime_sig, is_async=runtime_is_async) |
| 131 | self.runtime_desc = _truncate(description, 100) |
| 132 | else: |
| 133 | self.runtime_desc = runtime_desc |
| 134 | |
| 135 | def is_missing_stub(self) -> bool: |
| 136 | """Whether or not the error is for something missing from the stub.""" |
| 137 | return isinstance(self.stub_object, Missing) |
| 138 | |
| 139 | def is_positional_only_related(self) -> bool: |
| 140 | """Whether or not the error is for something being (or not being) positional-only.""" |
| 141 | # TODO: This is hacky, use error codes or something more resilient |
| 142 | return "should be positional" in self.message |
| 143 | |
| 144 | def is_disjoint_base_related(self) -> bool: |
| 145 | """Whether or not the error is related to @disjoint_base.""" |
| 146 | # TODO: This is hacky, use error codes or something more resilient |
| 147 | return "@disjoint_base" in self.message |
| 148 | |
| 149 | def is_private_type_check_only_related(self) -> bool: |
| 150 | """Whether or not the error is related to @type_check_only on private types.""" |
| 151 | # TODO: This is hacky, use error codes or something more resilient |
| 152 | return self.message.endswith('Maybe mark it as "@type_check_only"?') |
no outgoing calls
searching dependent graphs…