11from __future__ import annotations
22
3- from typing import TypeAlias
3+ from typing import TYPE_CHECKING , TypeAlias
44
55from pydantic import BaseModel , Field
66
7+ if TYPE_CHECKING :
8+ from typing_extensions import Self
9+
710Rule : TypeAlias = str
811
912
@@ -26,17 +29,72 @@ class RuleConfig(BaseModel):
2629 ignored: Managed ignored rules.
2730 unmanaged_selected: Unmanaged selected rules.
2831 unmanaged_ignored: Unmanaged ignored rules.
32+ tests_unmanaged_ignored: Unmanaged cases of rules ignored for specifically the
33+ tests directory.
2934 """
3035
3136 selected : list [Rule ] = Field (default_factory = list )
3237 ignored : list [Rule ] = Field (default_factory = list )
3338 unmanaged_selected : list [Rule ] = Field (default_factory = list )
3439 unmanaged_ignored : list [Rule ] = Field (default_factory = list )
40+ tests_unmanaged_ignored : list [Rule ] = Field (default_factory = list )
3541
3642 def get_all_selected (self ) -> list [Rule ]:
37- """Get all selected rules."""
43+ """Get all (project-scope) selected rules."""
3844 return self .selected + self .unmanaged_selected
3945
4046 def get_all_ignored (self ) -> list [Rule ]:
41- """Get all ignored rules."""
47+ """Get all (project-scope) ignored rules."""
4248 return self .ignored + self .unmanaged_ignored
49+
50+ @property
51+ def empty (self ) -> bool :
52+ """Check if the rule config is empty."""
53+ return (
54+ not self .selected
55+ and not self .ignored
56+ and not self .unmanaged_selected
57+ and not self .unmanaged_ignored
58+ and not self .tests_unmanaged_ignored
59+ )
60+
61+ def __repr__ (self ) -> str :
62+ """Representation which omits empty-list fields."""
63+ args = []
64+ if self .selected :
65+ args .append (f"selected={ self .selected } " )
66+ if self .ignored :
67+ args .append (f"ignored={ self .ignored } " )
68+ if self .unmanaged_selected :
69+ args .append (f"unmanaged_selected={ self .unmanaged_selected } " )
70+ if self .unmanaged_ignored :
71+ args .append (f"unmanaged_ignored={ self .unmanaged_ignored } " )
72+ if self .tests_unmanaged_ignored :
73+ args .append (f"tests_unmanaged_ignored={ self .tests_unmanaged_ignored } " )
74+ arg_str = ", " .join (args )
75+ return f"RuleConfig({ arg_str } )"
76+
77+ def __or__ (self , other : Self ) -> Self :
78+ """Merge multiple rule configs together.
79+
80+ Examples:
81+ >>> RuleConfig(selected=["A"]) | RuleConfig(selected=["B"])
82+ RuleConfig(selected=['A', 'B'])
83+ >>> RuleConfig(selected=["A"]) | RuleConfig(ignored=["B"])
84+ RuleConfig(selected=['A'], ignored=['B'])
85+ """
86+ if not isinstance (other , self .__class__ ):
87+ msg = (
88+ f"Cannot merge '{ self .__class__ .__name__ } ' with "
89+ f"'{ other .__class__ .__name__ } '"
90+ )
91+ raise NotImplementedError (msg )
92+
93+ return type (self )(
94+ selected = self .selected + other .selected ,
95+ ignored = self .ignored + other .ignored ,
96+ unmanaged_selected = self .unmanaged_selected + other .unmanaged_selected ,
97+ unmanaged_ignored = self .unmanaged_ignored + other .unmanaged_ignored ,
98+ tests_unmanaged_ignored = self .tests_unmanaged_ignored
99+ + other .tests_unmanaged_ignored ,
100+ )
0 commit comments