randino 1.0.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.
- randino-1.0.0/.gitignore +40 -0
- randino-1.0.0/CHANGELOG.md +11 -0
- randino-1.0.0/LICENSE +21 -0
- randino-1.0.0/PKG-INFO +181 -0
- randino-1.0.0/README.md +149 -0
- randino-1.0.0/pyproject.toml +115 -0
- randino-1.0.0/src/randino/__init__.py +84 -0
- randino-1.0.0/src/randino/_internal/__init__.py +1 -0
- randino-1.0.0/src/randino/_internal/parse.py +50 -0
- randino-1.0.0/src/randino/_internal/utils.py +63 -0
- randino-1.0.0/src/randino/_types.py +107 -0
- randino-1.0.0/src/randino/name/__init__.py +25 -0
- randino-1.0.0/src/randino/name/_generator.py +597 -0
- randino-1.0.0/src/randino/name/_romanize.py +334 -0
- randino-1.0.0/src/randino/name/data/__init__.py +45 -0
- randino-1.0.0/src/randino/name/data/_types.py +133 -0
- randino-1.0.0/src/randino/name/data/de.py +34 -0
- randino-1.0.0/src/randino/name/data/en.py +63 -0
- randino-1.0.0/src/randino/name/data/es.py +35 -0
- randino-1.0.0/src/randino/name/data/it.py +35 -0
- randino-1.0.0/src/randino/name/data/ja.py +52 -0
- randino-1.0.0/src/randino/name/data/ko.py +92 -0
- randino-1.0.0/src/randino/name/data/ru.py +46 -0
- randino-1.0.0/src/randino/name/data/syllables.py +57 -0
- randino-1.0.0/src/randino/name/data/vi.py +41 -0
- randino-1.0.0/src/randino/name/data/zh.py +64 -0
- randino-1.0.0/src/randino/name/name_length_range.py +51 -0
- randino-1.0.0/src/randino/name/name_supports_middle_name.py +24 -0
- randino-1.0.0/src/randino/name/name_supports_roman.py +18 -0
- randino-1.0.0/src/randino/name/random_name.py +72 -0
- randino-1.0.0/src/randino/name/random_name_details.py +42 -0
- randino-1.0.0/src/randino/nickname/__init__.py +27 -0
- randino-1.0.0/src/randino/nickname/_generator.py +614 -0
- randino-1.0.0/src/randino/nickname/data/__init__.py +56 -0
- randino-1.0.0/src/randino/nickname/data/_types.py +93 -0
- randino-1.0.0/src/randino/nickname/data/en.py +172 -0
- randino-1.0.0/src/randino/nickname/data/ja.py +138 -0
- randino-1.0.0/src/randino/nickname/data/ko.py +153 -0
- randino-1.0.0/src/randino/nickname/data/zh.py +134 -0
- randino-1.0.0/src/randino/nickname/nickname_length_range.py +42 -0
- randino-1.0.0/src/randino/nickname/random_nickname.py +93 -0
- randino-1.0.0/src/randino/nickname/random_nickname_details.py +51 -0
- randino-1.0.0/src/randino/py.typed +0 -0
- randino-1.0.0/tests/__init__.py +1 -0
- randino-1.0.0/tests/test_base.py +101 -0
- randino-1.0.0/tests/test_name.py +377 -0
- randino-1.0.0/tests/test_nickname.py +402 -0
randino-1.0.0/.gitignore
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Build output
|
|
2
|
+
dist/
|
|
3
|
+
docs-dist/
|
|
4
|
+
|
|
5
|
+
# Node.js
|
|
6
|
+
node_modules/
|
|
7
|
+
|
|
8
|
+
# Dart
|
|
9
|
+
.dart_tool/
|
|
10
|
+
build/
|
|
11
|
+
# A library pins nothing, so its lock file is noise in every diff.
|
|
12
|
+
packages/dart/pubspec.lock
|
|
13
|
+
|
|
14
|
+
# Python
|
|
15
|
+
__pycache__/
|
|
16
|
+
*.py[cod]
|
|
17
|
+
.venv/
|
|
18
|
+
*.egg-info/
|
|
19
|
+
.pytest_cache/
|
|
20
|
+
.mypy_cache/
|
|
21
|
+
.ruff_cache/
|
|
22
|
+
|
|
23
|
+
# VitePress
|
|
24
|
+
docs/.vitepress/.temp/
|
|
25
|
+
docs/.vitepress/cache/
|
|
26
|
+
|
|
27
|
+
# Generated by `docs/scripts/copy-changelog.mjs` from each package's CHANGELOG.md
|
|
28
|
+
docs/*/changelog.md
|
|
29
|
+
|
|
30
|
+
# IDEs
|
|
31
|
+
.idea/
|
|
32
|
+
|
|
33
|
+
# Generated by MacOS
|
|
34
|
+
.DS_Store
|
|
35
|
+
|
|
36
|
+
# Generated by Windows
|
|
37
|
+
Thumbs.db
|
|
38
|
+
|
|
39
|
+
# Log files
|
|
40
|
+
*.log
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
**2026-09-01**
|
|
6
|
+
|
|
7
|
+
- The first release of the Python package, ported from the JavaScript one.
|
|
8
|
+
- `random_name` and `random_name_details` generate person names in 9 languages, with the English pronunciation of each.
|
|
9
|
+
- `random_nickname` and `random_nickname_details` generate nicknames in 4 languages across 14 themes.
|
|
10
|
+
- `name_length_range`, `name_supports_middle_name`, `name_supports_roman` and `nickname_length_range` report what a language can produce before you ask it to.
|
|
11
|
+
- No dependencies. Requires Python 3.10 or newer, and ships a `py.typed` marker.
|
randino-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CDGet <jooy2.contact@gmail.com> (https://cdget.com).
|
|
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
|
randino-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: randino
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Generates random person names and nicknames in the language you ask for — Korean, English, Japanese, Chinese and six more. No dependencies, pure Python.
|
|
5
|
+
Project-URL: Homepage, https://randino.cdget.com
|
|
6
|
+
Project-URL: Documentation, https://randino.cdget.com
|
|
7
|
+
Project-URL: Repository, https://github.com/jooy2/randino
|
|
8
|
+
Project-URL: Issues, https://github.com/jooy2/randino/issues
|
|
9
|
+
Project-URL: Changelog, https://randino.cdget.com/changelog
|
|
10
|
+
Author-email: CDGet <jooy2.contact@gmail.com>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: dummy,i18n,mock,name,name-generator,nickname,nickname-generator,random,romanize,username
|
|
14
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Topic :: Software Development :: Testing
|
|
24
|
+
Classifier: Topic :: Text Processing :: Linguistic
|
|
25
|
+
Classifier: Typing :: Typed
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: mypy>=1.15; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=8.3; extra == 'dev'
|
|
30
|
+
Requires-Dist: ruff>=0.9; extra == 'dev'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
<img src="https://raw.githubusercontent.com/jooy2/randino/main/docs/public/128x128.png" alt="randino" width="96" height="96" />
|
|
34
|
+
|
|
35
|
+
# randino for Python
|
|
36
|
+
|
|
37
|
+
[](https://github.com/jooy2/randino/blob/main/LICENSE) [](https://pypi.org/project/randino/)
|
|
38
|
+
|
|
39
|
+
### 📘 [**randino.cdget.com**](https://randino.cdget.com)
|
|
40
|
+
|
|
41
|
+
Every option and every example, with **Python** picked in the sidebar. This README is just the quick start.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
**randino** generates random person names and nicknames in the language you ask for.
|
|
46
|
+
|
|
47
|
+
- **Person names** read like names people actually carry — 김민준, Emma Clover, Иванов Иван — and come with their English pronunciation. 9 languages.
|
|
48
|
+
- **Nicknames** are the handles you would pick for a game or a website — 멋진사자, MistyOwl, 고양이꼬리. Built from everyday words across fourteen themes, never from person names.
|
|
49
|
+
- Every argument is keyword-only and optional, so `random_name()` on its own works.
|
|
50
|
+
- **Pure Python, no dependencies.** It imports nothing outside the standard library, and ships a `py.typed` marker so mypy and Pyright read the annotations.
|
|
51
|
+
|
|
52
|
+
This is the Python half. The [npm package](https://www.npmjs.com/package/randino) and the [pub.dev package](https://pub.dev/packages/randino) are the others, and all three generate from the same datasets under the same rules. They version independently, so this package's number and the others' will not always agree.
|
|
53
|
+
|
|
54
|
+
## Install
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install randino
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Requires **Python 3.10 or newer**. There is nothing else to install.
|
|
61
|
+
|
|
62
|
+
## Person names
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from randino import random_name, random_name_details
|
|
66
|
+
|
|
67
|
+
random_name()
|
|
68
|
+
# ['Emma Clover']
|
|
69
|
+
|
|
70
|
+
random_name(language="ko", count=3)
|
|
71
|
+
# ['김태윤', '원동혁', '조진우']
|
|
72
|
+
|
|
73
|
+
random_name(language="ko", script="roman")
|
|
74
|
+
# ['Kim Minjun']
|
|
75
|
+
|
|
76
|
+
random_name(language="en", gender="female", include_middle_name=True)
|
|
77
|
+
# ['Grace Amelia Bennett']
|
|
78
|
+
|
|
79
|
+
random_name_details(language="ko")[0]
|
|
80
|
+
# NameDetail(native='여미주', roman='Yeo Miju', language='ko', gender='female')
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
| Argument | Type | Default |
|
|
84
|
+
| --------------------------- | ----------------------------- | ---------- |
|
|
85
|
+
| `language` | `NameLanguageOption` | `"all"` |
|
|
86
|
+
| `gender` | `NameGenderOption` | `"all"` |
|
|
87
|
+
| `count` | `int` | `1` |
|
|
88
|
+
| `style` | `int` (0 real … 100 invented) | `0` |
|
|
89
|
+
| `min_length` / `max_length` | `int \| None` | _language_ |
|
|
90
|
+
| `include_surname` | `bool` | `True` |
|
|
91
|
+
| `include_middle_name` | `bool` | `False` |
|
|
92
|
+
| `script` | `NameScript` | `"native"` |
|
|
93
|
+
| `starts_with` | `str` | `""` |
|
|
94
|
+
| `unique` | `bool` | `False` |
|
|
95
|
+
|
|
96
|
+
`random_name_details` takes the same arguments except `script`, and returns a `NameDetail` — `native`, `roman`, `language` and `gender` — for each name.
|
|
97
|
+
|
|
98
|
+
## Nicknames
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from randino import random_nickname, random_nickname_details
|
|
102
|
+
|
|
103
|
+
random_nickname(language="ko", count=3)
|
|
104
|
+
# ['오래된곰', '영원한도마뱀', '귀여운신화다발']
|
|
105
|
+
|
|
106
|
+
random_nickname(language="en", count=2)
|
|
107
|
+
# ['FoggyHillside', 'CraneVoyage']
|
|
108
|
+
|
|
109
|
+
random_nickname(language="ko", theme="animal", count=2)
|
|
110
|
+
# ['깊은연어', '하얀여우갈기']
|
|
111
|
+
|
|
112
|
+
random_nickname(language="ko", unique_suffix=True, count=2)
|
|
113
|
+
# ['달력_U7aNZ', '조용한바구니_RUKAP']
|
|
114
|
+
|
|
115
|
+
random_nickname(base_word="고양이", count=3)
|
|
116
|
+
# ['하얀고양이', '고양이바람', '귀여운고양이뿔']
|
|
117
|
+
|
|
118
|
+
random_nickname_details(language="ko", unique_suffix=True)[0]
|
|
119
|
+
# NicknameDetail(nickname='오래된발견_zVShs', words=('오래된', '발견'), suffix='_zVShs', language='ko', theme='concept')
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
| Argument | Type | Default |
|
|
123
|
+
| --------------------------- | --------------------------------- | ---------- |
|
|
124
|
+
| `language` | `NicknameLanguageOption \| None` | `None` |
|
|
125
|
+
| `theme` | `NicknameThemeOption` | `"all"` |
|
|
126
|
+
| `count` | `int` | `1` |
|
|
127
|
+
| `style` | `int` (0 real … 100 invented) | `0` |
|
|
128
|
+
| `min_length` / `max_length` | `int \| None` | _language_ |
|
|
129
|
+
| `include_modifier` | `bool` | `True` |
|
|
130
|
+
| `word_separator` | `str \| None` | _language_ |
|
|
131
|
+
| `base_word` | `str` | `""` |
|
|
132
|
+
| `unique_suffix` | `bool` | `False` |
|
|
133
|
+
| `unique_suffix_length` | `int` | `5` |
|
|
134
|
+
| `unique_suffix_separator` | `str` | `"_"` |
|
|
135
|
+
| `unique_suffix_charset` | `str` | _built-in_ |
|
|
136
|
+
| `starts_with` | `str` | `""` |
|
|
137
|
+
| `unique` | `bool` | `False` |
|
|
138
|
+
|
|
139
|
+
`language` is the one argument whose default is `None` rather than `"all"`, and the two are not the same thing: left out, a `base_word` picks the language it is written in, so `"고양이"` is never handed an English modifier. Passing `"all"` mixes every language regardless.
|
|
140
|
+
|
|
141
|
+
Themes: `animal`, `object`, `nature`, `plant`, `gem`, `concept`, `myth`, `job`, `music`, `place`, `food`, `sport`, `vehicle`, `product`.
|
|
142
|
+
|
|
143
|
+
## Helpers and constants
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
from randino import name_length_range, name_supports_roman, nickname_length_range
|
|
147
|
+
|
|
148
|
+
name_length_range("ko") # (3, 3)
|
|
149
|
+
name_length_range("en", include_middle_name=True) # (12, 24)
|
|
150
|
+
name_supports_middle_name("ko") # False
|
|
151
|
+
name_supports_roman("en") # False
|
|
152
|
+
nickname_length_range("ko") # (1, 12)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`NAME_LANGUAGES`, `NICKNAME_LANGUAGES` and `NICKNAME_THEMES` list what the generators accept; `NAME_COUNT_MAX`, `NAME_LENGTH_MIN` / `MAX`, `NICKNAME_COUNT_MAX`, `NICKNAME_LENGTH_MIN` / `MAX`, `NICKNAME_SUFFIX_LENGTH_MAX` and `NICKNAME_SUFFIX_CHARSET` are the bounds every argument is clamped to.
|
|
156
|
+
|
|
157
|
+
## Differences from the npm package
|
|
158
|
+
|
|
159
|
+
The two generate the same output from the same data, and only the surface is Python's rather than JavaScript's.
|
|
160
|
+
|
|
161
|
+
| npm | PyPI |
|
|
162
|
+
| ------------------------------------------ | ----------------------------------------------- |
|
|
163
|
+
| One options object | Keyword-only arguments |
|
|
164
|
+
| `includeSurname`, `minLength` | `include_surname`, `min_length` |
|
|
165
|
+
| `language: 'ko'`, `language: 'all'` | The same strings, as `Literal` types |
|
|
166
|
+
| `[number, number]` | `tuple[int, int]` |
|
|
167
|
+
| `NameDetail` / `NicknameDetail` interfaces | The same two names, as frozen dataclasses |
|
|
168
|
+
| `detail.words` is an array | `detail.words` is a tuple |
|
|
169
|
+
|
|
170
|
+
## Development
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
uv venv && uv pip install -e ".[dev]"
|
|
174
|
+
pytest
|
|
175
|
+
ruff check . && ruff format --check .
|
|
176
|
+
mypy
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## License
|
|
180
|
+
|
|
181
|
+
MIT © [CDGet](https://cdget.com)
|
randino-1.0.0/README.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
<img src="https://raw.githubusercontent.com/jooy2/randino/main/docs/public/128x128.png" alt="randino" width="96" height="96" />
|
|
2
|
+
|
|
3
|
+
# randino for Python
|
|
4
|
+
|
|
5
|
+
[](https://github.com/jooy2/randino/blob/main/LICENSE) [](https://pypi.org/project/randino/)
|
|
6
|
+
|
|
7
|
+
### 📘 [**randino.cdget.com**](https://randino.cdget.com)
|
|
8
|
+
|
|
9
|
+
Every option and every example, with **Python** picked in the sidebar. This README is just the quick start.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
**randino** generates random person names and nicknames in the language you ask for.
|
|
14
|
+
|
|
15
|
+
- **Person names** read like names people actually carry — 김민준, Emma Clover, Иванов Иван — and come with their English pronunciation. 9 languages.
|
|
16
|
+
- **Nicknames** are the handles you would pick for a game or a website — 멋진사자, MistyOwl, 고양이꼬리. Built from everyday words across fourteen themes, never from person names.
|
|
17
|
+
- Every argument is keyword-only and optional, so `random_name()` on its own works.
|
|
18
|
+
- **Pure Python, no dependencies.** It imports nothing outside the standard library, and ships a `py.typed` marker so mypy and Pyright read the annotations.
|
|
19
|
+
|
|
20
|
+
This is the Python half. The [npm package](https://www.npmjs.com/package/randino) and the [pub.dev package](https://pub.dev/packages/randino) are the others, and all three generate from the same datasets under the same rules. They version independently, so this package's number and the others' will not always agree.
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install randino
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Requires **Python 3.10 or newer**. There is nothing else to install.
|
|
29
|
+
|
|
30
|
+
## Person names
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from randino import random_name, random_name_details
|
|
34
|
+
|
|
35
|
+
random_name()
|
|
36
|
+
# ['Emma Clover']
|
|
37
|
+
|
|
38
|
+
random_name(language="ko", count=3)
|
|
39
|
+
# ['김태윤', '원동혁', '조진우']
|
|
40
|
+
|
|
41
|
+
random_name(language="ko", script="roman")
|
|
42
|
+
# ['Kim Minjun']
|
|
43
|
+
|
|
44
|
+
random_name(language="en", gender="female", include_middle_name=True)
|
|
45
|
+
# ['Grace Amelia Bennett']
|
|
46
|
+
|
|
47
|
+
random_name_details(language="ko")[0]
|
|
48
|
+
# NameDetail(native='여미주', roman='Yeo Miju', language='ko', gender='female')
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
| Argument | Type | Default |
|
|
52
|
+
| --------------------------- | ----------------------------- | ---------- |
|
|
53
|
+
| `language` | `NameLanguageOption` | `"all"` |
|
|
54
|
+
| `gender` | `NameGenderOption` | `"all"` |
|
|
55
|
+
| `count` | `int` | `1` |
|
|
56
|
+
| `style` | `int` (0 real … 100 invented) | `0` |
|
|
57
|
+
| `min_length` / `max_length` | `int \| None` | _language_ |
|
|
58
|
+
| `include_surname` | `bool` | `True` |
|
|
59
|
+
| `include_middle_name` | `bool` | `False` |
|
|
60
|
+
| `script` | `NameScript` | `"native"` |
|
|
61
|
+
| `starts_with` | `str` | `""` |
|
|
62
|
+
| `unique` | `bool` | `False` |
|
|
63
|
+
|
|
64
|
+
`random_name_details` takes the same arguments except `script`, and returns a `NameDetail` — `native`, `roman`, `language` and `gender` — for each name.
|
|
65
|
+
|
|
66
|
+
## Nicknames
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from randino import random_nickname, random_nickname_details
|
|
70
|
+
|
|
71
|
+
random_nickname(language="ko", count=3)
|
|
72
|
+
# ['오래된곰', '영원한도마뱀', '귀여운신화다발']
|
|
73
|
+
|
|
74
|
+
random_nickname(language="en", count=2)
|
|
75
|
+
# ['FoggyHillside', 'CraneVoyage']
|
|
76
|
+
|
|
77
|
+
random_nickname(language="ko", theme="animal", count=2)
|
|
78
|
+
# ['깊은연어', '하얀여우갈기']
|
|
79
|
+
|
|
80
|
+
random_nickname(language="ko", unique_suffix=True, count=2)
|
|
81
|
+
# ['달력_U7aNZ', '조용한바구니_RUKAP']
|
|
82
|
+
|
|
83
|
+
random_nickname(base_word="고양이", count=3)
|
|
84
|
+
# ['하얀고양이', '고양이바람', '귀여운고양이뿔']
|
|
85
|
+
|
|
86
|
+
random_nickname_details(language="ko", unique_suffix=True)[0]
|
|
87
|
+
# NicknameDetail(nickname='오래된발견_zVShs', words=('오래된', '발견'), suffix='_zVShs', language='ko', theme='concept')
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
| Argument | Type | Default |
|
|
91
|
+
| --------------------------- | --------------------------------- | ---------- |
|
|
92
|
+
| `language` | `NicknameLanguageOption \| None` | `None` |
|
|
93
|
+
| `theme` | `NicknameThemeOption` | `"all"` |
|
|
94
|
+
| `count` | `int` | `1` |
|
|
95
|
+
| `style` | `int` (0 real … 100 invented) | `0` |
|
|
96
|
+
| `min_length` / `max_length` | `int \| None` | _language_ |
|
|
97
|
+
| `include_modifier` | `bool` | `True` |
|
|
98
|
+
| `word_separator` | `str \| None` | _language_ |
|
|
99
|
+
| `base_word` | `str` | `""` |
|
|
100
|
+
| `unique_suffix` | `bool` | `False` |
|
|
101
|
+
| `unique_suffix_length` | `int` | `5` |
|
|
102
|
+
| `unique_suffix_separator` | `str` | `"_"` |
|
|
103
|
+
| `unique_suffix_charset` | `str` | _built-in_ |
|
|
104
|
+
| `starts_with` | `str` | `""` |
|
|
105
|
+
| `unique` | `bool` | `False` |
|
|
106
|
+
|
|
107
|
+
`language` is the one argument whose default is `None` rather than `"all"`, and the two are not the same thing: left out, a `base_word` picks the language it is written in, so `"고양이"` is never handed an English modifier. Passing `"all"` mixes every language regardless.
|
|
108
|
+
|
|
109
|
+
Themes: `animal`, `object`, `nature`, `plant`, `gem`, `concept`, `myth`, `job`, `music`, `place`, `food`, `sport`, `vehicle`, `product`.
|
|
110
|
+
|
|
111
|
+
## Helpers and constants
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from randino import name_length_range, name_supports_roman, nickname_length_range
|
|
115
|
+
|
|
116
|
+
name_length_range("ko") # (3, 3)
|
|
117
|
+
name_length_range("en", include_middle_name=True) # (12, 24)
|
|
118
|
+
name_supports_middle_name("ko") # False
|
|
119
|
+
name_supports_roman("en") # False
|
|
120
|
+
nickname_length_range("ko") # (1, 12)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`NAME_LANGUAGES`, `NICKNAME_LANGUAGES` and `NICKNAME_THEMES` list what the generators accept; `NAME_COUNT_MAX`, `NAME_LENGTH_MIN` / `MAX`, `NICKNAME_COUNT_MAX`, `NICKNAME_LENGTH_MIN` / `MAX`, `NICKNAME_SUFFIX_LENGTH_MAX` and `NICKNAME_SUFFIX_CHARSET` are the bounds every argument is clamped to.
|
|
124
|
+
|
|
125
|
+
## Differences from the npm package
|
|
126
|
+
|
|
127
|
+
The two generate the same output from the same data, and only the surface is Python's rather than JavaScript's.
|
|
128
|
+
|
|
129
|
+
| npm | PyPI |
|
|
130
|
+
| ------------------------------------------ | ----------------------------------------------- |
|
|
131
|
+
| One options object | Keyword-only arguments |
|
|
132
|
+
| `includeSurname`, `minLength` | `include_surname`, `min_length` |
|
|
133
|
+
| `language: 'ko'`, `language: 'all'` | The same strings, as `Literal` types |
|
|
134
|
+
| `[number, number]` | `tuple[int, int]` |
|
|
135
|
+
| `NameDetail` / `NicknameDetail` interfaces | The same two names, as frozen dataclasses |
|
|
136
|
+
| `detail.words` is an array | `detail.words` is a tuple |
|
|
137
|
+
|
|
138
|
+
## Development
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
uv venv && uv pip install -e ".[dev]"
|
|
142
|
+
pytest
|
|
143
|
+
ruff check . && ruff format --check .
|
|
144
|
+
mypy
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## License
|
|
148
|
+
|
|
149
|
+
MIT © [CDGet](https://cdget.com)
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "randino"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Generates random person names and nicknames in the language you ask for — Korean, English, Japanese, Chinese and six more. No dependencies, pure Python."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
# 3.10 is where `X | Y` in annotations and `dataclass(slots=True)` both landed,
|
|
13
|
+
# and 3.9 reached end of life in October 2025.
|
|
14
|
+
requires-python = ">=3.10"
|
|
15
|
+
authors = [{ name = "CDGet", email = "jooy2.contact@gmail.com" }]
|
|
16
|
+
keywords = [
|
|
17
|
+
"random",
|
|
18
|
+
"name",
|
|
19
|
+
"nickname",
|
|
20
|
+
"username",
|
|
21
|
+
"name-generator",
|
|
22
|
+
"nickname-generator",
|
|
23
|
+
"mock",
|
|
24
|
+
"dummy",
|
|
25
|
+
"i18n",
|
|
26
|
+
"romanize",
|
|
27
|
+
]
|
|
28
|
+
classifiers = [
|
|
29
|
+
"Development Status :: 5 - Production/Stable",
|
|
30
|
+
"Intended Audience :: Developers",
|
|
31
|
+
"Operating System :: OS Independent",
|
|
32
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
33
|
+
"Programming Language :: Python :: 3.10",
|
|
34
|
+
"Programming Language :: Python :: 3.11",
|
|
35
|
+
"Programming Language :: Python :: 3.12",
|
|
36
|
+
"Programming Language :: Python :: 3.13",
|
|
37
|
+
"Programming Language :: Python :: 3.14",
|
|
38
|
+
"Topic :: Software Development :: Testing",
|
|
39
|
+
"Topic :: Text Processing :: Linguistic",
|
|
40
|
+
"Typing :: Typed",
|
|
41
|
+
]
|
|
42
|
+
# No runtime dependencies. This is a hard constraint, not a preference — it is
|
|
43
|
+
# why the Hangul romanizer is written out in `name/_romanize.py`.
|
|
44
|
+
dependencies = []
|
|
45
|
+
|
|
46
|
+
[project.urls]
|
|
47
|
+
Homepage = "https://randino.cdget.com"
|
|
48
|
+
Documentation = "https://randino.cdget.com"
|
|
49
|
+
Repository = "https://github.com/jooy2/randino"
|
|
50
|
+
Issues = "https://github.com/jooy2/randino/issues"
|
|
51
|
+
Changelog = "https://randino.cdget.com/changelog"
|
|
52
|
+
|
|
53
|
+
[project.optional-dependencies]
|
|
54
|
+
dev = ["mypy>=1.15", "pytest>=8.3", "ruff>=0.9"]
|
|
55
|
+
|
|
56
|
+
[tool.hatch.build.targets.wheel]
|
|
57
|
+
packages = ["src/randino"]
|
|
58
|
+
|
|
59
|
+
[tool.hatch.build.targets.sdist]
|
|
60
|
+
# The tests travel with the source distribution; nothing else outside the package
|
|
61
|
+
# is worth shipping.
|
|
62
|
+
include = ["src/randino", "tests", "README.md", "CHANGELOG.md", "LICENSE"]
|
|
63
|
+
# Hatchling also ships the VCS ignore file it finds walking up, which here is the
|
|
64
|
+
# repository's own. Neither `exclude` nor `ignore-vcs` suppresses it, so the
|
|
65
|
+
# sdist carries a stray `.gitignore` describing `node_modules/`. Harmless, and
|
|
66
|
+
# not worth dead configuration that does not actually remove it.
|
|
67
|
+
|
|
68
|
+
[tool.ruff]
|
|
69
|
+
line-length = 100
|
|
70
|
+
src = ["src", "tests"]
|
|
71
|
+
|
|
72
|
+
[tool.ruff.lint]
|
|
73
|
+
select = [
|
|
74
|
+
"E", # pycodestyle
|
|
75
|
+
"W", # pycodestyle warnings
|
|
76
|
+
"F", # pyflakes
|
|
77
|
+
"I", # import sorting
|
|
78
|
+
"N", # pep8-naming
|
|
79
|
+
"UP", # pyupgrade
|
|
80
|
+
"B", # bugbear
|
|
81
|
+
"SIM", # flake8-simplify
|
|
82
|
+
"RUF", # ruff's own
|
|
83
|
+
"D", # pydocstyle — everything public carries a docstring
|
|
84
|
+
]
|
|
85
|
+
ignore = [
|
|
86
|
+
# The datasets are whitespace-separated pools inside a triple-quoted string.
|
|
87
|
+
# Their line lengths follow the JavaScript package's, and reflowing them by
|
|
88
|
+
# hand to a column count would make the two harder to diff.
|
|
89
|
+
"E501",
|
|
90
|
+
# A one-line summary is what these modules and functions have; a blank line
|
|
91
|
+
# before a closing `"""` and a mandated period are noise.
|
|
92
|
+
"D203",
|
|
93
|
+
"D213",
|
|
94
|
+
# Homoglyph detection, aimed at a Cyrillic `а` smuggled into an identifier.
|
|
95
|
+
# Half of what this package ships is Cyrillic, Hangul and kana pools, and the
|
|
96
|
+
# romanizer's comments quote them — every hit here is the data doing its job.
|
|
97
|
+
"RUF001",
|
|
98
|
+
"RUF002",
|
|
99
|
+
"RUF003",
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
[tool.ruff.lint.per-file-ignores]
|
|
103
|
+
# Tests describe themselves in their names; `data/` files are pools, not prose.
|
|
104
|
+
"tests/*" = ["D103"]
|
|
105
|
+
|
|
106
|
+
[tool.ruff.lint.pydocstyle]
|
|
107
|
+
convention = "google"
|
|
108
|
+
|
|
109
|
+
[tool.ruff.format]
|
|
110
|
+
docstring-code-format = true
|
|
111
|
+
|
|
112
|
+
[tool.mypy]
|
|
113
|
+
files = ["src", "tests"]
|
|
114
|
+
python_version = "3.10"
|
|
115
|
+
strict = true
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""randino — random person names and nicknames, per language, with no dependencies.
|
|
2
|
+
|
|
3
|
+
Two separate concerns, deliberately. `random_name` produces names a person could
|
|
4
|
+
actually carry (`김민준`, `Emma Clover`); `random_nickname` produces the handle
|
|
5
|
+
someone would pick for a game or a website (`멋진사자`, `MistyOwl`), built from
|
|
6
|
+
everyday words and never from person names.
|
|
7
|
+
|
|
8
|
+
Example:
|
|
9
|
+
>>> from randino import random_name, random_nickname
|
|
10
|
+
>>> random_name(language="ko", count=3)
|
|
11
|
+
['김민준', '이서연', '박지호']
|
|
12
|
+
>>> random_nickname(language="en")
|
|
13
|
+
['MistyOwl']
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from randino._types import (
|
|
17
|
+
NameDetail,
|
|
18
|
+
NameGender,
|
|
19
|
+
NameGenderOption,
|
|
20
|
+
NameLanguage,
|
|
21
|
+
NameLanguageOption,
|
|
22
|
+
NameScript,
|
|
23
|
+
NicknameDetail,
|
|
24
|
+
NicknameLanguage,
|
|
25
|
+
NicknameLanguageOption,
|
|
26
|
+
NicknameTheme,
|
|
27
|
+
NicknameThemeOption,
|
|
28
|
+
)
|
|
29
|
+
from randino.name import (
|
|
30
|
+
NAME_COUNT_MAX,
|
|
31
|
+
NAME_LANGUAGES,
|
|
32
|
+
NAME_LENGTH_MAX,
|
|
33
|
+
NAME_LENGTH_MIN,
|
|
34
|
+
name_length_range,
|
|
35
|
+
name_supports_middle_name,
|
|
36
|
+
name_supports_roman,
|
|
37
|
+
random_name,
|
|
38
|
+
random_name_details,
|
|
39
|
+
)
|
|
40
|
+
from randino.nickname import (
|
|
41
|
+
NICKNAME_COUNT_MAX,
|
|
42
|
+
NICKNAME_LANGUAGES,
|
|
43
|
+
NICKNAME_LENGTH_MAX,
|
|
44
|
+
NICKNAME_LENGTH_MIN,
|
|
45
|
+
NICKNAME_SUFFIX_CHARSET,
|
|
46
|
+
NICKNAME_SUFFIX_LENGTH_MAX,
|
|
47
|
+
NICKNAME_THEMES,
|
|
48
|
+
nickname_length_range,
|
|
49
|
+
random_nickname,
|
|
50
|
+
random_nickname_details,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
__all__ = [
|
|
54
|
+
"NAME_COUNT_MAX",
|
|
55
|
+
"NAME_LANGUAGES",
|
|
56
|
+
"NAME_LENGTH_MAX",
|
|
57
|
+
"NAME_LENGTH_MIN",
|
|
58
|
+
"NICKNAME_COUNT_MAX",
|
|
59
|
+
"NICKNAME_LANGUAGES",
|
|
60
|
+
"NICKNAME_LENGTH_MAX",
|
|
61
|
+
"NICKNAME_LENGTH_MIN",
|
|
62
|
+
"NICKNAME_SUFFIX_CHARSET",
|
|
63
|
+
"NICKNAME_SUFFIX_LENGTH_MAX",
|
|
64
|
+
"NICKNAME_THEMES",
|
|
65
|
+
"NameDetail",
|
|
66
|
+
"NameGender",
|
|
67
|
+
"NameGenderOption",
|
|
68
|
+
"NameLanguage",
|
|
69
|
+
"NameLanguageOption",
|
|
70
|
+
"NameScript",
|
|
71
|
+
"NicknameDetail",
|
|
72
|
+
"NicknameLanguage",
|
|
73
|
+
"NicknameLanguageOption",
|
|
74
|
+
"NicknameTheme",
|
|
75
|
+
"NicknameThemeOption",
|
|
76
|
+
"name_length_range",
|
|
77
|
+
"name_supports_middle_name",
|
|
78
|
+
"name_supports_roman",
|
|
79
|
+
"nickname_length_range",
|
|
80
|
+
"random_name",
|
|
81
|
+
"random_name_details",
|
|
82
|
+
"random_nickname",
|
|
83
|
+
"random_nickname_details",
|
|
84
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Helpers shared by both generators. Nothing here is part of the public API."""
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Helpers that keep the datasets readable.
|
|
2
|
+
|
|
3
|
+
Pools are written as whitespace-separated strings inside a triple-quoted string
|
|
4
|
+
instead of one list entry per line, which keeps a 120-name pool to a handful of
|
|
5
|
+
lines.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import NamedTuple
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class NameToken(NamedTuple):
|
|
12
|
+
"""A name part that carries its own romanization (Japanese kanji, Chinese hanzi)."""
|
|
13
|
+
|
|
14
|
+
n: str
|
|
15
|
+
"""The part in its own script."""
|
|
16
|
+
|
|
17
|
+
r: str
|
|
18
|
+
"""How that part is read in the Latin alphabet."""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def words(source: str) -> tuple[str, ...]:
|
|
22
|
+
"""Split a whitespace-separated pool.
|
|
23
|
+
|
|
24
|
+
`_` stands for a space inside a single entry, so multi-word names survive the
|
|
25
|
+
split (`De_Luca` -> `De Luca`).
|
|
26
|
+
"""
|
|
27
|
+
return tuple(word.replace("_", " ") for word in source.split())
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def tokens(source: str) -> tuple[NameToken, ...]:
|
|
31
|
+
"""Split a whitespace-separated pool of `native:roman` pairs.
|
|
32
|
+
|
|
33
|
+
For scripts whose characters carry their own reading (Japanese kanji, Chinese
|
|
34
|
+
hanzi).
|
|
35
|
+
"""
|
|
36
|
+
return tuple(NameToken(*pair.split(":", 1)) for pair in words(source))
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def weights(source: str) -> dict[str, int]:
|
|
40
|
+
"""Split a whitespace-separated pool of `native:weight` pairs into a lookup.
|
|
41
|
+
|
|
42
|
+
For pools whose entries are not equally likely (surname frequency). Entries left
|
|
43
|
+
out of the source keep whatever default the caller falls back to.
|
|
44
|
+
"""
|
|
45
|
+
return {token.n: int(token.r) for token in tokens(source)}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def roman_map(source: str) -> dict[str, str]:
|
|
49
|
+
"""Build a native -> romanization lookup from `native:roman` pairs."""
|
|
50
|
+
return {token.n: token.r for token in tokens(source)}
|