keboola.component 1.8.2__tar.gz → 1.9.2__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 (25) hide show
  1. {keboola_component-1.8.2/src/keboola.component.egg-info → keboola_component-1.9.2}/PKG-INFO +84 -46
  2. {keboola_component-1.8.2 → keboola_component-1.9.2}/README.md +81 -41
  3. {keboola_component-1.8.2 → keboola_component-1.9.2}/pyproject.toml +11 -7
  4. {keboola_component-1.8.2 → keboola_component-1.9.2}/src/keboola/component/base.py +151 -92
  5. {keboola_component-1.8.2 → keboola_component-1.9.2}/src/keboola/component/dao.py +577 -538
  6. {keboola_component-1.8.2 → keboola_component-1.9.2}/src/keboola/component/interface.py +460 -442
  7. {keboola_component-1.8.2 → keboola_component-1.9.2}/src/keboola/component/sync_actions.py +11 -11
  8. {keboola_component-1.8.2 → keboola_component-1.9.2}/src/keboola/component/table_schema.py +18 -15
  9. {keboola_component-1.8.2 → keboola_component-1.9.2/src/keboola.component.egg-info}/PKG-INFO +84 -46
  10. keboola_component-1.9.2/src/keboola.component.egg-info/requires.txt +3 -0
  11. {keboola_component-1.8.2 → keboola_component-1.9.2}/tests/test_base.py +16 -23
  12. keboola_component-1.9.2/tests/test_dao.py +929 -0
  13. keboola_component-1.9.2/tests/test_interface.py +1103 -0
  14. {keboola_component-1.8.2 → keboola_component-1.9.2}/tests/test_schema.py +65 -47
  15. {keboola_component-1.8.2 → keboola_component-1.9.2}/tests/test_sync_actions.py +3 -6
  16. keboola_component-1.8.2/src/keboola.component.egg-info/requires.txt +0 -3
  17. keboola_component-1.8.2/tests/test_dao.py +0 -853
  18. keboola_component-1.8.2/tests/test_interface.py +0 -1052
  19. {keboola_component-1.8.2 → keboola_component-1.9.2}/LICENSE +0 -0
  20. {keboola_component-1.8.2 → keboola_component-1.9.2}/setup.cfg +0 -0
  21. {keboola_component-1.8.2 → keboola_component-1.9.2}/src/keboola/component/__init__.py +0 -0
  22. {keboola_component-1.8.2 → keboola_component-1.9.2}/src/keboola/component/exceptions.py +0 -0
  23. {keboola_component-1.8.2 → keboola_component-1.9.2}/src/keboola.component.egg-info/SOURCES.txt +0 -0
  24. {keboola_component-1.8.2 → keboola_component-1.9.2}/src/keboola.component.egg-info/dependency_links.txt +0 -0
  25. {keboola_component-1.8.2 → keboola_component-1.9.2}/src/keboola.component.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: keboola.component
3
- Version: 1.8.2
3
+ Version: 1.9.2
4
4
  Summary: General library for Python applications running in Keboola Connection environment
5
5
  Author-email: Keboola KDS Team <support@keboola.com>
6
6
  License-Expression: MIT
@@ -8,8 +8,6 @@ Project-URL: Documentation, https://keboola.github.io/python-component/interface
8
8
  Project-URL: Repository, https://github.com/keboola/python-component
9
9
  Project-URL: Component Template project, https://github.com/keboola/cookiecutter-python-component
10
10
  Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.8
12
- Classifier: Programming Language :: Python :: 3.9
13
11
  Classifier: Programming Language :: Python :: 3.10
14
12
  Classifier: Programming Language :: Python :: 3.11
15
13
  Classifier: Programming Language :: Python :: 3.12
@@ -22,19 +20,58 @@ Classifier: Intended Audience :: Education
22
20
  Classifier: Topic :: Software Development :: Libraries
23
21
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
22
  Classifier: Development Status :: 5 - Production/Stable
25
- Requires-Python: >=3.8
23
+ Requires-Python: >=3.10
26
24
  Description-Content-Type: text/markdown
27
25
  License-File: LICENSE
28
26
  Requires-Dist: pygelf
29
- Requires-Dist: pytz<2021.0
30
27
  Requires-Dist: deprecated
28
+ Requires-Dist: keboola.vcr>=0.1.1
31
29
  Dynamic: license-file
32
30
 
33
31
  # Keboola Python Component library
34
32
 
33
+ ## Table of Contents
34
+
35
+ - [Keboola Python Component library](#keboola-python-component-library)
36
+ - [Table of Contents](#table-of-contents)
37
+ - [Introduction](#introduction)
38
+ - [Links](#links)
39
+ - [Quick start](#quick-start)
40
+ - [Installation](#installation)
41
+ - [For Developers](#for-developers)
42
+ - [Core structure \& functionality](#core-structure--functionality)
43
+ - [CommonInterface](#commoninterface)
44
+ - [Initialization](#initialization)
45
+ - [Loading configuration parameters:](#loading-configuration-parameters)
46
+ - [Processing input tables - Manifest vs I/O mapping](#processing-input-tables---manifest-vs-io-mapping)
47
+ - [Manifest \& input folder content](#manifest--input-folder-content)
48
+ - [Using I/O mapping](#using-io-mapping)
49
+ - [I/O table manifests and processing results](#io-table-manifests-and-processing-results)
50
+ - [Get input table by name](#get-input-table-by-name)
51
+ - [Working with Input/Output Mapping](#working-with-inputoutput-mapping)
52
+ - [Accessing Input Tables from Mapping](#accessing-input-tables-from-mapping)
53
+ - [Creating Output Tables based on Output Mapping](#creating-output-tables-based-on-output-mapping)
54
+ - [Combining Input and Output Mapping](#combining-input-and-output-mapping)
55
+ - [Processing input files](#processing-input-files)
56
+ - [Grouping Files by Tags](#grouping-files-by-tags)
57
+ - [Creating Output Files](#creating-output-files)
58
+ - [Processing state files](#processing-state-files)
59
+ - [Logging](#logging)
60
+ - [ComponentBase](#componentbase)
61
+ - [Table Schemas in ComponentBase](#table-schemas-in-componentbase)
62
+ - [JSON Table Schema example file](#json-table-schema-example-file)
63
+ - [Out table definition from schema example](#out-table-definition-from-schema-example)
64
+ - [Sync Actions](#sync-actions)
65
+ - [Creating Sync Actions](#creating-sync-actions)
66
+ - [Returning Data from Sync Actions](#returning-data-from-sync-actions)
67
+ - [Validation Message Action](#validation-message-action)
68
+ - [No output](#no-output)
69
+ - [License](#license)
70
+
71
+
35
72
  ## Introduction
36
73
 
37
- ![Build & Test](https://github.com/keboola/python-component/workflows/Build%20&%20Test/badge.svg?branch=main)
74
+ ![Build & Test](https://github.com/keboola/python-component/workflows/Build%20&%20Test/badge.svg)
38
75
  [![Code Climate](https://codeclimate.com/github/keboola/python-component/badges/gpa.svg)](https://codeclimate.com/github/keboola/python-component)
39
76
  [![PyPI version](https://badge.fury.io/py/keboola.component.svg)](https://badge.fury.io/py/keboola.component)
40
77
 
@@ -53,27 +90,28 @@ to simplify the I/O handling.
53
90
 
54
91
  ### Links
55
92
 
56
- - API Documentation: [API docs](https://keboola.github.io/python-component/interface.html)
57
- - Source code: [https://github.com/keboola/python-component](https://github.com/keboola/python-component)
58
- - PYPI project
59
- code: [https://test.pypi.org/project/keboola.component-kds/](https://test.pypi.org/project/keboola.component-kds/)
60
- -
61
-
62
- Documentation: [https://developers.keboola.com/extend/component/python-component-library](https://developers.keboola.com/extend/component/)
63
-
64
- - Python Component Cookiecutter template
65
- project: [https://bitbucket.org/kds_consulting_team/cookiecutter-python-component](https://bitbucket.org/kds_consulting_team/cookiecutter-python-component)
93
+ - [PyPI](https://pypi.org/project/keboola.component/) & [TestPyPI](https://test.pypi.org/project/keboola.component/)
94
+ - [API Documentation](https://keboola.github.io/python-component/interface.html)
95
+ - [Keboola Components for developers](https://developers.keboola.com/extend/component/)
96
+ - [Python Component Cookiecutter template project](https://github.com/keboola/cookiecutter-python-component)
66
97
 
67
98
  # Quick start
68
99
 
69
100
  ## Installation
70
101
 
71
- The package may be installed via PIP:
102
+ The package may be installed via uv 💜:
72
103
 
73
104
  ```
74
- pip install keboola.component
105
+ uv add keboola.component
75
106
  ```
76
107
 
108
+ ## For Developers
109
+
110
+ > **Note for contributors:** Before creating a pull request, make sure to manually run the
111
+ > [Generate Documentation](https://github.com/keboola/python-component/actions/workflows/generate-docs.yml)
112
+ > workflow on your branch. This ensures the API documentation in the `docs/` folder is up-to-date
113
+ > with your code changes. The workflow can be triggered from the Actions tab on GitHub.
114
+
77
115
  ## Core structure & functionality
78
116
 
79
117
  The package contains two core modules:
@@ -293,7 +331,7 @@ with open(out_table.full_path, 'w', newline='') as f:
293
331
  "status": "completed",
294
332
  "value": "123.45"
295
333
  })
296
-
334
+
297
335
  # Write manifest
298
336
  ci.write_manifest(out_table)
299
337
  ```
@@ -317,7 +355,7 @@ out_table = ci.create_out_table_definition(
317
355
 
318
356
  # Add columns using different data type methods
319
357
  # Method 1: Using BaseType helper
320
- out_table.add_column("id",
358
+ out_table.add_column("id",
321
359
  ColumnDefinition(
322
360
  primary_key=True,
323
361
  data_types=BaseType.integer()
@@ -325,7 +363,7 @@ out_table.add_column("id",
325
363
  )
326
364
 
327
365
  # Method 2: Using SupportedDataTypes enum
328
- out_table.add_column("created_at",
366
+ out_table.add_column("created_at",
329
367
  ColumnDefinition(
330
368
  data_types=BaseType(dtype=SupportedDataTypes.TIMESTAMP)
331
369
  )
@@ -335,7 +373,7 @@ out_table.add_column("created_at",
335
373
  out_table.add_column("status", ColumnDefinition())
336
374
 
337
375
  # Method 4: Using BaseType with parameters
338
- out_table.add_column("price",
376
+ out_table.add_column("price",
339
377
  ColumnDefinition(
340
378
  data_types=BaseType.numeric(length="10,2"),
341
379
  description="Product price with 2 decimal places"
@@ -343,7 +381,7 @@ out_table.add_column("price",
343
381
  )
344
382
 
345
383
  # Method 5: Backend-specific data types
346
- out_table.add_column("metadata",
384
+ out_table.add_column("metadata",
347
385
  ColumnDefinition(
348
386
  data_types={
349
387
  "snowflake": DataType(dtype="VARIANT"),
@@ -355,7 +393,7 @@ out_table.add_column("metadata",
355
393
  )
356
394
 
357
395
  # Update existing column (example of column modification)
358
- out_table.update_column("price",
396
+ out_table.update_column("price",
359
397
  ColumnDefinition(
360
398
  data_types={
361
399
  "snowflake": DataType(dtype="NUMBER", length="15,4"),
@@ -377,7 +415,7 @@ with open(out_table.full_path, 'w', newline='') as f:
377
415
  "price": "99.9999",
378
416
  "metadata": '{"category": "electronics", "brand": "TechCorp"}'
379
417
  })
380
-
418
+
381
419
  # Write manifest
382
420
  ci.write_manifest(out_table)
383
421
  ```
@@ -441,16 +479,16 @@ input_tables = ci.configuration.tables_input_mapping
441
479
  for table in input_tables:
442
480
  # Get the destination (filename in the /data/in/tables directory)
443
481
  table_name = table.destination
444
-
482
+
445
483
  # Load table definition from manifest
446
484
  table_def = ci.get_input_table_definition_by_name(table_name)
447
-
485
+
448
486
  # Print information about the table
449
487
  print(f"Processing table: {table_name}")
450
488
  print(f" - Source: {table.source}")
451
489
  print(f" - Full path: {table_def.full_path}")
452
490
  print(f" - Columns: {table_def.column_names}")
453
-
491
+
454
492
  # Read data from the CSV file
455
493
  with open(table_def.full_path, 'r') as input_file:
456
494
  csv_reader = csv.DictReader(input_file)
@@ -476,20 +514,20 @@ for i, table_mapping in enumerate(output_tables):
476
514
  # Get source (filename that should be created) and destination (where it will be stored in KBC)
477
515
  source = table_mapping.source
478
516
  destination = table_mapping.destination
479
-
517
+
480
518
  # Create output table definition
481
519
  out_table = ci.create_out_table_definition(
482
520
  name=source,
483
521
  destination=destination,
484
522
  incremental=table_mapping.incremental
485
523
  )
486
-
524
+
487
525
  # Add some sample data (in a real component, this would be your processed data)
488
526
  with open(out_table.full_path, 'w', newline='') as out_file:
489
527
  writer = csv.DictWriter(out_file, fieldnames=['id', 'data'])
490
528
  writer.writeheader()
491
529
  writer.writerow({'id': f'{i+1}', 'data': f'Data for {destination}'})
492
-
530
+
493
531
  # Write manifest file
494
532
  ci.write_manifest(out_table)
495
533
  ```
@@ -513,27 +551,27 @@ output_tables = ci.configuration.tables_output_mapping
513
551
  for i, out_mapping in enumerate(output_tables):
514
552
  # Find corresponding input table if possible (matching by index for simplicity)
515
553
  in_mapping = input_tables[i] if i < len(input_tables) else None
516
-
554
+
517
555
  # Create output table
518
556
  out_table = ci.create_out_table_definition(
519
557
  name=out_mapping.source,
520
558
  destination=out_mapping.destination,
521
559
  incremental=out_mapping.incremental
522
560
  )
523
-
561
+
524
562
  # If we have an input table, transform its data
525
563
  if in_mapping:
526
564
  in_table = ci.get_input_table_definition_by_name(in_mapping.destination)
527
-
565
+
528
566
  # Read input and write to output with transformation
529
567
  with open(in_table.full_path, 'r') as in_file, open(out_table.full_path, 'w', newline='') as out_file:
530
568
  reader = csv.DictReader(in_file)
531
-
569
+
532
570
  # Create writer with same field names
533
571
  fieldnames = reader.fieldnames
534
572
  writer = csv.DictWriter(out_file, fieldnames=fieldnames)
535
573
  writer.writeheader()
536
-
574
+
537
575
  # Transform each row and write to output
538
576
  for row in reader:
539
577
  # Simple transformation example - uppercase all values
@@ -545,7 +583,7 @@ for i, out_mapping in enumerate(output_tables):
545
583
  writer = csv.DictWriter(out_file, fieldnames=['id', 'data'])
546
584
  writer.writeheader()
547
585
  writer.writerow({'id': f'{i+1}', 'data': f'Sample data for {out_mapping.destination}'})
548
-
586
+
549
587
  # Write manifest
550
588
  ci.write_manifest(out_table)
551
589
  ```
@@ -575,14 +613,14 @@ for file in input_files:
575
613
  print(f"Processing file: {file.name}")
576
614
  print(f" - Full path: {file.full_path}")
577
615
  print(f" - Tags: {file.tags}")
578
-
616
+
579
617
  # Example: Process image files
580
618
  if 'images' in file.tags:
581
619
  # Process image using appropriate library
582
620
  print(f" - Processing image: {file.name}")
583
621
  # image = Image.open(file.full_path)
584
622
  # ... process image ...
585
-
623
+
586
624
  # Example: Process document files
587
625
  if 'documents' in file.tags:
588
626
  print(f" - Processing document: {file.name}")
@@ -944,7 +982,7 @@ class Component(ComponentBase):
944
982
  def run(self):
945
983
  # Main component logic
946
984
  pass
947
-
985
+
948
986
  @sync_action('testConnection')
949
987
  def test_connection(self):
950
988
  """
@@ -952,11 +990,11 @@ class Component(ComponentBase):
952
990
  """
953
991
  params = self.configuration.parameters
954
992
  connection = params.get('connection', {})
955
-
993
+
956
994
  # Validate connection parameters
957
995
  if not connection.get('host') or not connection.get('username'):
958
996
  raise UserException("Connection failed: Missing host or username")
959
-
997
+
960
998
  # If no exception is raised, the connection test is considered successful
961
999
  # The framework automatically returns {"status": "success"}
962
1000
  ```
@@ -981,7 +1019,7 @@ class Component(ComponentBase):
981
1019
  {"id": "orders", "name": "Order History"},
982
1020
  {"id": "products", "name": "Product Catalog"}
983
1021
  ]
984
-
1022
+
985
1023
  # Return as list of SelectElement objects for UI dropdown
986
1024
  return [
987
1025
  SelectElement(value=table["id"], label=table["name"])
@@ -1004,7 +1042,7 @@ class Component(ComponentBase):
1004
1042
  Validates the component configuration
1005
1043
  """
1006
1044
  params = self.configuration.parameters
1007
-
1045
+
1008
1046
  # Check configuration parameters
1009
1047
  if params.get('extraction_type') == 'incremental' and not params.get('incremental_key'):
1010
1048
  # Return warning message that will be displayed in UI
@@ -1012,7 +1050,7 @@ class Component(ComponentBase):
1012
1050
  "Incremental extraction requires specifying an incremental key column.",
1013
1051
  MessageType.WARNING
1014
1052
  )
1015
-
1053
+
1016
1054
  # Check for potential issues
1017
1055
  if params.get('row_limit') and int(params.get('row_limit')) > 1000000:
1018
1056
  # Return info message
@@ -1020,7 +1058,7 @@ class Component(ComponentBase):
1020
1058
  "Large row limit may cause performance issues.",
1021
1059
  MessageType.INFO
1022
1060
  )
1023
-
1061
+
1024
1062
  # Success with no message
1025
1063
  return None
1026
1064
  ```
@@ -1,8 +1,47 @@
1
1
  # Keboola Python Component library
2
2
 
3
+ ## Table of Contents
4
+
5
+ - [Keboola Python Component library](#keboola-python-component-library)
6
+ - [Table of Contents](#table-of-contents)
7
+ - [Introduction](#introduction)
8
+ - [Links](#links)
9
+ - [Quick start](#quick-start)
10
+ - [Installation](#installation)
11
+ - [For Developers](#for-developers)
12
+ - [Core structure \& functionality](#core-structure--functionality)
13
+ - [CommonInterface](#commoninterface)
14
+ - [Initialization](#initialization)
15
+ - [Loading configuration parameters:](#loading-configuration-parameters)
16
+ - [Processing input tables - Manifest vs I/O mapping](#processing-input-tables---manifest-vs-io-mapping)
17
+ - [Manifest \& input folder content](#manifest--input-folder-content)
18
+ - [Using I/O mapping](#using-io-mapping)
19
+ - [I/O table manifests and processing results](#io-table-manifests-and-processing-results)
20
+ - [Get input table by name](#get-input-table-by-name)
21
+ - [Working with Input/Output Mapping](#working-with-inputoutput-mapping)
22
+ - [Accessing Input Tables from Mapping](#accessing-input-tables-from-mapping)
23
+ - [Creating Output Tables based on Output Mapping](#creating-output-tables-based-on-output-mapping)
24
+ - [Combining Input and Output Mapping](#combining-input-and-output-mapping)
25
+ - [Processing input files](#processing-input-files)
26
+ - [Grouping Files by Tags](#grouping-files-by-tags)
27
+ - [Creating Output Files](#creating-output-files)
28
+ - [Processing state files](#processing-state-files)
29
+ - [Logging](#logging)
30
+ - [ComponentBase](#componentbase)
31
+ - [Table Schemas in ComponentBase](#table-schemas-in-componentbase)
32
+ - [JSON Table Schema example file](#json-table-schema-example-file)
33
+ - [Out table definition from schema example](#out-table-definition-from-schema-example)
34
+ - [Sync Actions](#sync-actions)
35
+ - [Creating Sync Actions](#creating-sync-actions)
36
+ - [Returning Data from Sync Actions](#returning-data-from-sync-actions)
37
+ - [Validation Message Action](#validation-message-action)
38
+ - [No output](#no-output)
39
+ - [License](#license)
40
+
41
+
3
42
  ## Introduction
4
43
 
5
- ![Build & Test](https://github.com/keboola/python-component/workflows/Build%20&%20Test/badge.svg?branch=main)
44
+ ![Build & Test](https://github.com/keboola/python-component/workflows/Build%20&%20Test/badge.svg)
6
45
  [![Code Climate](https://codeclimate.com/github/keboola/python-component/badges/gpa.svg)](https://codeclimate.com/github/keboola/python-component)
7
46
  [![PyPI version](https://badge.fury.io/py/keboola.component.svg)](https://badge.fury.io/py/keboola.component)
8
47
 
@@ -21,27 +60,28 @@ to simplify the I/O handling.
21
60
 
22
61
  ### Links
23
62
 
24
- - API Documentation: [API docs](https://keboola.github.io/python-component/interface.html)
25
- - Source code: [https://github.com/keboola/python-component](https://github.com/keboola/python-component)
26
- - PYPI project
27
- code: [https://test.pypi.org/project/keboola.component-kds/](https://test.pypi.org/project/keboola.component-kds/)
28
- -
29
-
30
- Documentation: [https://developers.keboola.com/extend/component/python-component-library](https://developers.keboola.com/extend/component/)
31
-
32
- - Python Component Cookiecutter template
33
- project: [https://bitbucket.org/kds_consulting_team/cookiecutter-python-component](https://bitbucket.org/kds_consulting_team/cookiecutter-python-component)
63
+ - [PyPI](https://pypi.org/project/keboola.component/) & [TestPyPI](https://test.pypi.org/project/keboola.component/)
64
+ - [API Documentation](https://keboola.github.io/python-component/interface.html)
65
+ - [Keboola Components for developers](https://developers.keboola.com/extend/component/)
66
+ - [Python Component Cookiecutter template project](https://github.com/keboola/cookiecutter-python-component)
34
67
 
35
68
  # Quick start
36
69
 
37
70
  ## Installation
38
71
 
39
- The package may be installed via PIP:
72
+ The package may be installed via uv 💜:
40
73
 
41
74
  ```
42
- pip install keboola.component
75
+ uv add keboola.component
43
76
  ```
44
77
 
78
+ ## For Developers
79
+
80
+ > **Note for contributors:** Before creating a pull request, make sure to manually run the
81
+ > [Generate Documentation](https://github.com/keboola/python-component/actions/workflows/generate-docs.yml)
82
+ > workflow on your branch. This ensures the API documentation in the `docs/` folder is up-to-date
83
+ > with your code changes. The workflow can be triggered from the Actions tab on GitHub.
84
+
45
85
  ## Core structure & functionality
46
86
 
47
87
  The package contains two core modules:
@@ -261,7 +301,7 @@ with open(out_table.full_path, 'w', newline='') as f:
261
301
  "status": "completed",
262
302
  "value": "123.45"
263
303
  })
264
-
304
+
265
305
  # Write manifest
266
306
  ci.write_manifest(out_table)
267
307
  ```
@@ -285,7 +325,7 @@ out_table = ci.create_out_table_definition(
285
325
 
286
326
  # Add columns using different data type methods
287
327
  # Method 1: Using BaseType helper
288
- out_table.add_column("id",
328
+ out_table.add_column("id",
289
329
  ColumnDefinition(
290
330
  primary_key=True,
291
331
  data_types=BaseType.integer()
@@ -293,7 +333,7 @@ out_table.add_column("id",
293
333
  )
294
334
 
295
335
  # Method 2: Using SupportedDataTypes enum
296
- out_table.add_column("created_at",
336
+ out_table.add_column("created_at",
297
337
  ColumnDefinition(
298
338
  data_types=BaseType(dtype=SupportedDataTypes.TIMESTAMP)
299
339
  )
@@ -303,7 +343,7 @@ out_table.add_column("created_at",
303
343
  out_table.add_column("status", ColumnDefinition())
304
344
 
305
345
  # Method 4: Using BaseType with parameters
306
- out_table.add_column("price",
346
+ out_table.add_column("price",
307
347
  ColumnDefinition(
308
348
  data_types=BaseType.numeric(length="10,2"),
309
349
  description="Product price with 2 decimal places"
@@ -311,7 +351,7 @@ out_table.add_column("price",
311
351
  )
312
352
 
313
353
  # Method 5: Backend-specific data types
314
- out_table.add_column("metadata",
354
+ out_table.add_column("metadata",
315
355
  ColumnDefinition(
316
356
  data_types={
317
357
  "snowflake": DataType(dtype="VARIANT"),
@@ -323,7 +363,7 @@ out_table.add_column("metadata",
323
363
  )
324
364
 
325
365
  # Update existing column (example of column modification)
326
- out_table.update_column("price",
366
+ out_table.update_column("price",
327
367
  ColumnDefinition(
328
368
  data_types={
329
369
  "snowflake": DataType(dtype="NUMBER", length="15,4"),
@@ -345,7 +385,7 @@ with open(out_table.full_path, 'w', newline='') as f:
345
385
  "price": "99.9999",
346
386
  "metadata": '{"category": "electronics", "brand": "TechCorp"}'
347
387
  })
348
-
388
+
349
389
  # Write manifest
350
390
  ci.write_manifest(out_table)
351
391
  ```
@@ -409,16 +449,16 @@ input_tables = ci.configuration.tables_input_mapping
409
449
  for table in input_tables:
410
450
  # Get the destination (filename in the /data/in/tables directory)
411
451
  table_name = table.destination
412
-
452
+
413
453
  # Load table definition from manifest
414
454
  table_def = ci.get_input_table_definition_by_name(table_name)
415
-
455
+
416
456
  # Print information about the table
417
457
  print(f"Processing table: {table_name}")
418
458
  print(f" - Source: {table.source}")
419
459
  print(f" - Full path: {table_def.full_path}")
420
460
  print(f" - Columns: {table_def.column_names}")
421
-
461
+
422
462
  # Read data from the CSV file
423
463
  with open(table_def.full_path, 'r') as input_file:
424
464
  csv_reader = csv.DictReader(input_file)
@@ -444,20 +484,20 @@ for i, table_mapping in enumerate(output_tables):
444
484
  # Get source (filename that should be created) and destination (where it will be stored in KBC)
445
485
  source = table_mapping.source
446
486
  destination = table_mapping.destination
447
-
487
+
448
488
  # Create output table definition
449
489
  out_table = ci.create_out_table_definition(
450
490
  name=source,
451
491
  destination=destination,
452
492
  incremental=table_mapping.incremental
453
493
  )
454
-
494
+
455
495
  # Add some sample data (in a real component, this would be your processed data)
456
496
  with open(out_table.full_path, 'w', newline='') as out_file:
457
497
  writer = csv.DictWriter(out_file, fieldnames=['id', 'data'])
458
498
  writer.writeheader()
459
499
  writer.writerow({'id': f'{i+1}', 'data': f'Data for {destination}'})
460
-
500
+
461
501
  # Write manifest file
462
502
  ci.write_manifest(out_table)
463
503
  ```
@@ -481,27 +521,27 @@ output_tables = ci.configuration.tables_output_mapping
481
521
  for i, out_mapping in enumerate(output_tables):
482
522
  # Find corresponding input table if possible (matching by index for simplicity)
483
523
  in_mapping = input_tables[i] if i < len(input_tables) else None
484
-
524
+
485
525
  # Create output table
486
526
  out_table = ci.create_out_table_definition(
487
527
  name=out_mapping.source,
488
528
  destination=out_mapping.destination,
489
529
  incremental=out_mapping.incremental
490
530
  )
491
-
531
+
492
532
  # If we have an input table, transform its data
493
533
  if in_mapping:
494
534
  in_table = ci.get_input_table_definition_by_name(in_mapping.destination)
495
-
535
+
496
536
  # Read input and write to output with transformation
497
537
  with open(in_table.full_path, 'r') as in_file, open(out_table.full_path, 'w', newline='') as out_file:
498
538
  reader = csv.DictReader(in_file)
499
-
539
+
500
540
  # Create writer with same field names
501
541
  fieldnames = reader.fieldnames
502
542
  writer = csv.DictWriter(out_file, fieldnames=fieldnames)
503
543
  writer.writeheader()
504
-
544
+
505
545
  # Transform each row and write to output
506
546
  for row in reader:
507
547
  # Simple transformation example - uppercase all values
@@ -513,7 +553,7 @@ for i, out_mapping in enumerate(output_tables):
513
553
  writer = csv.DictWriter(out_file, fieldnames=['id', 'data'])
514
554
  writer.writeheader()
515
555
  writer.writerow({'id': f'{i+1}', 'data': f'Sample data for {out_mapping.destination}'})
516
-
556
+
517
557
  # Write manifest
518
558
  ci.write_manifest(out_table)
519
559
  ```
@@ -543,14 +583,14 @@ for file in input_files:
543
583
  print(f"Processing file: {file.name}")
544
584
  print(f" - Full path: {file.full_path}")
545
585
  print(f" - Tags: {file.tags}")
546
-
586
+
547
587
  # Example: Process image files
548
588
  if 'images' in file.tags:
549
589
  # Process image using appropriate library
550
590
  print(f" - Processing image: {file.name}")
551
591
  # image = Image.open(file.full_path)
552
592
  # ... process image ...
553
-
593
+
554
594
  # Example: Process document files
555
595
  if 'documents' in file.tags:
556
596
  print(f" - Processing document: {file.name}")
@@ -912,7 +952,7 @@ class Component(ComponentBase):
912
952
  def run(self):
913
953
  # Main component logic
914
954
  pass
915
-
955
+
916
956
  @sync_action('testConnection')
917
957
  def test_connection(self):
918
958
  """
@@ -920,11 +960,11 @@ class Component(ComponentBase):
920
960
  """
921
961
  params = self.configuration.parameters
922
962
  connection = params.get('connection', {})
923
-
963
+
924
964
  # Validate connection parameters
925
965
  if not connection.get('host') or not connection.get('username'):
926
966
  raise UserException("Connection failed: Missing host or username")
927
-
967
+
928
968
  # If no exception is raised, the connection test is considered successful
929
969
  # The framework automatically returns {"status": "success"}
930
970
  ```
@@ -949,7 +989,7 @@ class Component(ComponentBase):
949
989
  {"id": "orders", "name": "Order History"},
950
990
  {"id": "products", "name": "Product Catalog"}
951
991
  ]
952
-
992
+
953
993
  # Return as list of SelectElement objects for UI dropdown
954
994
  return [
955
995
  SelectElement(value=table["id"], label=table["name"])
@@ -972,7 +1012,7 @@ class Component(ComponentBase):
972
1012
  Validates the component configuration
973
1013
  """
974
1014
  params = self.configuration.parameters
975
-
1015
+
976
1016
  # Check configuration parameters
977
1017
  if params.get('extraction_type') == 'incremental' and not params.get('incremental_key'):
978
1018
  # Return warning message that will be displayed in UI
@@ -980,7 +1020,7 @@ class Component(ComponentBase):
980
1020
  "Incremental extraction requires specifying an incremental key column.",
981
1021
  MessageType.WARNING
982
1022
  )
983
-
1023
+
984
1024
  # Check for potential issues
985
1025
  if params.get('row_limit') and int(params.get('row_limit')) > 1000000:
986
1026
  # Return info message
@@ -988,7 +1028,7 @@ class Component(ComponentBase):
988
1028
  "Large row limit may cause performance issues.",
989
1029
  MessageType.INFO
990
1030
  )
991
-
1031
+
992
1032
  # Success with no message
993
1033
  return None
994
1034
  ```