infrared-sdk 0.4.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 (139) hide show
  1. infrared_sdk-0.4.0/.env.example +2 -0
  2. infrared_sdk-0.4.0/.github/CODEOWNERS +1 -0
  3. infrared_sdk-0.4.0/.github/ISSUE_TEMPLATE/bug_report.yml +54 -0
  4. infrared_sdk-0.4.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  5. infrared_sdk-0.4.0/.github/ISSUE_TEMPLATE/feature_request.yml +25 -0
  6. infrared_sdk-0.4.0/.github/PULL_REQUEST_TEMPLATE.md +10 -0
  7. infrared_sdk-0.4.0/.github/workflows/ci.yml +42 -0
  8. infrared_sdk-0.4.0/.github/workflows/publish.yml +21 -0
  9. infrared_sdk-0.4.0/.github/workflows/pypi-publish.yml +50 -0
  10. infrared_sdk-0.4.0/.github/workflows/pypi-test-publish.yml +49 -0
  11. infrared_sdk-0.4.0/.gitignore +234 -0
  12. infrared_sdk-0.4.0/.pre-commit-config.yaml +18 -0
  13. infrared_sdk-0.4.0/.vscode/settings.json +14 -0
  14. infrared_sdk-0.4.0/CHANGELOG.md +93 -0
  15. infrared_sdk-0.4.0/CLAUDE.md +180 -0
  16. infrared_sdk-0.4.0/CODE_OF_CONDUCT.md +13 -0
  17. infrared_sdk-0.4.0/LICENSE +201 -0
  18. infrared_sdk-0.4.0/NOTICE +5 -0
  19. infrared_sdk-0.4.0/PKG-INFO +1107 -0
  20. infrared_sdk-0.4.0/README.md +1093 -0
  21. infrared_sdk-0.4.0/SECURITY.md +22 -0
  22. infrared_sdk-0.4.0/assets/logo-teal.svg +1 -0
  23. infrared_sdk-0.4.0/assets/per_tile_coordinate_transform_standalone.svg +94 -0
  24. infrared_sdk-0.4.0/assets/polygon_bbox_sw_frame_standalone.svg +69 -0
  25. infrared_sdk-0.4.0/assets/solar_tiling_diagram_standalone.svg +58 -0
  26. infrared_sdk-0.4.0/assets/time_period_filter_diagram_standalone.svg +87 -0
  27. infrared_sdk-0.4.0/assets/wind_tiling_diagram_standalone.svg +63 -0
  28. infrared_sdk-0.4.0/demos/areas_demo_async/.env.example +17 -0
  29. infrared_sdk-0.4.0/demos/areas_demo_async/README.md +191 -0
  30. infrared_sdk-0.4.0/demos/areas_demo_async/db.py +496 -0
  31. infrared_sdk-0.4.0/demos/areas_demo_async/generate_visualizations.py +269 -0
  32. infrared_sdk-0.4.0/demos/areas_demo_async/requirements.txt +5 -0
  33. infrared_sdk-0.4.0/demos/areas_demo_async/submit_analyses.py +590 -0
  34. infrared_sdk-0.4.0/demos/areas_demo_async/visualize.py +563 -0
  35. infrared_sdk-0.4.0/demos/areas_demo_async/webhook_server.py +205 -0
  36. infrared_sdk-0.4.0/demos/demo_advanced_usage.py +527 -0
  37. infrared_sdk-0.4.0/demos/demo_fetch_layers.py +166 -0
  38. infrared_sdk-0.4.0/demos/demo_tiling.py +134 -0
  39. infrared_sdk-0.4.0/demos/demo_utci_analysis.py +147 -0
  40. infrared_sdk-0.4.0/demos/demo_vegetation_ground.py +130 -0
  41. infrared_sdk-0.4.0/demos/demo_vienna.py +464 -0
  42. infrared_sdk-0.4.0/demos/demo_wind_analysis.py +110 -0
  43. infrared_sdk-0.4.0/public-demos/.env.example +9 -0
  44. infrared_sdk-0.4.0/public-demos/00_quickstart.ipynb +269 -0
  45. infrared_sdk-0.4.0/public-demos/01_buildings.ipynb +338 -0
  46. infrared_sdk-0.4.0/public-demos/02_vegetation_and_ground.ipynb +313 -0
  47. infrared_sdk-0.4.0/public-demos/03_weather_and_time_periods.ipynb +289 -0
  48. infrared_sdk-0.4.0/public-demos/04_tiling_and_area_api.ipynb +416 -0
  49. infrared_sdk-0.4.0/public-demos/05_analysis_types_tour.ipynb +504 -0
  50. infrared_sdk-0.4.0/public-demos/06_image_rendering.ipynb +333 -0
  51. infrared_sdk-0.4.0/public-demos/07_async_and_webhooks.ipynb +302 -0
  52. infrared_sdk-0.4.0/public-demos/README.md +93 -0
  53. infrared_sdk-0.4.0/public-demos/cities.py +135 -0
  54. infrared_sdk-0.4.0/public-demos/requirements.txt +11 -0
  55. infrared_sdk-0.4.0/public-demos/webhook_receiver.py +155 -0
  56. infrared_sdk-0.4.0/pyproject.toml +57 -0
  57. infrared_sdk-0.4.0/skills/async-jobs.md +297 -0
  58. infrared_sdk-0.4.0/skills/infrared-async-api-guide.md +313 -0
  59. infrared_sdk-0.4.0/skills/infrared-sdk-agents/SKILL.md +253 -0
  60. infrared_sdk-0.4.0/skills/infrared-sdk-consumers/SKILL.md +174 -0
  61. infrared_sdk-0.4.0/skills/infrared-sdk-contributors/SKILL.md +284 -0
  62. infrared_sdk-0.4.0/src/infrared_sdk/__init__.py +139 -0
  63. infrared_sdk-0.4.0/src/infrared_sdk/_area/__init__.py +0 -0
  64. infrared_sdk-0.4.0/src/infrared_sdk/_area/_layers.py +78 -0
  65. infrared_sdk-0.4.0/src/infrared_sdk/_area/_merging.py +337 -0
  66. infrared_sdk-0.4.0/src/infrared_sdk/_area/_polling.py +146 -0
  67. infrared_sdk-0.4.0/src/infrared_sdk/_area/_submission.py +414 -0
  68. infrared_sdk-0.4.0/src/infrared_sdk/_area/_thread_clients.py +56 -0
  69. infrared_sdk-0.4.0/src/infrared_sdk/analyses/__init__.py +34 -0
  70. infrared_sdk-0.4.0/src/infrared_sdk/analyses/jobs.py +628 -0
  71. infrared_sdk-0.4.0/src/infrared_sdk/analyses/service.py +90 -0
  72. infrared_sdk-0.4.0/src/infrared_sdk/analyses/types.py +473 -0
  73. infrared_sdk-0.4.0/src/infrared_sdk/buildings/__init__.py +18 -0
  74. infrared_sdk-0.4.0/src/infrared_sdk/buildings/service.py +577 -0
  75. infrared_sdk-0.4.0/src/infrared_sdk/buildings/types.py +205 -0
  76. infrared_sdk-0.4.0/src/infrared_sdk/ground_materials/__init__.py +9 -0
  77. infrared_sdk-0.4.0/src/infrared_sdk/ground_materials/dedup.py +223 -0
  78. infrared_sdk-0.4.0/src/infrared_sdk/ground_materials/service.py +369 -0
  79. infrared_sdk-0.4.0/src/infrared_sdk/ground_materials/types.py +24 -0
  80. infrared_sdk-0.4.0/src/infrared_sdk/layers/__init__.py +7 -0
  81. infrared_sdk-0.4.0/src/infrared_sdk/layers/service.py +219 -0
  82. infrared_sdk-0.4.0/src/infrared_sdk/models.py +228 -0
  83. infrared_sdk-0.4.0/src/infrared_sdk/preflight/__init__.py +27 -0
  84. infrared_sdk-0.4.0/src/infrared_sdk/preflight/sun_context.py +525 -0
  85. infrared_sdk-0.4.0/src/infrared_sdk/py.typed +0 -0
  86. infrared_sdk-0.4.0/src/infrared_sdk/sdk.py +641 -0
  87. infrared_sdk-0.4.0/src/infrared_sdk/tiling/__init__.py +25 -0
  88. infrared_sdk-0.4.0/src/infrared_sdk/tiling/config.py +121 -0
  89. infrared_sdk-0.4.0/src/infrared_sdk/tiling/executor.py +521 -0
  90. infrared_sdk-0.4.0/src/infrared_sdk/tiling/merger.py +282 -0
  91. infrared_sdk-0.4.0/src/infrared_sdk/tiling/orchestrator.py +94 -0
  92. infrared_sdk-0.4.0/src/infrared_sdk/tiling/tiles.py +466 -0
  93. infrared_sdk-0.4.0/src/infrared_sdk/tiling/transforms.py +291 -0
  94. infrared_sdk-0.4.0/src/infrared_sdk/tiling/types.py +732 -0
  95. infrared_sdk-0.4.0/src/infrared_sdk/tiling/validation.py +274 -0
  96. infrared_sdk-0.4.0/src/infrared_sdk/vegetation/__init__.py +14 -0
  97. infrared_sdk-0.4.0/src/infrared_sdk/vegetation/dedup.py +161 -0
  98. infrared_sdk-0.4.0/src/infrared_sdk/vegetation/service.py +284 -0
  99. infrared_sdk-0.4.0/src/infrared_sdk/vegetation/types.py +23 -0
  100. infrared_sdk-0.4.0/src/infrared_sdk/webhooks/NOTE.md +18 -0
  101. infrared_sdk-0.4.0/src/infrared_sdk/webhooks/__init__.py +28 -0
  102. infrared_sdk-0.4.0/src/infrared_sdk/webhooks/service.py +356 -0
  103. infrared_sdk-0.4.0/src/infrared_sdk/webhooks/types.py +112 -0
  104. infrared_sdk-0.4.0/tests/__init__.py +0 -0
  105. infrared_sdk-0.4.0/tests/analyses/__init__.py +0 -0
  106. infrared_sdk-0.4.0/tests/analyses/test_analyses.py +829 -0
  107. infrared_sdk-0.4.0/tests/analyses/test_analyses_client.py +288 -0
  108. infrared_sdk-0.4.0/tests/analyses/test_jobs.py +1041 -0
  109. infrared_sdk-0.4.0/tests/area_benchmark.py +604 -0
  110. infrared_sdk-0.4.0/tests/buildings/__init__.py +0 -0
  111. infrared_sdk-0.4.0/tests/buildings/test_buildings.py +232 -0
  112. infrared_sdk-0.4.0/tests/buildings/test_buildings_area.py +1016 -0
  113. infrared_sdk-0.4.0/tests/buildings/test_buildings_client.py +204 -0
  114. infrared_sdk-0.4.0/tests/buildings/test_buildings_tiled.py +603 -0
  115. infrared_sdk-0.4.0/tests/fixtures/buildings_api_response.json +25 -0
  116. infrared_sdk-0.4.0/tests/fixtures/sample_geometry.json +59416 -0
  117. infrared_sdk-0.4.0/tests/layers/__init__.py +0 -0
  118. infrared_sdk-0.4.0/tests/layers/test_ground_materials.py +245 -0
  119. infrared_sdk-0.4.0/tests/layers/test_vegetation.py +243 -0
  120. infrared_sdk-0.4.0/tests/layers/test_weather_client.py +95 -0
  121. infrared_sdk-0.4.0/tests/models/__init__.py +0 -0
  122. infrared_sdk-0.4.0/tests/models/test_utils.py +239 -0
  123. infrared_sdk-0.4.0/tests/preflight/__init__.py +0 -0
  124. infrared_sdk-0.4.0/tests/preflight/test_sun_context.py +615 -0
  125. infrared_sdk-0.4.0/tests/test_run_area.py +1714 -0
  126. infrared_sdk-0.4.0/tests/test_types.py +559 -0
  127. infrared_sdk-0.4.0/tests/test_webhooks.py +466 -0
  128. infrared_sdk-0.4.0/tests/tile_benchmark.py +591 -0
  129. infrared_sdk-0.4.0/tests/tiling/__init__.py +0 -0
  130. infrared_sdk-0.4.0/tests/tiling/test_composable.py +35 -0
  131. infrared_sdk-0.4.0/tests/tiling/test_executor.py +926 -0
  132. infrared_sdk-0.4.0/tests/tiling/test_generate_tiles.py +200 -0
  133. infrared_sdk-0.4.0/tests/tiling/test_merger.py +431 -0
  134. infrared_sdk-0.4.0/tests/tiling/test_orchestrator.py +706 -0
  135. infrared_sdk-0.4.0/tests/tiling/test_tiles.py +612 -0
  136. infrared_sdk-0.4.0/tests/tiling/test_transforms.py +587 -0
  137. infrared_sdk-0.4.0/tests/tiling/test_types.py +267 -0
  138. infrared_sdk-0.4.0/tests/tiling/test_validation.py +271 -0
  139. infrared_sdk-0.4.0/uv.lock +556 -0
@@ -0,0 +1,2 @@
1
+ INFRARED_API_KEY="your_api_key_here"
2
+ INFRARED_BASE_URL="https://api.infrared.city"
@@ -0,0 +1 @@
1
+ * @Infrared-city/sdk-maintainers
@@ -0,0 +1,54 @@
1
+ name: Bug Report
2
+ description: Report a bug in the Infrared SDK
3
+ labels: ["bug"]
4
+ body:
5
+ - type: input
6
+ id: sdk-version
7
+ attributes:
8
+ label: SDK Version
9
+ placeholder: "0.2.0"
10
+ validations:
11
+ required: true
12
+ - type: input
13
+ id: python-version
14
+ attributes:
15
+ label: Python Version
16
+ placeholder: "3.12"
17
+ validations:
18
+ required: true
19
+ - type: input
20
+ id: os
21
+ attributes:
22
+ label: Operating System
23
+ placeholder: "macOS 15, Ubuntu 24.04, Windows 11"
24
+ validations:
25
+ required: true
26
+ - type: textarea
27
+ id: description
28
+ attributes:
29
+ label: Description
30
+ description: What happened?
31
+ validations:
32
+ required: true
33
+ - type: textarea
34
+ id: steps
35
+ attributes:
36
+ label: Steps to Reproduce
37
+ description: Minimal code or steps to reproduce the issue.
38
+ render: python
39
+ validations:
40
+ required: true
41
+ - type: textarea
42
+ id: expected
43
+ attributes:
44
+ label: Expected Behavior
45
+ description: What did you expect to happen?
46
+ validations:
47
+ required: true
48
+ - type: textarea
49
+ id: actual
50
+ attributes:
51
+ label: Actual Behavior
52
+ description: What actually happened? Include error messages or tracebacks.
53
+ validations:
54
+ required: true
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Questions & Discussions
4
+ url: https://github.com/Infrared-city/infrared-sdk-python/discussions
5
+ about: Ask questions and discuss ideas
@@ -0,0 +1,25 @@
1
+ name: Feature Request
2
+ description: Suggest a new feature or improvement
3
+ labels: ["enhancement"]
4
+ body:
5
+ - type: textarea
6
+ id: use-case
7
+ attributes:
8
+ label: Use Case
9
+ description: What problem are you trying to solve?
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: proposed-solution
14
+ attributes:
15
+ label: Proposed Solution
16
+ description: How would you like this to work?
17
+ validations:
18
+ required: true
19
+ - type: textarea
20
+ id: alternatives
21
+ attributes:
22
+ label: Alternatives Considered
23
+ description: What workarounds or alternatives have you tried?
24
+ validations:
25
+ required: false
@@ -0,0 +1,10 @@
1
+ ## Summary
2
+
3
+ <!-- Brief description of the changes -->
4
+
5
+ ## Checklist
6
+
7
+ - [ ] Tests added/updated
8
+ - [ ] `ruff check .` and `ruff format --check .` pass
9
+ - [ ] `mypy src/infrared_sdk/` passes
10
+ - [ ] CHANGELOG.md updated under `[Unreleased]`
@@ -0,0 +1,42 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.11", "3.12", "3.13"]
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: astral-sh/setup-uv@v4
18
+ with:
19
+ python-version: ${{ matrix.python-version }}
20
+ - run: uv sync --group dev
21
+ - run: uv run pytest --cov=infrared_sdk -v
22
+
23
+ lint:
24
+ runs-on: ubuntu-latest
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+ - uses: astral-sh/setup-uv@v4
28
+ with:
29
+ python-version: "3.13"
30
+ - run: uv sync --group dev
31
+ - run: uv run ruff check .
32
+ - run: uv run ruff format --check .
33
+
34
+ typecheck:
35
+ runs-on: ubuntu-latest
36
+ steps:
37
+ - uses: actions/checkout@v4
38
+ - uses: astral-sh/setup-uv@v4
39
+ with:
40
+ python-version: "3.13"
41
+ - run: uv sync --group dev
42
+ - run: uv run pyright src/infrared_sdk/
@@ -0,0 +1,21 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ permissions:
9
+ id-token: write
10
+
11
+ jobs:
12
+ publish:
13
+ runs-on: ubuntu-latest
14
+ environment: pypi
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: astral-sh/setup-uv@v4
18
+ with:
19
+ python-version: "3.13"
20
+ - run: uv build
21
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,50 @@
1
+ name: Upload to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ release-build:
13
+ runs-on: ubuntu-latest
14
+
15
+ steps:
16
+ - uses: actions/checkout@v6
17
+
18
+ - name: Install uv
19
+ uses: astral-sh/setup-uv@v8.0.0
20
+
21
+ - name: Build release distributions
22
+ run: uv build
23
+
24
+ - name: Upload distributions
25
+ uses: actions/upload-artifact@v7
26
+ with:
27
+ name: release-dists
28
+ path: dist/
29
+
30
+ pypi-publish:
31
+ runs-on: ubuntu-latest
32
+ needs:
33
+ - release-build
34
+ permissions:
35
+ id-token: write
36
+
37
+ environment:
38
+ name: pypi
39
+
40
+ steps:
41
+ - name: Retrieve release distributions
42
+ uses: actions/download-artifact@v8
43
+ with:
44
+ name: release-dists
45
+ path: dist/
46
+
47
+ - name: Publish release distributions to PyPI
48
+ uses: pypa/gh-action-pypi-publish@release/v1
49
+ with:
50
+ packages-dir: dist/
@@ -0,0 +1,49 @@
1
+ name: Upload to TestPyPI
2
+
3
+ on:
4
+ workflow_dispatch:
5
+
6
+ permissions:
7
+ contents: read
8
+
9
+ jobs:
10
+ release-build:
11
+ runs-on: ubuntu-latest
12
+
13
+ steps:
14
+ - uses: actions/checkout@v6
15
+
16
+ - name: Install uv
17
+ uses: astral-sh/setup-uv@v8.0.0
18
+
19
+ - name: Build release distributions
20
+ run: uv build
21
+
22
+ - name: Upload distributions
23
+ uses: actions/upload-artifact@v7
24
+ with:
25
+ name: release-dists
26
+ path: dist/
27
+
28
+ testpypi-publish:
29
+ runs-on: ubuntu-latest
30
+ needs:
31
+ - release-build
32
+ permissions:
33
+ id-token: write
34
+
35
+ environment:
36
+ name: testpypi
37
+
38
+ steps:
39
+ - name: Retrieve release distributions
40
+ uses: actions/download-artifact@v8
41
+ with:
42
+ name: release-dists
43
+ path: dist/
44
+
45
+ - name: Publish release distributions to TestPyPI
46
+ uses: pypa/gh-action-pypi-publish@release/v1
47
+ with:
48
+ repository-url: https://test.pypi.org/legacy/
49
+ packages-dir: dist/
@@ -0,0 +1,234 @@
1
+ # Created by https://gitignore.org
2
+ # Python.gitignore
3
+
4
+ # Byte-compiled / optimized / DLL files
5
+ __pycache__/
6
+ *.py[codz]
7
+ *$py.class
8
+
9
+ # C extensions
10
+ *.so
11
+
12
+ .flow
13
+ .claude
14
+
15
+ # Distribution / packaging
16
+ .Python
17
+ build/
18
+ develop-eggs/
19
+ dist/
20
+ downloads/
21
+ eggs/
22
+ .eggs/
23
+ lib/
24
+ lib64/
25
+ parts/
26
+ sdist/
27
+ var/
28
+ wheels/
29
+ share/python-wheels/
30
+ *.egg-info/
31
+ .installed.cfg
32
+ *.egg
33
+ MANIFEST
34
+
35
+ # PyInstaller
36
+ # Usually these files are written by a python script from a template
37
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
38
+ *.manifest
39
+ *.spec
40
+
41
+ # Installer logs
42
+ pip-log.txt
43
+ pip-delete-this-directory.txt
44
+
45
+ # Unit test / coverage reports
46
+ htmlcov/
47
+ .tox/
48
+ .nox/
49
+ .coverage
50
+ .coverage.*
51
+ .cache
52
+ cache
53
+ nosetests.xml
54
+ coverage.xml
55
+ *.cover
56
+ *.py.cover
57
+ .hypothesis/
58
+ .pytest_cache/
59
+ cover/
60
+
61
+ # Translations
62
+ *.mo
63
+ *.pot
64
+
65
+ # Django stuff:
66
+ *.log
67
+ local_settings.py
68
+ db.sqlite3
69
+ db.sqlite3-journal
70
+
71
+ # Flask stuff:
72
+ instance/
73
+ .webassets-cache
74
+
75
+ # Scrapy stuff:
76
+ .scrapy
77
+
78
+ # Sphinx documentation
79
+ docs/_build/
80
+
81
+ # PyBuilder
82
+ .pybuilder/
83
+ target/
84
+
85
+ # Jupyter Notebook
86
+ .ipynb_checkpoints
87
+
88
+ # IPython
89
+ profile_default/
90
+ ipython_config.py
91
+ model_payloads/*
92
+
93
+ # pyenv
94
+ # For a library or package, you might want to ignore these files since the code is
95
+ # intended to run in multiple environments; otherwise, check them in:
96
+ # .python-version
97
+
98
+ # pipenv
99
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
100
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
101
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
102
+ # install all needed dependencies.
103
+ # Pipfile.lock
104
+
105
+ # UV
106
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
107
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
108
+ # commonly ignored for libraries.
109
+ # uv.lock
110
+
111
+ # poetry
112
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
113
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
114
+ # commonly ignored for libraries.
115
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
116
+ # poetry.lock
117
+ # poetry.toml
118
+
119
+ # pdm
120
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
121
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
122
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
123
+ # pdm.lock
124
+ # pdm.toml
125
+ .pdm-python
126
+ .pdm-build/
127
+
128
+ # pixi
129
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
130
+ # pixi.lock
131
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
132
+ # in the .venv directory. It is recommended not to include this directory in version control.
133
+ .pixi
134
+
135
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
136
+ __pypackages__/
137
+
138
+ # Celery stuff
139
+ celerybeat-schedule
140
+ celerybeat.pid
141
+
142
+ # Redis
143
+ *.rdb
144
+ *.aof
145
+ *.pid
146
+
147
+ # RabbitMQ
148
+ mnesia/
149
+ rabbitmq/
150
+ rabbitmq-data/
151
+
152
+ # ActiveMQ
153
+ activemq-data/
154
+
155
+ # SageMath parsed files
156
+ *.sage.py
157
+
158
+ # Environments
159
+ .env
160
+ .envrc
161
+ .venv
162
+ env/
163
+ venv/
164
+ ENV/
165
+ env.bak/
166
+ venv.bak/
167
+
168
+ # Spyder project settings
169
+ .spyderproject
170
+ .spyproject
171
+
172
+ # Rope project settings
173
+ .ropeproject
174
+
175
+ # mkdocs documentation
176
+ /site
177
+
178
+ # mypy
179
+ .mypy_cache/
180
+ .dmypy.json
181
+ dmypy.json
182
+
183
+ # Pyre type checker
184
+ .pyre/
185
+
186
+ # pytype static type analyzer
187
+ .pytype/
188
+
189
+ # Cython debug symbols
190
+ cython_debug/
191
+
192
+ # PyCharm
193
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
194
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
195
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
196
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
197
+ # .idea/
198
+
199
+ # Abstra
200
+ # Abstra is an AI-powered process automation framework.
201
+ # Ignore directories containing user credentials, local state, and settings.
202
+ # Learn more at https://abstra.io/docs
203
+ .abstra/
204
+
205
+ # Visual Studio Code
206
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
207
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
208
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
209
+ # you could uncomment the following to ignore the entire vscode folder
210
+ # .vscode/
211
+
212
+ # Ruff stuff:
213
+ .ruff_cache/
214
+
215
+ # PyPI configuration file
216
+ .pypirc
217
+
218
+ # Marimo
219
+ marimo/_static/
220
+ marimo/_lsp/
221
+ __marimo__/
222
+
223
+ # Streamlit
224
+ .streamlit/secrets.toml
225
+
226
+ .DS_Store
227
+ .osgrep/
228
+ .osgrep
229
+ demo.db
230
+ demo.db-*
231
+ demos/areas_demo_async/outputs/
232
+ demos/areas_demo_async/cache/
233
+ demos/*.html
234
+ public-demos/_outputs_*/
@@ -0,0 +1,18 @@
1
+ repos:
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
+ rev: v5.0.0
4
+ hooks:
5
+ - id: trailing-whitespace
6
+ - id: end-of-file-fixer
7
+ - id: check-yaml
8
+ - id: check-toml
9
+ - id: check-added-large-files
10
+ args: ["--maxkb=500"]
11
+ - id: debug-statements
12
+
13
+ - repo: https://github.com/astral-sh/ruff-pre-commit
14
+ rev: v0.11.6
15
+ hooks:
16
+ - id: ruff
17
+ args: [--fix]
18
+ - id: ruff-format
@@ -0,0 +1,14 @@
1
+ {
2
+ "python.testing.pytestArgs": [
3
+ "tests"
4
+ ],
5
+ "python.testing.unittestEnabled": false,
6
+ "python.testing.pytestEnabled": true,
7
+ "python-envs.pythonProjects": [
8
+ {
9
+ "path": ".",
10
+ "envManager": "ms-python.python:venv",
11
+ "packageManager": "ms-python.python:pip"
12
+ }
13
+ ]
14
+ }
@@ -0,0 +1,93 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.4.0] - 2026-04-29
11
+
12
+ ### Breaking
13
+ - `DEFAULT_BASE_URL` is now `https://api.infrared.city/v2` (was `https://api.infrared.city`). The previous default returned `403 {"message":"Forbidden"}` on every call because the AWS API Gateway custom domain `api.infrared.city` only has `/v2`, `/v1`, and `/v1.1` base-path mappings — there is no no-prefix mapping. Users who pinned the old default explicitly (constructor arg or `INFRARED_BASE_URL` env var) need to add `/v2`; users who relied on the default are unaffected (silently changes from "always 403" to "works"). The `/v2` mapping points at the production REST API; `/v1` and `/v1.1` continue to route to the older API for callers that explicitly opt in. (#98)
14
+ - `merge_area_jobs` (and therefore `run_area_and_wait`) now raises a new `AreaRunError` when every job in an area run terminates without producing a usable tile. Previously it returned an `AreaResult` with `succeeded_jobs=0` and an all-NaN merged grid — visually indistinguishable from a successful run unless the caller manually inspected `succeeded_jobs`. Callers that did not check `succeeded_jobs` will see exceptions in this scenario; wrap calls in `try ... except AreaRunError` to handle. Partial failures (≥1 success + ≥N failures) still return an `AreaResult` so callers don't lose the data they did get; jobs still pending also still return a result. The exception carries `failed_jobs`, `skipped_jobs`, `total_jobs`. The "no usable output" gate covers four paths: every job's server status was Failed; every download permanently errored; every grid was the wrong shape; every grid extractor raised. (#95)
15
+
16
+ ### Added
17
+ - `AreaRunError` exception — exported from the top-level package alongside `AreaTimeoutError` and `TiledRunError`. (#95)
18
+ - `AreaBuildings.failed_tiles: list[dict]` — partial-tile failures from `client.buildings.get_area(...)` are now surfaced on the returned object (each entry: `tile_id`, `row`, `col`, `error`). Empty list when every tile succeeded. The pre-existing log warning is unchanged. Same structural fix is recommended for `AreaVegetation` / `AreaGroundMaterials` next; tracked separately. (#95)
19
+
20
+ ### Fixed
21
+ - README weather example: replaced the obsolete `{"identifier": ..., "name": ...}` station-dict shape with the actual response (`uuid`, `fileName`, `location_data`) and updated the `filter_weather_data(identifier=locations[0]["uuid"], ...)` call accordingly. (#95)
22
+ - README quick-start examples for UTCI / TCS / PWC switched from a multi-month `TimePeriod` (which currently fails server-side with `DNI length 828 != sun_vectors 270`) to single-month windows that round-trip cleanly. Each affected snippet has a callout explaining the constraint. (#97)
23
+ - README Output Reference and AreaResult sections gained a `None`-fallback note for `min_legend` / `max_legend` — the API does not currently emit these for any analysis, so naive `zmin=result.min_legend` plotting passes `None` to matplotlib/Plotly. Snippets now use `np.nanmin/np.nanmax(merged_grid)` as the fallback. (#97)
24
+ - README `Error Handling` section now lists `AreaRunError`, `AreaTimeoutError`, and `TiledRunError` alongside the job-level error table; previously these area-level exceptions had no documented surface despite being raisable from the headline `run_area_and_wait` example. (#95)
25
+ - README "Install from source" block removed (referenced the private SDK source repo). `CONTRIBUTING.md` removed entirely (private repo, no external contributors). (#99, follow-ups)
26
+
27
+ ### CI / dev infrastructure
28
+ - CI pipeline finally green: `ruff check`, `ruff format --check`, `pyright`, and `pytest --cov` all pass on Python 3.11/3.12/3.13. Previously every PR for ~3 days landed on a red pipeline (both v0.3.0 and v0.3.1 release merges shipped on red CI). Causes were structural lint debt (`E402` in `buildings/service.py`), 37 files drifted from the formatter, missing dev deps (`pytest-cov`), and the workflow calling `mypy` while the project configures `pyright`. (#102)
29
+ - `pytest-cov>=5.0` added to the `dev` dependency group.
30
+ - Workflow typecheck step switched from `mypy` to `pyright` to match the configured tool.
31
+ - Latent pyright errors fixed by widening 7 over-narrow signatures in `_area/_submission.py` and `tiling/tiles.py` (no behaviour change).
32
+
33
+ ## [0.3.1] - 2026-04-29
34
+
35
+ ### Added
36
+ - `infrared_sdk.preflight.estimate_sun_context_loss(...)` — client-side pre-flight check that flags `direct-sun-hours` / daylight / solar / thermal-comfort configurations whose low-sun shadows exceed the per-tile geometry buffer. Returns a `SunContextResult` (`info` / `ok` / `marginal` / `warning` / `critical`) with a human-readable message. Pure math; no API calls; never raises (`#86`).
37
+ - `CLAUDE.md` — onboarding guide for AI assistants and human contributors covering repo layout, branching, conventions, and the PyPI release recipe.
38
+
39
+ ### Fixed
40
+ - README: cookbook notebook URLs now point at `cookbook/notebooks/` in `Infrared-city/infrared-skills` (previously 404'd at the repo root) (#90).
41
+ - README: top-of-file link bar to https://infrared.city/docs/sdk/, the skills repo, and the knowledge base. Dropped CI badge that pointed at a non-existent repo (#92).
42
+
43
+ ## [0.3.0] - 2026-04-28
44
+
45
+ ### Added
46
+ - `TimePeriod` now validates calendar inputs: end-before-start, zero-length windows, and impossible day-of-month combinations (April 31, February 30, June 31, September 31, November 31) raise `ValidationError`. February 29 is accepted because `TimePeriod` carries no year context. Year-wrap windows (e.g. Nov→Feb) are not supported — split them into two periods.
47
+ - Typed exception hierarchy mirrored across service clients: `WeatherServiceError`, `BuildingsServiceError`, plus subclasses, and the `JobsServiceClient` hierarchy under `InfraredJobError` (#79). Response bodies live on `.response_body`, kept out of `args[0]` so they are not captured in default error-tracking message fields.
48
+ - HTTP timeouts on every outbound call across the 5 service clients (`(10, 300)` for control plane, `(10, 600)` for S3 downloads) (#79).
49
+ - `Retry-After` header is honored across the area orchestration path (submission, polling, result download) — when present on a 429/503, the SDK sleeps for the advertised duration instead of using jittered backoff. The header value is propagated through the typed exception hierarchy (`JobSubmitError.retry_after`, `JobPollError.retry_after`, `ResultsDownloadError.retry_after`) so the area path retries against the typed exceptions it actually catches. HTTP-date format is intentionally not parsed; only delta-seconds are honored.
50
+
51
+ ### Changed
52
+ - **Breaking**: `AreaState.from_job_states({})` now returns status `"empty"` instead of `"completed"`. Code that branches on `state.status == "completed"` for empty schedules will silently stop matching (#76). Migrate to either `state.is_complete` or `state.status in {"completed", "empty"}`.
53
+ - **Breaking**: error response bodies that previously could be reached via `exc.args[1]` now live exclusively on the typed `.response_body` attribute (#79).
54
+ - `AreaSchedule.jobs` is now a frozen `MappingProxyType` rather than a mutable dict. Direct mutation raises `TypeError`; rebuild a new schedule instead (#76).
55
+ - `TilingConfig.from_dict()` tolerates unknown keys, so newer configs from the server roll forward without breaking older clients (#78).
56
+ - `api_key` is wrapped in a `pydantic.SecretStr` to prevent plaintext leakage in logs and repr output (#72).
57
+
58
+ ### Fixed
59
+ - Continent-scale polygons are pre-capped before tile materialization to avoid OOM (#75).
60
+ - Numpy polygon coordinates are canonicalized for dtype-stable tile IDs across float32/float64 inputs (#77).
61
+ - Zero-area polygons now raise `PolygonValidationError` instead of producing empty schedules silently (#74).
62
+ - `"nan"` strings in API responses are coerced to `None` rather than producing string fields where floats are expected (#74).
63
+ - `AreaResult.to_dict()` always emits `min_legend` and `max_legend` keys (set to `None` when no legend bounds are available) for stable downstream consumers (#73).
64
+
65
+ ### Known limitations
66
+ - 100k-vertex polygons hit an O(n²) self-intersection check that can hang. Batch polygons through a simplifier first or split into smaller pieces. A sweep-line replacement is on the v0.3.x backlog.
67
+
68
+ ## [0.2.0] - 2025-04-15
69
+
70
+ ### Added
71
+ - Area orchestration API (`run_area`, `run_area_multi`, `run_area_and_wait`) for multi-tile polygon analysis
72
+ - Automatic polygon tiling with 512m tiles and 256m overlap blending
73
+ - `get_buildings_in_area()` for fetching, deduplicating, and transforming buildings across tiles
74
+ - Model-grouped tiling configuration for wind and solar analyses
75
+ - `gen_grid_image()` parameters: `analysis_type`, `criteria`, `subtype`
76
+ - Python 3.11 support with strict type checking
77
+ - Vegetation and ground materials pipeline (fetch, dedup, tile assignment)
78
+ - `x-infrared-application: sdk` header on all API requests
79
+
80
+ ### Fixed
81
+ - Type errors for Python 3.11 strict type checking
82
+ - Single-line f-strings for Python 3.11 compatibility
83
+
84
+ ## [0.1.0] - 2024-12-01
85
+
86
+ ### Added
87
+ - Core analysis types: wind speed, pedestrian wind comfort, daylight availability, direct sun hours, sky view factors, solar radiation, thermal comfort index, thermal comfort statistics
88
+ - Async job system with exponential backoff polling
89
+ - Webhook integration for job status notifications
90
+ - Buildings API with DotBim, GeoJSON, and Mesh output formats
91
+ - Weather data API (search stations, fetch data, filter by time period)
92
+ - Grid image generation utility
93
+ - Context manager support for HTTP session lifecycle