slugsmith 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,10 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "pip"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ - package-ecosystem: "github-actions"
8
+ directory: "/"
9
+ schedule:
10
+ interval: "weekly"
@@ -0,0 +1,41 @@
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: ${{ matrix.os }}
12
+ strategy:
13
+ matrix:
14
+ os: [ubuntu-latest, macos-latest]
15
+ python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
16
+ fail-fast: false
17
+ steps:
18
+ - uses: actions/checkout@v6
19
+ - uses: actions/setup-python@v5
20
+ with:
21
+ python-version: ${{ matrix.python-version }}
22
+ - name: Install uv
23
+ uses: astral-sh/setup-uv@v5
24
+ - name: Install dependencies
25
+ run: uv sync
26
+ - name: Run tests
27
+ run: uv run pytest tests/ -v
28
+
29
+ typecheck:
30
+ runs-on: ubuntu-latest
31
+ steps:
32
+ - uses: actions/checkout@v6
33
+ - uses: actions/setup-python@v5
34
+ with:
35
+ python-version: "3.13"
36
+ - name: Install uv
37
+ uses: astral-sh/setup-uv@v5
38
+ - name: Install dependencies
39
+ run: uv sync
40
+ - name: Run mypy
41
+ run: uv run mypy src/ --strict
@@ -0,0 +1,20 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+ environment: pypi
11
+ permissions:
12
+ id-token: write
13
+ steps:
14
+ - uses: actions/checkout@v6
15
+ - name: Install uv
16
+ uses: astral-sh/setup-uv@v5
17
+ - name: Build distribution
18
+ run: uv build
19
+ - name: Publish to PyPI
20
+ run: uv publish
@@ -0,0 +1,14 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ .venv/
5
+ .env
6
+ dist/
7
+ build/
8
+ *.egg-info/
9
+ .mypy_cache/
10
+ .pytest_cache/
11
+ .ruff_cache/
12
+ coverage/
13
+ htmlcov/
14
+ .coverage
@@ -0,0 +1,13 @@
1
+ # Changelog
2
+
3
+ ## [0.1.0] - 2026-03-14
4
+
5
+ ### Added
6
+
7
+ - Initial release of slugsmith — modern, zero-dependency URL slug generator
8
+ - Built-in Unicode transliteration (no external deps) covering Latin, Greek, Cyrillic, and CJK scripts
9
+ - Language-specific character mappings (German ü→ue, ß→ss, etc.)
10
+ - Full `python-slugify`-compatible API (`slugify()` with `separator`, `max_length`, `word_boundary`, `stopwords`, `replacements`, `lowercase`, `truncate_chars` parameters)
11
+ - Strict type annotations throughout (PEP 561 `py.typed` marker)
12
+ - Comprehensive test suite (87 tests) covering edge cases and Unicode handling
13
+ - Python 3.9–3.13 support
@@ -0,0 +1,22 @@
1
+ .PHONY: install build test lint fmt clean ci
2
+
3
+ install:
4
+ uv sync
5
+
6
+ build:
7
+ uv build
8
+
9
+ test:
10
+ uv run pytest tests/ -v
11
+
12
+ lint:
13
+ uv run ruff check src/
14
+ uv run mypy src/
15
+
16
+ fmt:
17
+ uv run ruff format src/ tests/
18
+
19
+ clean:
20
+ rm -rf dist/ build/ *.egg-info/ .pytest_cache/ .mypy_cache/
21
+
22
+ ci: lint test
@@ -0,0 +1,176 @@
1
+ Metadata-Version: 2.4
2
+ Name: slugsmith
3
+ Version: 0.1.0
4
+ Summary: Modern, zero-dependency URL slug generator with built-in Unicode transliteration
5
+ Project-URL: Homepage, https://github.com/agentine/slugsmith
6
+ Project-URL: Repository, https://github.com/agentine/slugsmith
7
+ Author: Agentine
8
+ License-Expression: MIT
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Typing :: Typed
19
+ Requires-Python: >=3.9
20
+ Description-Content-Type: text/markdown
21
+
22
+ # slugsmith
23
+
24
+ [![CI](https://github.com/agentine/slugsmith/actions/workflows/ci.yml/badge.svg)](https://github.com/agentine/slugsmith/actions/workflows/ci.yml)
25
+ [![PyPI](https://img.shields.io/pypi/v/slugsmith)](https://pypi.org/project/slugsmith/)
26
+ [![Python](https://img.shields.io/pypi/pyversions/slugsmith)](https://pypi.org/project/slugsmith/)
27
+
28
+ Modern, zero-dependency Python library for generating URL-friendly slugs from Unicode text.
29
+
30
+ A drop-in replacement for [python-slugify](https://github.com/un33k/python-slugify) with built-in transliteration, no external dependencies, and full type annotations.
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install slugsmith
36
+ ```
37
+
38
+ ## Quick Start
39
+
40
+ ```python
41
+ from slugsmith import slugify
42
+
43
+ slugify("Hello World") # "hello-world"
44
+ slugify("café latte") # "cafe-latte"
45
+ slugify("Ελληνικά") # "ellinika"
46
+ slugify("Привет мир") # "privet-mir"
47
+ slugify("北京") # "bei-jing"
48
+ ```
49
+
50
+ ## Features
51
+
52
+ - **Zero dependencies** — built-in Unicode→ASCII transliteration; no `text-unidecode` or `Unidecode` required
53
+ - **Drop-in replacement** for `python-slugify` — same `slugify()` signature
54
+ - **Language-aware** — language-specific mappings for German, Turkish, Polish, Czech, Finnish, Swedish
55
+ - **Type-safe** — full type annotations, PEP 561 compliant, passes mypy strict
56
+ - **MIT licensed** — no GPL dependency concerns
57
+
58
+ ## API Reference
59
+
60
+ ### `slugify(text, **options) -> str`
61
+
62
+ Generate a URL-friendly slug from `text`.
63
+
64
+ | Parameter | Type | Default | Description |
65
+ |-----------|------|---------|-------------|
66
+ | `text` | `str` | *(required)* | Input string to slugify |
67
+ | `separator` | `str` | `"-"` | Character(s) between words |
68
+ | `lowercase` | `bool` | `True` | Convert to lowercase |
69
+ | `max_length` | `int` | `0` | Max slug length (0 = unlimited) |
70
+ | `word_boundary` | `bool` | `False` | Truncate at word boundary when `max_length` is set |
71
+ | `save_order` | `bool` | `False` | Accepted for python-slugify compatibility (word order is always preserved) |
72
+ | `stopwords` | `Iterable[str]` | `()` | Words to remove from the slug |
73
+ | `regex_pattern` | `str \| None` | `None` | Custom regex pattern for allowed characters |
74
+ | `replacements` | `Sequence[Sequence[str]] \| None` | `None` | Sequence of `(old, new)` pairs applied before transliteration; accepts lists of tuples or lists of lists |
75
+ | `allow_unicode` | `bool` | `False` | Keep Unicode characters in the slug |
76
+ | `lang` | `str \| None` | `None` | Language code for language-specific transliteration |
77
+
78
+ Returns an empty string if `text` is empty.
79
+
80
+ ## Examples
81
+
82
+ ### Separator and case
83
+
84
+ ```python
85
+ slugify("Hello World", separator="_") # "hello_world"
86
+ slugify("Hello World", lowercase=False) # "Hello-World"
87
+ slugify("Hello World", separator="") # "helloworld"
88
+ ```
89
+
90
+ ### Length limiting
91
+
92
+ ```python
93
+ slugify("the quick brown fox", max_length=15) # "the-quick-brow"
94
+ slugify("the quick brown fox", max_length=15, word_boundary=True) # "the-quick"
95
+ ```
96
+
97
+ ### Stopwords
98
+
99
+ ```python
100
+ slugify("the quick brown fox", stopwords=("the",)) # "quick-brown-fox"
101
+ ```
102
+
103
+ ### Replacements
104
+
105
+ ```python
106
+ slugify("C++ is great", replacements=[("++", "pp")]) # "cpp-is-great"
107
+ slugify("$100 deal", replacements=[("$", "dollar")]) # "dollar100-deal"
108
+ ```
109
+
110
+ ### Unicode passthrough
111
+
112
+ ```python
113
+ slugify("café au lait", allow_unicode=True) # "café-au-lait"
114
+ slugify("北京 city", allow_unicode=True) # "北京-city"
115
+ ```
116
+
117
+ ### Language-specific transliteration
118
+
119
+ ```python
120
+ slugify("Ü-bung", lang="de") # "ue-bung" (German: ü→ue, ö→oe, ä→ae)
121
+ slugify("çalış", lang="tr") # "calis" (Turkish: ç→c, ş→s)
122
+ slugify("łódź", lang="pl") # "lodz" (Polish: ł→l, ó→o, ź→z)
123
+ slugify("říjen", lang="cs") # "rijen" (Czech: ř→r, í→i)
124
+ ```
125
+
126
+ Supported language codes: `de` (German), `tr` (Turkish), `pl` (Polish), `cs` (Czech), `fi` (Finnish), `sv` (Swedish).
127
+
128
+ ### Script coverage
129
+
130
+ slugsmith's built-in transliteration covers a wide range of Unicode scripts without any external dependencies:
131
+
132
+ | Script | Coverage | Example |
133
+ |--------|----------|---------|
134
+ | Latin Extended | Full diacritics (NFKD + explicit map) | `café` → `cafe` |
135
+ | Cyrillic | Russian + Ukrainian | `Привет` → `Privet`, `їжак` → `yizhak` |
136
+ | Greek | Modern Greek alphabet | `Ελληνικά` → `Ellinika` |
137
+ | Arabic | Basic alphabet (28 letters) | `مرحبا` → `mrhba` |
138
+ | Hebrew | Basic alphabet (22 letters + finals) | `שלום` → `shalom` |
139
+ | Symbols | Common currency and typographic symbols | `€100` → `euro100`, `™` → `tm` |
140
+
141
+ Characters not covered by the table are decomposed via NFKD normalisation; if decomposition yields ASCII, that is used. Remaining non-ASCII characters are silently dropped (same behaviour as `text-unidecode`).
142
+
143
+ ### Custom regex
144
+
145
+ ```python
146
+ # Allow only alphanumeric and hyphens (strip underscores too)
147
+ slugify("hello_world foo", regex_pattern=r"[^a-z0-9-]") # "helloworld-foo"
148
+ ```
149
+
150
+ ## Migration from python-slugify
151
+
152
+ slugsmith is a drop-in replacement:
153
+
154
+ ```python
155
+ # Before
156
+ from slugify import slugify
157
+
158
+ # After
159
+ from slugsmith import slugify
160
+ ```
161
+
162
+ The `slugify()` signature is identical. No other code changes are needed.
163
+
164
+ **Behavioural differences:**
165
+
166
+ | Feature | python-slugify | slugsmith |
167
+ |---------|---------------|-----------|
168
+ | Transliteration | `text-unidecode` (external dep) | Built-in table (zero deps) |
169
+ | License | MIT | MIT (no GPL risk) |
170
+ | Python support | 3.7+ | 3.9+ |
171
+ | Type annotations | Partial | Full (mypy strict) |
172
+ | Language-specific | Not built-in | `lang=` parameter |
173
+
174
+ ## License
175
+
176
+ MIT
@@ -0,0 +1,65 @@
1
+ # Slugsmith — Implementation Plan
2
+
3
+ ## Overview
4
+
5
+ **Slugsmith** is a modern, self-contained Python library for generating URL-friendly slugs from Unicode text. It replaces **python-slugify** (62M/month downloads, single maintainer inactive since March 2024, stale dependency chain).
6
+
7
+ **PyPI name:** `slugsmith` (verified available)
8
+
9
+ ## Target Library: python-slugify
10
+
11
+ - **Downloads:** 62M/month (2.4M/day)
12
+ - **Maintainer:** un33k (Val Neekman) — last code commit March 2024
13
+ - **Issues:** 4 open, 3 unmerged PRs, no review activity
14
+ - **Key risk:** Depends on `text-unidecode` (last release 2019, abandoned)
15
+ - **License concern:** Alternative dependency `Unidecode` is GPL; many projects cannot use it
16
+
17
+ ## Architecture
18
+
19
+ ### Core Module: `slugsmith/`
20
+
21
+ ```
22
+ slugsmith/
23
+ ├── __init__.py # Public API: slugify()
24
+ ├── slugify.py # Core slugification logic
25
+ ├── transliterate.py # Built-in Unicode→ASCII transliteration (no external deps)
26
+ ├── special.py # Language-specific character mappings (German ü→ue, etc.)
27
+ ├── py.typed # PEP 561 marker
28
+ └── _version.py # Version string
29
+ ```
30
+
31
+ ### Key Design Decisions
32
+
33
+ 1. **Zero dependencies** — Built-in transliteration tables eliminate the need for text-unidecode or Unidecode. Ship comprehensive Unicode→ASCII mappings derived from CLDR/Unicode data (MIT-compatible sources only).
34
+
35
+ 2. **API compatibility** — Provide a `slugify()` function with the same core parameters as python-slugify (`text`, `separator`, `lowercase`, `max_length`, `word_boundary`, `save_order`, `stopwords`, `regex_pattern`, `replacements`, `allow_unicode`). Easy migration path.
36
+
37
+ 3. **Type-safe** — Full type annotations, PEP 561 compliant, passes mypy strict.
38
+
39
+ 4. **Performance** — Optimize hot paths. Avoid unnecessary regex compilation on each call (pre-compile patterns). Target ≥2x throughput vs python-slugify.
40
+
41
+ 5. **Modern Python** — Require Python 3.9+. Use modern string/regex features.
42
+
43
+ 6. **MIT licensed** — Clear, permissive license with no GPL dependencies.
44
+
45
+ ### Transliteration Strategy
46
+
47
+ - Ship a comprehensive mapping table covering Latin Extended, Cyrillic, Greek, CJK (basic), Arabic, Hebrew, Thai, and other major scripts.
48
+ - Source mappings from CLDR transliteration rules and Unicode NFKD decomposition.
49
+ - Support language-specific transliteration (e.g., German: ü→ue, ö→oe; Turkish: ı→i).
50
+ - Use `unicodedata.normalize('NFKD', ...)` as first pass, then apply custom mappings for characters that don't decompose cleanly.
51
+
52
+ ## Deliverables
53
+
54
+ 1. Core `slugify()` function with full parameter compatibility
55
+ 2. Built-in transliteration engine (no external dependencies)
56
+ 3. Language-specific character mappings
57
+ 4. Comprehensive test suite (unit + property-based)
58
+ 5. Migration guide from python-slugify
59
+ 6. PyPI package published as `slugsmith`
60
+
61
+ ## Non-Goals
62
+
63
+ - Django integration (users can wrap `slugify()` themselves)
64
+ - CLI tool (keep scope focused on the library)
65
+ - Python 2 or Python <3.9 support
@@ -0,0 +1,155 @@
1
+ # slugsmith
2
+
3
+ [![CI](https://github.com/agentine/slugsmith/actions/workflows/ci.yml/badge.svg)](https://github.com/agentine/slugsmith/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/slugsmith)](https://pypi.org/project/slugsmith/)
5
+ [![Python](https://img.shields.io/pypi/pyversions/slugsmith)](https://pypi.org/project/slugsmith/)
6
+
7
+ Modern, zero-dependency Python library for generating URL-friendly slugs from Unicode text.
8
+
9
+ A drop-in replacement for [python-slugify](https://github.com/un33k/python-slugify) with built-in transliteration, no external dependencies, and full type annotations.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ pip install slugsmith
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ ```python
20
+ from slugsmith import slugify
21
+
22
+ slugify("Hello World") # "hello-world"
23
+ slugify("café latte") # "cafe-latte"
24
+ slugify("Ελληνικά") # "ellinika"
25
+ slugify("Привет мир") # "privet-mir"
26
+ slugify("北京") # "bei-jing"
27
+ ```
28
+
29
+ ## Features
30
+
31
+ - **Zero dependencies** — built-in Unicode→ASCII transliteration; no `text-unidecode` or `Unidecode` required
32
+ - **Drop-in replacement** for `python-slugify` — same `slugify()` signature
33
+ - **Language-aware** — language-specific mappings for German, Turkish, Polish, Czech, Finnish, Swedish
34
+ - **Type-safe** — full type annotations, PEP 561 compliant, passes mypy strict
35
+ - **MIT licensed** — no GPL dependency concerns
36
+
37
+ ## API Reference
38
+
39
+ ### `slugify(text, **options) -> str`
40
+
41
+ Generate a URL-friendly slug from `text`.
42
+
43
+ | Parameter | Type | Default | Description |
44
+ |-----------|------|---------|-------------|
45
+ | `text` | `str` | *(required)* | Input string to slugify |
46
+ | `separator` | `str` | `"-"` | Character(s) between words |
47
+ | `lowercase` | `bool` | `True` | Convert to lowercase |
48
+ | `max_length` | `int` | `0` | Max slug length (0 = unlimited) |
49
+ | `word_boundary` | `bool` | `False` | Truncate at word boundary when `max_length` is set |
50
+ | `save_order` | `bool` | `False` | Accepted for python-slugify compatibility (word order is always preserved) |
51
+ | `stopwords` | `Iterable[str]` | `()` | Words to remove from the slug |
52
+ | `regex_pattern` | `str \| None` | `None` | Custom regex pattern for allowed characters |
53
+ | `replacements` | `Sequence[Sequence[str]] \| None` | `None` | Sequence of `(old, new)` pairs applied before transliteration; accepts lists of tuples or lists of lists |
54
+ | `allow_unicode` | `bool` | `False` | Keep Unicode characters in the slug |
55
+ | `lang` | `str \| None` | `None` | Language code for language-specific transliteration |
56
+
57
+ Returns an empty string if `text` is empty.
58
+
59
+ ## Examples
60
+
61
+ ### Separator and case
62
+
63
+ ```python
64
+ slugify("Hello World", separator="_") # "hello_world"
65
+ slugify("Hello World", lowercase=False) # "Hello-World"
66
+ slugify("Hello World", separator="") # "helloworld"
67
+ ```
68
+
69
+ ### Length limiting
70
+
71
+ ```python
72
+ slugify("the quick brown fox", max_length=15) # "the-quick-brow"
73
+ slugify("the quick brown fox", max_length=15, word_boundary=True) # "the-quick"
74
+ ```
75
+
76
+ ### Stopwords
77
+
78
+ ```python
79
+ slugify("the quick brown fox", stopwords=("the",)) # "quick-brown-fox"
80
+ ```
81
+
82
+ ### Replacements
83
+
84
+ ```python
85
+ slugify("C++ is great", replacements=[("++", "pp")]) # "cpp-is-great"
86
+ slugify("$100 deal", replacements=[("$", "dollar")]) # "dollar100-deal"
87
+ ```
88
+
89
+ ### Unicode passthrough
90
+
91
+ ```python
92
+ slugify("café au lait", allow_unicode=True) # "café-au-lait"
93
+ slugify("北京 city", allow_unicode=True) # "北京-city"
94
+ ```
95
+
96
+ ### Language-specific transliteration
97
+
98
+ ```python
99
+ slugify("Ü-bung", lang="de") # "ue-bung" (German: ü→ue, ö→oe, ä→ae)
100
+ slugify("çalış", lang="tr") # "calis" (Turkish: ç→c, ş→s)
101
+ slugify("łódź", lang="pl") # "lodz" (Polish: ł→l, ó→o, ź→z)
102
+ slugify("říjen", lang="cs") # "rijen" (Czech: ř→r, í→i)
103
+ ```
104
+
105
+ Supported language codes: `de` (German), `tr` (Turkish), `pl` (Polish), `cs` (Czech), `fi` (Finnish), `sv` (Swedish).
106
+
107
+ ### Script coverage
108
+
109
+ slugsmith's built-in transliteration covers a wide range of Unicode scripts without any external dependencies:
110
+
111
+ | Script | Coverage | Example |
112
+ |--------|----------|---------|
113
+ | Latin Extended | Full diacritics (NFKD + explicit map) | `café` → `cafe` |
114
+ | Cyrillic | Russian + Ukrainian | `Привет` → `Privet`, `їжак` → `yizhak` |
115
+ | Greek | Modern Greek alphabet | `Ελληνικά` → `Ellinika` |
116
+ | Arabic | Basic alphabet (28 letters) | `مرحبا` → `mrhba` |
117
+ | Hebrew | Basic alphabet (22 letters + finals) | `שלום` → `shalom` |
118
+ | Symbols | Common currency and typographic symbols | `€100` → `euro100`, `™` → `tm` |
119
+
120
+ Characters not covered by the table are decomposed via NFKD normalisation; if decomposition yields ASCII, that is used. Remaining non-ASCII characters are silently dropped (same behaviour as `text-unidecode`).
121
+
122
+ ### Custom regex
123
+
124
+ ```python
125
+ # Allow only alphanumeric and hyphens (strip underscores too)
126
+ slugify("hello_world foo", regex_pattern=r"[^a-z0-9-]") # "helloworld-foo"
127
+ ```
128
+
129
+ ## Migration from python-slugify
130
+
131
+ slugsmith is a drop-in replacement:
132
+
133
+ ```python
134
+ # Before
135
+ from slugify import slugify
136
+
137
+ # After
138
+ from slugsmith import slugify
139
+ ```
140
+
141
+ The `slugify()` signature is identical. No other code changes are needed.
142
+
143
+ **Behavioural differences:**
144
+
145
+ | Feature | python-slugify | slugsmith |
146
+ |---------|---------------|-----------|
147
+ | Transliteration | `text-unidecode` (external dep) | Built-in table (zero deps) |
148
+ | License | MIT | MIT (no GPL risk) |
149
+ | Python support | 3.7+ | 3.9+ |
150
+ | Type annotations | Partial | Full (mypy strict) |
151
+ | Language-specific | Not built-in | `lang=` parameter |
152
+
153
+ ## License
154
+
155
+ MIT
@@ -0,0 +1,49 @@
1
+ [project]
2
+ name = "slugsmith"
3
+ version = "0.1.0"
4
+ description = "Modern, zero-dependency URL slug generator with built-in Unicode transliteration"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ authors = [
8
+ { name = "Agentine" }
9
+ ]
10
+ requires-python = ">=3.9"
11
+ dependencies = []
12
+ classifiers = [
13
+ "Development Status :: 3 - Alpha",
14
+ "Intended Audience :: Developers",
15
+ "License :: OSI Approved :: MIT License",
16
+ "Programming Language :: Python :: 3",
17
+ "Programming Language :: Python :: 3.9",
18
+ "Programming Language :: Python :: 3.10",
19
+ "Programming Language :: Python :: 3.11",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Programming Language :: Python :: 3.13",
22
+ "Typing :: Typed",
23
+ ]
24
+
25
+ [project.urls]
26
+ Homepage = "https://github.com/agentine/slugsmith"
27
+ Repository = "https://github.com/agentine/slugsmith"
28
+
29
+ [build-system]
30
+ requires = ["hatchling"]
31
+ build-backend = "hatchling.build"
32
+
33
+ [tool.hatch.build.targets.wheel]
34
+ packages = ["src/slugsmith"]
35
+
36
+ [dependency-groups]
37
+ dev = [
38
+ "mypy>=1.19",
39
+ "pytest>=8.0",
40
+ "ruff>=0.11",
41
+ ]
42
+
43
+ [tool.pytest.ini_options]
44
+ testpaths = ["tests"]
45
+
46
+ [tool.mypy]
47
+ strict = true
48
+ warn_return_any = true
49
+ warn_unused_configs = true
@@ -0,0 +1,6 @@
1
+ """Slugsmith — modern, zero-dependency URL slug generator."""
2
+
3
+ from slugsmith._version import __version__
4
+ from slugsmith.slugify import slugify
5
+
6
+ __all__ = ["slugify", "__version__"]
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
File without changes