dc-python-sdk 1.4.3__tar.gz → 1.5.0__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 (27) hide show
  1. {dc_python_sdk-1.4.3 → dc_python_sdk-1.5.0}/LICENSE +21 -21
  2. dc_python_sdk-1.5.0/PKG-INFO +502 -0
  3. dc_python_sdk-1.5.0/README.md +478 -0
  4. dc_python_sdk-1.5.0/pyproject.toml +40 -0
  5. {dc_python_sdk-1.4.3 → dc_python_sdk-1.5.0}/setup.cfg +36 -32
  6. dc_python_sdk-1.5.0/src/dc_python_sdk.egg-info/PKG-INFO +502 -0
  7. {dc_python_sdk-1.4.3 → dc_python_sdk-1.5.0}/src/dc_python_sdk.egg-info/SOURCES.txt +10 -1
  8. dc_python_sdk-1.5.0/src/dc_python_sdk.egg-info/entry_points.txt +2 -0
  9. dc_python_sdk-1.5.0/src/dc_python_sdk.egg-info/requires.txt +9 -0
  10. dc_python_sdk-1.5.0/src/dc_sdk/cli.py +18 -0
  11. {dc_python_sdk-1.4.3 → dc_python_sdk-1.5.0}/src/dc_sdk/conftest.py +369 -369
  12. {dc_python_sdk-1.4.3 → dc_python_sdk-1.5.0}/src/dc_sdk/errors.py +324 -324
  13. dc_python_sdk-1.5.0/src/dc_sdk/handler.py +67 -0
  14. dc_python_sdk-1.5.0/src/dc_sdk/loader.py +40 -0
  15. dc_python_sdk-1.5.0/src/dc_sdk/mapping.py +109 -0
  16. {dc_python_sdk-1.4.3 → dc_python_sdk-1.5.0}/src/dc_sdk/pytest.txt +11 -11
  17. dc_python_sdk-1.5.0/src/dc_sdk/server.py +86 -0
  18. dc_python_sdk-1.5.0/src/dc_sdk/session.py +19 -0
  19. {dc_python_sdk-1.4.3 → dc_python_sdk-1.5.0}/src/dc_sdk/test_connector.py +477 -477
  20. dc_python_sdk-1.5.0/src/dc_sdk/types.py +38 -0
  21. dc_python_sdk-1.4.3/PKG-INFO +0 -25
  22. dc_python_sdk-1.4.3/README.md +0 -9
  23. dc_python_sdk-1.4.3/pyproject.toml +0 -11
  24. dc_python_sdk-1.4.3/src/dc_python_sdk.egg-info/PKG-INFO +0 -25
  25. {dc_python_sdk-1.4.3 → dc_python_sdk-1.5.0}/src/dc_python_sdk.egg-info/dependency_links.txt +0 -0
  26. {dc_python_sdk-1.4.3 → dc_python_sdk-1.5.0}/src/dc_python_sdk.egg-info/top_level.txt +0 -0
  27. {dc_python_sdk-1.4.3 → dc_python_sdk-1.5.0}/src/dc_sdk/__init__.py +0 -0
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) [year] [fullname]
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) [year] [fullname]
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,502 @@
1
+ Metadata-Version: 2.4
2
+ Name: dc-python-sdk
3
+ Version: 1.5.0
4
+ Summary: Data Connector Python SDK
5
+ Home-page: https://github.com/data-connector/dc-python-sdk
6
+ Author: DataConnector
7
+ Author-email: josh@dataconnector.com
8
+ Project-URL: Bug Tracker, https://github.com/data-connector/dc-python-sdk/issues
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.6
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: fastapi
16
+ Requires-Dist: uvicorn
17
+ Requires-Dist: awslambdaric
18
+ Provides-Extra: test
19
+ Requires-Dist: python-dotenv>=0.20.0; extra == "test"
20
+ Requires-Dist: faker>=13.12.0; extra == "test"
21
+ Requires-Dist: numpy>=1.21.6; extra == "test"
22
+ Requires-Dist: pandas>=1.3.5; extra == "test"
23
+ Dynamic: license-file
24
+
25
+ # Data Connector Python SDK
26
+
27
+ A comprehensive Python SDK for building robust data connectors with standardized error handling and graceful failure management.
28
+
29
+ [![PyPI version](https://badge.fury.io/py/dc-python-sdk.svg)](https://badge.fury.io/py/dc-python-sdk)
30
+ [![Python versions](https://img.shields.io/pypi/pyversions/dc-python-sdk.svg)](https://pypi.org/project/dc-python-sdk/)
31
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
32
+
33
+ ## Table of Contents
34
+
35
+ - [Installation](#installation)
36
+ - [Quick Start](#quick-start)
37
+ - [Error Handling](#error-handling)
38
+ - [Error Categories](#error-categories)
39
+ - [Best Practices](#best-practices)
40
+ - [Examples](#examples)
41
+ - [Development](#development)
42
+ - [Version Management](#version-management-and-release-process)
43
+ - [Contributing](#contributing)
44
+
45
+ ## Installation
46
+
47
+ ### Install from PyPI
48
+
49
+ ```bash
50
+ pip install dc-python-sdk
51
+ ```
52
+
53
+ ### Install from Source
54
+
55
+ ```bash
56
+ git clone https://github.com/data-connector/dc-python-sdk.git
57
+ cd dc-python-sdk
58
+ pip install -e .
59
+ ```
60
+
61
+ ### Requirements
62
+
63
+ - Python >= 3.6
64
+ - setuptools >= 42
65
+
66
+ ## Quick Start
67
+
68
+ ### Using the error classes
69
+
70
+ ```python
71
+ from dc_sdk import errors
72
+
73
+ # Example: Handling authentication failure
74
+ try:
75
+ # Your authentication logic here
76
+ authenticate_user(credentials)
77
+ except Exception as e:
78
+ raise errors.AuthenticationError("Invalid credentials provided. Please check your username and password.")
79
+
80
+ # Example: Handling missing objects
81
+ def get_available_objects():
82
+ objects = fetch_objects_from_api()
83
+ if not objects:
84
+ raise errors.NoObjectsFoundError("No tables or objects found for this account. Please ensure your account has accessible data.")
85
+ return objects
86
+ ```
87
+
88
+ ### Running the local HTTP server
89
+
90
+ Install the SDK and start the HTTP server that wraps your connector:
91
+
92
+ ```bash
93
+ pip install dc-python-sdk
94
+
95
+ # starts a FastAPI server on port 8000
96
+ dc-sdk http
97
+ ```
98
+
99
+ Then you can POST to the `/invoke` endpoint:
100
+
101
+ ```bash
102
+ curl -X POST http://localhost:8000/invoke \
103
+ -H "Content-Type: application/json" \
104
+ -d '{
105
+ "method": "get_objects",
106
+ "credentials": { "api_key": "YOUR_KEY" },
107
+ "params": {}
108
+ }'
109
+ ```
110
+
111
+ ### Using the AWS Lambda handler
112
+
113
+ The SDK also exposes a Lambda-style handler in `dc_sdk.handler`:
114
+
115
+ ```python
116
+ from dc_sdk.handler import handler
117
+
118
+ def lambda_handler(event, context):
119
+ return handler(event, context)
120
+ ```
121
+
122
+ ## Error Handling
123
+
124
+ > **Reference**: [Error Handling Documentation](https://data-connector.atlassian.net/wiki/spaces/SDL/pages/113705073/Error+Handling+-+Please+Read)
125
+
126
+ Error handling is one of the most important ways we can provide users with clear, informative feedback—so they're not left wondering what some random "Error 500" means (because nothing says "fun" like debugging a vague server error at 2 AM).
127
+
128
+ Our system uses the `dc_sdk` library to gracefully throw errors. This ensures:
129
+
130
+ - **Users see helpful messages** instead of cryptic stack traces
131
+ - **Unhandled errors escalate** as server errors, which automatically generate a bug ticket for the engineering team
132
+ - **Errors can be tested, logged, and surfaced consistently** across all connectors
133
+
134
+ ## Error Categories
135
+
136
+ The SDK provides 21 different error classes organized into logical categories. Each error is designed to handle specific failure scenarios:
137
+
138
+ ### Authentication Errors
139
+ - `AuthenticationError` - Invalid credentials, expired tokens
140
+ - `WhitelistError` - IP not whitelisted, connection refused
141
+
142
+ ### Object & Field Errors
143
+ - `NoObjectsFoundError` - No tables/objects available
144
+ - `GetObjectsError` - Failed to retrieve objects
145
+ - `NoFieldsFoundError` - Object exists but has no fields
146
+ - `GetFieldsError` - Cannot retrieve field information
147
+ - `BadFieldIDError` - Invalid field ID for object
148
+ - `BadObjectIDError` - Object ID doesn't exist
149
+
150
+ ### Data Filtering & Mapping Errors
151
+ - `FilterDataTypeError` - Invalid data type for filtering
152
+ - `FieldDataTypeError` - Unsupported field data type
153
+ - `MappingError` - Data mapping failures
154
+
155
+ ### Data Retrieval Errors
156
+ - `DataError` - Generic data retrieval failure
157
+ - `APIRequestError` - API returned error status
158
+ - `APITimeoutError` - Request timeout
159
+ - `APIPermissionError` - Insufficient API permissions
160
+ - `NoRowsFoundError` - Query successful but no data
161
+
162
+ ### Data Loading Errors
163
+ - `LoadDataError` - Failed to load data to destination
164
+ - `NotADestinationError` - Connector is read-only
165
+ - `UpdateMethodNotSupportedError` - Invalid update method
166
+
167
+ ### Implementation Errors
168
+ - `NotImplementedError` - Required method not implemented
169
+
170
+ For detailed examples and usage patterns, see the [Examples](#examples) section below.
171
+
172
+ ## Best Practices
173
+
174
+ 1. **Always raise the most specific error possible** (don't just raise `Error`)
175
+
176
+ 2. **Add a helpful message**—this is surfaced directly to the user
177
+
178
+ 3. **Differentiate between client-facing and internal errors**:
179
+ - **Client-facing errors** (e.g., `AuthenticationError`, `WhitelistError`) provide actionable guidance
180
+ - **Internal errors** (e.g., `GetObjectsError`) indicate issues within the connector or API
181
+
182
+ 4. **Use descriptive error messages** that help users understand what went wrong and how to fix it
183
+
184
+ 5. **Include context** in error messages when possible (e.g., which field, table, or operation failed)
185
+
186
+ ## Examples
187
+
188
+ ### Basic Usage
189
+
190
+ ```python
191
+ from dc_sdk import errors
192
+
193
+ # Authentication example
194
+ def authenticate_user(api_key):
195
+ if not api_key:
196
+ raise errors.AuthenticationError("API key is required")
197
+
198
+ if not validate_api_key(api_key):
199
+ raise errors.AuthenticationError("Invalid API key. Please check your credentials.")
200
+
201
+ # Object validation example
202
+ def get_table_data(table_name):
203
+ if table_name not in available_tables:
204
+ available = ", ".join(available_tables.keys())
205
+ raise errors.BadObjectIDError(f"Table '{table_name}' not found. Available: {available}")
206
+
207
+ try:
208
+ return fetch_table_data(table_name)
209
+ except Exception as e:
210
+ raise errors.DataError(f"Failed to retrieve data from '{table_name}': {str(e)}")
211
+ ```
212
+
213
+ ### Advanced Error Handling
214
+
215
+ ```python
216
+ from dc_sdk import errors
217
+
218
+ class DataConnector:
219
+ def sync_data(self, source_table, destination_table, update_method="append"):
220
+ # Validate update method
221
+ supported_methods = ["append", "replace"]
222
+ if update_method not in supported_methods:
223
+ raise errors.UpdateMethodNotSupportedError(
224
+ f"Update method '{update_method}' not supported. Use: {', '.join(supported_methods)}"
225
+ )
226
+
227
+ # Check if connector supports destinations
228
+ if not self.is_destination:
229
+ raise errors.NotADestinationError("This connector is read-only and cannot receive data")
230
+
231
+ try:
232
+ # Perform the sync
233
+ result = self.perform_sync(source_table, destination_table, update_method)
234
+ if not result.success:
235
+ raise errors.LoadDataError(f"Sync failed: {result.error_message}")
236
+ except TimeoutError:
237
+ raise errors.APITimeoutError("Sync operation timed out. Please try again with smaller batches.")
238
+ except PermissionError:
239
+ raise errors.APIPermissionError("Insufficient permissions to write to destination table")
240
+ ```
241
+
242
+ ## Development
243
+
244
+ ### Setting up Development Environment
245
+
246
+ ```bash
247
+ # Clone the repository
248
+ git clone https://github.com/data-connector/dc-python-sdk.git
249
+ cd dc-python-sdk
250
+
251
+ # Create virtual environment
252
+ python -m venv venv
253
+ source venv/bin/activate # On Windows: venv\Scripts\activate
254
+
255
+ # Install development dependencies
256
+ pip install -e .
257
+ pip install pytest pytest-cov
258
+
259
+ # Run tests
260
+ pytest
261
+ ```
262
+
263
+ ### Version Management and Release Process
264
+
265
+ #### Semantic Versioning
266
+
267
+ This project follows [Semantic Versioning](https://semver.org/) (SemVer):
268
+
269
+ - **MAJOR** version (X.y.z): Breaking changes that are not backward compatible
270
+ - **MINOR** version (x.Y.z): New features that are backward compatible
271
+ - **PATCH** version (x.y.Z): Bug fixes and minor improvements that are backward compatible
272
+
273
+ **Examples:**
274
+ - `1.4.3` → `1.4.4`: Bug fixes or minor improvements
275
+ - `1.4.3` → `1.5.0`: New features added (backward compatible)
276
+ - `1.4.3` → `2.0.0`: Breaking changes (not backward compatible)
277
+
278
+ **Current version:** `1.5.0`
279
+
280
+ #### 1. Update Version Number
281
+
282
+ Edit the version in `pyproject.toml`:
283
+
284
+ ```toml
285
+ [project]
286
+ name = "dc-python-sdk"
287
+ version = "1.5.0" # bump this
288
+ ```
289
+
290
+ #### 2. Update Package Description (Optional)
291
+
292
+ While updating the version, you can also update the package description in `pyproject.toml`:
293
+
294
+ ```toml
295
+ [project]
296
+ name = "dc-python-sdk"
297
+ version = "1.5.0"
298
+ description = "Data Connector Python SDK for building robust connectors with standardized error handling"
299
+ ```
300
+
301
+ #### 3. Commit Changes
302
+
303
+ ```bash
304
+ # Stage your changes
305
+ git add pyproject.toml README.md
306
+
307
+ # Commit with a descriptive message
308
+ git commit -m "Bump version to 1.4.4 and update documentation"
309
+
310
+ # Push to main branch
311
+ git push origin main
312
+ ```
313
+
314
+ #### 4. Create GitHub Release
315
+
316
+ You have two options for creating a release:
317
+
318
+ **Option A: Using GitHub Web Interface**
319
+
320
+ 1. Go to your repository on GitHub
321
+ 2. Click on "Releases" in the right sidebar
322
+ 3. Click "Create a new release"
323
+ 4. Fill in the release details:
324
+ - **Tag version**: `v1.4.4` (must match your version in setup.cfg)
325
+ - **Release title**: `v1.4.4 - Description of changes`
326
+ - **Description**: Add release notes describing what changed
327
+ 5. Click "Publish release"
328
+
329
+ **Option B: Using GitHub CLI**
330
+
331
+ ```bash
332
+ # Install GitHub CLI if not already installed
333
+ # Windows: winget install GitHub.cli
334
+ # macOS: brew install gh
335
+ # Linux: See https://cli.github.com/
336
+
337
+ # Create and push a tag
338
+ git tag v1.4.4
339
+ git push origin v1.4.4
340
+
341
+ # Create the release
342
+ gh release create v1.4.4 \
343
+ --title "v1.4.4 - Enhanced Error Handling Documentation" \
344
+ --notes "
345
+ ## What's Changed
346
+ - Updated comprehensive README with installation instructions
347
+ - Added detailed error handling documentation
348
+ - Improved code examples and best practices
349
+ - Enhanced development setup instructions
350
+
351
+ ## Installation
352
+ \`\`\`bash
353
+ pip install dc-python-sdk==1.4.4
354
+ \`\`\`
355
+ "
356
+ ```
357
+
358
+ #### 5. Automated Publishing
359
+
360
+ Once you create a GitHub release, the automated workflow (`.github/workflows/publish.yml`) will:
361
+
362
+ 1. ✅ Automatically build the package
363
+ 2. ✅ Run tests (if configured)
364
+ 3. ✅ Publish to PyPI using the stored `PYPI_API_TOKEN`
365
+
366
+ **Monitor the workflow:**
367
+ - Go to the "Actions" tab in your GitHub repository
368
+ - Watch the "Publish Python 🐍 package" workflow run
369
+ - Verify successful publication to PyPI
370
+
371
+ #### 6. Verify Release
372
+
373
+ ```bash
374
+ # Check that the new version is available on PyPI
375
+ pip install dc-python-sdk==1.4.4
376
+
377
+ # Or upgrade to the latest version
378
+ pip install --upgrade dc-python-sdk
379
+
380
+ # Verify the version in Python
381
+ python -c "import dc_sdk; print('Version installed successfully')"
382
+ ```
383
+
384
+ #### Quick Release Commands
385
+
386
+ For common release scenarios, here are the complete command sequences:
387
+
388
+ **Patch Release (Bug fixes):**
389
+ ```bash
390
+ # 1. Update version in pyproject.toml (1.5.0 → 1.5.1)
391
+ # 2. Commit and release
392
+ git add pyproject.toml
393
+ git commit -m "Bump version to 1.5.1 - Bug fixes and documentation updates"
394
+ git push origin main
395
+ git tag v1.5.1
396
+ git push origin v1.5.1
397
+ gh release create v1.5.1 --title "v1.5.1 - Bug Fixes" --notes "Bug fixes and minor improvements"
398
+ ```
399
+
400
+ **Minor Release (New features):**
401
+ ```bash
402
+ # 1. Update version in pyproject.toml (1.5.1 → 1.6.0)
403
+ # 2. Commit and release
404
+ git add pyproject.toml
405
+ git commit -m "Bump version to 1.6.0 - New error handling features"
406
+ git push origin main
407
+ git tag v1.6.0
408
+ git push origin v1.6.0
409
+ gh release create v1.6.0 --title "v1.6.0 - New Features" --notes "Added new error classes and improved documentation"
410
+ ```
411
+
412
+ **Major Release (Breaking changes):**
413
+ ```bash
414
+ # 1. Update version in pyproject.toml (1.6.0 → 2.0.0)
415
+ # 2. Commit and release
416
+ git add pyproject.toml
417
+ git commit -m "Bump version to 2.0.0 - Breaking changes to error API"
418
+ git push origin main
419
+ git tag v2.0.0
420
+ git push origin v2.0.0
421
+ gh release create v2.0.0 --title "v2.0.0 - Major Release" --notes "⚠️ Breaking changes: Updated error class signatures"
422
+ ```
423
+
424
+ ### Complete Release Checklist
425
+
426
+ - [ ] Update version in `pyproject.toml`
427
+ - [ ] Update any documentation or changelog
428
+ - [ ] Test changes locally
429
+ - [ ] Commit and push changes
430
+ - [ ] Create GitHub release with proper tag (v1.4.4)
431
+ - [ ] Monitor GitHub Actions workflow
432
+ - [ ] Verify package is published to PyPI
433
+ - [ ] Test installation of new version
434
+
435
+ ### Manual Building and Publishing (Alternative)
436
+
437
+ If you need to manually build and publish (not recommended for production):
438
+
439
+ ```bash
440
+ # Build the package
441
+ python -m build
442
+
443
+ # Upload to PyPI (requires credentials)
444
+ python -m twine upload --repository pypi dist/*
445
+
446
+ # Upload to TestPyPI first (recommended for testing)
447
+ python -m twine upload --repository testpypi dist/*
448
+ ```
449
+
450
+ ### Project Structure
451
+
452
+ ```
453
+ dc-python-sdk/
454
+ ├── src/
455
+ │ └── dc_sdk/
456
+ │ ├── __init__.py
457
+ │ ├── errors.py # All error classes
458
+ │ ├── cli.py # dc-sdk CLI entrypoint
459
+ │ ├── server.py # FastAPI HTTP server for connectors
460
+ │ ├── handler.py # AWS Lambda handler
461
+ │ ├── loader.py # Connector loader utilities
462
+ │ ├── mapping.py # Mapping abstraction used by handler
463
+ │ ├── session.py # In-memory session management for HTTP server
464
+ │ ├── types.py # Shared type definitions
465
+ │ └── test_connector.py # Test utilities
466
+ ├── setup.cfg # Legacy setuptools configuration
467
+ ├── pyproject.toml # Project & build configuration
468
+ ├── README.md # This file
469
+ ├── LICENSE # MIT License
470
+ └── .github/
471
+ └── workflows/
472
+ └── publish.yml # Automated PyPI publishing
473
+ ```
474
+
475
+ ## Contributing
476
+
477
+ 1. Fork the repository
478
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
479
+ 3. Make your changes
480
+ 4. Add tests for your changes
481
+ 5. Ensure all tests pass (`pytest`)
482
+ 6. Commit your changes (`git commit -m 'Add amazing feature'`)
483
+ 7. Push to the branch (`git push origin feature/amazing-feature`)
484
+ 8. Open a Pull Request
485
+
486
+ ## License
487
+
488
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
489
+
490
+ ## Support
491
+
492
+ - **Bug Reports**: [GitHub Issues](https://github.com/data-connector/dc-python-sdk/issues)
493
+ - **Documentation**: [Error Handling Guide](https://data-connector.atlassian.net/wiki/spaces/SDL/pages/113705073/Error+Handling+-+Please+Read)
494
+ - **Email**: josh@dataconnector.com
495
+
496
+ ---
497
+
498
+ ## Summary
499
+
500
+ Use these errors to make the user's life easier (and to keep support tickets sane). The system is designed so that **graceful errors = happy users**, while **unhandled errors = bug tickets**.
501
+
502
+ Remember: Error handling isn't just about catching exceptions—it's about providing a great user experience even when things go wrong.