clear-skies 1.21.1__py3-none-any.whl → 1.21.3__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.

Potentially problematic release.


This version of clear-skies might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: clear-skies
3
- Version: 1.21.1
3
+ Version: 1.21.3
4
4
  Summary: A framework for building backends in the cloud
5
5
  Home-page: https://github.com/cmancone/clearskies
6
6
  License: MIT
@@ -59,7 +59,7 @@ clearskies/column_types/__init__.py,sha256=wofhLfyW00I6tb6o9DMsMx7j9hlbbqefhDzWf
59
59
  clearskies/column_types/audit.py,sha256=2YcrZVVElpOUdmxYTQ_6CshL1HVou6fz65dOOs_b8Gw,9659
60
60
  clearskies/column_types/belongs_to.py,sha256=tH1tbTOfjifSNuVjO-KbMF7GiUIoLfcDItrrS3TGGM8,11044
61
61
  clearskies/column_types/boolean.py,sha256=1yyM1CUfgD84pPE65c1OP1Qjf_J0Z45hjPrDR51AUkQ,1878
62
- clearskies/column_types/category_tree.py,sha256=PgNmzZPyqYS5NADH_QTCxLvDXZFxzv5ESKTkvPrrLXo,9140
62
+ clearskies/column_types/category_tree.py,sha256=kPx0fNTJxHaaEI_-0JxQ7NBcV2bYgUDGmtf1wmTqoEg,13172
63
63
  clearskies/column_types/column.py,sha256=ftuDFswjk-KE9Frxo1rhgkjr4sjSjnUc5ZtfNrnGLIc,15530
64
64
  clearskies/column_types/created.py,sha256=LIWSzPJ9rbHuk1u53pNvKtVCOG9y9XCn-mEEsSi97Zc,649
65
65
  clearskies/column_types/created_by_authorization_data.py,sha256=--1w1TOSo2CMwrpn6Y_iorl2RTqLgG8MbR8k27qreew,1108
@@ -68,7 +68,7 @@ clearskies/column_types/created_by_ip.py,sha256=wwCUoEwHEVGN89x4xP7NJ6QR85Aum6v3
68
68
  clearskies/column_types/created_by_routing_data.py,sha256=EhVorRaGV2OhEb0YSPwPmrsK2NQycYgGEd4ab8-qI2I,569
69
69
  clearskies/column_types/created_by_user_agent.py,sha256=sSYDRrqSjsCwcYlhF_s9NO-iDww3PaH6aO2ATp_SKGQ,419
70
70
  clearskies/column_types/created_micro.py,sha256=Y_YADPg-TYPfWCFuGbs1b7NeM1Ixi_oBP8OQfJgTI7s,670
71
- clearskies/column_types/datetime.py,sha256=VCVLDTxEN1yQ0h-BprejKWCYSOneQkvm7EeKy3c_T-Q,4339
71
+ clearskies/column_types/datetime.py,sha256=xtuZpUC9fA16i1oO80kPIx--8RDPuei9RdsDDqensbw,4340
72
72
  clearskies/column_types/datetime_micro.py,sha256=ewQSniCc2MmNIyX2XNuNcCIwh5Fpf1HcvpLfzB8lz8g,382
73
73
  clearskies/column_types/email.py,sha256=qq0Yo_C3KxUqT68q2HWXocBBR4xwMqjxcIdgZRv218U,584
74
74
  clearskies/column_types/float.py,sha256=j8jJeBueSOusPtAFCWgLHYBncfLnqT1U7bh1zcAkYiA,1332
@@ -120,7 +120,7 @@ clearskies/di/__init__.py,sha256=T7SgQNny2XAZQPeFkdmp1XxxmEVxtnpcRiGK8YflkwU,304
120
120
  clearskies/di/additional_config.py,sha256=jdoS_HWC0MAabori3WwLRAG1i5YKZmQfQ1o0hCoxsPs,526
121
121
  clearskies/di/additional_config_auto_import.py,sha256=m57IODPbnCAus9iDu3mDp42u4H87oPZvjAlBGoS8uRQ,111
122
122
  clearskies/di/di.py,sha256=g0U0PI73eNp0mkGH3KUN1fmqNic5eEUK-_IB8hQh-Kg,15511
123
- clearskies/di/standard_dependencies.py,sha256=fgD4GT4Z0bcGPBaPDrzCqCtblD0UP572XD5d0O_DJxE,4523
123
+ clearskies/di/standard_dependencies.py,sha256=NW8tNZ2Punwq70XaH_e9IhmQ7ggsFFvum8ymwinoD7U,4522
124
124
  clearskies/di/test_module/__init__.py,sha256=7YHQF7JHP0FdI7GdEGANSZ_t1EISQYhUNm1wqOg0NKw,88
125
125
  clearskies/di/test_module/another_module/__init__.py,sha256=8SRmHPDepLKGWTUSc1ucDF6U8mJPsNDsBDmBQCpzPWo,35
126
126
  clearskies/di/test_module/module_class.py,sha256=I_-wnMuHfbsvti-7d2Z4bXnr6deo__uvww9nds9qrlE,46
@@ -181,7 +181,7 @@ clearskies/input_requirements/unique.py,sha256=gpbm9uoXcy8WCHsuWqAotwockbjDfJOWi
181
181
  clearskies/mocks/__init__.py,sha256=T68OUB9gGCX0WoisGzsY3Bt2cCFX7ILHKPqi6XKTJM0,113
182
182
  clearskies/mocks/input_output.py,sha256=2wD5GbUyVSkXcBg1GTZ-Oz9VzcYxNHfTlmZAODW-7CI,3898
183
183
  clearskies/mocks/models.py,sha256=DCzsnMddBvPoBA8JwwbSOhzY7enQWrosgeYD4gx2deI,5124
184
- clearskies/model.py,sha256=ZI75_1KP4J-PID2Aw9l_mNHCeY-HOZH887QKdxRoTdg,13511
184
+ clearskies/model.py,sha256=N5el03awXEfTBfhqjS3Yuc6ozMjATs7cMLs_IoZNuaE,13511
185
185
  clearskies/models.py,sha256=1H5Vohv1U4avN5_YHqULzc7ynZDRytmZ56x775xWTIo,13038
186
186
  clearskies/secrets/__init__.py,sha256=ctTmA_etV9G_5U21APWENI1HvThrBS4DidGWRtEDHQs,1053
187
187
  clearskies/secrets/additional_configs/__init__.py,sha256=cFCrbtKF5nuR061S2y1iKZp349x-y8Srdwe3VZbfSFU,1119
@@ -205,7 +205,7 @@ clearskies/tests/simple_api/models/__init__.py,sha256=nUA0W6fgXw_Bxa9CudkaDkC80t
205
205
  clearskies/tests/simple_api/models/status.py,sha256=PEhPbaQh5qdUNHp8O0gz91LOLENAEBtqSaHxUPXchaM,699
206
206
  clearskies/tests/simple_api/models/user.py,sha256=5_P4Tp1tTdX7PkMJ__epPM5MA7JAeVYGas69vcWloLc,819
207
207
  clearskies/tests/simple_api/users_api.py,sha256=KYXCgEofDxHeRdQK67txN5oYUPvxxmB8JTku7L-apk4,2344
208
- clear_skies-1.21.1.dist-info/LICENSE,sha256=3Ehd0g3YOpCj8sqj0Xjq5qbOtjjgk9qzhhD9YjRQgOA,1053
209
- clear_skies-1.21.1.dist-info/METADATA,sha256=gUmBHTE31EscgWpY1XRDst7EdoQlbySciQkEvh_fdoA,1817
210
- clear_skies-1.21.1.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
211
- clear_skies-1.21.1.dist-info/RECORD,,
208
+ clear_skies-1.21.3.dist-info/LICENSE,sha256=3Ehd0g3YOpCj8sqj0Xjq5qbOtjjgk9qzhhD9YjRQgOA,1053
209
+ clear_skies-1.21.3.dist-info/METADATA,sha256=tV9vLb2zbcNwdE9QlBah3O39Kec5D4im3eO4dowTkTI,1817
210
+ clear_skies-1.21.3.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
211
+ clear_skies-1.21.3.dist-info/RECORD,,
@@ -119,6 +119,10 @@ class CategoryTree(BelongsTo):
119
119
  "tree_level_column_name",
120
120
  "max_iterations",
121
121
  "parent_models_class",
122
+ "children_column_name",
123
+ "descendents_column_name",
124
+ "ancestors_column_name",
125
+ "load_relatives_strategy",
122
126
  ]
123
127
 
124
128
  def __init__(self, di):
@@ -137,6 +141,11 @@ class CategoryTree(BelongsTo):
137
141
  configuration["tree_models_class"],
138
142
  config_name="tree_models_class",
139
143
  )
144
+ load_relatives_strategy = configuration.get("load_relatives_strategy", None)
145
+ if load_relatives_strategy and load_relatives_strategy not in ["join", "where_in", "individual"]:
146
+ raise ValueError(
147
+ f"Configuration error for category_tree column '{self.name} in model class '{self.model_class.__name__}': load_relatives_strategy must be one of ['join', 'where_in', or 'individual']"
148
+ )
140
149
 
141
150
  def _finalize_configuration(self, configuration):
142
151
  return {
@@ -152,6 +161,10 @@ class CategoryTree(BelongsTo):
152
161
  "tree_is_parent_column_name": configuration.get("tree_is_parent_column_name", "is_parent"),
153
162
  "tree_level_column_name": configuration.get("tree_level_column_name", "level"),
154
163
  "max_iterations": configuration.get("max_iterations", 100),
164
+ "children_column_name": configuration.get("children_column_name", "children"),
165
+ "descendents_column_name": configuration.get("descendents_column_name", "descendents"),
166
+ "ancestors_column_name": configuration.get("ancestors_column_name", "ancestors"),
167
+ "load_relatives_strategy": configuration.get("load_relatives_strategy", "join"),
155
168
  },
156
169
  }
157
170
 
@@ -167,7 +180,7 @@ class CategoryTree(BelongsTo):
167
180
  return data
168
181
 
169
182
  def force_tree_update(self, model):
170
- self.update_tree_table(model, model.id, model.__getattr__(self.name))
183
+ self.update_tree_table(model, model.get(self.id_column_name), model.__getattr__(self.name))
171
184
 
172
185
  def update_tree_table(self, model, child_id, direct_parent_id):
173
186
  tree_models = self.tree_models
@@ -224,3 +237,68 @@ class CategoryTree(BelongsTo):
224
237
  + "You may have accidentally created a circular cateogry tree. If not, and your category tree "
225
238
  + "really _is_ that deep, then adjust the 'max_iterations' configuration for this column accordingly. "
226
239
  )
240
+
241
+ def can_provide(self, column_name):
242
+ return column_name in [
243
+ self.config("model_column_name"),
244
+ self.config("children_column_name"),
245
+ self.config("descendents_column_name"),
246
+ self.config("ancestors_column_name"),
247
+ ]
248
+
249
+ def provide(self, data, column_name):
250
+ if column_name == self.config("model_column_name"):
251
+ return super().provide(data, column_name)
252
+
253
+ if column_name == self.config("children_column_name"):
254
+ return self.relatives(data)
255
+
256
+ if column_name == self.config("descendents_column_name"):
257
+ return self.relatives(data, include_all=True)
258
+
259
+ if column_name == self.config("ancestors_column_name"):
260
+ return self.relatives(data, find_parents=True, include_all=True)
261
+
262
+ def relatives(self, data, include_all=False, find_parents=False):
263
+ id_column_name = self.model_class.id_column_name
264
+ model_id = data[self.model_class.id_column_name]
265
+ model_table_name = self.model_class.table_name()
266
+ tree_table_name = self.config("tree_models_class").table_name()
267
+ parent_id_column_name = self.config("tree_parent_id_column_name")
268
+ child_id_column_name = self.config("tree_child_id_column_name")
269
+ is_parent_column_name = self.config("tree_is_parent_column_name")
270
+ level_column_name = self.config("tree_level_column_name")
271
+
272
+ if find_parents:
273
+ join_on = parent_id_column_name
274
+ search_on = child_id_column_name
275
+ else:
276
+ join_on = child_id_column_name
277
+ search_on = parent_id_column_name
278
+
279
+ # if we can join then use a join.
280
+ if self.config("load_relatives_strategy") == "join":
281
+ relatives = self.parent_models.join(
282
+ f"{tree_table_name} as tree on tree.{join_on}={model_table_name}.{id_column_name}"
283
+ )
284
+ relatives = relatives.where(f"tree.{search_on}={model_id}")
285
+ if not include_all:
286
+ relatives = relatives.where(f"tree.{is_parent_column_name}=1")
287
+ if find_parents:
288
+ relatives = relatives.sort_by(level_column_name, "asc")
289
+ return relatives
290
+
291
+ # joins only work for SQL-like backends. Otherwise, we have to pull out our list of ids
292
+ branches = self.tree_models.where(f"{search_on}={model_id}")
293
+ if not include_all:
294
+ branches = branches.where(f"{is_parent_column_name}=1")
295
+ if find_parents:
296
+ branches = branches.sort_by(level_column_name, "asc")
297
+ ids = [str(branch.get(join_on)) for branch in branches]
298
+
299
+ # Can we search with a WHERE IN() clause? If the backend supports it, it is probably faster
300
+ if self.config("load_relatives_strategy") == "where_in":
301
+ return self.parent_models.where(f"{id_column_name} IN ('" + "','".join(ids) + "')")
302
+
303
+ # otherwise we have to load each model individually which is SLOW....
304
+ return [self.parent_models.find(f"{id_column_name}={id}") for id in ids]
@@ -3,6 +3,7 @@ from datetime import datetime, timezone
3
3
  import dateparser
4
4
  from ..autodoc.schema import DateTime as AutoDocDateTime
5
5
 
6
+
6
7
  class DateTime(Column):
7
8
  _auto_doc_class = AutoDocDateTime
8
9
  _date_format = "%Y-%m-%d %H:%M:%S"
@@ -138,8 +138,9 @@ class StandardDependencies(DI):
138
138
 
139
139
  def provide_uuid(self):
140
140
  return uuid
141
-
141
+
142
142
  def provide_timezone(self):
143
143
  """Set the default timezone."""
144
144
  import datetime
145
+
145
146
  return datetime.UTC
clearskies/model.py CHANGED
@@ -10,6 +10,7 @@ try:
10
10
  except ModuleNotFoundError:
11
11
  from typing import Self
12
12
 
13
+
13
14
  class Model(Models):
14
15
  _configured_columns = None
15
16
  _data = None
@@ -202,7 +203,7 @@ class Model(Models):
202
203
  return data[key]
203
204
  return self.__getattr__(key)
204
205
 
205
- def was_changed(self: Self, key) -> bool:
206
+ def was_changed(self: Self, key) -> bool:
206
207
  """Returns True/False to denote if a column was changed in the last save"""
207
208
  if self._previous_data is None:
208
209
  raise ValueError("was_changed was called before a save was finished - you must save something first")