brilliance-admin 0.43.7__py3-none-any.whl → 0.44.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  # pylint: disable=wildcard-import, unused-wildcard-import, unused-import
2
2
  # flake8: noqa: F405
3
3
  from .admin_schema import AdminSchema, AdminSchemaData
4
- from .category import Category
4
+ from .category import CategoryGroup, CategoryLink
5
5
  from .graphs import *
6
- from .group import Group
7
6
  from .table import *
7
+ from .table.category_table import CategoryTable
@@ -7,11 +7,12 @@ from urllib.parse import urljoin
7
7
  from fastapi import FastAPI, Request
8
8
  from fastapi.middleware.cors import CORSMiddleware
9
9
  from fastapi.staticfiles import StaticFiles
10
+ from pydantic import Field
10
11
  from pydantic.dataclasses import dataclass
11
12
 
12
13
  from brilliance_admin.auth import UserABC
13
14
  from brilliance_admin.docs import build_redoc_docs, build_scalar_docs
14
- from brilliance_admin.schema.group import Group, GroupSchemaData
15
+ from brilliance_admin.schema.category import BaseCategory, CategorySchemaData
15
16
  from brilliance_admin.translations import LanguageContext, LanguageManager
16
17
  from brilliance_admin.utils import DataclassBase, SupportsStr
17
18
 
@@ -23,8 +24,8 @@ DEFAULT_LANGUAGES = {
23
24
 
24
25
  @dataclass
25
26
  class AdminSchemaData(DataclassBase):
26
- groups: Dict[str, GroupSchemaData]
27
27
  profile: UserABC | Any
28
+ categories: Dict[str, CategorySchemaData] = Field(default_factory=dict)
28
29
 
29
30
  def __post_init__(self):
30
31
  if not isinstance(self.profile, UserABC):
@@ -50,7 +51,7 @@ class AdminIndexContextData(DataclassBase):
50
51
 
51
52
  @dataclass
52
53
  class AdminSchema:
53
- groups: List[Group]
54
+ categories: List[BaseCategory]
54
55
  auth: Any
55
56
 
56
57
  title: SupportsStr | None = 'Admin'
@@ -68,9 +69,9 @@ class AdminSchema:
68
69
  language_manager: LanguageManager | None = None
69
70
 
70
71
  def __post_init__(self):
71
- for group in self.groups:
72
- if not issubclass(group.__class__, Group):
73
- raise TypeError(f'Group "{group}" is not instance of Group subclass')
72
+ for category in self.categories:
73
+ if not issubclass(category.__class__, BaseCategory):
74
+ raise TypeError(f'Root category "{category}" is not instance of BaseCategory subclass')
74
75
 
75
76
  if not self.language_manager:
76
77
  self.language_manager = LanguageManager(DEFAULT_LANGUAGES)
@@ -81,24 +82,25 @@ class AdminSchema:
81
82
  def generate_schema(self, user: UserABC, language_slug: str | None) -> AdminSchemaData:
82
83
  language_context: LanguageContext = self.get_language_context(language_slug)
83
84
 
84
- groups = {}
85
+ result = AdminSchemaData(profile=user)
85
86
 
86
- for group in self.groups:
87
- if not group.slug:
88
- msg = f'Category group {type(group).__name__}.slug is empty'
87
+ for category in self.categories:
88
+ if not category.slug:
89
+ msg = f'Category {type(category).__name__}.slug is empty'
89
90
  raise AttributeError(msg)
90
91
 
91
- groups[group.slug] = group.generate_schema(user, language_context)
92
+ try:
93
+ result.categories[category.slug] = category.generate_schema(user, language_context).to_dict(keep_none=False)
94
+ except Exception as e:
95
+ msg = f'Root category "{category.slug}" generate_schema error: {e}'
96
+ raise Exception(msg) from e
92
97
 
93
- return AdminSchemaData(
94
- groups=groups,
95
- profile=user,
96
- )
98
+ return result
97
99
 
98
- def get_group(self, group_slug: str) -> Optional[Group]:
99
- for group in self.groups:
100
- if group.slug == group_slug:
101
- return group
100
+ def get_group(self, group_slug: str) -> Optional[BaseCategory]:
101
+ for category in self.categories:
102
+ if category.slug == group_slug:
103
+ return category
102
104
 
103
105
  return None
104
106
 
@@ -4,10 +4,13 @@ from typing import Any, ClassVar, Dict, List
4
4
  from pydantic import Field
5
5
  from pydantic.dataclasses import dataclass
6
6
  from pydantic_core import core_schema
7
+ from structlog import get_logger
7
8
 
8
9
  from brilliance_admin.auth import UserABC
9
10
  from brilliance_admin.translations import LanguageContext
10
- from brilliance_admin.utils import DataclassBase, SupportsStr, humanize_field_name
11
+ from brilliance_admin.utils import DataclassBase, KwargsInitMixin, SupportsStr, humanize_field_name
12
+
13
+ logger = get_logger()
11
14
 
12
15
 
13
16
  # pylint: disable=too-many-instance-attributes
@@ -106,37 +109,56 @@ class CategorySchemaData(DataclassBase):
106
109
  icon: str | None
107
110
  type: str
108
111
 
112
+ categories: dict = Field(default_factory=dict)
113
+
109
114
  table_info: TableInfoSchemaData | None = None
110
115
  graph_info: GraphInfoSchemaData | None = None
111
116
 
117
+ link: str | None = None
118
+
112
119
  def __repr__(self):
113
120
  return f'<CategorySchemaData type={self.type} "{self.title}">'
114
121
 
115
122
 
116
- class Category(abc.ABC):
117
- slug: ClassVar[str]
118
- title: ClassVar[SupportsStr | None] = None
119
- description: ClassVar[SupportsStr | None] = None
123
+ class BaseCategory(KwargsInitMixin, abc.ABC):
124
+ slug: str
125
+ title: SupportsStr | None = None
126
+ description: SupportsStr | None = None
120
127
 
121
128
  # https://pictogrammers.com/library/mdi/
122
- icon: ClassVar[str | None] = None
129
+ icon: str | None = None
123
130
 
124
131
  _type_slug: ClassVar[str]
125
132
 
126
133
  def generate_schema(self, user: UserABC, language_context: LanguageContext) -> CategorySchemaData:
127
- return CategorySchemaData(
134
+ type_slug = getattr(type(self), '_type_slug', None)
135
+ if not type_slug:
136
+ msg = f'{type(self).__name__}._type_slug must be set!'
137
+ raise AttributeError(msg)
138
+
139
+ result = CategorySchemaData(
128
140
  title=language_context.get_text(self.title) or humanize_field_name(self.slug),
129
141
  description=language_context.get_text(self.description),
130
142
  icon=self.icon,
131
- type=self._type_slug,
143
+ type=type_slug,
132
144
  )
145
+ return result
146
+
147
+ def __init_subclass__(cls, **kwargs):
148
+ super().__init_subclass__(**kwargs)
149
+
150
+ if cls is BaseCategory:
151
+ return
152
+
153
+ if not issubclass(cls, BaseCategory):
154
+ raise TypeError(f'{cls.__name__} must inherit from Category')
133
155
 
134
156
  @classmethod
135
157
  def __get_pydantic_core_schema__(cls, source_type: Any, handler: Any) -> core_schema.CoreSchema:
136
- def validate(v: Any) -> "Category":
158
+ def validate(v: Any) -> "BaseCategory":
137
159
  if isinstance(v, cls):
138
160
  return v
139
- raise TypeError(f"Expected {cls.__name__} instance")
161
+ raise TypeError(f"Expected {cls.__name__} instance, recieved: {type(v)} {v}")
140
162
 
141
163
  return core_schema.no_info_plain_validator_function(
142
164
  validate,
@@ -146,3 +168,56 @@ class Category(abc.ABC):
146
168
  return_schema=core_schema.str_schema(),
147
169
  ),
148
170
  )
171
+
172
+
173
+ class CategoryLink(BaseCategory):
174
+ _type_slug: str = 'link'
175
+
176
+ link: str
177
+
178
+ def generate_schema(self, user: UserABC, language_context: LanguageContext) -> CategorySchemaData:
179
+ result = super().generate_schema(user, language_context)
180
+ result.link = self.link
181
+ return result
182
+
183
+
184
+ class CategoryGroup(BaseCategory):
185
+ _type_slug: str = 'group'
186
+
187
+ subcategories: list = Field(default_factory=list)
188
+
189
+ def __init__(self, *args, **kwargs):
190
+ super().__init__(*args, **kwargs)
191
+
192
+ for category in self.subcategories:
193
+ if not isinstance(category, BaseCategory):
194
+ raise TypeError(f'Category "{category}" is not instance of BaseCategory subclass')
195
+
196
+ def generate_schema(self, user: UserABC, language_context: LanguageContext) -> CategorySchemaData:
197
+ result = super().generate_schema(user, language_context)
198
+
199
+ for category in self.subcategories:
200
+
201
+ if not category.slug:
202
+ msg = f'Category {type(category).__name__}.slug is empty'
203
+ raise AttributeError(msg)
204
+
205
+ if category.slug in result.categories:
206
+ exists = result.categories[category.slug]
207
+ msg = f'Category {type(category).__name__}.slug "{self.slug}" already registered by "{exists.title}"'
208
+ raise KeyError(msg)
209
+
210
+ try:
211
+ result.categories[category.slug] = category.generate_schema(user, language_context)
212
+ except Exception as e:
213
+ msg = f'Category "{category.slug}" {type(category)} generate_schema error: {e}'
214
+ raise Exception(msg) from e
215
+
216
+ return result
217
+
218
+ def get_category(self, category_slug: str):
219
+ for category in self.subcategories:
220
+ if category.slug == category_slug:
221
+ return category
222
+
223
+ return None
@@ -2,8 +2,7 @@ from typing import Any, Dict, List
2
2
 
3
3
  from pydantic import BaseModel, Field
4
4
 
5
- from brilliance_admin.schema import Category
6
- from brilliance_admin.schema.category import GraphInfoSchemaData
5
+ from brilliance_admin.schema.category import BaseCategory, GraphInfoSchemaData
7
6
  from brilliance_admin.schema.table.fields_schema import FieldsSchema
8
7
  from brilliance_admin.translations import LanguageContext
9
8
  from brilliance_admin.utils import SupportsStr
@@ -26,7 +25,7 @@ class GraphsDataResult(BaseModel):
26
25
  charts: List[ChartData]
27
26
 
28
27
 
29
- class CategoryGraphs(Category):
28
+ class CategoryGraphs(BaseCategory):
30
29
  _type_slug: str = 'graphs'
31
30
 
32
31
  search_enabled: bool = False
@@ -8,7 +8,7 @@ from pydantic import Field
8
8
 
9
9
  from brilliance_admin.auth import UserABC
10
10
  from brilliance_admin.exceptions import AdminAPIException, APIError
11
- from brilliance_admin.schema import Category
11
+ from brilliance_admin.schema.category import BaseCategory
12
12
  from brilliance_admin.schema.category import TableInfoSchemaData
13
13
  from brilliance_admin.schema.table.admin_action import ActionData, ActionResult
14
14
  from brilliance_admin.schema.table.fields_schema import FieldsSchema
@@ -17,7 +17,7 @@ from brilliance_admin.translations import LanguageContext
17
17
  from brilliance_admin.utils import DeserializeAction, SupportsStr
18
18
 
19
19
 
20
- class CategoryTable(Category):
20
+ class CategoryTable(BaseCategory):
21
21
  _type_slug: str = 'table'
22
22
 
23
23
  search_enabled: bool = False
@@ -32,6 +32,8 @@ class CategoryTable(Category):
32
32
  pk_name: str | None = None
33
33
 
34
34
  def __init__(self, *args, table_schema=None, table_filters=None, **kwargs):
35
+ super().__init__(*args, **kwargs)
36
+
35
37
  if table_schema:
36
38
  self.table_schema = table_schema
37
39