t2d2-sdk 2.6.0__tar.gz → 2.6.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 (30) hide show
  1. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/.github/workflows/sphinx.yml +11 -11
  2. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/PKG-INFO +1 -1
  3. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/docs/requirements.txt +2 -2
  4. t2d2_sdk-2.6.2/docs/source/_static/.gitkeep +0 -0
  5. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/src/_version.py +3 -3
  6. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/src/t2d2_sdk.egg-info/PKG-INFO +1 -1
  7. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/src/t2d2_sdk.egg-info/SOURCES.txt +1 -0
  8. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/src/t2d2_sdk.egg-info/scm_file_list.json +1 -0
  9. t2d2_sdk-2.6.2/src/t2d2_sdk.egg-info/scm_version.json +8 -0
  10. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/src/t2d2_sdk.py +44 -10
  11. t2d2_sdk-2.6.0/src/t2d2_sdk.egg-info/scm_version.json +0 -8
  12. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/.github/workflows/publish_pypi.yaml +0 -0
  13. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/.gitignore +0 -0
  14. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/LICENSE +0 -0
  15. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/README.md +0 -0
  16. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/docs/Makefile +0 -0
  17. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/docs/make.bat +0 -0
  18. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/docs/source/conf.py +0 -0
  19. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/docs/source/index.rst +0 -0
  20. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/pyproject.toml +0 -0
  21. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/requirements.txt +0 -0
  22. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/setup.cfg +0 -0
  23. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/src/condition_report_service.py +0 -0
  24. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/src/t2d2_sdk.egg-info/dependency_links.txt +0 -0
  25. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/src/t2d2_sdk.egg-info/requires.txt +0 -0
  26. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/src/t2d2_sdk.egg-info/top_level.txt +0 -0
  27. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/src/test.py +0 -0
  28. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/t2d2_image/t2d2.png +0 -0
  29. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/tests/t2d2_test.py +0 -0
  30. {t2d2_sdk-2.6.0 → t2d2_sdk-2.6.2}/tests/test_datasets.py +0 -0
@@ -8,12 +8,6 @@ on:
8
8
  # Allows you to run this workflow manually from the Actions tab
9
9
  workflow_dispatch:
10
10
 
11
- # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
12
- permissions:
13
- contents: read
14
- pages: write
15
- id-token: write
16
-
17
11
  # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
18
12
  # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
19
13
  concurrency:
@@ -28,22 +22,28 @@ jobs:
28
22
  steps:
29
23
  - uses: actions/checkout@v4
30
24
  - name: Set up Python
31
- uses: actions/setup-python@v2
25
+ uses: actions/setup-python@v5
32
26
  with:
33
- python-version: '3.x'
27
+ # The SDK uses `X | None` annotations (Python >= 3.10). Do not build
28
+ # docs in the sphinx-action Docker image (Python 3.8): autodoc fails to
29
+ # import the SDK there and the API reference silently comes out empty.
30
+ python-version: '3.11'
31
+ cache: pip
32
+ cache-dependency-path: docs/requirements.txt
34
33
  - name: Install dependencies
35
34
  run: |
36
35
  python -m pip install --upgrade pip
37
- pip install -r docs/requirements.txt
36
+ pip install -r docs/requirements.txt
38
37
  - name: Build HTML
39
- uses: ammaraskar/sphinx-action@master
38
+ # -W turns warnings (e.g. autodoc import failures) into errors
39
+ run: sphinx-build -W --keep-going -b html docs/source docs/build/html
40
40
  - name: Upload artifacts
41
41
  uses: actions/upload-artifact@v4
42
42
  with:
43
43
  name: html-docs
44
44
  path: docs/build/html/
45
45
  - name: Deploy
46
- uses: peaceiris/actions-gh-pages@v3
46
+ uses: peaceiris/actions-gh-pages@v4
47
47
  if: github.ref == 'refs/heads/main'
48
48
  with:
49
49
  github_token: ${{ secrets.GITHUB_TOKEN }}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: t2d2-sdk
3
- Version: 2.6.0
3
+ Version: 2.6.2
4
4
  Summary: T2D2 SDK
5
5
  Author-email: Badri Hiriyur <badri@t2d2.ai>
6
6
  Project-URL: Homepage, https://t2d2.ai
@@ -1,6 +1,6 @@
1
+ sphinx
1
2
  myst-parser
2
- jinja2==3.1
3
+ jinja2
3
4
  requests
4
5
  boto3
5
6
  sentry-sdk
6
- sphinx-rtd-theme
File without changes
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '2.6.0'
22
- __version_tuple__ = version_tuple = (2, 6, 0)
21
+ __version__ = version = '2.6.2'
22
+ __version_tuple__ = version_tuple = (2, 6, 2)
23
23
 
24
- __commit_id__ = commit_id = 'g63d857420'
24
+ __commit_id__ = commit_id = 'g386ace5d5'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: t2d2-sdk
3
- Version: 2.6.0
3
+ Version: 2.6.2
4
4
  Summary: T2D2 SDK
5
5
  Author-email: Badri Hiriyur <badri@t2d2.ai>
6
6
  Project-URL: Homepage, https://t2d2.ai
@@ -10,6 +10,7 @@ docs/make.bat
10
10
  docs/requirements.txt
11
11
  docs/source/conf.py
12
12
  docs/source/index.rst
13
+ docs/source/_static/.gitkeep
13
14
  src/_version.py
14
15
  src/condition_report_service.py
15
16
  src/t2d2_sdk.py
@@ -8,6 +8,7 @@
8
8
  "docs/Makefile",
9
9
  "docs/make.bat",
10
10
  "docs/requirements.txt",
11
+ "docs/source/_static/.gitkeep",
11
12
  "docs/source/conf.py",
12
13
  "docs/source/index.rst",
13
14
  "pyproject.toml",
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "2.6.2",
3
+ "distance": 0,
4
+ "node": "g386ace5d592d33c12ef91fd60996b7dc4bc9bcd3",
5
+ "dirty": false,
6
+ "branch": "main",
7
+ "node_date": "2026-11-13"
8
+ }
@@ -445,14 +445,35 @@ def ts2date(ts):
445
445
  return datetime.fromtimestamp(ts).strftime("%Y-%m-%d %H:%M:%S")
446
446
 
447
447
 
448
+ def _is_s3_url(url: str) -> bool:
449
+ """True for s3:// and virtual-hosted Amazon S3 HTTPS URLs."""
450
+ parsed = urlparse(url)
451
+ if parsed.scheme == "s3":
452
+ return True
453
+ host = (parsed.netloc or "").lower()
454
+ return host.endswith(".amazonaws.com") and "s3" in host.split(".")
455
+
456
+
457
+ def _s3_bucket_and_key(url: str):
458
+ """Parse bucket and object key from an s3:// or virtual-hosted S3 URL."""
459
+ parsed = urlparse(url)
460
+ if parsed.scheme == "s3":
461
+ return parsed.netloc.split(".")[0], parsed.path.lstrip("/")
462
+ host = parsed.netloc
463
+ # bucket.s3.amazonaws.com or bucket.s3.region.amazonaws.com
464
+ bucket = host.split(".s3")[0]
465
+ return bucket, parsed.path.lstrip("/")
466
+
467
+
448
468
  def download_file(url: str, file_path: str):
449
469
  """
450
- Download a file from an S3 URL to a local path.
451
-
452
- This function parses the S3 URL to extract bucket and key information,
453
- then downloads the file to the specified local path.
470
+ Download a file from S3 or HTTPS (CloudFront/CDN) to a local path.
471
+
472
+ Image records from the T2D2 API typically use CloudFront HTTPS URLs.
473
+ Those must be fetched over HTTP; treating them as S3 bucket names fails
474
+ (e.g. ``s3.download_file("dvd30yayquknd", ...)``) and leaves no local file.
454
475
 
455
- :param url: S3 URL of the file to download
476
+ :param url: HTTPS, CloudFront, or S3 URL of the file to download
456
477
  :type url: str
457
478
  :param file_path: Local path where the file should be saved
458
479
  :type file_path: str
@@ -460,20 +481,33 @@ def download_file(url: str, file_path: str):
460
481
  :return: Dictionary containing success status and message
461
482
  :rtype: dict
462
483
 
463
- :raises Exception: If there is an error during download
464
-
465
484
  :example:
485
+ >>> download_file('https://cdn.example.net/projects/1/images/a.jpg', '/tmp/a.jpg')
486
+ {'success': True, 'message': 'File downloaded'}
466
487
  >>> download_file('s3://my-bucket/path/to/file.jpg', '/local/path/file.jpg')
467
488
  {'success': True, 'message': 'File downloaded'}
468
489
  """
490
+ bucket = key = None
469
491
  try:
492
+ dest_dir = os.path.dirname(file_path)
493
+ if dest_dir:
494
+ os.makedirs(dest_dir, exist_ok=True)
495
+
496
+ if not _is_s3_url(url):
497
+ res = requests.get(url, timeout=TIMEOUT, stream=True)
498
+ res.raise_for_status()
499
+ with open(file_path, "wb") as out:
500
+ for chunk in res.iter_content(chunk_size=1024 * 1024):
501
+ if chunk:
502
+ out.write(chunk)
503
+ return {"success": True, "message": "File downloaded"}
504
+
470
505
  s3 = boto3.client("s3")
471
- parsed_url = urlparse(url)
472
- bucket = parsed_url.netloc.split(".")[0]
473
- key = parsed_url.path[1:]
506
+ bucket, key = _s3_bucket_and_key(url)
474
507
  s3.download_file(bucket, key, file_path)
475
508
  return {"success": True, "message": "File downloaded"}
476
509
  except Exception as e:
510
+ logger.error("Failed to download %s to %s: %s", url, file_path, e)
477
511
  return {
478
512
  "success": False,
479
513
  "message": f"{str(e)} \n{bucket} \n{key} \n{file_path}",
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "2.6.0",
3
- "distance": 0,
4
- "node": "g63d857420424ebf3ac02c6fa979760aa0d50cea3",
5
- "dirty": false,
6
- "branch": "main",
7
- "node_date": "2026-09-01"
8
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes