nsj-rest-lib2 0.0.20__py3-none-any.whl → 0.0.22__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.
@@ -25,18 +25,6 @@ from nsj_rest_lib2.compiler.edl_model.entity_model import EntityModel
25
25
 
26
26
  from nsj_rest_lib2.settings import get_logger
27
27
 
28
- # TODO GET e POST de relacionamentos 1X1
29
- # TODO Revisar compilação de valores default (sensível a tipos)
30
- # TODO Implementar suporte a conjuntos
31
- # TODO Autenticação nas rotas
32
- # TODO Atualizar o status da entidade pelo worker de compilação (e talvez parar uma compilação, quando se delete uma entidade)
33
- # TODO Classes Abstratas
34
- # TODO Partial Classes
35
- # TODO Migrations
36
- # TODO Criar imagem docker base para as aplicações, usando venv (para poderem atualizar o pydantic)
37
-
38
- # TODO Suporte ao "min_items" dos relacionamentos no RestLib1
39
-
40
28
 
41
29
  class EDLCompiler:
42
30
  def __init__(self) -> None:
@@ -117,7 +105,9 @@ class EDLCompiler:
117
105
  f"Entidade base '{entity_model.partial_of}' da extensão parcial '{entity_model.id}' é inválida."
118
106
  )
119
107
 
120
- self._validate_partial_model(entity_model, base_model_candidate, entity_models)
108
+ self._validate_partial_model(
109
+ entity_model, base_model_candidate, entity_models
110
+ )
121
111
  partial_metadata = self._build_partial_metadata(
122
112
  entity_model, base_model_candidate
123
113
  )
@@ -252,13 +242,13 @@ class EDLCompiler:
252
242
  compiler_result.entity_code = entity_code
253
243
  compiler_result.dto_class_name = dto_class_name
254
244
  compiler_result.dto_code = dto_code
245
+ compiler_result.relations_dependencies = relations_dependencies_complete
255
246
 
256
247
  # Compilando questões das APIs
257
248
  if isinstance(entity_model, EntityModel):
258
249
  compiler_result.api_expose = entity_model.api.expose
259
250
  compiler_result.api_resource = entity_model.api.resource
260
251
  compiler_result.api_verbs = entity_model.api.verbs
261
- compiler_result.relations_dependencies = relations_dependencies_complete
262
252
 
263
253
  get_logger().debug(f"código gerado para a entidade: {entity_model.id}")
264
254
  get_logger().debug("DTO Code:")
@@ -48,6 +48,14 @@ MAPPING_PRIMITIVE_TYPES_TO_PYTHON = {
48
48
  BasicTypes = int | bool | float | str
49
49
  DefaultTypes = BasicTypes | List[BasicTypes]
50
50
 
51
+ STR_BASED_TYPES = {
52
+ PrimitiveTypes.STRING,
53
+ PrimitiveTypes.EMAIL,
54
+ PrimitiveTypes.CPF,
55
+ PrimitiveTypes.CNPJ,
56
+ PrimitiveTypes.CPF_CNPJ,
57
+ }
58
+
51
59
 
52
60
  class CardinalityTypes(enum.Enum):
53
61
  C1_1 = "1_1"
@@ -36,7 +36,6 @@ class PropertyMetaModel(BaseModel):
36
36
  None, description="Comprimento máximo (para strings)."
37
37
  )
38
38
 
39
- ## TODO Sugestões de validação
40
39
  min_length: Optional[int] = Field(
41
40
  None, description="Comprimento mínimo (para strings)."
42
41
  )
@@ -1,5 +1,7 @@
1
1
  import ast
2
+ import datetime
2
3
  import re
4
+ import uuid
3
5
 
4
6
  from nsj_rest_lib2.compiler.compiler_structures import (
5
7
  IndexCompilerStructure,
@@ -13,6 +15,7 @@ from nsj_rest_lib2.compiler.edl_model.primitives import (
13
15
  PrimitiveTypes,
14
16
  REGEX_EXTERNAL_REF,
15
17
  REGEX_INTERNAL_REF,
18
+ STR_BASED_TYPES,
16
19
  )
17
20
  from nsj_rest_lib2.compiler.edl_model.property_meta_model import PropertyMetaModel
18
21
  from nsj_rest_lib2.compiler.edl_model.trait_property_meta_model import (
@@ -27,10 +30,6 @@ from nsj_rest_lib2.compiler.util.type_naming_util import (
27
30
  )
28
31
  from nsj_rest_lib2.compiler.util.type_util import TypeUtil
29
32
 
30
- # TODO pattern
31
- # TODO lowercase
32
- # TODO uppercase
33
-
34
33
 
35
34
  class EDLPropertyCompiler:
36
35
 
@@ -51,9 +50,6 @@ class EDLPropertyCompiler:
51
50
  list[RelationDependency],
52
51
  list[tuple[str, BasicTypes]],
53
52
  ]:
54
-
55
- # TODO Criar opção de campo calculado?
56
-
57
53
  # Descobrindo os atributos marcados como PK (e recuperando a chave primária)
58
54
  # TODO Verificar se devemos manter essa verificação
59
55
  pk_keys = []
@@ -64,8 +60,8 @@ class EDLPropertyCompiler:
64
60
  if prop.pk:
65
61
  pk_keys.append(pkey)
66
62
 
67
- is_partial_extension = (
68
- isinstance(entity_model, EntityModel) and bool(entity_model.partial_of)
63
+ is_partial_extension = isinstance(entity_model, EntityModel) and bool(
64
+ entity_model.partial_of
69
65
  )
70
66
 
71
67
  if not entity_model.mixin:
@@ -944,16 +940,6 @@ class EDLPropertyCompiler:
944
940
  )
945
941
  )
946
942
 
947
- if (
948
- prop.default
949
- ): # TODO Verificar esse modo de tratar valores default (principalmente expressões)
950
- keywords.append(
951
- ast.keyword(
952
- arg="default_value",
953
- value=ast.Name(str(prop.default), ctx=ast.Load()),
954
- )
955
- )
956
-
957
943
  if prop.trim:
958
944
  keywords.append(ast.keyword(arg="strip", value=ast.Constant(True)))
959
945
 
@@ -1086,6 +1072,15 @@ class EDLPropertyCompiler:
1086
1072
  enum_class_name, ast_enum_class = result
1087
1073
  aux_classes.append(ast_enum_class)
1088
1074
 
1075
+ default_value_ast = self._build_default_value_ast(pkey, prop, enum_class_name)
1076
+ if default_value_ast is not None:
1077
+ keywords.append(
1078
+ ast.keyword(
1079
+ arg="default_value",
1080
+ value=default_value_ast,
1081
+ )
1082
+ )
1083
+
1089
1084
  # Resolvendo o nome da propriedade no Entity
1090
1085
  if (
1091
1086
  properties_structure.entity_properties
@@ -1118,6 +1113,258 @@ class EDLPropertyCompiler:
1118
1113
 
1119
1114
  ast_entity_attributes.append(ast_entity_attr)
1120
1115
 
1116
+ def _build_default_value_ast(
1117
+ self,
1118
+ pkey: str,
1119
+ prop: PropertyMetaModel,
1120
+ enum_class_name: str | None,
1121
+ ) -> ast.expr | None:
1122
+ default_value = prop.default
1123
+ if default_value is None:
1124
+ return None
1125
+
1126
+ if prop.domain_config and enum_class_name:
1127
+ return self._build_enum_default_value_ast(
1128
+ pkey, prop, enum_class_name, default_value
1129
+ )
1130
+
1131
+ if not isinstance(prop.type, PrimitiveTypes):
1132
+ raise ValueError(
1133
+ f"Propriedade '{pkey}' não suporta valor default para relacionamentos."
1134
+ )
1135
+
1136
+ return self._build_primitive_default_value_ast(pkey, prop, default_value)
1137
+
1138
+ def _build_enum_default_value_ast(
1139
+ self,
1140
+ pkey: str,
1141
+ prop: PropertyMetaModel,
1142
+ enum_class_name: str,
1143
+ default_value: object,
1144
+ ) -> ast.expr:
1145
+ target_option = None
1146
+ for option in prop.domain_config or []:
1147
+ if option.value == default_value:
1148
+ target_option = option
1149
+ break
1150
+
1151
+ if option.mapped_value is not None and option.mapped_value == default_value:
1152
+ target_option = option
1153
+ break
1154
+
1155
+ if not target_option:
1156
+ raise ValueError(
1157
+ f"Propriedade '{pkey}' possui valor default '{default_value}' que não corresponde a nenhuma opção do enum."
1158
+ )
1159
+
1160
+ enum_member_name = CompilerStrUtil.to_enum_member_name(target_option.value)
1161
+
1162
+ return ast.Attribute(
1163
+ value=ast.Name(id=enum_class_name, ctx=ast.Load()),
1164
+ attr=enum_member_name,
1165
+ ctx=ast.Load(),
1166
+ )
1167
+
1168
+ def _build_primitive_default_value_ast(
1169
+ self,
1170
+ pkey: str,
1171
+ prop: PropertyMetaModel,
1172
+ default_value: object,
1173
+ ) -> ast.expr:
1174
+ primitive_type = prop.type
1175
+
1176
+ if isinstance(default_value, str):
1177
+ expression_ast = self._build_python_expression_from_string(default_value)
1178
+ if expression_ast is not None:
1179
+ return expression_ast
1180
+
1181
+ if primitive_type in STR_BASED_TYPES:
1182
+ if not isinstance(default_value, str):
1183
+ raise ValueError(
1184
+ f"Propriedade '{pkey}' exige valor default textual, recebido '{default_value}'."
1185
+ )
1186
+ return ast.Constant(value=default_value)
1187
+
1188
+ if primitive_type == PrimitiveTypes.BOOLEAN:
1189
+ if isinstance(default_value, bool):
1190
+ return ast.Constant(value=default_value)
1191
+ raise ValueError(
1192
+ f"Propriedade '{pkey}' exige valor default booleano, recebido '{default_value}'."
1193
+ )
1194
+
1195
+ if primitive_type == PrimitiveTypes.INTEGER:
1196
+ return self._build_numeric_constant_default_ast(
1197
+ pkey,
1198
+ default_value,
1199
+ int,
1200
+ "inteiro",
1201
+ forbid_fraction=True,
1202
+ )
1203
+
1204
+ if primitive_type in (
1205
+ PrimitiveTypes.NUMBER,
1206
+ PrimitiveTypes.CURRENCY,
1207
+ PrimitiveTypes.QUANTITY,
1208
+ ):
1209
+ return self._build_numeric_constant_default_ast(
1210
+ pkey,
1211
+ default_value,
1212
+ float,
1213
+ "numérico",
1214
+ )
1215
+
1216
+ if primitive_type == PrimitiveTypes.UUID:
1217
+ return self._build_uuid_default_ast(pkey, default_value)
1218
+
1219
+ if primitive_type == PrimitiveTypes.DATE:
1220
+ return self._build_iso_datetime_default_ast(
1221
+ pkey,
1222
+ default_value,
1223
+ target="date",
1224
+ )
1225
+
1226
+ if primitive_type == PrimitiveTypes.DATETIME:
1227
+ return self._build_iso_datetime_default_ast(
1228
+ pkey,
1229
+ default_value,
1230
+ target="datetime",
1231
+ )
1232
+
1233
+ raise ValueError(
1234
+ f"Propriedade '{pkey}' não suporta valor default para o tipo '{primitive_type.value}'."
1235
+ )
1236
+
1237
+ def _build_numeric_constant_default_ast(
1238
+ self,
1239
+ pkey: str,
1240
+ default_value: object,
1241
+ cast_type: type,
1242
+ type_label: str,
1243
+ *,
1244
+ forbid_fraction: bool = False,
1245
+ ) -> ast.expr:
1246
+ if isinstance(default_value, bool):
1247
+ raise ValueError(
1248
+ f"Propriedade '{pkey}' exige valor default {type_label}, recebido '{default_value}'."
1249
+ )
1250
+
1251
+ value_to_convert = (
1252
+ default_value.strip()
1253
+ if isinstance(default_value, str)
1254
+ else default_value
1255
+ )
1256
+
1257
+ if forbid_fraction and isinstance(value_to_convert, float):
1258
+ if not value_to_convert.is_integer():
1259
+ raise ValueError(
1260
+ f"Propriedade '{pkey}' exige valor default inteiro, recebido '{default_value}'."
1261
+ )
1262
+
1263
+ try:
1264
+ converted_value = cast_type(value_to_convert)
1265
+ except (TypeError, ValueError) as exc:
1266
+ raise ValueError(
1267
+ f"Propriedade '{pkey}' exige valor default {type_label}, recebido '{default_value}'."
1268
+ ) from exc
1269
+
1270
+ if forbid_fraction and isinstance(value_to_convert, float):
1271
+ converted_value = int(converted_value)
1272
+
1273
+ return ast.Constant(value=converted_value)
1274
+
1275
+ def _build_uuid_default_ast(
1276
+ self,
1277
+ pkey: str,
1278
+ default_value: object,
1279
+ ) -> ast.expr:
1280
+ if isinstance(default_value, uuid.UUID):
1281
+ uuid_value = str(default_value)
1282
+ elif isinstance(default_value, str):
1283
+ try:
1284
+ uuid_value = str(uuid.UUID(default_value))
1285
+ except ValueError as exc:
1286
+ raise ValueError(
1287
+ f"Propriedade '{pkey}' exige UUID válido ou expressão Python, recebido '{default_value}'."
1288
+ ) from exc
1289
+ else:
1290
+ raise ValueError(
1291
+ f"Propriedade '{pkey}' exige UUID válido ou expressão Python, recebido '{default_value}'."
1292
+ )
1293
+
1294
+ return ast.Call(
1295
+ func=ast.Attribute(
1296
+ value=ast.Name(id="uuid", ctx=ast.Load()),
1297
+ attr="UUID",
1298
+ ctx=ast.Load(),
1299
+ ),
1300
+ args=[ast.Constant(value=uuid_value)],
1301
+ keywords=[],
1302
+ )
1303
+
1304
+ def _build_iso_datetime_default_ast(
1305
+ self,
1306
+ pkey: str,
1307
+ default_value: object,
1308
+ *,
1309
+ target: str,
1310
+ ) -> ast.expr:
1311
+ if target == "date":
1312
+ parser = datetime.date
1313
+ else:
1314
+ parser = datetime.datetime
1315
+
1316
+ if isinstance(default_value, parser):
1317
+ iso_value = default_value.isoformat()
1318
+ elif isinstance(default_value, str):
1319
+ iso_value = default_value.strip()
1320
+ else:
1321
+ raise ValueError(
1322
+ f"Propriedade '{pkey}' exige {target} em formato ISO ou expressão Python, recebido '{default_value}'."
1323
+ )
1324
+
1325
+ try:
1326
+ parser.fromisoformat(iso_value)
1327
+ except ValueError as exc:
1328
+ raise ValueError(
1329
+ f"Propriedade '{pkey}' exige {target} em formato ISO ou expressão Python, recebido '{default_value}'."
1330
+ ) from exc
1331
+
1332
+ return ast.Call(
1333
+ func=ast.Attribute(
1334
+ value=ast.Attribute(
1335
+ value=ast.Name(id="datetime", ctx=ast.Load()),
1336
+ attr=target,
1337
+ ctx=ast.Load(),
1338
+ ),
1339
+ attr="fromisoformat",
1340
+ ctx=ast.Load(),
1341
+ ),
1342
+ args=[ast.Constant(value=iso_value)],
1343
+ keywords=[],
1344
+ )
1345
+
1346
+ def _build_python_expression_from_string(self, expression: str) -> ast.expr | None:
1347
+ try:
1348
+ parsed_expr = ast.parse(expression, mode="eval").body
1349
+ except SyntaxError:
1350
+ return None
1351
+
1352
+ if self._is_safe_python_expression(parsed_expr):
1353
+ return parsed_expr
1354
+
1355
+ return None
1356
+
1357
+ def _is_safe_python_expression(self, node: ast.AST) -> bool:
1358
+ if isinstance(node, ast.Name):
1359
+ return True
1360
+ if isinstance(node, ast.Attribute):
1361
+ return self._is_safe_python_expression(node.value)
1362
+ if isinstance(node, ast.Call):
1363
+ if node.keywords or node.args:
1364
+ return False
1365
+ return self._is_safe_python_expression(node.func)
1366
+ return False
1367
+
1121
1368
  def _compile_domain_config(
1122
1369
  self,
1123
1370
  pkey: str,
@@ -1139,7 +1386,7 @@ class EDLPropertyCompiler:
1139
1386
  # Compilando as opções do enum
1140
1387
  ast_values = []
1141
1388
  for value in prop.domain_config:
1142
- value_name = CompilerStrUtil.to_snake_case(value.value).upper()
1389
+ value_name = CompilerStrUtil.to_enum_member_name(value.value)
1143
1390
 
1144
1391
  if use_mapped_value and value.mapped_value is None:
1145
1392
  raise Exception(
@@ -1,3 +1,6 @@
1
+ import re
2
+
3
+
1
4
  class CompilerStrUtil:
2
5
  @staticmethod
3
6
  def to_camel_case(snake_str: str) -> str:
@@ -20,3 +23,10 @@ class CompilerStrUtil:
20
23
  snake_str += "_"
21
24
  snake_str += char.lower()
22
25
  return snake_str
26
+
27
+ @staticmethod
28
+ def to_enum_member_name(raw_value: str) -> str:
29
+ """Converte um valor livre para o nome de membro enum padronizado."""
30
+ sanitized = re.sub(r"[^0-9A-Za-z]+", "_", raw_value.strip())
31
+ sanitized = sanitized.strip("_")
32
+ return CompilerStrUtil.to_snake_case(sanitized).upper()
@@ -15,7 +15,6 @@ from nsj_rest_lib2.redis_config import get_redis
15
15
  from nsj_rest_lib2.settings import ESCOPO_RESTLIB2, MIN_TIME_SOURCE_REFRESH
16
16
 
17
17
 
18
- # TODO Verificar se está atualizando o loaded_at, quando o hash não muda
19
18
  class LoadedEntity:
20
19
  def __init__(self):
21
20
  self.dto_class_name: str = ""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nsj_rest_lib2
3
- Version: 0.0.20
3
+ Version: 0.0.22
4
4
  Summary: Biblioteca para permitir a distribuição de rotas dinâmicas numa API, configuradas por meio de EDLs declarativos (em formato JSON).
5
5
  Home-page: https://github.com/Nasajon/nsj_rest_lib2
6
6
  Author: Nasajon Sistemas
@@ -25,12 +25,3 @@ Biblioteca para permitir a distribuição de rotas dinâmicas numa API, configur
25
25
 
26
26
  [ESPECIFICAÇÃO DO MODELO DE ENTIDADES](docs/especificacao.md)
27
27
 
28
- ## TODO
29
- * Unificar o arquivo redis_config.py
30
- * Usar pydantic, ou similar, para transformar a configuração das entidades, no redis, num objeto
31
- * Rever modo de usar o InjectFactory (talvez dando ciência, ao RestLib, do padrão multibanco)
32
- * Implementar e documentar campos join
33
- * Implementar e documentar conjuntos
34
- * Dar erro ao haver conflito de nomes das propriedades (por qualquer tipo de herança)
35
- * Rotas para o inline
36
- * inline será para composição (arquivo externo é agregação)
@@ -4,12 +4,12 @@ nsj_rest_lib2/redis_config.py,sha256=4KLcvYS3nJO7PMQgF6F9_j6r-TyqcS7TBbd3LEQuKDU
4
4
  nsj_rest_lib2/settings.py,sha256=Hn_o1HZmievnYb8D1kNT2Nq-OEjxbyNjOiOpbnFsMwE,367
5
5
  nsj_rest_lib2/compiler/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  nsj_rest_lib2/compiler/ai_compiler.py,sha256=shAtN4T0ai_52qh15L3mK1QbeC6glHOR6C3J3gj14II,9029
7
- nsj_rest_lib2/compiler/compiler.py,sha256=K8npaE6BPs_Bxu3uSvB-hZF5JEIxgu4sVsKYqLk6wcI,27572
7
+ nsj_rest_lib2/compiler/compiler.py,sha256=vSA_hukm_l3WYjNn3UfDtydCxPEAVFPpfhUgmS-q3no,27056
8
8
  nsj_rest_lib2/compiler/compiler_structures.py,sha256=a_DF_nU4VgCt0sWJI03Ky6fPHvoIM0cjMkwQb_dYv6Q,1437
9
9
  nsj_rest_lib2/compiler/dto_compiler.py,sha256=mvZo19owtpFTjanCE20T0jmBKjhKXIVUsnR5raiGoRM,6728
10
10
  nsj_rest_lib2/compiler/entity_compiler.py,sha256=-mDA1-dHKYp0umQi1A4GbA0F1hlaC-gQRqj69vkADC4,6536
11
11
  nsj_rest_lib2/compiler/model.py,sha256=QDBoM26qoZdiNcykl1nvXCrFDhg-6Q__QzVq6uY1QzE,1460
12
- nsj_rest_lib2/compiler/property_compiler.py,sha256=Kqo9c1AvAjBN-7A4PBvrrXRPkngogH7FUZ6-pMuf8TE,41460
12
+ nsj_rest_lib2/compiler/property_compiler.py,sha256=3PIt0l8jrUeSxwTfM48X5fjwAYe0_0s0PGq9Z4cMmBQ,49713
13
13
  nsj_rest_lib2/compiler/edl_model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  nsj_rest_lib2/compiler/edl_model/ai_entity_edl.py,sha256=664QBDcOgVnyfwtUOXO1W7AKaZhueBG335x5DuogruY,7644
15
15
  nsj_rest_lib2/compiler/edl_model/api_model.py,sha256=pH0Uiq_64AGvkHqwY44TrulWWZXbi6M0EKJWUhSqKj0,837
@@ -18,19 +18,19 @@ nsj_rest_lib2/compiler/edl_model/entity_model.py,sha256=Yc6wvjsiwacmz796mZIU-i9h
18
18
  nsj_rest_lib2/compiler/edl_model/entity_model_base.py,sha256=eRn0pirIPHvniqGpT0xE-mmgqz5RIVtqghxcnfxKNdQ,4345
19
19
  nsj_rest_lib2/compiler/edl_model/entity_model_root.py,sha256=VinsxFlNyCaKKk37ZzcbmWaWgoUP2-dZBG61Ke7NvVs,231
20
20
  nsj_rest_lib2/compiler/edl_model/index_model.py,sha256=cXWlu0hxtro5vvYoirkDW4R3PCnBW5oCCWjRJ6AX5zE,508
21
- nsj_rest_lib2/compiler/edl_model/primitives.py,sha256=GTo8e1mf9munvl_J1-fmaXgSJ8yQvGX56f2rwS85M1Y,1459
22
- nsj_rest_lib2/compiler/edl_model/property_meta_model.py,sha256=ie3roNZAqYTwz7q0TTdceMjY5khnBiED2yp0XBqqk7E,3909
21
+ nsj_rest_lib2/compiler/edl_model/primitives.py,sha256=y6wvz76R995BHVAW9z2Kywd7sUIF4uwvk0-O2H_Zd1w,1613
22
+ nsj_rest_lib2/compiler/edl_model/property_meta_model.py,sha256=ciphkgdTtfPfLpeMQpcf3GXQ_qx7xl1tzgeUoJBjPBU,3871
23
23
  nsj_rest_lib2/compiler/edl_model/repository_model.py,sha256=OmtUzSq2LKmM76VXefGrKwg8xtVFCutt3JNH2nv42qU,1821
24
24
  nsj_rest_lib2/compiler/edl_model/trait_property_meta_model.py,sha256=NtMVZeOPu3LJwXI-8tCOLVuQiGua_0t7kL1h9gL7HuM,657
25
25
  nsj_rest_lib2/compiler/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
- nsj_rest_lib2/compiler/util/str_util.py,sha256=lVP1yHhj1pOd6ULtTnkcfX6Gqrpe4yCBratHUhBNGcI,843
26
+ nsj_rest_lib2/compiler/util/str_util.py,sha256=0ReIQ2Vy4zAmVMvGv0FcUehRQw15hlz0e7yDsF89ghk,1178
27
27
  nsj_rest_lib2/compiler/util/type_naming_util.py,sha256=wTfxPCezCTt-ltSg_hkaYNH7Z05k-mlJKZd-9AMA9ac,768
28
28
  nsj_rest_lib2/compiler/util/type_util.py,sha256=HTKOH4uRTOY0YgoM8oUv_6cEcReE_bgKYXFBsQCb-3A,357
29
29
  nsj_rest_lib2/controller/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
30
  nsj_rest_lib2/controller/dynamic_controller.py,sha256=XMqxe1NW-NE5XwomXb4pSNdALQHpP74Hc26R4fnmXqg,15194
31
31
  nsj_rest_lib2/service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
- nsj_rest_lib2/service/entity_loader.py,sha256=uB0xXih9Px2jSTMdZNIu6_3dngE37K7adKX03cYSRug,15660
33
- nsj_rest_lib2-0.0.20.dist-info/METADATA,sha256=SC3lNUvvmPq0kvWSdMfvbyzpo0jOTGY0VrVGR7bhBLU,1585
34
- nsj_rest_lib2-0.0.20.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
35
- nsj_rest_lib2-0.0.20.dist-info/top_level.txt,sha256=L6zh0EfH8_rur7OJ8_V-El-XEMf4qg3bkF8ADgqLVIA,14
36
- nsj_rest_lib2-0.0.20.dist-info/RECORD,,
32
+ nsj_rest_lib2/service/entity_loader.py,sha256=-Adgj8shMkLXrIV4ZDAqpOLSN--B5k9Uokfy9nrQA4I,15585
33
+ nsj_rest_lib2-0.0.22.dist-info/METADATA,sha256=-YyM5sMuF6_0dZ0r09vyzQuZoDcZb0FEsKzOBF31PjM,1094
34
+ nsj_rest_lib2-0.0.22.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
35
+ nsj_rest_lib2-0.0.22.dist-info/top_level.txt,sha256=L6zh0EfH8_rur7OJ8_V-El-XEMf4qg3bkF8ADgqLVIA,14
36
+ nsj_rest_lib2-0.0.22.dist-info/RECORD,,