|
8 | 8 | from abc import ABCMeta |
9 | 9 | from copy import copy |
10 | 10 | from dataclasses import dataclass, field |
11 | | -from typing import Any |
| 11 | +from typing import TYPE_CHECKING, Any |
12 | 12 |
|
13 | 13 | import polars as pl |
14 | 14 |
|
@@ -164,12 +164,16 @@ def __new__( |
164 | 164 |
|
165 | 165 | return cls |
166 | 166 |
|
167 | | - def __getattribute__(cls, name: str) -> Any: |
168 | | - val = super().__getattribute__(name) |
169 | | - # Dynamically set the name of the column if it is a `Column` instance. |
170 | | - if isinstance(val, Column): |
171 | | - val._name = val.alias or name |
172 | | - return val |
| 167 | + if not TYPE_CHECKING: |
| 168 | + # Only define __getattribute__ at runtime to allow type checkers to properly |
| 169 | + # validate attribute access. When TYPE_CHECKING is True, type checkers will use |
| 170 | + # the default metaclass behavior which correctly identifies non-existent attributes. |
| 171 | + def __getattribute__(cls, name: str) -> Any: |
| 172 | + val = super().__getattribute__(name) |
| 173 | + # Dynamically set the name of the column if it is a `Column` instance. |
| 174 | + if isinstance(val, Column): |
| 175 | + val._name = val.alias or name |
| 176 | + return val |
173 | 177 |
|
174 | 178 | @staticmethod |
175 | 179 | def _get_metadata_recursively(kls: type[object]) -> Metadata: |
@@ -199,9 +203,9 @@ def _get_metadata(source: dict[str, Any]) -> Metadata: |
199 | 203 | def __repr__(cls) -> str: |
200 | 204 | parts = [f'[Schema "{cls.__name__}"]'] |
201 | 205 | parts.append(textwrap.indent("Columns:", prefix=" " * 2)) |
202 | | - for name, col in cls.columns().items(): |
| 206 | + for name, col in cls.columns().items(): # type: ignore[attr-defined] |
203 | 207 | parts.append(textwrap.indent(f'- "{name}": {col!r}', prefix=" " * 4)) |
204 | | - if validation_rules := cls._schema_validation_rules(): |
| 208 | + if validation_rules := cls._schema_validation_rules(): # type: ignore[attr-defined] |
205 | 209 | parts.append(textwrap.indent("Rules:", prefix=" " * 2)) |
206 | 210 | for name, rule in validation_rules.items(): |
207 | 211 | parts.append(textwrap.indent(f'- "{name}": {rule!r}', prefix=" " * 4)) |
|
0 commit comments