rhinestone 0.1.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.
- rhinestone-0.1.0/LICENSE +21 -0
- rhinestone-0.1.0/PKG-INFO +140 -0
- rhinestone-0.1.0/README.md +113 -0
- rhinestone-0.1.0/pyproject.toml +87 -0
- rhinestone-0.1.0/pyproject.toml.orig +73 -0
- rhinestone-0.1.0/src/rhinestone/__init__.py +60 -0
- rhinestone-0.1.0/src/rhinestone/_http.py +152 -0
- rhinestone-0.1.0/src/rhinestone/adapters/__init__.py +33 -0
- rhinestone-0.1.0/src/rhinestone/adapters/execution/__init__.py +17 -0
- rhinestone-0.1.0/src/rhinestone/adapters/execution/_resource.py +14 -0
- rhinestone-0.1.0/src/rhinestone/adapters/execution/base.py +47 -0
- rhinestone-0.1.0/src/rhinestone/adapters/execution/gdal/README.md +10 -0
- rhinestone-0.1.0/src/rhinestone/adapters/execution/gdal/__init__.py +114 -0
- rhinestone-0.1.0/src/rhinestone/adapters/execution/json_service/README.md +10 -0
- rhinestone-0.1.0/src/rhinestone/adapters/execution/json_service/__init__.py +103 -0
- rhinestone-0.1.0/src/rhinestone/adapters/execution/pyogrio/README.md +10 -0
- rhinestone-0.1.0/src/rhinestone/adapters/execution/pyogrio/__init__.py +44 -0
- rhinestone-0.1.0/src/rhinestone/adapters/execution/rasterio/README.md +9 -0
- rhinestone-0.1.0/src/rhinestone/adapters/execution/rasterio/__init__.py +38 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/__init__.py +29 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/_knowledge.py +59 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/_uri.py +20 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/base.py +234 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/ckan/README.md +12 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/ckan/__init__.py +176 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/ckan/schema.json +11 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/dcat/README.md +12 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/dcat/__init__.py +178 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/dcat/schema.json +13 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/direct/README.md +10 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/direct/__init__.py +56 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/direct/schema.json +17 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/gsi_fundamental/README.md +11 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/gsi_fundamental/__init__.py +43 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/gsi_fundamental/schema.json +32 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/odpt/README.md +11 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/odpt/__init__.py +140 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/odpt/schema.json +15 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/ogc/README.md +12 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/ogc/__init__.py +171 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/ogc/schema.json +12 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/plateau/README.md +12 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/plateau/__init__.py +96 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/plateau/schema.json +24 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/search_ckan_jp/__init__.py +154 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/search_ckan_jp/schema.json +9 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/stac/README.md +11 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/stac/__init__.py +188 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/stac/schema.json +13 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/static/__init__.py +217 -0
- rhinestone-0.1.0/src/rhinestone/adapters/source/static/schema.json +10 -0
- rhinestone-0.1.0/src/rhinestone/api.py +396 -0
- rhinestone-0.1.0/src/rhinestone/catalogs/__init__.py +147 -0
- rhinestone-0.1.0/src/rhinestone/catalogs/sources.json +188 -0
- rhinestone-0.1.0/src/rhinestone/errors.py +69 -0
- rhinestone-0.1.0/src/rhinestone/execution.py +39 -0
- rhinestone-0.1.0/src/rhinestone/models.py +342 -0
- rhinestone-0.1.0/src/rhinestone/pipeline.py +96 -0
- rhinestone-0.1.0/src/rhinestone/py.typed +0 -0
- rhinestone-0.1.0/src/rhinestone/registry.py +99 -0
- rhinestone-0.1.0/src/rhinestone/resolution.py +102 -0
- rhinestone-0.1.0/src/rhinestone/search.py +172 -0
- rhinestone-0.1.0/src/rhinestone/security.py +231 -0
- rhinestone-0.1.0/src/rhinestone/sources.py +31 -0
rhinestone-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 kitazawa
|
|
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,140 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rhinestone
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Knowledge and specification layer for Japanese public and geospatial data
|
|
5
|
+
Keywords: geospatial,open-data,japan,data-access
|
|
6
|
+
Author: kitazawa
|
|
7
|
+
Author-email: kitazawa <88121050+U-KITAZAWA@users.noreply.github.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Dist: jsonschema>=4.18,<5
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Project-URL: Homepage, https://github.com/u-kitazawa/rhinestone
|
|
23
|
+
Project-URL: Repository, https://github.com/u-kitazawa/rhinestone
|
|
24
|
+
Project-URL: Issues, https://github.com/u-kitazawa/rhinestone/issues
|
|
25
|
+
Project-URL: Documentation, https://github.com/u-kitazawa/rhinestone/tree/main/docs
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# Rhinestone
|
|
29
|
+
|
|
30
|
+
Rhinestoneは、日本の公的・地理空間データを探し、利用可能なResourceへ解決し、既存の専門ライブラリへ渡すPythonライブラリです。
|
|
31
|
+
|
|
32
|
+
利用者が覚える中心概念は次の4つです。
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
Catalog -> Provider -> Result -> Resource
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- `Catalog`: Rhinestoneが知っているProviderの集合
|
|
39
|
+
- `Provider`: データを提供する主体・サービス
|
|
40
|
+
- `Result`: 検索で見つかった候補
|
|
41
|
+
- `Resource`: 実際に利用できる具体的なデータ
|
|
42
|
+
|
|
43
|
+
## 対象ユーザー
|
|
44
|
+
|
|
45
|
+
Rhinestoneは、次のような利用者を対象にしています。
|
|
46
|
+
|
|
47
|
+
- 日本の行政・公的オープンデータをPythonから横断的に探索したい利用者
|
|
48
|
+
- GIS・リモートセンシングの研究者
|
|
49
|
+
- 公的データを扱うデータエンジニア・データ基盤開発者
|
|
50
|
+
- Rasterio、GDAL、pyogrioなどへ渡す前のProvider固有処理を共通化したい利用者
|
|
51
|
+
|
|
52
|
+
Rhinestoneは、Catalogに構成されたProvider内のデータを検索してResultとして発見し、Resourceへ解決することを担当します。実際のGIS処理やデータ解析は既存の専門ライブラリへ委譲します。
|
|
53
|
+
|
|
54
|
+
## 対象外のユースケース
|
|
55
|
+
|
|
56
|
+
RhinestoneはGIS処理ライブラリやワークフローエンジンではありません。次の用途には、そのまま利用できないか、追加の検討が必要です。
|
|
57
|
+
|
|
58
|
+
- GISの空間演算・形式変換・解析そのもの
|
|
59
|
+
- ETLやワークフローの実行基盤
|
|
60
|
+
- 外部RuntimeやProvider固有の制約を完全に隠蔽すること
|
|
61
|
+
- 0.1.x時点で公開APIの長期固定を前提とする本番システム
|
|
62
|
+
|
|
63
|
+
対応するProvider、Runtime、形式の範囲は[Compatibility](docs/compatibility.md)を、Runtimeの注入方法は[Configuration](docs/configuration.md)を参照してください。RhinestoneはAlpha版のため、公開APIは今後変更される可能性があります。
|
|
64
|
+
|
|
65
|
+
## インストール
|
|
66
|
+
|
|
67
|
+
```console
|
|
68
|
+
python -m pip install rhinestone
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## 基本的な使い方
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from rhinestone import configure
|
|
75
|
+
from rhinestone.catalogs import BUILTIN
|
|
76
|
+
|
|
77
|
+
app = configure(catalog=BUILTIN)
|
|
78
|
+
results = app.search(text="河川")
|
|
79
|
+
resource = app.resolve(results[0])
|
|
80
|
+
|
|
81
|
+
print(resource.uri)
|
|
82
|
+
print(resource.metadata)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`BUILTIN`はRhinestoneが提供する組み込みCatalogです。`search()`はCatalogに構成されたProvider内のデータを検索してResultを返し、検索結果は`app.resolve(result)`で直接Resourceへ解決できます。
|
|
86
|
+
複数Provider時の整数indexingは構成したProvider順の走査用であり、Providerを横断した関連度rankingではありません。詳細は[Search resultの順序](docs/search.md#結果の順序)を参照してください。
|
|
87
|
+
|
|
88
|
+
検索を使わず、既知のProviderを選んで構成することもできます。
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from rhinestone import Catalog, Provider, configure
|
|
92
|
+
|
|
93
|
+
catalog = Catalog((
|
|
94
|
+
Provider(
|
|
95
|
+
id="my-stac",
|
|
96
|
+
adapter_type="stac",
|
|
97
|
+
settings={"endpoint": "https://stac.example/api"},
|
|
98
|
+
),
|
|
99
|
+
))
|
|
100
|
+
app = configure(catalog=catalog)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## RuntimeとCredential
|
|
104
|
+
|
|
105
|
+
GDAL、Rasterio、pyogrio、RDFLibなどの外部Runtimeは利用者が用意します。API keyやtokenはCredentialとして分離します。
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
app = configure(
|
|
109
|
+
catalog=BUILTIN,
|
|
110
|
+
dependencies={"rasterio": rasterio},
|
|
111
|
+
credentials={"odpt": lambda: odpt_consumer_key},
|
|
112
|
+
)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
HTTP通信はRhinestoneに組み込まれています。
|
|
116
|
+
|
|
117
|
+
## 内部アーキテクチャ
|
|
118
|
+
|
|
119
|
+
利用者が意識する必要のない`Source`、`Config`、`AccessPlan`、`Resolver`、各種Adapter、Registryは内部実装です。内部では責務分離のためにこれらの段階を保持しますが、通常の利用導線には出しません。
|
|
120
|
+
|
|
121
|
+
RhinestoneはGIS I/O、形式変換、空間演算、データ解析を実装せず、解決済みResourceを既存の専門Runtimeへ渡します。
|
|
122
|
+
|
|
123
|
+
## ドキュメント
|
|
124
|
+
|
|
125
|
+
- [Documentation](docs/index.md)
|
|
126
|
+
- [Getting started](docs/getting-started.md)
|
|
127
|
+
- [Configuration](docs/configuration.md)
|
|
128
|
+
- [API reference](docs/api.md)
|
|
129
|
+
- [Compatibility](docs/compatibility.md)
|
|
130
|
+
- [Runtime guide](docs/runtimes.md)
|
|
131
|
+
- [API stability and release policy](docs/release-policy.md)
|
|
132
|
+
|
|
133
|
+
## 開発環境
|
|
134
|
+
|
|
135
|
+
```console
|
|
136
|
+
uv sync --dev
|
|
137
|
+
bash scripts/check.sh
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
MIT Licenseです。
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Rhinestone
|
|
2
|
+
|
|
3
|
+
Rhinestoneは、日本の公的・地理空間データを探し、利用可能なResourceへ解決し、既存の専門ライブラリへ渡すPythonライブラリです。
|
|
4
|
+
|
|
5
|
+
利用者が覚える中心概念は次の4つです。
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
Catalog -> Provider -> Result -> Resource
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
- `Catalog`: Rhinestoneが知っているProviderの集合
|
|
12
|
+
- `Provider`: データを提供する主体・サービス
|
|
13
|
+
- `Result`: 検索で見つかった候補
|
|
14
|
+
- `Resource`: 実際に利用できる具体的なデータ
|
|
15
|
+
|
|
16
|
+
## 対象ユーザー
|
|
17
|
+
|
|
18
|
+
Rhinestoneは、次のような利用者を対象にしています。
|
|
19
|
+
|
|
20
|
+
- 日本の行政・公的オープンデータをPythonから横断的に探索したい利用者
|
|
21
|
+
- GIS・リモートセンシングの研究者
|
|
22
|
+
- 公的データを扱うデータエンジニア・データ基盤開発者
|
|
23
|
+
- Rasterio、GDAL、pyogrioなどへ渡す前のProvider固有処理を共通化したい利用者
|
|
24
|
+
|
|
25
|
+
Rhinestoneは、Catalogに構成されたProvider内のデータを検索してResultとして発見し、Resourceへ解決することを担当します。実際のGIS処理やデータ解析は既存の専門ライブラリへ委譲します。
|
|
26
|
+
|
|
27
|
+
## 対象外のユースケース
|
|
28
|
+
|
|
29
|
+
RhinestoneはGIS処理ライブラリやワークフローエンジンではありません。次の用途には、そのまま利用できないか、追加の検討が必要です。
|
|
30
|
+
|
|
31
|
+
- GISの空間演算・形式変換・解析そのもの
|
|
32
|
+
- ETLやワークフローの実行基盤
|
|
33
|
+
- 外部RuntimeやProvider固有の制約を完全に隠蔽すること
|
|
34
|
+
- 0.1.x時点で公開APIの長期固定を前提とする本番システム
|
|
35
|
+
|
|
36
|
+
対応するProvider、Runtime、形式の範囲は[Compatibility](docs/compatibility.md)を、Runtimeの注入方法は[Configuration](docs/configuration.md)を参照してください。RhinestoneはAlpha版のため、公開APIは今後変更される可能性があります。
|
|
37
|
+
|
|
38
|
+
## インストール
|
|
39
|
+
|
|
40
|
+
```console
|
|
41
|
+
python -m pip install rhinestone
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 基本的な使い方
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from rhinestone import configure
|
|
48
|
+
from rhinestone.catalogs import BUILTIN
|
|
49
|
+
|
|
50
|
+
app = configure(catalog=BUILTIN)
|
|
51
|
+
results = app.search(text="河川")
|
|
52
|
+
resource = app.resolve(results[0])
|
|
53
|
+
|
|
54
|
+
print(resource.uri)
|
|
55
|
+
print(resource.metadata)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`BUILTIN`はRhinestoneが提供する組み込みCatalogです。`search()`はCatalogに構成されたProvider内のデータを検索してResultを返し、検索結果は`app.resolve(result)`で直接Resourceへ解決できます。
|
|
59
|
+
複数Provider時の整数indexingは構成したProvider順の走査用であり、Providerを横断した関連度rankingではありません。詳細は[Search resultの順序](docs/search.md#結果の順序)を参照してください。
|
|
60
|
+
|
|
61
|
+
検索を使わず、既知のProviderを選んで構成することもできます。
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from rhinestone import Catalog, Provider, configure
|
|
65
|
+
|
|
66
|
+
catalog = Catalog((
|
|
67
|
+
Provider(
|
|
68
|
+
id="my-stac",
|
|
69
|
+
adapter_type="stac",
|
|
70
|
+
settings={"endpoint": "https://stac.example/api"},
|
|
71
|
+
),
|
|
72
|
+
))
|
|
73
|
+
app = configure(catalog=catalog)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## RuntimeとCredential
|
|
77
|
+
|
|
78
|
+
GDAL、Rasterio、pyogrio、RDFLibなどの外部Runtimeは利用者が用意します。API keyやtokenはCredentialとして分離します。
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
app = configure(
|
|
82
|
+
catalog=BUILTIN,
|
|
83
|
+
dependencies={"rasterio": rasterio},
|
|
84
|
+
credentials={"odpt": lambda: odpt_consumer_key},
|
|
85
|
+
)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
HTTP通信はRhinestoneに組み込まれています。
|
|
89
|
+
|
|
90
|
+
## 内部アーキテクチャ
|
|
91
|
+
|
|
92
|
+
利用者が意識する必要のない`Source`、`Config`、`AccessPlan`、`Resolver`、各種Adapter、Registryは内部実装です。内部では責務分離のためにこれらの段階を保持しますが、通常の利用導線には出しません。
|
|
93
|
+
|
|
94
|
+
RhinestoneはGIS I/O、形式変換、空間演算、データ解析を実装せず、解決済みResourceを既存の専門Runtimeへ渡します。
|
|
95
|
+
|
|
96
|
+
## ドキュメント
|
|
97
|
+
|
|
98
|
+
- [Documentation](docs/index.md)
|
|
99
|
+
- [Getting started](docs/getting-started.md)
|
|
100
|
+
- [Configuration](docs/configuration.md)
|
|
101
|
+
- [API reference](docs/api.md)
|
|
102
|
+
- [Compatibility](docs/compatibility.md)
|
|
103
|
+
- [Runtime guide](docs/runtimes.md)
|
|
104
|
+
- [API stability and release policy](docs/release-policy.md)
|
|
105
|
+
|
|
106
|
+
## 開発環境
|
|
107
|
+
|
|
108
|
+
```console
|
|
109
|
+
uv sync --dev
|
|
110
|
+
bash scripts/check.sh
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
MIT Licenseです。
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "rhinestone"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Knowledge and specification layer for Japanese public and geospatial data"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
requires-python = ">=3.10"
|
|
9
|
+
keywords = [
|
|
10
|
+
"geospatial",
|
|
11
|
+
"open-data",
|
|
12
|
+
"japan",
|
|
13
|
+
"data-access",
|
|
14
|
+
]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 3 - Alpha",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"License :: OSI Approved :: MIT License",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Typing :: Typed",
|
|
26
|
+
]
|
|
27
|
+
dependencies = ["jsonschema>=4.18,<5"]
|
|
28
|
+
|
|
29
|
+
[[project.authors]]
|
|
30
|
+
name = "kitazawa"
|
|
31
|
+
email = "88121050+U-KITAZAWA@users.noreply.github.com"
|
|
32
|
+
|
|
33
|
+
[project.urls]
|
|
34
|
+
Homepage = "https://github.com/u-kitazawa/rhinestone"
|
|
35
|
+
Repository = "https://github.com/u-kitazawa/rhinestone"
|
|
36
|
+
Issues = "https://github.com/u-kitazawa/rhinestone/issues"
|
|
37
|
+
Documentation = "https://github.com/u-kitazawa/rhinestone/tree/main/docs"
|
|
38
|
+
|
|
39
|
+
[dependency-groups]
|
|
40
|
+
dev = [
|
|
41
|
+
"rdflib>=6,<7",
|
|
42
|
+
"pyright>=1.1.339,<1.1.390",
|
|
43
|
+
"pytest>=7.4.4,<8",
|
|
44
|
+
"pytest-cov>=4.1,<5",
|
|
45
|
+
"ruff>=0.12.12,<0.13",
|
|
46
|
+
"mkdocs-material>=9.7.7",
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
[tool.coverage.run]
|
|
50
|
+
source = ["rhinestone"]
|
|
51
|
+
|
|
52
|
+
[tool.pytest.ini_options]
|
|
53
|
+
addopts = [
|
|
54
|
+
"--cov=rhinestone",
|
|
55
|
+
"--cov-branch",
|
|
56
|
+
"--cov-report=term-missing",
|
|
57
|
+
"--cov-fail-under=100",
|
|
58
|
+
]
|
|
59
|
+
testpaths = ["tests"]
|
|
60
|
+
|
|
61
|
+
[tool.ruff]
|
|
62
|
+
line-length = 88
|
|
63
|
+
target-version = "py37"
|
|
64
|
+
|
|
65
|
+
[tool.ruff.lint]
|
|
66
|
+
select = [
|
|
67
|
+
"E4",
|
|
68
|
+
"E7",
|
|
69
|
+
"E9",
|
|
70
|
+
"F",
|
|
71
|
+
"I",
|
|
72
|
+
"UP",
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
[tool.pyright]
|
|
76
|
+
include = [
|
|
77
|
+
"src",
|
|
78
|
+
"tests",
|
|
79
|
+
]
|
|
80
|
+
pythonVersion = "3.10"
|
|
81
|
+
typeCheckingMode = "strict"
|
|
82
|
+
venv = ".venv"
|
|
83
|
+
venvPath = "."
|
|
84
|
+
|
|
85
|
+
[build-system]
|
|
86
|
+
requires = ["uv_build>=0.12.9,<0.13.0"]
|
|
87
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "rhinestone"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Knowledge and specification layer for Japanese public and geospatial data"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "kitazawa", email = "88121050+U-KITAZAWA@users.noreply.github.com" }
|
|
10
|
+
]
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
keywords = ["geospatial", "open-data", "japan", "data-access"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 3 - Alpha",
|
|
15
|
+
"Intended Audience :: Developers",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
"Typing :: Typed",
|
|
24
|
+
]
|
|
25
|
+
dependencies = [
|
|
26
|
+
"jsonschema>=4.18,<5",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
Homepage = "https://github.com/u-kitazawa/rhinestone"
|
|
31
|
+
Repository = "https://github.com/u-kitazawa/rhinestone"
|
|
32
|
+
Issues = "https://github.com/u-kitazawa/rhinestone/issues"
|
|
33
|
+
Documentation = "https://github.com/u-kitazawa/rhinestone/tree/main/docs"
|
|
34
|
+
|
|
35
|
+
[dependency-groups]
|
|
36
|
+
dev = [
|
|
37
|
+
"rdflib>=6,<7",
|
|
38
|
+
"pyright>=1.1.339,<1.1.390",
|
|
39
|
+
"pytest>=7.4.4,<8",
|
|
40
|
+
"pytest-cov>=4.1,<5",
|
|
41
|
+
"ruff>=0.12.12,<0.13",
|
|
42
|
+
"mkdocs-material>=9.7.7",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
[tool.coverage.run]
|
|
46
|
+
source = ["rhinestone"]
|
|
47
|
+
|
|
48
|
+
[build-system]
|
|
49
|
+
requires = ["uv_build>=0.12.9,<0.13.0"]
|
|
50
|
+
build-backend = "uv_build"
|
|
51
|
+
|
|
52
|
+
[tool.pytest.ini_options]
|
|
53
|
+
addopts = [
|
|
54
|
+
"--cov=rhinestone",
|
|
55
|
+
"--cov-branch",
|
|
56
|
+
"--cov-report=term-missing",
|
|
57
|
+
"--cov-fail-under=100",
|
|
58
|
+
]
|
|
59
|
+
testpaths = ["tests"]
|
|
60
|
+
|
|
61
|
+
[tool.ruff]
|
|
62
|
+
line-length = 88
|
|
63
|
+
target-version = "py37"
|
|
64
|
+
|
|
65
|
+
[tool.ruff.lint]
|
|
66
|
+
select = ["E4", "E7", "E9", "F", "I", "UP"]
|
|
67
|
+
|
|
68
|
+
[tool.pyright]
|
|
69
|
+
include = ["src", "tests"]
|
|
70
|
+
pythonVersion = "3.10"
|
|
71
|
+
typeCheckingMode = "strict"
|
|
72
|
+
venv = ".venv"
|
|
73
|
+
venvPath = "."
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Rhinestone public package."""
|
|
2
|
+
|
|
3
|
+
from . import sources
|
|
4
|
+
from .api import Rhinestone, configure
|
|
5
|
+
from .catalogs import Catalog
|
|
6
|
+
from .models import (
|
|
7
|
+
AccessPlan,
|
|
8
|
+
Config,
|
|
9
|
+
Dependencies,
|
|
10
|
+
FileAccessPlan,
|
|
11
|
+
LibraryName,
|
|
12
|
+
Metadata,
|
|
13
|
+
Provenance,
|
|
14
|
+
Provider,
|
|
15
|
+
RemoteDatasetPlan,
|
|
16
|
+
Resource,
|
|
17
|
+
ResourceCandidate,
|
|
18
|
+
Result,
|
|
19
|
+
Runtime,
|
|
20
|
+
RuntimeFactory,
|
|
21
|
+
SearchDiagnostic,
|
|
22
|
+
SearchQuery,
|
|
23
|
+
SearchResult,
|
|
24
|
+
ServiceQueryPlan,
|
|
25
|
+
Source,
|
|
26
|
+
SourceDefinition,
|
|
27
|
+
)
|
|
28
|
+
from .search import SearchResults
|
|
29
|
+
from .security import DestinationPolicy, DestinationRule, NetworkPolicyLevel
|
|
30
|
+
|
|
31
|
+
__all__ = [
|
|
32
|
+
"AccessPlan",
|
|
33
|
+
"Catalog",
|
|
34
|
+
"Config",
|
|
35
|
+
"DestinationPolicy",
|
|
36
|
+
"DestinationRule",
|
|
37
|
+
"Dependencies",
|
|
38
|
+
"FileAccessPlan",
|
|
39
|
+
"LibraryName",
|
|
40
|
+
"Metadata",
|
|
41
|
+
"NetworkPolicyLevel",
|
|
42
|
+
"Provenance",
|
|
43
|
+
"Provider",
|
|
44
|
+
"RemoteDatasetPlan",
|
|
45
|
+
"Rhinestone",
|
|
46
|
+
"Resource",
|
|
47
|
+
"ResourceCandidate",
|
|
48
|
+
"Result",
|
|
49
|
+
"Runtime",
|
|
50
|
+
"RuntimeFactory",
|
|
51
|
+
"SearchDiagnostic",
|
|
52
|
+
"SearchQuery",
|
|
53
|
+
"SearchResult",
|
|
54
|
+
"SearchResults",
|
|
55
|
+
"ServiceQueryPlan",
|
|
56
|
+
"Source",
|
|
57
|
+
"SourceDefinition",
|
|
58
|
+
"configure",
|
|
59
|
+
"sources",
|
|
60
|
+
]
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""Built-in standard-library HTTP transport."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Any, Mapping, Optional, cast
|
|
5
|
+
from urllib.error import HTTPError
|
|
6
|
+
from urllib.parse import urlencode, urlsplit, urlunsplit
|
|
7
|
+
from urllib.request import HTTPRedirectHandler, Request, build_opener, urlopen
|
|
8
|
+
|
|
9
|
+
from .errors import ProviderResponseError
|
|
10
|
+
|
|
11
|
+
_TIMEOUT_SECONDS = 30
|
|
12
|
+
_DEFAULT_HEADERS = {
|
|
13
|
+
"Accept": "application/json",
|
|
14
|
+
"User-Agent": "rhinestone",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class _JsonIntegerDecodeError(ValueError):
|
|
19
|
+
"""JSON integer conversion failed inside the decoder."""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _parse_json_int(value: str) -> int:
|
|
23
|
+
try:
|
|
24
|
+
return int(value)
|
|
25
|
+
except ValueError as error:
|
|
26
|
+
raise _JsonIntegerDecodeError from error
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class JsonDocument(dict[str, Any]):
|
|
30
|
+
"""Decoded JSON object together with the URI that supplied it."""
|
|
31
|
+
|
|
32
|
+
def __init__(self, value: Mapping[str, Any], response_uri: str) -> None:
|
|
33
|
+
super().__init__(value)
|
|
34
|
+
self.response_uri = response_uri
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def get_json(
|
|
38
|
+
url: str,
|
|
39
|
+
params: Mapping[str, Any],
|
|
40
|
+
headers: Optional[Mapping[str, str]] = None,
|
|
41
|
+
) -> Any:
|
|
42
|
+
"""Fetch and decode JSON over HTTP using the standard library."""
|
|
43
|
+
request = _request(url, params, headers)
|
|
44
|
+
opener = (
|
|
45
|
+
build_opener(_NoRedirectHandler())
|
|
46
|
+
if getattr(headers, "_rhinestone_no_redirects", False)
|
|
47
|
+
else None
|
|
48
|
+
)
|
|
49
|
+
open_request = opener.open if opener is not None else urlopen
|
|
50
|
+
with open_request(request, timeout=_TIMEOUT_SECONDS) as response:
|
|
51
|
+
try:
|
|
52
|
+
decoded = json.load(response, parse_int=_parse_json_int)
|
|
53
|
+
except (
|
|
54
|
+
UnicodeDecodeError,
|
|
55
|
+
json.JSONDecodeError,
|
|
56
|
+
_JsonIntegerDecodeError,
|
|
57
|
+
):
|
|
58
|
+
raise ProviderResponseError("Provider response is not valid JSON") from None
|
|
59
|
+
if isinstance(decoded, Mapping):
|
|
60
|
+
response_uri = getattr(response, "geturl", lambda: request.full_url)()
|
|
61
|
+
return JsonDocument(
|
|
62
|
+
cast(Mapping[str, Any], decoded), response_uri or request.full_url
|
|
63
|
+
)
|
|
64
|
+
return decoded
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def get_text(url: str) -> str:
|
|
68
|
+
"""Fetch a text document without following HTTP redirects."""
|
|
69
|
+
request = Request(url, headers={"User-Agent": "rhinestone"})
|
|
70
|
+
opener = build_opener(_NoRedirectHandler())
|
|
71
|
+
with opener.open(request, timeout=_TIMEOUT_SECONDS) as response:
|
|
72
|
+
charset = response.headers.get_content_charset() or "utf-8"
|
|
73
|
+
return response.read().decode(charset)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class JsonServiceRuntime:
|
|
77
|
+
"""Small requests-compatible runtime used by ``JsonServiceAdapter``."""
|
|
78
|
+
|
|
79
|
+
def get(
|
|
80
|
+
self,
|
|
81
|
+
url: str,
|
|
82
|
+
*,
|
|
83
|
+
params: Mapping[str, Any],
|
|
84
|
+
headers: Mapping[str, str],
|
|
85
|
+
timeout: int,
|
|
86
|
+
allow_redirects: bool,
|
|
87
|
+
) -> "JsonResponse":
|
|
88
|
+
request = _request(url, params, headers)
|
|
89
|
+
opener = build_opener(_NoRedirectHandler())
|
|
90
|
+
try:
|
|
91
|
+
response = opener.open(request, timeout=timeout)
|
|
92
|
+
except HTTPError as error:
|
|
93
|
+
response = error
|
|
94
|
+
with response:
|
|
95
|
+
charset = response.headers.get_content_charset() or "utf-8"
|
|
96
|
+
status_code = cast(int, response.getcode())
|
|
97
|
+
return JsonResponse(status_code, response.read(), charset)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class JsonResponse:
|
|
101
|
+
"""Subset of the requests response contract used by ``JsonServiceAdapter``."""
|
|
102
|
+
|
|
103
|
+
def __init__(self, status_code: int, body: bytes, charset: str) -> None:
|
|
104
|
+
self.status_code = status_code
|
|
105
|
+
self._body = body
|
|
106
|
+
self._charset = charset
|
|
107
|
+
|
|
108
|
+
def raise_for_status(self) -> None:
|
|
109
|
+
if self.status_code >= 400:
|
|
110
|
+
raise OSError(f"HTTP request failed with status {self.status_code}")
|
|
111
|
+
|
|
112
|
+
def json(self) -> Any:
|
|
113
|
+
return json.loads(self._body.decode(self._charset))
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class _NoRedirectHandler(HTTPRedirectHandler):
|
|
117
|
+
def redirect_request(
|
|
118
|
+
self,
|
|
119
|
+
req: Request,
|
|
120
|
+
fp: Any,
|
|
121
|
+
code: int,
|
|
122
|
+
msg: str,
|
|
123
|
+
headers: Any,
|
|
124
|
+
newurl: str,
|
|
125
|
+
) -> Optional[Request]:
|
|
126
|
+
return None
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _request(
|
|
130
|
+
url: str,
|
|
131
|
+
params: Mapping[str, Any],
|
|
132
|
+
headers: Optional[Mapping[str, str]] = None,
|
|
133
|
+
) -> Request:
|
|
134
|
+
request_url = _append_query(url, params)
|
|
135
|
+
return Request(
|
|
136
|
+
request_url,
|
|
137
|
+
headers={**_DEFAULT_HEADERS, **dict(headers or {})},
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _append_query(url: str, params: Mapping[str, Any]) -> str:
|
|
142
|
+
"""Append parameters without replacing or normalizing an existing query."""
|
|
143
|
+
additional_query = urlencode(params, doseq=True)
|
|
144
|
+
if not additional_query:
|
|
145
|
+
return url
|
|
146
|
+
components = urlsplit(url)
|
|
147
|
+
query = (
|
|
148
|
+
f"{components.query}&{additional_query}"
|
|
149
|
+
if components.query
|
|
150
|
+
else additional_query
|
|
151
|
+
)
|
|
152
|
+
return urlunsplit(components._replace(query=query))
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Compatibility exports for built-in source adapters."""
|
|
2
|
+
|
|
3
|
+
from .execution import ExecutionAdapter
|
|
4
|
+
from .source import (
|
|
5
|
+
CkanAdapter,
|
|
6
|
+
DcatAdapter,
|
|
7
|
+
DirectAdapter,
|
|
8
|
+
GsiFundamentalAdapter,
|
|
9
|
+
JsonGetter,
|
|
10
|
+
JsonObject,
|
|
11
|
+
OdptAdapter,
|
|
12
|
+
OgcFeaturesAdapter,
|
|
13
|
+
PlateauAdapter,
|
|
14
|
+
ProviderAdapter,
|
|
15
|
+
StacAdapter,
|
|
16
|
+
StaticAdapter,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"CkanAdapter",
|
|
21
|
+
"DirectAdapter",
|
|
22
|
+
"DcatAdapter",
|
|
23
|
+
"GsiFundamentalAdapter",
|
|
24
|
+
"JsonGetter",
|
|
25
|
+
"JsonObject",
|
|
26
|
+
"OdptAdapter",
|
|
27
|
+
"OgcFeaturesAdapter",
|
|
28
|
+
"PlateauAdapter",
|
|
29
|
+
"ProviderAdapter",
|
|
30
|
+
"StacAdapter",
|
|
31
|
+
"StaticAdapter",
|
|
32
|
+
"ExecutionAdapter",
|
|
33
|
+
]
|