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.
@@ -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."""
@@ -0,0 +1,5 @@
1
+ """Japanese backend (GiNza / Sudachi)."""
2
+
3
+ from sentence_struct.backends.ja.segment import analyze
4
+
5
+ __all__ = ["analyze"]