sentence-struct 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.
- sentence_struct-0.1.0/.github/workflows/ci.yml +34 -0
- sentence_struct-0.1.0/.github/workflows/release.yml +66 -0
- sentence_struct-0.1.0/.gitignore +27 -0
- sentence_struct-0.1.0/.python-version +1 -0
- sentence_struct-0.1.0/CHANGELOG.md +18 -0
- sentence_struct-0.1.0/LICENSE +21 -0
- sentence_struct-0.1.0/PKG-INFO +114 -0
- sentence_struct-0.1.0/README.md +81 -0
- sentence_struct-0.1.0/RELEASING.md +111 -0
- sentence_struct-0.1.0/pyproject.toml +75 -0
- sentence_struct-0.1.0/src/sentence_struct/__init__.py +15 -0
- sentence_struct-0.1.0/src/sentence_struct/api.py +44 -0
- sentence_struct-0.1.0/src/sentence_struct/backends/__init__.py +1 -0
- sentence_struct-0.1.0/src/sentence_struct/backends/ja/__init__.py +5 -0
- sentence_struct-0.1.0/src/sentence_struct/backends/ja/chunks.py +163 -0
- sentence_struct-0.1.0/src/sentence_struct/backends/ja/segment.py +222 -0
- sentence_struct-0.1.0/src/sentence_struct/backends/ja/taxonomy.py +90 -0
- sentence_struct-0.1.0/src/sentence_struct/backends/ja/token_merge.py +125 -0
- sentence_struct-0.1.0/src/sentence_struct/cli.py +74 -0
- sentence_struct-0.1.0/src/sentence_struct/models.py +40 -0
- sentence_struct-0.1.0/src/sentence_struct/serialize.py +64 -0
- sentence_struct-0.1.0/tests/smoke_test.py +19 -0
- sentence_struct-0.1.0/tests/test_api_unit.py +52 -0
- sentence_struct-0.1.0/tests/test_ja_integration.py +47 -0
- sentence_struct-0.1.0/uv.lock +1677 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, master]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
fail-fast: false
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Install uv
|
|
19
|
+
uses: astral-sh/setup-uv@v5
|
|
20
|
+
with:
|
|
21
|
+
enable-cache: true
|
|
22
|
+
python-version: ${{ matrix.python-version }}
|
|
23
|
+
|
|
24
|
+
- name: Sync dependencies
|
|
25
|
+
run: uv sync --group dev
|
|
26
|
+
|
|
27
|
+
- name: Unit tests
|
|
28
|
+
run: uv run pytest -m "not integration" -q
|
|
29
|
+
|
|
30
|
+
- name: Integration tests (GiNza)
|
|
31
|
+
run: uv run pytest -m integration -q
|
|
32
|
+
|
|
33
|
+
- name: Build package
|
|
34
|
+
run: uv build
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Publish release to PyPI (Trusted Publishing + uv)
|
|
2
|
+
|
|
3
|
+
name: Release
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
tags:
|
|
8
|
+
- "v[0-9]+.[0-9]+.[0-9]+"
|
|
9
|
+
- "v[0-9]+.[0-9]+.[0-9]+rc[0-9]+"
|
|
10
|
+
- "v[0-9]+.[0-9]+.[0-9]+[ab][0-9]+"
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
build:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
steps:
|
|
19
|
+
- name: Checkout
|
|
20
|
+
uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- name: Install uv
|
|
23
|
+
uses: astral-sh/setup-uv@v5
|
|
24
|
+
with:
|
|
25
|
+
enable-cache: true
|
|
26
|
+
|
|
27
|
+
- name: Set up Python
|
|
28
|
+
run: uv python install
|
|
29
|
+
|
|
30
|
+
- name: Build
|
|
31
|
+
run: uv build
|
|
32
|
+
|
|
33
|
+
- name: Smoke test (wheel)
|
|
34
|
+
run: uv run --isolated --no-project --with dist/*.whl tests/smoke_test.py
|
|
35
|
+
|
|
36
|
+
- name: Smoke test (sdist)
|
|
37
|
+
run: uv run --isolated --no-project --with dist/*.tar.gz tests/smoke_test.py
|
|
38
|
+
|
|
39
|
+
- name: Upload distributions
|
|
40
|
+
uses: actions/upload-artifact@v4
|
|
41
|
+
with:
|
|
42
|
+
name: dist
|
|
43
|
+
path: dist/
|
|
44
|
+
|
|
45
|
+
publish:
|
|
46
|
+
needs: [build]
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
environment:
|
|
49
|
+
name: pypi
|
|
50
|
+
url: https://pypi.org/p/sentence-struct
|
|
51
|
+
permissions:
|
|
52
|
+
id-token: write
|
|
53
|
+
steps:
|
|
54
|
+
- name: Install uv
|
|
55
|
+
uses: astral-sh/setup-uv@v5
|
|
56
|
+
with:
|
|
57
|
+
enable-cache: false
|
|
58
|
+
|
|
59
|
+
- name: Download distributions
|
|
60
|
+
uses: actions/download-artifact@v4
|
|
61
|
+
with:
|
|
62
|
+
name: dist
|
|
63
|
+
path: dist/
|
|
64
|
+
|
|
65
|
+
- name: Publish to PyPI
|
|
66
|
+
run: uv publish
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
dist/
|
|
7
|
+
build/
|
|
8
|
+
.venv/
|
|
9
|
+
venv/
|
|
10
|
+
|
|
11
|
+
# Tools
|
|
12
|
+
.pytest_cache/
|
|
13
|
+
.coverage
|
|
14
|
+
htmlcov/
|
|
15
|
+
.mypy_cache/
|
|
16
|
+
.ruff_cache/
|
|
17
|
+
.idea/
|
|
18
|
+
.vscode/
|
|
19
|
+
|
|
20
|
+
# OS / local
|
|
21
|
+
.DS_Store
|
|
22
|
+
.env
|
|
23
|
+
*.local
|
|
24
|
+
|
|
25
|
+
# Package outputs
|
|
26
|
+
out/
|
|
27
|
+
*.json.bak
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
|
@@ -0,0 +1,18 @@
|
|
|
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.1.0] - 2026-09-17
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Initial public API: `analyze(text, language="ja")` → document dict with
|
|
15
|
+
`sentences[].tokens` and `sentences[].chunks`.
|
|
16
|
+
- Japanese backend via GiNza / Sudachi (segmentation, token merge, chunking, taxonomy).
|
|
17
|
+
- CLI: `sentence-struct`.
|
|
18
|
+
- GitHub Actions CI and uv-based PyPI release workflow (Trusted Publishing).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 sentence-struct contributors
|
|
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,114 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: sentence-struct
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Multilingual sentence structure analysis: sentences with tokens and syntactic chunks
|
|
5
|
+
Project-URL: Homepage, https://github.com/memshare-project/sentence-struct
|
|
6
|
+
Project-URL: Repository, https://github.com/memshare-project/sentence-struct
|
|
7
|
+
Project-URL: Issues, https://github.com/memshare-project/sentence-struct/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/memshare-project/sentence-struct/blob/main/CHANGELOG.md
|
|
9
|
+
Author: sentence-struct contributors
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: chunking,japanese,linguistics,nlp,sentence-structure,tokenization
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Text Processing :: Linguistic
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Requires-Dist: ginza>=5.2.1
|
|
23
|
+
Requires-Dist: ja-ginza>=5.2.0
|
|
24
|
+
Requires-Dist: spacy>=3.8.0
|
|
25
|
+
Requires-Dist: sudachidict-core>=20240409
|
|
26
|
+
Requires-Dist: sudachipy>=0.6.8
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest-cov>=6.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
30
|
+
Provides-Extra: ja-full
|
|
31
|
+
Requires-Dist: sudachidict-full>=20240409; extra == 'ja-full'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# sentence-struct
|
|
35
|
+
|
|
36
|
+
Analyze text into a learner-friendly structure:
|
|
37
|
+
|
|
38
|
+
**document → sentences[] → { tokens[], chunks[] }**
|
|
39
|
+
|
|
40
|
+
Chunks are siblings of tokens and reference them via `tokenIndices` (not nested).
|
|
41
|
+
|
|
42
|
+
Japanese (`ja`) is implemented first via GiNza / Sudachi. More languages later.
|
|
43
|
+
|
|
44
|
+
## Install
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install sentence-struct
|
|
48
|
+
# or
|
|
49
|
+
uv add sentence-struct
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Optional larger Sudachi dictionary:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install "sentence-struct[ja-full]"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Requires Python ≥ 3.11. First install pulls spaCy / GiNza / Sudachi (hundreds of MB).
|
|
59
|
+
|
|
60
|
+
## Usage
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from sentence_struct import analyze
|
|
64
|
+
|
|
65
|
+
doc = analyze("秋が近づくにつれ、朝晩の涼しさが心地よい。", language="ja")
|
|
66
|
+
print(doc["sentence_count"], doc["token_count"], doc["chunk_count"])
|
|
67
|
+
print(doc["sentences"][0]["tokens"][0])
|
|
68
|
+
print(doc["sentences"][0]["chunks"][0])
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
CLI:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
sentence-struct "秋が近づく。"
|
|
75
|
+
sentence-struct -f essay.txt -o out.json
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Schema (abbreviated)
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"language": "ja",
|
|
83
|
+
"text": "...",
|
|
84
|
+
"sentences": [
|
|
85
|
+
{
|
|
86
|
+
"index": 1,
|
|
87
|
+
"text": "...",
|
|
88
|
+
"tokens": [
|
|
89
|
+
{"text": "秋", "pos": "名詞", "posGroup": "名詞", "lemma": "秋", "reading": "アキ"}
|
|
90
|
+
],
|
|
91
|
+
"chunks": [
|
|
92
|
+
{"type": "NP", "typeGroup": "NP", "tokenIndices": [0, 1], "text": "秋が", "role": "nsubj"}
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Develop (uv)
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
uv sync
|
|
103
|
+
uv run pytest -m "not integration"
|
|
104
|
+
uv run pytest -m integration
|
|
105
|
+
uv run sentence-struct "今日は良い天気です。"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Release
|
|
109
|
+
|
|
110
|
+
See [RELEASING.md](RELEASING.md). Tag `vX.Y.Z` → GitHub Actions builds with **uv** and publishes to PyPI via Trusted Publishing.
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
MIT
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# sentence-struct
|
|
2
|
+
|
|
3
|
+
Analyze text into a learner-friendly structure:
|
|
4
|
+
|
|
5
|
+
**document → sentences[] → { tokens[], chunks[] }**
|
|
6
|
+
|
|
7
|
+
Chunks are siblings of tokens and reference them via `tokenIndices` (not nested).
|
|
8
|
+
|
|
9
|
+
Japanese (`ja`) is implemented first via GiNza / Sudachi. More languages later.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install sentence-struct
|
|
15
|
+
# or
|
|
16
|
+
uv add sentence-struct
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Optional larger Sudachi dictionary:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install "sentence-struct[ja-full]"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Requires Python ≥ 3.11. First install pulls spaCy / GiNza / Sudachi (hundreds of MB).
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from sentence_struct import analyze
|
|
31
|
+
|
|
32
|
+
doc = analyze("秋が近づくにつれ、朝晩の涼しさが心地よい。", language="ja")
|
|
33
|
+
print(doc["sentence_count"], doc["token_count"], doc["chunk_count"])
|
|
34
|
+
print(doc["sentences"][0]["tokens"][0])
|
|
35
|
+
print(doc["sentences"][0]["chunks"][0])
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
CLI:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
sentence-struct "秋が近づく。"
|
|
42
|
+
sentence-struct -f essay.txt -o out.json
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Schema (abbreviated)
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"language": "ja",
|
|
50
|
+
"text": "...",
|
|
51
|
+
"sentences": [
|
|
52
|
+
{
|
|
53
|
+
"index": 1,
|
|
54
|
+
"text": "...",
|
|
55
|
+
"tokens": [
|
|
56
|
+
{"text": "秋", "pos": "名詞", "posGroup": "名詞", "lemma": "秋", "reading": "アキ"}
|
|
57
|
+
],
|
|
58
|
+
"chunks": [
|
|
59
|
+
{"type": "NP", "typeGroup": "NP", "tokenIndices": [0, 1], "text": "秋が", "role": "nsubj"}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Develop (uv)
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
uv sync
|
|
70
|
+
uv run pytest -m "not integration"
|
|
71
|
+
uv run pytest -m integration
|
|
72
|
+
uv run sentence-struct "今日は良い天気です。"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Release
|
|
76
|
+
|
|
77
|
+
See [RELEASING.md](RELEASING.md). Tag `vX.Y.Z` → GitHub Actions builds with **uv** and publishes to PyPI via Trusted Publishing.
|
|
78
|
+
|
|
79
|
+
## License
|
|
80
|
+
|
|
81
|
+
MIT
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Releasing sentence-struct
|
|
2
|
+
|
|
3
|
+
Standard flow: **bump version → CHANGELOG → commit → tag → push tag → Actions publishes to PyPI**.
|
|
4
|
+
|
|
5
|
+
## One-time setup
|
|
6
|
+
|
|
7
|
+
### 1. GitHub Environment
|
|
8
|
+
|
|
9
|
+
Repo → **Settings → Environments → New environment** → name: `pypi`
|
|
10
|
+
(Must match `.github/workflows/release.yml` `environment.name`.)
|
|
11
|
+
|
|
12
|
+
Optional: add required reviewers for production publishes.
|
|
13
|
+
|
|
14
|
+
### 2. PyPI Trusted Publisher
|
|
15
|
+
|
|
16
|
+
1. Create the project on PyPI (or claim the name with a first manual upload / pending publisher).
|
|
17
|
+
2. Project → **Publishing** → **Add a new pending/trusted publisher**:
|
|
18
|
+
- Owner: your GitHub org/user
|
|
19
|
+
- Repository: `sentence-struct`
|
|
20
|
+
- Workflow: `release.yml`
|
|
21
|
+
- Environment: `pypi`
|
|
22
|
+
3. No `PYPI_TOKEN` secret needed when Trusted Publishing is configured.
|
|
23
|
+
|
|
24
|
+
### 3. Test PyPI (optional)
|
|
25
|
+
|
|
26
|
+
Add a second environment `testpypi` and a workflow that runs:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
uv publish --publish-url https://test.pypi.org/legacy/
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
with a matching Trusted Publisher on TestPyPI.
|
|
33
|
+
|
|
34
|
+
## Release checklist
|
|
35
|
+
|
|
36
|
+
1. **Green CI on main**
|
|
37
|
+
Unit + integration tests pass.
|
|
38
|
+
|
|
39
|
+
2. **Bump version** (keep these in sync):
|
|
40
|
+
- `pyproject.toml` → `[project].version`
|
|
41
|
+
- `src/sentence_struct/__init__.py` → `__version__`
|
|
42
|
+
|
|
43
|
+
With uv (example):
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# edit version fields, then:
|
|
47
|
+
uv lock
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
3. **Update CHANGELOG.md**
|
|
51
|
+
Move items under `## Unreleased` into `## [X.Y.Z] - YYYY-MM-DD`.
|
|
52
|
+
|
|
53
|
+
4. **Commit on main**
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
git add -A
|
|
57
|
+
git commit -m "Release vX.Y.Z"
|
|
58
|
+
git push origin main
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
5. **Create annotated tag and push**
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
git tag -a "vX.Y.Z" -m "Release vX.Y.Z"
|
|
65
|
+
git push origin "vX.Y.Z"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Tag pattern must match the workflow: `v1.2.3`, `v1.2.3rc1`, `v1.2.3a1`, `v1.2.3b1`.
|
|
69
|
+
|
|
70
|
+
6. **Optional: GitHub Release UI**
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
gh release create "vX.Y.Z" --title "vX.Y.Z" --notes-file CHANGELOG.md
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Publishing is triggered by the **git tag push**, not by the GitHub Release form (unless you also push the tag).
|
|
77
|
+
|
|
78
|
+
7. **Watch Actions**
|
|
79
|
+
Workflow **Release**: build → smoke import → `uv publish`.
|
|
80
|
+
|
|
81
|
+
8. **Verify**
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
pip index versions sentence-struct
|
|
85
|
+
uvx sentence-struct "秋が近づく。"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Versioning
|
|
89
|
+
|
|
90
|
+
Follow [SemVer](https://semver.org/):
|
|
91
|
+
|
|
92
|
+
| Change | Bump |
|
|
93
|
+
|--------|------|
|
|
94
|
+
| Break public schema / API | MAJOR |
|
|
95
|
+
| New language / features | MINOR |
|
|
96
|
+
| Bugfix | PATCH |
|
|
97
|
+
| Pre-release | `X.Y.ZrcN` / `aN` / `bN` |
|
|
98
|
+
|
|
99
|
+
## Bad release?
|
|
100
|
+
|
|
101
|
+
- Prefer **yank** on PyPI (Options → Yank) with a reason, then ship a fixed version.
|
|
102
|
+
- Avoid deleting published files unless necessary; yanked is enough for most cases.
|
|
103
|
+
- You generally **cannot** re-upload the same filename after delete.
|
|
104
|
+
|
|
105
|
+
## Local dry-run
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
uv build
|
|
109
|
+
uv run --isolated --no-project --with dist/*.whl tests/smoke_test.py
|
|
110
|
+
# Do NOT run uv publish against production unless intentional.
|
|
111
|
+
```
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "sentence-struct"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Multilingual sentence structure analysis: sentences with tokens and syntactic chunks"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
authors = [{ name = "sentence-struct contributors" }]
|
|
13
|
+
keywords = [
|
|
14
|
+
"nlp",
|
|
15
|
+
"japanese",
|
|
16
|
+
"tokenization",
|
|
17
|
+
"chunking",
|
|
18
|
+
"sentence-structure",
|
|
19
|
+
"linguistics",
|
|
20
|
+
]
|
|
21
|
+
classifiers = [
|
|
22
|
+
"Development Status :: 3 - Alpha",
|
|
23
|
+
"Intended Audience :: Developers",
|
|
24
|
+
"License :: OSI Approved :: MIT License",
|
|
25
|
+
"Programming Language :: Python :: 3",
|
|
26
|
+
"Programming Language :: Python :: 3.11",
|
|
27
|
+
"Programming Language :: Python :: 3.12",
|
|
28
|
+
"Programming Language :: Python :: 3.13",
|
|
29
|
+
"Topic :: Text Processing :: Linguistic",
|
|
30
|
+
]
|
|
31
|
+
# Japanese is the only backend today; future languages will be extras or additional deps.
|
|
32
|
+
dependencies = [
|
|
33
|
+
"ginza>=5.2.1",
|
|
34
|
+
"ja-ginza>=5.2.0",
|
|
35
|
+
"spacy>=3.8.0",
|
|
36
|
+
"sudachidict-core>=20240409",
|
|
37
|
+
"sudachipy>=0.6.8",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.optional-dependencies]
|
|
41
|
+
ja-full = ["sudachidict-full>=20240409"]
|
|
42
|
+
dev = ["pytest>=8.0", "pytest-cov>=6.0"]
|
|
43
|
+
|
|
44
|
+
[project.urls]
|
|
45
|
+
Homepage = "https://github.com/memshare-project/sentence-struct"
|
|
46
|
+
Repository = "https://github.com/memshare-project/sentence-struct"
|
|
47
|
+
Issues = "https://github.com/memshare-project/sentence-struct/issues"
|
|
48
|
+
Changelog = "https://github.com/memshare-project/sentence-struct/blob/main/CHANGELOG.md"
|
|
49
|
+
|
|
50
|
+
[project.scripts]
|
|
51
|
+
sentence-struct = "sentence_struct.cli:main"
|
|
52
|
+
|
|
53
|
+
[dependency-groups]
|
|
54
|
+
dev = ["pytest>=8.0", "pytest-cov>=6.0"]
|
|
55
|
+
|
|
56
|
+
[tool.uv]
|
|
57
|
+
default-groups = ["dev"]
|
|
58
|
+
|
|
59
|
+
[tool.pytest.ini_options]
|
|
60
|
+
testpaths = ["tests"]
|
|
61
|
+
markers = [
|
|
62
|
+
"integration: needs GiNza Japanese model (slower)",
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
[tool.coverage.run]
|
|
66
|
+
source = ["sentence_struct"]
|
|
67
|
+
omit = ["tests/*"]
|
|
68
|
+
|
|
69
|
+
[tool.coverage.report]
|
|
70
|
+
show_missing = true
|
|
71
|
+
skip_empty = true
|
|
72
|
+
exclude_lines = [
|
|
73
|
+
"if TYPE_CHECKING:",
|
|
74
|
+
"if __name__ == .__main__.:",
|
|
75
|
+
]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""sentence-struct: multilingual sentence structure analysis."""
|
|
2
|
+
|
|
3
|
+
from sentence_struct.api import SUPPORTED_LANGUAGES, analyze, analyze_sentences
|
|
4
|
+
from sentence_struct.models import Chunk, Sentence, Token
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"SUPPORTED_LANGUAGES",
|
|
8
|
+
"Chunk",
|
|
9
|
+
"Sentence",
|
|
10
|
+
"Token",
|
|
11
|
+
"analyze",
|
|
12
|
+
"analyze_sentences",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Public analyze() entrypoint with language dispatch."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from sentence_struct.models import Sentence
|
|
8
|
+
from sentence_struct.serialize import document_to_dict
|
|
9
|
+
|
|
10
|
+
SUPPORTED_LANGUAGES = frozenset({"ja"})
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def analyze_sentences(text: str, *, language: str = "ja") -> list[Sentence]:
|
|
14
|
+
"""Analyze text into Sentence objects (tokens + chunks per sentence)."""
|
|
15
|
+
lang = language.lower().strip()
|
|
16
|
+
if lang not in SUPPORTED_LANGUAGES:
|
|
17
|
+
supported = ", ".join(sorted(SUPPORTED_LANGUAGES))
|
|
18
|
+
raise ValueError(f"Unsupported language {language!r}. Supported: {supported}")
|
|
19
|
+
|
|
20
|
+
if lang == "ja":
|
|
21
|
+
from sentence_struct.backends.ja.segment import analyze as analyze_ja
|
|
22
|
+
|
|
23
|
+
return analyze_ja(text)
|
|
24
|
+
|
|
25
|
+
raise ValueError(f"Unsupported language {language!r}")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def analyze(text: str, *, language: str = "ja") -> dict[str, Any]:
|
|
29
|
+
"""Analyze text into the public document dict.
|
|
30
|
+
|
|
31
|
+
Schema::
|
|
32
|
+
|
|
33
|
+
{
|
|
34
|
+
"language": "ja",
|
|
35
|
+
"text": "...",
|
|
36
|
+
"sentences": [
|
|
37
|
+
{"index": 1, "text": "...", "tokens": [...], "chunks": [...]}
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
Chunks are siblings of tokens and reference them via ``tokenIndices``.
|
|
42
|
+
"""
|
|
43
|
+
sentences = analyze_sentences(text, language=language)
|
|
44
|
+
return document_to_dict(text, sentences, language=language.lower().strip())
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Language backends. Japanese ships first; more languages later."""
|