spinta 0.2.dev21__py3-none-any.whl → 0.2.dev22__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.
spinta/auth.py CHANGED
@@ -58,6 +58,7 @@ from spinta.exceptions import (
58
58
  InvalidClientsKeymapStructure,
59
59
  InvalidScopes,
60
60
  InvalidClientFileFormat,
61
+ ModelNotFound,
61
62
  )
62
63
  from spinta.utils import passwords
63
64
  from spinta.utils.config import get_clients_path, get_keymap_path, get_id_path, get_helpers_path
@@ -858,40 +859,46 @@ def authorized(
858
859
  scope_formatter: ScopeFormatterFunc = None,
859
860
  ):
860
861
  config: Config = context.get("config")
862
+
863
+ # Disable access to nodes that have lower access level than config.access
864
+ if config.access > node.access:
865
+ if throw:
866
+ raise ModelNotFound(model=node.name)
867
+ return False
868
+
861
869
  token = context.get("auth.token")
862
- # Unauthorized clients can only access open nodes.
863
- unauthorized = token.get_client_id() == get_default_auth_client_id(context)
864
- open_node = node.access >= Access.open
865
- if unauthorized and not open_node:
870
+
871
+ # Unauthenticated clients can only access nodes if spinta config.access is open.
872
+ unauthenticated = token.get_client_id() == get_default_auth_client_id(context)
873
+
874
+ if unauthenticated and config.access < Access.open:
866
875
  if throw:
867
876
  raise AuthorizedClientsOnly()
868
877
  else:
869
878
  return False
870
879
 
871
- # Private nodes can only be accessed with explicit node scope.
880
+ # Add explicit node scope
872
881
  scopes = [node]
873
882
 
874
- # Protected and higher level nodes can be accessed with parent nodes scopes.
875
- if node.access > Access.private:
876
- ns = None
877
-
878
- if isinstance(node, Property):
879
- # Hidden nodes also require explicit scope.
880
- # XXX: `hidden` parameter should only be used for API control, not
881
- # access control. See docs.
882
- if not node.hidden:
883
- scopes.append(node.model)
884
- scopes.append(node.model.ns)
885
- ns = node.model.ns
886
- elif isinstance(node, Model):
887
- scopes.append(node.ns)
888
- ns = node.ns
889
- elif isinstance(node, Namespace):
890
- ns = node
891
-
892
- # Add all parent namespace scopes too.
893
- if ns:
894
- scopes.extend(ns.parents())
883
+ # Add parent node scopes
884
+ ns = None
885
+ if isinstance(node, Property):
886
+ # Hidden nodes also require explicit scope.
887
+ # XXX: `hidden` parameter should only be used for API control, not
888
+ # access control. See docs.
889
+ if not node.hidden:
890
+ scopes.append(node.model)
891
+ scopes.append(node.model.ns)
892
+ ns = node.model.ns
893
+ elif isinstance(node, Model):
894
+ scopes.append(node.ns)
895
+ ns = node.ns
896
+ elif isinstance(node, Namespace):
897
+ ns = node
898
+
899
+ # Add all parent namespace scopes too.
900
+ if ns:
901
+ scopes.extend(ns.parents())
895
902
 
896
903
  # Build scope names.
897
904
  scope_formatter = scope_formatter or config.scope_formatter
@@ -1,8 +1,6 @@
1
1
  from contextlib import ExitStack
2
2
  from typing import Generator
3
3
 
4
- from alembic.operations import Operations
5
- from alembic.runtime.migration import MigrationContext
6
4
  from click import echo
7
5
  from sqlalchemy.engine import Inspector
8
6
  from tqdm import tqdm
@@ -105,6 +103,9 @@ def gather_associated_tables(backend: PostgreSQL, table_identifier: TableIdentif
105
103
 
106
104
 
107
105
  def migrate_schemas(context: Context, **kwargs):
106
+ from alembic.operations import Operations
107
+ from alembic.runtime.migration import MigrationContext
108
+
108
109
  ensure_store_is_loaded(context)
109
110
  store = context.get("store")
110
111
 
spinta/components.py CHANGED
@@ -1095,7 +1095,8 @@ class Config:
1095
1095
  scope_log: bool
1096
1096
  check_contract_scopes: bool
1097
1097
  default_auth_client: str
1098
- default_access_level: str
1098
+ default_access_level: Access
1099
+ access: Access
1099
1100
  http_basic_auth: bool
1100
1101
  token_validation_key: dict | None = None
1101
1102
  token_validation_keys_download_url: str | None = None
spinta/config.py CHANGED
@@ -344,7 +344,8 @@ CONFIG = {
344
344
  },
345
345
  "config_path": pathlib.Path("tests/config"),
346
346
  "default_auth_client": "baa448a8-205c-4faa-a048-a10e4b32a136",
347
- "default_access_level": "protected",
347
+ "default_access_level": "open",
348
+ "access": "open",
348
349
  "sync_retry_count": 0,
349
350
  },
350
351
  },
@@ -164,7 +164,7 @@ def getall(
164
164
  builder.update(model=model, params={param.name: param for param in resource.params}, url_query_params=query)
165
165
 
166
166
  props = {}
167
- for prop in model.properties.values():
167
+ for prop in model.flatprops.values():
168
168
  if prop.external and prop.external.name:
169
169
  root_source = _get_prop_full_source(model.external.name, prop.external.name)
170
170
  props[prop.external.name] = {
@@ -276,6 +276,11 @@ def dask_get_all(
276
276
  val = _get_row_value(context, row, sel, env.params)
277
277
  if sel.prop:
278
278
  if isinstance(sel.prop.dtype, PrimaryKey):
279
+ if isinstance(val, list):
280
+ val = [
281
+ list_value.get("_id", list_value) if isinstance(list_value, dict) else list_value
282
+ for list_value in val
283
+ ]
279
284
  val = keymap.encode(sel.prop.model.model_type(), val)
280
285
  elif isinstance(sel.prop.dtype, Ref):
281
286
  val = handle_ref_key_assignment(context, keymap, env, val, sel.prop.dtype)
@@ -336,12 +336,15 @@ def select(env: DaskDataFrameQueryBuilder, selected: Selected) -> Selected:
336
336
 
337
337
  @ufunc.resolver(DaskDataFrameQueryBuilder, Ref, GetAttr)
338
338
  def select(env: DaskDataFrameQueryBuilder, dtype: Ref, prep: GetAttr) -> Selected | None:
339
- prep = env.call("select", prep)
340
- if prep is not None:
341
- return Selected(
342
- prop=dtype.prop,
343
- prep=prep,
344
- )
339
+ resolved_prep = env.call("select", prep)
340
+
341
+ result = {}
342
+ result["_id"] = Selected(prop=dtype.prop, prep=resolved_prep)
343
+ for prop in dtype.properties.values():
344
+ sel = env.call("select", prop)
345
+ result[prop.name] = sel
346
+
347
+ return Selected(prop=dtype.prop, prep=result)
345
348
 
346
349
 
347
350
  @ufunc.resolver(DaskDataFrameQueryBuilder, Ref, object)
@@ -353,6 +356,18 @@ def select(env: DaskDataFrameQueryBuilder, dtype: Ref, prep: Any) -> Selected:
353
356
  )
354
357
 
355
358
 
359
+ @ufunc.resolver(DaskDataFrameQueryBuilder, Ref)
360
+ def select(env: DaskDataFrameQueryBuilder, dtype: Ref) -> Selected:
361
+ prep = {}
362
+ prep["_id"] = Selected(item=dtype.prop.external.name, prop=dtype.prop)
363
+
364
+ for prop in dtype.properties.values():
365
+ sel = env.call("select", prop)
366
+ prep[prop.name] = sel
367
+
368
+ return Selected(prop=dtype.prop, prep=prep)
369
+
370
+
356
371
  @ufunc.resolver(DaskDataFrameQueryBuilder, GetAttr)
357
372
  def select(env: DaskDataFrameQueryBuilder, attr: GetAttr) -> Selected:
358
373
  resolved = env.resolve_property(attr)
@@ -14,6 +14,10 @@ from spinta.utils.schema import NA
14
14
 
15
15
 
16
16
  def handle_ref_key_assignment(context: Context, keymap: KeyMap, env: Env, value: Any, ref: Ref) -> dict:
17
+ original_value = value
18
+ if isinstance(value, dict):
19
+ value = value["_id"]
20
+
17
21
  keymap_name = ref.model.model_type()
18
22
  if ref.refprops != ref.model.external.pkeys:
19
23
  keymap_name = f"{keymap_name}.{'_'.join(prop.name for prop in ref.refprops)}"
@@ -55,7 +59,16 @@ def handle_ref_key_assignment(context: Context, keymap: KeyMap, env: Env, value:
55
59
 
56
60
  # FIXME Quick hack when trying to get `Internal` model keys while running in `External` mode (should probably return error, or None)
57
61
  if ref_model.mode == Mode.external and not check_if_model_has_backend_and_source(ref_model):
58
- return {"_id": keymap.encode(keymap_name, target_value)}
62
+ val = {"_id": keymap.encode(keymap_name, target_value)}
63
+ if isinstance(original_value, dict):
64
+ for nested_prop_name, nested_prop in ref.properties.items():
65
+ nested_value = original_value[nested_prop_name]
66
+ if isinstance(nested_value, dict):
67
+ nested_value = handle_ref_key_assignment(
68
+ context, keymap, env, nested_value, nested_prop.dtype
69
+ )
70
+ val[nested_prop_name] = nested_value
71
+ return val
59
72
 
60
73
  expr_parts = ["select()"]
61
74
  for i, prop in enumerate(ref.refprops):
@@ -67,7 +80,10 @@ def handle_ref_key_assignment(context: Context, keymap: KeyMap, env: Env, value:
67
80
  for row in rows:
68
81
  if val is not None:
69
82
  raise MultiplePrimaryKeyCandidatesFound(ref, values=target_value)
70
- val = row["_id"]
83
+ if "_id" in row:
84
+ val = row["_id"]
85
+ else:
86
+ val = keymap.encode(keymap_name, target_value)
71
87
  found_value = True
72
88
 
73
89
  if not found_value:
@@ -84,6 +100,13 @@ def handle_ref_key_assignment(context: Context, keymap: KeyMap, env: Env, value:
84
100
  values = values[0]
85
101
  val[prop] = values
86
102
  i = i + count
103
+
104
+ if isinstance(original_value, dict):
105
+ for nested_prop_name, nested_prop in ref.properties.items():
106
+ nested_value = original_value[nested_prop_name]
107
+ if isinstance(nested_value, dict):
108
+ nested_value = handle_ref_key_assignment(context, keymap, env, nested_value, nested_prop.dtype)
109
+ val[nested_prop_name] = nested_value
87
110
  return val
88
111
 
89
112
 
spinta/exceptions.py CHANGED
@@ -1223,3 +1223,9 @@ class SourceOrPrepareNotAllowed(UserError):
1223
1223
  template = """
1224
1224
  The source {source} was not expected. Delete it from the manifest or update the prepare function to allow it.
1225
1225
  """
1226
+
1227
+
1228
+ class PartialIncorrectProperty(BaseError):
1229
+ template = (
1230
+ "The composite property {property} is not correct. Check if all parts of the composite property are present."
1231
+ )
spinta/testing/client.py CHANGED
@@ -94,7 +94,6 @@ def create_remote_server(
94
94
  {
95
95
  "config_path": confdir,
96
96
  "default_auth_client": None,
97
- "default_access_level": "protected",
98
97
  }
99
98
  )
100
99
  context = create_test_context(rc)
@@ -294,7 +293,6 @@ def create_rc(
294
293
  },
295
294
  # tests/config/clients/3388ea36-4a4f-4821-900a-b574c8829d52.yml
296
295
  "default_auth_client": "3388ea36-4a4f-4821-900a-b574c8829d52",
297
- "default_access_level": "protected",
298
296
  }
299
297
  )
300
298
 
spinta/types/config.py CHANGED
@@ -83,6 +83,11 @@ def load(context: Context, config: Config) -> Config:
83
83
  default="private",
84
84
  cast=lambda name: get_enum_by_name(Access, name),
85
85
  )
86
+ config.access = rc.get(
87
+ "access",
88
+ default="open",
89
+ cast=lambda name: get_enum_by_name(Access, name),
90
+ )
86
91
  config.http_basic_auth = rc.get("http_basic_auth", default=False, cast=asbool)
87
92
  config.token_validation_key = rc.get("token_validation_key", cast=json.loads) or None
88
93
  config.token_validation_keys_download_url = rc.get("token_validation_keys_download_url")
@@ -2,23 +2,29 @@ from copy import copy
2
2
 
3
3
  from spinta import commands
4
4
  from spinta.components import Context, Property
5
- from spinta.exceptions import PartialTypeNotFound, ParentNodeNotFound
5
+ from spinta.core.enums import Mode
6
+ from spinta.exceptions import PartialTypeNotFound, ParentNodeNotFound, PartialIncorrectProperty
6
7
  from spinta.types.datatype import Partial, Ref
7
8
 
8
9
 
9
- def get_ref_value(context: Context, prop: Property):
10
+ def get_ref_value(context: Context, prop: Property) -> Property | None:
10
11
  parent = prop.parent
11
- if isinstance(parent, Property) and isinstance(parent.dtype, Ref):
12
- parent_parent = parent.parent
13
- if isinstance(parent_parent, Property) and isinstance(parent_parent.dtype, Ref):
14
- model = parent_parent.dtype.model
15
- first_level = model.properties[parent.name]
16
- if prop.name in first_level.dtype.properties:
17
- return first_level.dtype.properties[prop.name]
18
- else:
19
- model = parent.dtype.model
20
- if prop.name in model.properties:
21
- return model.properties[prop.name]
12
+ if not (isinstance(parent, Property) and isinstance(parent.dtype, Ref)):
13
+ return None
14
+ if isinstance(parent.dtype.model, str):
15
+ parent.dtype.model = commands.get_model(context, prop.model.manifest, parent.dtype.model)
16
+ model = parent.dtype.model
17
+
18
+ if prop.name not in model.properties:
19
+ return None
20
+
21
+ model_property_value = model.properties[prop.name]
22
+ model_dtype = model_property_value.dtype
23
+ if hasattr(model_dtype, "model") and isinstance(model_dtype.model, str):
24
+ model_property_value.dtype.model = commands.get_model(
25
+ context, prop.model.manifest, model_property_value.dtype.model
26
+ )
27
+ return model_property_value
22
28
 
23
29
 
24
30
  @commands.link.register(Context, Partial)
@@ -29,14 +35,23 @@ def link(context: Context, dtype: Partial):
29
35
  if isinstance(parent.dtype, Ref):
30
36
  props = dtype.properties
31
37
  result = get_ref_value(context, prop)
38
+ if not result:
39
+ raise PartialIncorrectProperty(dtype)
32
40
  prop.dtype = copy(result.dtype)
33
41
  prop.dtype.properties = props
34
42
  prop.dtype.inherited = True
35
43
  prop.given.explicit = False
36
44
  prop.given.name = ""
37
45
  prop.dtype.prop = prop
38
- for partial_prop in props.values():
39
- commands.link(context, partial_prop)
46
+ if prop.level is None:
47
+ prop.level = result.level
48
+ # For external mode copy the external mapping
49
+ # For internal mode leave it as is, because it breaks multi-level denormalization
50
+ if result.external and prop.model.mode == Mode.external:
51
+ prop.external = copy(result.external)
52
+ if isinstance(prop.dtype, Ref):
53
+ prop.dtype.refprops = []
54
+ commands.link(context, prop.dtype)
40
55
  else:
41
56
  raise PartialTypeNotFound(dtype)
42
57
  else:
spinta/types/ref/link.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from typing import List
2
2
 
3
3
  from spinta import commands
4
- from spinta.components import Context
4
+ from spinta.components import Context, Model
5
5
  from spinta.types.datatype import Ref
6
6
  from spinta.exceptions import ModelReferenceNotFound, MissingRefModel
7
7
  from spinta.exceptions import ModelReferenceKeyNotFound
@@ -25,6 +25,8 @@ def link(context: Context, dtype: Ref) -> None:
25
25
  # Self reference.
26
26
  dtype.model = dtype.prop.model
27
27
  else:
28
+ if isinstance(rmodel, Model):
29
+ rmodel = rmodel.name
28
30
  if not commands.has_model(context, dtype.prop.model.manifest, rmodel):
29
31
  raise ModelReferenceNotFound(dtype, ref=rmodel)
30
32
  dtype.model = commands.get_model(context, dtype.prop.model.manifest, rmodel)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spinta
3
- Version: 0.2.dev21
3
+ Version: 0.2.dev22
4
4
  Summary: A platform for describing, extracting, transforming, loading and serving open data.
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -12,7 +12,7 @@ spinta/api/inspect.py,sha256=sf3Q8gUEqqCusPCiT1ZqH4Kyc7T9voKWWVRlQXSoIU0,6776
12
12
  spinta/api/schema.py,sha256=rsWeKxk6JigoawD56pb8n8AYve59YIrKQyVrqpUsX9I,7634
13
13
  spinta/api/validators.py,sha256=GcdKAq-3n9oe58VLClNOBXo3MSNyguCtgWqracHR_9w,666
14
14
  spinta/asgi.py,sha256=Too66Cvo4UX0a05K-SSVRUrj8NEBVYpaql_1sq3d8gw,530
15
- spinta/auth.py,sha256=gCFAuCMBkOkV7NzPr5ckCzaNSyryYF3QJQE-PLpkjCM,42550
15
+ spinta/auth.py,sha256=4QmNrZpVrjaVU3E9g2OWWMkI_4pt7l0JXHW3JA6iXS0,42587
16
16
  spinta/backends/__init__.py,sha256=i8zlodXE0ku_N38EBoDoNXvLvBWvc_AIm5SGHSP3aAI,56972
17
17
  spinta/backends/components.py,sha256=4nV3Yvye2rYAnBe0PV-rPuK2IXnHzrUFm37ceGI47eo,1663
18
18
  spinta/backends/constants.py,sha256=RdmpPhIIUsSwO6sQv1eZdmdl6Rf1h_3qAHDUcTOYOy0,828
@@ -235,7 +235,7 @@ spinta/cli/helpers/upgrade/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQe
235
235
  spinta/cli/helpers/upgrade/scripts/backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
236
236
  spinta/cli/helpers/upgrade/scripts/backends/postgresql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
237
237
  spinta/cli/helpers/upgrade/scripts/backends/postgresql/comments.py,sha256=ZqbbY0yTgS1p46N_Fn-RDsWxYdgslIwqstcEczqTxGI,9239
238
- spinta/cli/helpers/upgrade/scripts/backends/postgresql/schemas.py,sha256=6CwhML-E8WCFQpzBiFPLmsGfrYgBWOPA5AVEcXe44pE,11522
238
+ spinta/cli/helpers/upgrade/scripts/backends/postgresql/schemas.py,sha256=lUoeup6OumGb9A_8iTMVctyBQrza7jsufuZXWkcaLxs,11531
239
239
  spinta/cli/helpers/upgrade/scripts/clients.py,sha256=-OrfJvJZ4e07TyYpE7ltPoqntBgs_21J2TuzH6ukYVQ,7420
240
240
  spinta/cli/helpers/upgrade/scripts/keymaps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
241
241
  spinta/cli/helpers/upgrade/scripts/keymaps/sqlalchemy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -266,8 +266,8 @@ spinta/commands/search.py,sha256=Yn-lxFhAQrDzDWFGlTm_WmQmUFXsu6NhuT7PpNJ67Ls,311
266
266
  spinta/commands/version.py,sha256=rZGszGCU_cgyJyRUgZgg_ts3ZldqemLcugpOOY_UJ64,745
267
267
  spinta/commands/write.py,sha256=en2dcD1nb2T28cQDMa41qbeIhZEVH2B1xPDP-nG8mBs,42398
268
268
  spinta/compat.py,sha256=eI-tsNtWww_rEW6Gw7tcgoLvUMOb_f1vV-kLjzFPRMs,2919
269
- spinta/components.py,sha256=jLgIFxMO6gwol-yxHmKGSWNhGs2qF99SbDvzLjwG1to,35373
270
- spinta/config.py,sha256=xrkMwNo_XrtUZLmXMS303-Pqcjoo0PfV7gT8wOOf4xk,16247
269
+ spinta/components.py,sha256=uZ6VFzonu0MolUN2lYSrl_Ggsaoak6cNP5VcZ1BbtMc,35395
270
+ spinta/config.py,sha256=YR4Cxt1ceg-u9B4lZxOYKuAeGrsqiJKKA9pTffppn4A,16272
271
271
  spinta/config.yml,sha256=RvUjqZt-EL5wnWaizmoz1b85aBz43NhQwK0fB9WWoHA,3447
272
272
  spinta/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
273
273
  spinta/core/access.py,sha256=EAfG-5hMmhvHdCRSZ65z1y_n6-8i-X-ISElMbR9MIxw,2247
@@ -285,7 +285,7 @@ spinta/datasets/backends/dataframe/backends/csv/commands/read.py,sha256=4klYZKtG
285
285
  spinta/datasets/backends/dataframe/backends/csv/components.py,sha256=0EZvqouPeaPq3sHtzSGX9HW4eLtMMnRjAlMNYlu4cAI,209
286
286
  spinta/datasets/backends/dataframe/backends/json/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
287
287
  spinta/datasets/backends/dataframe/backends/json/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
288
- spinta/datasets/backends/dataframe/backends/json/commands/read.py,sha256=WfU0R5dmlyI2ETmGzNe34oBNwN0uzo5HI4YQXioC4Vk,7119
288
+ spinta/datasets/backends/dataframe/backends/json/commands/read.py,sha256=pjSsUEbZiCeXs02qFDoicfpJFSAFhB81qp4Lps9yt0U,7118
289
289
  spinta/datasets/backends/dataframe/backends/json/components.py,sha256=kPKQEEvWGZKq_IpiwhVNG4A-7CaEux5fGEuwwcaHCLk,211
290
290
  spinta/datasets/backends/dataframe/backends/memory/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
291
291
  spinta/datasets/backends/dataframe/backends/memory/components.py,sha256=tByPlAR0hp8WsL0i5JxAPbOh7bdawlw9UQEfT5SUIEo,226
@@ -302,15 +302,15 @@ spinta/datasets/backends/dataframe/backends/xml/commands/read.py,sha256=dqb_8lL_
302
302
  spinta/datasets/backends/dataframe/backends/xml/components.py,sha256=CcqTkD2MWky4R_wuY588nUnuUrzagBWTctHa5kV47L4,209
303
303
  spinta/datasets/backends/dataframe/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
304
304
  spinta/datasets/backends/dataframe/commands/check.py,sha256=eghehENfCjCcGeCXGzPXRXczQenV7F5j9T1xuDVUx7c,1385
305
- spinta/datasets/backends/dataframe/commands/read.py,sha256=C0f1GZoM6btgyOV_NUBdTa12Dw7jcth8E6_APHYJ1IA,10831
305
+ spinta/datasets/backends/dataframe/commands/read.py,sha256=kzQu-MD21H5UaA2fDIt4wLEb-ukfTevW6spk6vhkQGY,11095
306
306
  spinta/datasets/backends/dataframe/components.py,sha256=cnlB1VlZrdtVo4-8q7LukyAvsUr9l2SD-R0PzqJSoMQ,235
307
307
  spinta/datasets/backends/dataframe/ufuncs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
308
308
  spinta/datasets/backends/dataframe/ufuncs/components.py,sha256=gmfS7P6gMyPbjJf2ZY-zWRySXGaIxbIPIqar6p9ARh8,90
309
309
  spinta/datasets/backends/dataframe/ufuncs/query/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
310
310
  spinta/datasets/backends/dataframe/ufuncs/query/components.py,sha256=uekQHMdpJi5506-sWH-HakCw_kGS_0BN5A5Ym1i4yAs,2342
311
- spinta/datasets/backends/dataframe/ufuncs/query/ufuncs.py,sha256=LQs10MMEIzQ4bX-mikHSpOFnME2EwhHpOrhwRZzDNJw,19023
311
+ spinta/datasets/backends/dataframe/ufuncs/query/ufuncs.py,sha256=LUCL7rAqM1unZar0BwBH0oIA-FLt-L4E4_J9nBhlyiE,19537
312
312
  spinta/datasets/backends/dataframe/ufuncs/ufuncs.py,sha256=LRy_jE48FYtW41-oj4G35ihA70P39qCGWfbgS7amv9U,391
313
- spinta/datasets/backends/helpers.py,sha256=yjoi5mx_UsY62wRcmSKT2zsM_908LVPCJRmyxXsYefE,6557
313
+ spinta/datasets/backends/helpers.py,sha256=2UZGZfEsb45jpsLRFmeDhMTuXBk9DX2cAqo_oD4jL3U,7689
314
314
  spinta/datasets/backends/notimpl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
315
315
  spinta/datasets/backends/notimpl/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
316
316
  spinta/datasets/backends/notimpl/commands/load.py,sha256=5wbxy7LJ61fBSM2YpSWqHRFWh2-OQgsG9SUiOW4zCzc,372
@@ -460,7 +460,7 @@ spinta/dimensions/prefix/commands/load.py,sha256=P8Lzd7smS-lJ30NTFBPs_2ywmZw2qlr
460
460
  spinta/dimensions/prefix/components.py,sha256=5VJel2wvZUCol_4riD119CD5F5R6TSdf5ISeWDglKsk,618
461
461
  spinta/dimensions/prefix/helpers.py,sha256=VE6TT50tqyy-9becV2PV_TMjA4HXGrSSidV4F7aUCxE,1003
462
462
  spinta/dispatcher.py,sha256=FZaBJ7O2J-0hZ4fGL2w3a_cO8jzOVuxqyfOqON6jg0E,3769
463
- spinta/exceptions.py,sha256=vKbaYqFmF-XgS2yMe7jabt_cLaq2YBI9f_JUum8merg,35860
463
+ spinta/exceptions.py,sha256=6KPBa-zLMyhz-focdNypsnTDyTXFCGzh4ShmPLM8Ohc,36046
464
464
  spinta/fetcher.py,sha256=55-nxQy9WuISrLAPuJOxjJjtZ0opqTlPiCHI7iABiic,1330
465
465
  spinta/formats/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
466
466
  spinta/formats/ascii/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -611,7 +611,7 @@ spinta/templates/error.html,sha256=nlC52cRicXqs1nxdwl_4ikMZA9-N9WKp1-OLOp_oJwA,1
611
611
  spinta/templates/form.html,sha256=Ioszr7D8v_-ZkwmEHNeeMyHnh6p60te0wMDkKwdDaCA,794
612
612
  spinta/testing/__init__.py,sha256=bXkhOgOOugNFKv6O6uHrANccQ98B4E352WeBtJDUZ4E,50
613
613
  spinta/testing/cli.py,sha256=HPwUHeo2W5q5dRl56kIytJIxvG7WTdi52N_CMylEuvM,1840
614
- spinta/testing/client.py,sha256=XdTF4J36GVpM-HXc1b6FG_TY4-lB5PyXNmKEPvJD2ls,10138
614
+ spinta/testing/client.py,sha256=q_SLseq_hLN7O8-pxWJmNfJqeoMCGQrfWPy8Fh-oqQ8,10040
615
615
  spinta/testing/config.py,sha256=o40GCI0qAeQGK1u-VrxtnUh45m0o-tPHySJ0oQmN4j4,2919
616
616
  spinta/testing/context.py,sha256=9lDGKEN1wV58TW9KlrJyuzCo2vMer_HSP2MKQsKPZqI,3382
617
617
  spinta/testing/csv.py,sha256=XxAXwlQLd9yHmNi7m3oClPJJcDCnMX2qqOAz4WrAbgA,214
@@ -636,7 +636,7 @@ spinta/types/array/resolve.py,sha256=o8fEPK0RZx5FT6oMQ2RZyE8WYT3WK9qdh6QTORzndD8
636
636
  spinta/types/backref/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
637
637
  spinta/types/backref/link.py,sha256=_q7wHvuRUuGpllth_zTerq6Eoajq3C_WqjsqjxZTc7c,4684
638
638
  spinta/types/command.py,sha256=pmlL4ZQYFwzNm0nMY4q7GZIoPNqiYxZ-k6CzfTByCg4,975
639
- spinta/types/config.py,sha256=wm-kFU15eIkOI0ZyOrDQgCrQv_5J5QT8uFXk7BJbO8Q,6438
639
+ spinta/types/config.py,sha256=Yl9oGiE3znHZgtHQNtr8s7BGARCV_O10ibe1Mp8orss,6572
640
640
  spinta/types/datatype.py,sha256=zbarMo6S9MX__NHfnekw2Oto3MGqj3X4Ms5tWGodjps,16747
641
641
  spinta/types/denorm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
642
642
  spinta/types/denorm/check.py,sha256=2lZrDwd_F71hkflF7jvgFp_vyPRtAQV3HVlFZAEodwY,606
@@ -659,10 +659,10 @@ spinta/types/object/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
659
659
  spinta/types/object/check.py,sha256=14D_lGNIsZvNevQ9FhRTKtGGK3VJA9ugCI83xg4QYX4,276
660
660
  spinta/types/object/link.py,sha256=wjtzkVcS4gN-9etAauj2sLJczOi8Gwig-WpVaSFu_aA,361
661
661
  spinta/types/partial/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
662
- spinta/types/partial/link.py,sha256=VusV7jenKC6LZNj7gFBp2ibmWQiBKP-D66UvQUv6JMY,1823
662
+ spinta/types/partial/link.py,sha256=G4ieydtTOJloGPqB7VHpjmyZ3BIKieA-I1ROX3cvyw0,2487
663
663
  spinta/types/ref/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
664
664
  spinta/types/ref/check.py,sha256=I8gFHJiuYWGw1UIlGx2vyxlqExt15EkJ1jPz409fLXs,853
665
- spinta/types/ref/link.py,sha256=b3tahnT5VGq2Rg1qEyL5r56r6HAFeBubXCNkp6-AJbY,2008
665
+ spinta/types/ref/link.py,sha256=Cuu1E6iUYBcGXLYYm814ptlBe6lXNWr-QvBDGQm1X8U,2086
666
666
  spinta/types/ref/resolve.py,sha256=X3J5etLCaBIWfp0saqBIb0XOS7DkpM8-tFhVUvlN8OQ,309
667
667
  spinta/types/store.py,sha256=6dVzeIUoYZC-1F-LVA4ZSG23t593twvRY0-aa1-RWiY,5234
668
668
  spinta/types/text/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -740,8 +740,8 @@ spinta/utils/tree.py,sha256=iF8eOSBagUoDmdJGNQgsYB_gshsFajmiUALXqU9luHE,591
740
740
  spinta/utils/types.py,sha256=lfYSxKGPuPeUsO14d2OYodtbRY3zsa-o-z8HveVH3t0,801
741
741
  spinta/utils/units.py,sha256=CFFLv1NHYsoSSzwiar3zXYmt4m3sccW5niUgkZQgo3k,747
742
742
  spinta/utils/url.py,sha256=b6sqQEpmCdT3oV4vGDzXnN8w415InAYjIW_o2djhQS8,2950
743
- spinta-0.2.dev21.dist-info/METADATA,sha256=aPvAeY7zuGWVoo5Uhv28-SZHYJkW1Y5nIvP4wWuJHfQ,10214
744
- spinta-0.2.dev21.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
745
- spinta-0.2.dev21.dist-info/entry_points.txt,sha256=-jdsOQZcMu3rUOwgIJNS3gZS4rwWPACuXXy128F676w,46
746
- spinta-0.2.dev21.dist-info/licenses/LICENSE,sha256=JKmjfBLapeFWNI_qdVr5bXGlsuMPa6nRarKPK5davKw,1071
747
- spinta-0.2.dev21.dist-info/RECORD,,
743
+ spinta-0.2.dev22.dist-info/METADATA,sha256=P_BrClJT9fCuAKLPRw8wd5wxV1SPvk-bASxDI1Su2JM,10214
744
+ spinta-0.2.dev22.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
745
+ spinta-0.2.dev22.dist-info/entry_points.txt,sha256=-jdsOQZcMu3rUOwgIJNS3gZS4rwWPACuXXy128F676w,46
746
+ spinta-0.2.dev22.dist-info/licenses/LICENSE,sha256=JKmjfBLapeFWNI_qdVr5bXGlsuMPa6nRarKPK5davKw,1071
747
+ spinta-0.2.dev22.dist-info/RECORD,,