keboola.component 1.6.7__tar.gz → 1.6.8__tar.gz

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.
Files changed (18) hide show
  1. {keboola.component-1.6.7/src/keboola.component.egg-info → keboola.component-1.6.8}/PKG-INFO +1 -1
  2. {keboola.component-1.6.7 → keboola.component-1.6.8}/setup.py +1 -1
  3. {keboola.component-1.6.7 → keboola.component-1.6.8}/src/keboola/component/base.py +52 -18
  4. {keboola.component-1.6.7 → keboola.component-1.6.8}/src/keboola/component/dao.py +33 -16
  5. {keboola.component-1.6.7 → keboola.component-1.6.8}/src/keboola/component/interface.py +10 -8
  6. {keboola.component-1.6.7 → keboola.component-1.6.8/src/keboola.component.egg-info}/PKG-INFO +1 -1
  7. {keboola.component-1.6.7 → keboola.component-1.6.8}/LICENSE +0 -0
  8. {keboola.component-1.6.7 → keboola.component-1.6.8}/README.md +0 -0
  9. {keboola.component-1.6.7 → keboola.component-1.6.8}/setup.cfg +0 -0
  10. {keboola.component-1.6.7 → keboola.component-1.6.8}/src/keboola/component/__init__.py +0 -0
  11. {keboola.component-1.6.7 → keboola.component-1.6.8}/src/keboola/component/exceptions.py +0 -0
  12. {keboola.component-1.6.7 → keboola.component-1.6.8}/src/keboola/component/sync_actions.py +0 -0
  13. {keboola.component-1.6.7 → keboola.component-1.6.8}/src/keboola/component/table_schema.py +0 -0
  14. {keboola.component-1.6.7 → keboola.component-1.6.8}/src/keboola.component.egg-info/SOURCES.txt +0 -0
  15. {keboola.component-1.6.7 → keboola.component-1.6.8}/src/keboola.component.egg-info/dependency_links.txt +0 -0
  16. {keboola.component-1.6.7 → keboola.component-1.6.8}/src/keboola.component.egg-info/not-zip-safe +0 -0
  17. {keboola.component-1.6.7 → keboola.component-1.6.8}/src/keboola.component.egg-info/requires.txt +0 -0
  18. {keboola.component-1.6.7 → keboola.component-1.6.8}/src/keboola.component.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: keboola.component
3
- Version: 1.6.7
3
+ Version: 1.6.8
4
4
  Summary: General library for Python applications running in Keboola Connection environment
5
5
  Home-page: https://github.com/keboola/python-component
6
6
  Author: Keboola KDS Team
@@ -13,7 +13,7 @@ project_urls = {
13
13
 
14
14
  setuptools.setup(
15
15
  name="keboola.component",
16
- version="1.6.7",
16
+ version="1.6.8",
17
17
  author="Keboola KDS Team",
18
18
  project_urls=project_urls,
19
19
  setup_requires=['pytest-runner', 'flake8'],
@@ -249,6 +249,18 @@ class ComponentBase(ABC, CommonInterface):
249
249
  raise AttributeError(f"The defined action {action} is not implemented!") from e
250
250
  return action_method()
251
251
 
252
+ def _generate_table_metadata_legacy(self, table_schema: ts.TableSchema) -> dao.TableMetadata:
253
+ """
254
+ Generates a TableMetadata object for the table definition using a TableSchema object.
255
+
256
+ """
257
+ table_metadata = dao.TableMetadata()
258
+ if table_schema.description:
259
+ table_metadata.add_table_description(table_schema.description)
260
+ table_metadata.add_column_descriptions({field.name: field.description for field in table_schema.fields})
261
+ table_metadata = self._add_field_data_types_to_table_metadata(table_schema, table_metadata)
262
+ return table_metadata
263
+
252
264
  def create_out_table_definition_from_schema(self, table_schema: ts.TableSchema, is_sliced: bool = False,
253
265
  destination: str = '', incremental: bool = None,
254
266
  enclosure: str = '"', delimiter: str = ',',
@@ -271,17 +283,33 @@ class ComponentBase(ABC, CommonInterface):
271
283
  TableDefinition object initialized with all table metadata defined in a schema
272
284
 
273
285
  """
274
- table_metadata = self._generate_table_metadata(table_schema)
275
- return self.create_out_table_definition(name=table_schema.csv_name,
276
- columns=table_schema.field_names,
277
- primary_key=table_schema.primary_keys,
278
- table_metadata=table_metadata,
279
- is_sliced=is_sliced,
280
- destination=destination,
281
- incremental=incremental,
282
- enclosure=enclosure,
283
- delimiter=delimiter,
284
- delete_where=delete_where)
286
+ if self._expects_legacy_manifest():
287
+ table_metadata = self._generate_table_metadata_legacy(table_schema)
288
+ table_def = self.create_out_table_definition(name=table_schema.csv_name,
289
+ columns=table_schema.field_names,
290
+ primary_key=table_schema.primary_keys,
291
+ table_metadata=table_metadata,
292
+ is_sliced=is_sliced,
293
+ destination=destination,
294
+ incremental=incremental,
295
+ enclosure=enclosure,
296
+ delimiter=delimiter,
297
+ delete_where=delete_where)
298
+ else:
299
+ schema = self._generate_schema_definition(table_schema)
300
+
301
+ table_def = self.create_out_table_definition(name=table_schema.csv_name,
302
+ primary_key=table_schema.primary_keys,
303
+ schema=schema,
304
+ is_sliced=is_sliced,
305
+ destination=destination,
306
+ incremental=incremental,
307
+ enclosure=enclosure,
308
+ delimiter=delimiter,
309
+ delete_where=delete_where,
310
+ description=table_schema.description)
311
+
312
+ return table_def
285
313
 
286
314
  def get_table_schema_by_name(self, schema_name: str,
287
315
  schema_folder_path: Optional[str] = None) -> ts.TableSchema:
@@ -324,18 +352,24 @@ class ComponentBase(ABC, CommonInterface):
324
352
  "from a schema. If a schema folder path is not defined, the schemas folder must be"
325
353
  " located in the 'src' directory of a component : src/schemas")
326
354
 
327
- def _generate_table_metadata(self, table_schema: ts.TableSchema) -> dao.TableMetadata:
355
+ def _generate_schema_definition(self, table_schema: ts.TableSchema) -> Dict[str, dao.ColumnDefinition]:
328
356
  """
329
357
  Generates a TableMetadata object for the table definition using a TableSchema object.
330
358
 
331
359
  """
332
- table_metadata = dao.TableMetadata()
333
- if table_schema.description:
334
- table_metadata.add_table_description(table_schema.description)
335
- table_metadata.add_column_descriptions({field.name: field.description for field in table_schema.fields})
336
- table_metadata = self._add_field_data_types_to_table_metadata(table_schema, table_metadata)
360
+ column_definitions = {}
361
+ for field in table_schema.fields:
362
+ if field.base_type:
363
+ data_types = dao.BaseType(field.base_type,
364
+ length=field.length,
365
+ default=field.default)
366
+ else:
367
+ data_types = dao.BaseType()
368
+ column_definitions[field.name] = dao.ColumnDefinition(data_types=data_types,
369
+ nullable=field.nullable,
370
+ description=field.description)
337
371
 
338
- return table_metadata
372
+ return column_definitions
339
373
 
340
374
  @staticmethod
341
375
  def _add_field_data_types_to_table_metadata(table_schema: ts.TableSchema,
@@ -1,5 +1,6 @@
1
1
  # Python 3.7 support
2
2
  from __future__ import annotations
3
+
3
4
  import dataclasses
4
5
  import json
5
6
  import logging
@@ -12,7 +13,6 @@ from enum import Enum
12
13
  from pathlib import Path
13
14
  from typing import List, Union, Dict, Optional, OrderedDict as TypeOrderedDict
14
15
 
15
-
16
16
  from deprecated import deprecated
17
17
 
18
18
  from .exceptions import UserException
@@ -204,15 +204,15 @@ class TableMetadata:
204
204
  """
205
205
  if legacy_manifest:
206
206
  final_metadata_list = [{'key': key,
207
- 'value': self.table_metadata[key]}
208
- for key in self.table_metadata]
207
+ 'value': value}
208
+ for key, value in self.table_metadata.items() if value not in [None, '']]
209
209
  else:
210
- final_metadata_list = [{key: self.table_metadata[key]}
211
- for key in self.table_metadata]
210
+ final_metadata_list = {key: value
211
+ for key, value in self.table_metadata.items() if value not in [None, '']}
212
212
 
213
213
  return final_metadata_list
214
214
 
215
- @deprecated(version='1.5.1', reason="Please use schema instead of Table Metadata")
215
+ @deprecated(version='1.5.1', reason="Please use schema instead of Column Metadata")
216
216
  def get_column_metadata_for_manifest(self) -> dict:
217
217
  """
218
218
  Returns column metadata dict as required by the
@@ -251,13 +251,14 @@ class TableMetadata:
251
251
  final_column_metadata[column] = list()
252
252
 
253
253
  column_metadata = [{'key': key,
254
- 'value': column_metadata_dicts[key]} for key in
255
- column_metadata_dicts]
254
+ 'value': value} for key, value in
255
+ column_metadata_dicts.items() if value not in [None, '']]
256
256
  final_column_metadata[column].extend(column_metadata)
257
257
 
258
258
  return final_column_metadata
259
259
 
260
260
  @property
261
+ @deprecated(version='1.5.1', reason="Please use TableDefinition.description instead of TableMetadata")
261
262
  def table_description(self) -> str:
262
263
  """
263
264
  Returns table description (KBC.description)
@@ -402,14 +403,20 @@ class TableMetadata:
402
403
  Args:
403
404
 
404
405
  """
406
+ if value is None:
407
+ return
405
408
  self.table_metadata = {**self.table_metadata, **{key: value}}
406
409
 
410
+ @deprecated(version='1.5.1', reason="Column metadata ere moved to dao.TableDefinition.schema property."
411
+ "Please use the dao.ColumnDefinition.metadata")
407
412
  def add_column_metadata(self, column: str, key: str, value: Union[str, bool, int], backend="base"):
408
413
  """
409
414
  Add/Updates column metadata and ensures the Key is unique.
410
415
  Args:
411
416
 
412
417
  """
418
+ if value is None:
419
+ return
413
420
  if not self.column_metadata.get(column):
414
421
  self.column_metadata[column] = dict()
415
422
 
@@ -417,6 +424,8 @@ class TableMetadata:
417
424
 
418
425
  # self.schema = [ColumnDefinition(name=column, data_type={backend: DataType(type=value)})]
419
426
 
427
+ @deprecated(version='1.5.1', reason="Column metadata ere moved to dao.TableDefinition.schema property."
428
+ "Please use the dao.ColumnDefinition.metadata")
420
429
  def add_multiple_column_metadata(self, column_metadata: Dict[str, List[dict]]):
421
430
  """
422
431
  Add key-value pairs to column metadata.
@@ -577,7 +586,7 @@ class SupportedManifestAttributes(SubscriptableDataclass):
577
586
  to_remove = ['primary_key', 'columns', 'distribution_key', 'column_metadata', 'metadata']
578
587
  attributes = list(set(attributes).difference(to_remove))
579
588
 
580
- to_add = ['manifest_type', 'has_header', 'description', 'table_metadata', 'schema']
589
+ to_add = ['manifest_type', 'has_header', 'table_metadata', 'schema']
581
590
  attributes.extend(to_add)
582
591
 
583
592
  elif stage == 'in':
@@ -773,13 +782,14 @@ class TableDefinition(IODefinition):
773
782
 
774
783
  MANIFEST_ATTRIBUTES = {'in': INPUT_MANIFEST_ATTRIBUTES,
775
784
  'out': OUTPUT_MANIFEST_ATTRIBUTES}
785
+ SCHEMA_TYPE = Union[Dict[str, ColumnDefinition], TypeOrderedDict[str, ColumnDefinition], List[str]]
776
786
 
777
787
  def __init__(self, name: str,
778
788
  full_path: Optional[Union[str, None]] = None,
779
789
  is_sliced: Optional[bool] = False,
780
790
  destination: Optional[str] = '',
781
791
  primary_key: Optional[List[str]] = None,
782
- schema: Optional[Union[TypeOrderedDict[str, ColumnDefinition], list[str]]] = None,
792
+ schema: SCHEMA_TYPE = None,
783
793
  incremental: Optional[bool] = None,
784
794
  table_metadata: Optional[TableMetadata] = None,
785
795
  enclosure: Optional[str] = '"',
@@ -788,6 +798,7 @@ class TableDefinition(IODefinition):
788
798
  stage: Optional[str] = 'out',
789
799
  write_always: Optional[bool] = False,
790
800
  has_header: Optional[bool] = None,
801
+ description: Optional[str] = None,
791
802
  # input
792
803
  **kwargs
793
804
  ):
@@ -815,6 +826,7 @@ class TableDefinition(IODefinition):
815
826
  write_always: Bool: If true, the table will be saved to Storage even when the job execution
816
827
  fails.
817
828
  schema: (dict|lis[str]) Mapping of column names andColumnDefinition objects, or a list of names
829
+ description: str: Table description
818
830
 
819
831
  """
820
832
  super().__init__(full_path)
@@ -824,7 +836,7 @@ class TableDefinition(IODefinition):
824
836
  # initialize manifest properties
825
837
  self._destination = None
826
838
  self.destination = destination
827
- self._schema = dict()
839
+ self._schema: Dict[str, ColumnDefinition] = dict()
828
840
 
829
841
  if schema:
830
842
  self.schema = schema
@@ -845,6 +857,8 @@ class TableDefinition(IODefinition):
845
857
  if not table_metadata:
846
858
  table_metadata = TableMetadata()
847
859
  self.table_metadata = table_metadata
860
+ if description:
861
+ self.table_metadata.add_table_description(description)
848
862
 
849
863
  self.delete_where_values = None
850
864
  self.delete_where_column = None
@@ -893,7 +907,8 @@ class TableDefinition(IODefinition):
893
907
  delimiter: Optional[str] = ',',
894
908
  delete_where: Optional[dict] = None,
895
909
  write_always: Optional[bool] = False,
896
- schema: Optional[Union[TypeOrderedDict[str, ColumnDefinition], list[str]]] = None,
910
+ schema: SCHEMA_TYPE = None,
911
+ description: Optional[str] = None,
897
912
  **kwargs
898
913
  ):
899
914
  """
@@ -914,6 +929,7 @@ class TableDefinition(IODefinition):
914
929
  delete_where (Optional[dict]): Criteria for row deletion in incremental loads. Defaults to None.
915
930
  write_always (Optional[bool]): If True, the table will be saved to storage even if the job fails.
916
931
  schema (Optional[List[ColumnDefinition]]): Dictionary of ColumnDefinition objects.
932
+ description (Optional[str]): The description of the table. Defaults to None.
917
933
 
918
934
  Returns:
919
935
  TableDefinition: An instance of TableDefinition configured for output tables.
@@ -929,6 +945,7 @@ class TableDefinition(IODefinition):
929
945
  delete_where=delete_where,
930
946
  write_always=write_always,
931
947
  schema=schema,
948
+ description=description,
932
949
  **kwargs
933
950
  )
934
951
 
@@ -1155,7 +1172,7 @@ class TableDefinition(IODefinition):
1155
1172
  name=name,
1156
1173
  destination=manifest.get('destination'),
1157
1174
  schema=cls.return_schema_from_manifest(manifest),
1158
- incremental=manifest.get('incremental'),
1175
+ incremental=manifest.get('incremental', False),
1159
1176
  primary_key=manifest.get('primary_key'),
1160
1177
  write_always=manifest.get('write_always', False),
1161
1178
  delimiter=manifest.get('delimiter', ','),
@@ -1255,7 +1272,6 @@ class TableDefinition(IODefinition):
1255
1272
  'column_metadata': self.table_metadata._get_legacy_column_metadata_for_manifest(),
1256
1273
  'manifest_type': manifest_type,
1257
1274
  'has_header': self.has_header,
1258
- 'description': None,
1259
1275
  'table_metadata': self.table_metadata.get_table_metadata_for_manifest(),
1260
1276
  'delete_where_column': self.delete_where_column,
1261
1277
  'delete_where_values': self.delete_where_values,
@@ -1263,6 +1279,7 @@ class TableDefinition(IODefinition):
1263
1279
  'schema': [col.to_dict(name)
1264
1280
  for name, col in self.schema.items()] if isinstance(self.schema, (OrderedDict, dict)) else []
1265
1281
  }
1282
+
1266
1283
  if legacy_manifest or self.stage == 'in':
1267
1284
  fields['columns'] = self.column_names
1268
1285
 
@@ -1387,8 +1404,8 @@ class TableDefinition(IODefinition):
1387
1404
 
1388
1405
  @incremental.setter
1389
1406
  def incremental(self, incremental: bool):
1390
- if incremental:
1391
- self._incremental = True
1407
+ if incremental is not None:
1408
+ self._incremental = incremental
1392
1409
 
1393
1410
  @property
1394
1411
  def write_always(self) -> bool:
@@ -18,7 +18,7 @@ from pygelf import GelfUdpHandler, GelfTcpHandler
18
18
  from pytz import utc
19
19
 
20
20
  from . import dao
21
- from .dao import ColumnDefinition
21
+ from .dao import ColumnDefinition, TableDefinition
22
22
  from .exceptions import UserException
23
23
 
24
24
 
@@ -338,7 +338,8 @@ class CommonInterface:
338
338
  write_always: bool = False,
339
339
  schema: Union[
340
340
  OrderedDict[str, ColumnDefinition], list[str]] = None,
341
- has_header: Optional[bool] = None) -> dao.TableDefinition:
341
+ has_header: Optional[bool] = None,
342
+ description: Optional[str] = None) -> dao.TableDefinition:
342
343
  """
343
344
  Helper method for dao.TableDefinition creation along with the "manifest".
344
345
  It initializes path according to the storage_stage type.
@@ -381,6 +382,7 @@ class CommonInterface:
381
382
  primary_key=primary_key,
382
383
  columns=columns,
383
384
  incremental=incremental,
385
+ description=description,
384
386
  table_metadata=table_metadata,
385
387
  enclosure=enclosure,
386
388
  delimiter=delimiter,
@@ -427,13 +429,11 @@ class CommonInterface:
427
429
  delete_where=delete_where,
428
430
  schema=schema)
429
431
 
430
- SCHEMA_TYPE = Union[Dict[str, ColumnDefinition], OrderedDict[str, ColumnDefinition], List[str]]
431
-
432
432
  def create_out_table_definition(self, name: str,
433
433
  is_sliced: bool = False,
434
434
  destination: str = '',
435
435
  primary_key: List[str] = None,
436
- schema: SCHEMA_TYPE = None,
436
+ schema: TableDefinition.SCHEMA_TYPE = None,
437
437
  incremental: bool = None,
438
438
  table_metadata: dao.TableMetadata = None,
439
439
  enclosure: str = '"',
@@ -441,6 +441,7 @@ class CommonInterface:
441
441
  delete_where: dict = None,
442
442
  write_always: bool = False,
443
443
  has_header: Optional[bool] = None,
444
+ description: Optional[str] = None,
444
445
  **kwargs
445
446
  ) -> dao.TableDefinition:
446
447
  """
@@ -464,6 +465,7 @@ class CommonInterface:
464
465
  fails.
465
466
  has_header:Optional[bool] = flag whether the header is present in the file,
466
467
  if None legacy method is used
468
+ description: Table description
467
469
  """
468
470
 
469
471
  return self._create_table_definition(name=name,
@@ -479,7 +481,8 @@ class CommonInterface:
479
481
  delete_where=delete_where,
480
482
  write_always=write_always,
481
483
  schema=schema,
482
- has_header=has_header)
484
+ has_header=has_header,
485
+ description=description)
483
486
 
484
487
  # # File processing
485
488
 
@@ -956,7 +959,6 @@ class CommonInterface:
956
959
  """
957
960
 
958
961
  if not legacy_manifest:
959
-
960
962
  legacy_manifest = self._expects_legacy_manifest()
961
963
 
962
964
  manifest = io_definition.get_manifest_dictionary(legacy_queue=self.is_legacy_queue,
@@ -967,7 +969,7 @@ class CommonInterface:
967
969
  json.dump(manifest, manifest_file)
968
970
 
969
971
  def _expects_legacy_manifest(self) -> bool:
970
- legacy_manifest =\
972
+ legacy_manifest = \
971
973
  (self._running_in_kbc and self.environment_variables.data_type_support not in ('authoritative', 'hints'))
972
974
 
973
975
  om_override = self.configuration.config_data.get('storage', {}).get('output', {}).get('data_type_support')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: keboola.component
3
- Version: 1.6.7
3
+ Version: 1.6.8
4
4
  Summary: General library for Python applications running in Keboola Connection environment
5
5
  Home-page: https://github.com/keboola/python-component
6
6
  Author: Keboola KDS Team