-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* refactor: shell for new warning handling * refactor; print first one * refactor; consisten naming * feat; improved print * fix: proper group name * style: remove * build: changelog * tests: fix tests * refactor: pygen warnings are now handleg internally * tests: updated test
- Loading branch information
Showing
12 changed files
with
262 additions
and
112 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
from __future__ import annotations | ||
|
||
import itertools | ||
import warnings | ||
from collections.abc import Callable | ||
from pathlib import Path | ||
from typing import Literal, cast | ||
|
||
from cognite.client.data_classes.data_modeling import PropertyId, ViewId | ||
|
||
|
||
class PygenWarning(UserWarning): | ||
"""Base class for warnings in pygen.""" | ||
|
||
def warn(self): | ||
warnings.warn(self, stacklevel=2) | ||
|
||
|
||
class NameCollisionWarning(PygenWarning, RuntimeWarning): | ||
@classmethod | ||
def create( | ||
cls, | ||
word: str, | ||
word_type: Literal["field", "data class", "parameter", "filename"], | ||
view_id: ViewId | None, | ||
property_name: str | None, | ||
) -> NameCollisionWarning: | ||
if view_id and property_name: | ||
return NameCollisionViewPropertyWarning(view_id, property_name, word) | ||
elif view_id and word_type == "filename": | ||
return NameCollisionFileNameWarning(view_id, word) | ||
elif view_id and word_type == "data class": | ||
return NameCollisionDataClassNameWarning(view_id, word) | ||
else: | ||
return NameCollisionParameterWarning(word) | ||
|
||
|
||
class NameCollisionFileNameWarning(NameCollisionWarning): | ||
def __init__(self, view_id: ViewId, word: str): | ||
self.view_id = view_id | ||
self.word = word | ||
|
||
def __str__(self) -> str: | ||
return ( | ||
f"Name collision detected in {self.view_id}: {self.word!r}. " | ||
f"An underscore will be added to the {self.word!r} to avoid name collision." | ||
) | ||
|
||
|
||
class NameCollisionDataClassNameWarning(NameCollisionWarning): | ||
def __init__(self, view_id: ViewId, word: str): | ||
self.view_id = view_id | ||
self.word = word | ||
|
||
def __str__(self) -> str: | ||
return ( | ||
f"Name collision detected in {self.view_id}: {self.word!r}. " | ||
f"An underscore will be added to the {self.word!r} to avoid name collision." | ||
) | ||
|
||
|
||
class NameCollisionViewPropertyWarning(NameCollisionWarning): | ||
def __init__(self, view_id: ViewId, property_name: str, word: str): | ||
self.view_id = view_id | ||
self.property_name = property_name | ||
self.word = word | ||
|
||
def __str__(self) -> str: | ||
return ( | ||
f"Name collision detected in {self.view_id}: {self.property_name!r}. " | ||
f"An underscore will be added to the {self.word!r} to avoid name collision." | ||
) | ||
|
||
|
||
class NameCollisionParameterWarning(NameCollisionWarning): | ||
def __init__(self, word: str): | ||
self.word = word | ||
|
||
def __str__(self) -> str: | ||
return ( | ||
f"Name collision detected. The following filter parameter {self.word!r} name is used by pygen." | ||
"An underscore will be added to this parameter to avoid name collision." | ||
) | ||
|
||
|
||
class MissingReverseDirectRelationTargetWarning(PygenWarning, UserWarning): | ||
def __init__(self, source: PropertyId, view: ViewId, property_: str) -> None: | ||
self.source = source | ||
self.view = view | ||
self.property_ = property_ | ||
|
||
def __str__(self) -> str: | ||
return ( | ||
f"Target {self.source!r} does not exists. " | ||
f"Skipping reverse direct relation {self.view.external_id}.{self.property_}." | ||
) | ||
|
||
|
||
class InvalidCodeGenerated(PygenWarning, UserWarning): | ||
def __init__(self, filepath: str | Path, error_message: str) -> None: | ||
self.filepath = filepath | ||
self.error_message = error_message | ||
|
||
def __str__(self) -> str: | ||
return f"Invalid code generated in {self.filepath}. {self.error_message}" | ||
|
||
|
||
class PydanticNamespaceCollisionWarning(PygenWarning, UserWarning): | ||
def __init__(self, view_id: ViewId, names: str) -> None: | ||
self.view_id = view_id | ||
self.names = names | ||
|
||
def __str__(self) -> str: | ||
return ( | ||
f"Field(s) {self.names} in view {self.view_id} has potential conflict " | ||
"with protected Pydantic namespace 'model_'" | ||
) | ||
|
||
|
||
def print_warnings( | ||
warning_list: list[warnings.WarningMessage], | ||
console: Callable[[str], None], | ||
context: Literal["notebook", "cli"] = "cli", | ||
) -> None: | ||
for group, group_warnings in itertools.groupby( | ||
sorted(warning_list, key=lambda w: w.category.__name__), | ||
key=lambda w: w.category, | ||
): | ||
group_list = [w.message for w in group_warnings if isinstance(w.message, PygenWarning)] | ||
_print_warning_group(group_list, group, console, context) | ||
|
||
|
||
def _print_warning_group( | ||
pygen_warnings: list[PygenWarning], | ||
group: type[PygenWarning], | ||
console: Callable[[str], None], | ||
context: Literal["notebook", "cli"], | ||
) -> None: | ||
if group is PydanticNamespaceCollisionWarning: | ||
return | ||
elif context == "notebook" and group is NameCollisionFileNameWarning: | ||
return | ||
elif group is InvalidCodeGenerated or len(pygen_warnings) == 1: | ||
_print_one_by_one(console, pygen_warnings) | ||
elif issubclass(group, NameCollisionWarning | MissingReverseDirectRelationTargetWarning): | ||
_print_group(console, group, pygen_warnings) | ||
|
||
|
||
def _print_one_by_one(console: Callable[[str], None], warning_list: list[PygenWarning]) -> None: | ||
for warning in warning_list: | ||
console(f"{warning!s}") | ||
|
||
|
||
def _print_group(console: Callable[[str], None], group: type[PygenWarning], warning_list: list[PygenWarning]) -> None: | ||
console(f"{group.__name__}: {len(warning_list)}") | ||
indent = " " * 4 | ||
if group in {NameCollisionFileNameWarning, NameCollisionDataClassNameWarning}: | ||
view_warnings = cast(list[NameCollisionFileNameWarning | NameCollisionDataClassNameWarning], warning_list) | ||
views_str = ", ".join(f"{warning.view_id!r}" for warning in view_warnings) | ||
console(f"{indent}The following views will have an underscore added to avoid name collision: {views_str}") | ||
elif group is NameCollisionViewPropertyWarning: | ||
property_warnings = cast(list[NameCollisionViewPropertyWarning], warning_list) | ||
for view, properties in itertools.groupby( | ||
sorted(property_warnings, key=lambda w: w.view_id.external_id), key=lambda w: w.view_id.external_id | ||
): | ||
properties_str = ", ".join(warning.property_name for warning in properties) | ||
console( | ||
f"{indent}The following properties in view {view} will have an underscore " | ||
f"added to avoid name collision: {properties_str}" | ||
) | ||
elif group is MissingReverseDirectRelationTargetWarning: | ||
relation_warnings = cast(list[MissingReverseDirectRelationTargetWarning], warning_list) | ||
for relation_warn in relation_warnings: | ||
console( | ||
f"{indent} Skipping reverse direct " | ||
f"relation {relation_warn.view.external_id}.{relation_warn.property_}." | ||
) | ||
else: | ||
for warning in warning_list: | ||
console(f"{indent}{warning!s}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.