namzy 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.
- namzy-0.1.0/.gitignore +5 -0
- namzy-0.1.0/.omc/sessions/53d9fa2f-6fc7-4ab8-ac23-dbc85451de77.json +8 -0
- namzy-0.1.0/CLAUDE.md +11 -0
- namzy-0.1.0/PKG-INFO +80 -0
- namzy-0.1.0/README.md +66 -0
- namzy-0.1.0/pyproject.toml +28 -0
- namzy-0.1.0/ruvector.db +0 -0
- namzy-0.1.0/src/namzy/CLAUDE.md +7 -0
- namzy-0.1.0/src/namzy/__init__.py +58 -0
- namzy-0.1.0/src/namzy/__main__.py +7 -0
- namzy-0.1.0/src/namzy/_mangle.py +52 -0
- namzy-0.1.0/src/namzy/_wordlist.py +18 -0
- namzy-0.1.0/src/namzy/cli.py +43 -0
namzy-0.1.0/.gitignore
ADDED
namzy-0.1.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<claude-mem-context>
|
|
2
|
+
# Recent Activity
|
|
3
|
+
|
|
4
|
+
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
|
|
5
|
+
|
|
6
|
+
### May 15, 2026
|
|
7
|
+
|
|
8
|
+
| ID | Time | T | Title | Read |
|
|
9
|
+
|----|------|---|-------|------|
|
|
10
|
+
| #7072 | 3:19 PM | 🟣 | Multi-language namzy implementation across TypeScript, Python, C++, and Rust | ~746 |
|
|
11
|
+
</claude-mem-context>
|
namzy-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: namzy
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Generate fun human-friendly project names
|
|
5
|
+
License: MIT
|
|
6
|
+
Keywords: fun,generator,name,project
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
# namzy
|
|
16
|
+
|
|
17
|
+
Generate fun, human-friendly project names — seeded by time, mangled for personality.
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install namzy
|
|
23
|
+
# or run without installing:
|
|
24
|
+
uvx namzy
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## CLI usage
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# One name, single word (default)
|
|
31
|
+
namzy
|
|
32
|
+
|
|
33
|
+
# Multiple names
|
|
34
|
+
namzy --count 5
|
|
35
|
+
|
|
36
|
+
# Output shapes
|
|
37
|
+
namzy --shape single # e.g. Tokyuriver
|
|
38
|
+
namzy --shape joined # e.g. TokyuRiver
|
|
39
|
+
namzy --shape spaced # e.g. Tokyu River
|
|
40
|
+
|
|
41
|
+
# Reproducible output
|
|
42
|
+
namzy --seed 42 --count 3
|
|
43
|
+
|
|
44
|
+
# Fetch words from a public API (falls back to offline on error)
|
|
45
|
+
namzy --online --count 3
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Library usage
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from namzy import generate
|
|
52
|
+
|
|
53
|
+
# Single word (default)
|
|
54
|
+
name = generate()
|
|
55
|
+
|
|
56
|
+
# Joined PascalCase
|
|
57
|
+
name = generate(shape="joined")
|
|
58
|
+
|
|
59
|
+
# Spaced words
|
|
60
|
+
name = generate(shape="spaced")
|
|
61
|
+
|
|
62
|
+
# Reproducible
|
|
63
|
+
name = generate(seed=42)
|
|
64
|
+
|
|
65
|
+
# Online mode
|
|
66
|
+
name = generate(online=True)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Modes
|
|
70
|
+
|
|
71
|
+
- **Offline** (default): Uses a bundled wordlist of ~40 geographic names and ~40 evocative English nouns. No network required.
|
|
72
|
+
- **Online**: Fetches two words from `random-word-api.herokuapp.com`. Falls back silently to offline on any error.
|
|
73
|
+
|
|
74
|
+
## Mangling
|
|
75
|
+
|
|
76
|
+
Names pass through a phonetic mangling pass: `tion→shun`, `ight→ite`, `oo→u`, `ck→kk`, `ph→f`, `ks→x`, trailing `s→z`. One or two substitutions apply randomly per word.
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
MIT
|
namzy-0.1.0/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# namzy
|
|
2
|
+
|
|
3
|
+
Generate fun, human-friendly project names — seeded by time, mangled for personality.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install namzy
|
|
9
|
+
# or run without installing:
|
|
10
|
+
uvx namzy
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## CLI usage
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# One name, single word (default)
|
|
17
|
+
namzy
|
|
18
|
+
|
|
19
|
+
# Multiple names
|
|
20
|
+
namzy --count 5
|
|
21
|
+
|
|
22
|
+
# Output shapes
|
|
23
|
+
namzy --shape single # e.g. Tokyuriver
|
|
24
|
+
namzy --shape joined # e.g. TokyuRiver
|
|
25
|
+
namzy --shape spaced # e.g. Tokyu River
|
|
26
|
+
|
|
27
|
+
# Reproducible output
|
|
28
|
+
namzy --seed 42 --count 3
|
|
29
|
+
|
|
30
|
+
# Fetch words from a public API (falls back to offline on error)
|
|
31
|
+
namzy --online --count 3
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Library usage
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from namzy import generate
|
|
38
|
+
|
|
39
|
+
# Single word (default)
|
|
40
|
+
name = generate()
|
|
41
|
+
|
|
42
|
+
# Joined PascalCase
|
|
43
|
+
name = generate(shape="joined")
|
|
44
|
+
|
|
45
|
+
# Spaced words
|
|
46
|
+
name = generate(shape="spaced")
|
|
47
|
+
|
|
48
|
+
# Reproducible
|
|
49
|
+
name = generate(seed=42)
|
|
50
|
+
|
|
51
|
+
# Online mode
|
|
52
|
+
name = generate(online=True)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Modes
|
|
56
|
+
|
|
57
|
+
- **Offline** (default): Uses a bundled wordlist of ~40 geographic names and ~40 evocative English nouns. No network required.
|
|
58
|
+
- **Online**: Fetches two words from `random-word-api.herokuapp.com`. Falls back silently to offline on any error.
|
|
59
|
+
|
|
60
|
+
## Mangling
|
|
61
|
+
|
|
62
|
+
Names pass through a phonetic mangling pass: `tion→shun`, `ight→ite`, `oo→u`, `ck→kk`, `ph→f`, `ks→x`, trailing `s→z`. One or two substitutions apply randomly per word.
|
|
63
|
+
|
|
64
|
+
## License
|
|
65
|
+
|
|
66
|
+
MIT
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "namzy"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Generate fun human-friendly project names"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
keywords = ["name", "generator", "project", "fun"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"License :: OSI Approved :: MIT License",
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Programming Language :: Python :: 3.10",
|
|
17
|
+
"Programming Language :: Python :: 3.11",
|
|
18
|
+
"Programming Language :: Python :: 3.12",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[project.scripts]
|
|
22
|
+
namzy = "namzy.cli:main"
|
|
23
|
+
|
|
24
|
+
[tool.hatch.version]
|
|
25
|
+
path = "src/namzy/__init__.py"
|
|
26
|
+
|
|
27
|
+
[tool.hatch.build.targets.wheel]
|
|
28
|
+
packages = ["src/namzy"]
|
namzy-0.1.0/ruvector.db
ADDED
|
Binary file
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# this_file: src/namzy/__init__.py
|
|
2
|
+
"""namzy — fun human-friendly project name generator."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import random
|
|
7
|
+
import time
|
|
8
|
+
|
|
9
|
+
from ._mangle import join_clean, mangle
|
|
10
|
+
from ._wordlist import COMMON, GEO
|
|
11
|
+
|
|
12
|
+
__version__ = "0.2.0"
|
|
13
|
+
|
|
14
|
+
__all__ = ["generate"]
|
|
15
|
+
|
|
16
|
+
_ONLINE_URL_TWO = "https://random-word-api.herokuapp.com/word?number=2&length=6"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _fetch_online() -> list[str] | None:
|
|
20
|
+
"""Fetch two words from a public API. Returns None on any error."""
|
|
21
|
+
try:
|
|
22
|
+
import json
|
|
23
|
+
import urllib.request
|
|
24
|
+
|
|
25
|
+
with urllib.request.urlopen(_ONLINE_URL_TWO, timeout=3) as resp:
|
|
26
|
+
data = json.loads(resp.read().decode())
|
|
27
|
+
if isinstance(data, list):
|
|
28
|
+
words = [w for w in data if w.isalpha()]
|
|
29
|
+
if len(words) >= 2:
|
|
30
|
+
return words[:2]
|
|
31
|
+
except Exception:
|
|
32
|
+
pass
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _pick_words(rng: random.Random, online: bool) -> tuple[str, str]:
|
|
37
|
+
"""Return two raw lowercase words."""
|
|
38
|
+
if online:
|
|
39
|
+
fetched = _fetch_online()
|
|
40
|
+
if fetched:
|
|
41
|
+
return fetched[0].lower(), fetched[1].lower()
|
|
42
|
+
return rng.choice(GEO).lower(), rng.choice(COMMON).lower()
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def generate(online: bool = False, seed: int | None = None) -> str:
|
|
46
|
+
"""Generate a fun project name.
|
|
47
|
+
|
|
48
|
+
Picks two words, fuses them with junction cleanup, applies consonant
|
|
49
|
+
rotation, and capitalizes the first letter.
|
|
50
|
+
"""
|
|
51
|
+
if seed is None:
|
|
52
|
+
seed = time.time_ns()
|
|
53
|
+
rng = random.Random(seed)
|
|
54
|
+
|
|
55
|
+
a, b = _pick_words(rng, online)
|
|
56
|
+
fused = join_clean(a, b)
|
|
57
|
+
rotated = mangle(fused)
|
|
58
|
+
return rotated[:1].upper() + rotated[1:]
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# this_file: src/namzy/_mangle.py
|
|
2
|
+
"""Consonant-rotation mangling and word-junction cleanup."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
_ROT = {
|
|
7
|
+
"c": "q",
|
|
8
|
+
"f": "v",
|
|
9
|
+
"k": "c",
|
|
10
|
+
"q": "k",
|
|
11
|
+
"s": "z",
|
|
12
|
+
"z": "s",
|
|
13
|
+
"v": "f",
|
|
14
|
+
"w": "u",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
_VOWELS = frozenset("aeiouy")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _rot_char(ch: str) -> str:
|
|
21
|
+
low = ch.lower()
|
|
22
|
+
if low in _ROT:
|
|
23
|
+
sub = _ROT[low]
|
|
24
|
+
return sub.upper() if ch.isupper() else sub
|
|
25
|
+
return ch
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def mangle(s: str) -> str:
|
|
29
|
+
"""Apply per-letter consonant rotation, case-preserving."""
|
|
30
|
+
return "".join(_rot_char(c) for c in s)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def join_clean(a: str, b: str) -> str:
|
|
34
|
+
"""Fuse two raw lowercase words, smoothing the junction.
|
|
35
|
+
|
|
36
|
+
Up to two passes: drop first char of tail if it duplicates the last char
|
|
37
|
+
of head (case-insensitive), or if both are vowels.
|
|
38
|
+
"""
|
|
39
|
+
head = a
|
|
40
|
+
tail = b
|
|
41
|
+
for _ in range(2):
|
|
42
|
+
if not head or not tail:
|
|
43
|
+
break
|
|
44
|
+
h = head[-1].lower()
|
|
45
|
+
t = tail[0].lower()
|
|
46
|
+
if h == t:
|
|
47
|
+
tail = tail[1:]
|
|
48
|
+
elif h in _VOWELS and t in _VOWELS:
|
|
49
|
+
tail = tail[1:]
|
|
50
|
+
else:
|
|
51
|
+
break
|
|
52
|
+
return head + tail
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# this_file: src/namzy/_wordlist.py
|
|
2
|
+
"""Bundled word lists for offline name generation."""
|
|
3
|
+
|
|
4
|
+
GEO = (
|
|
5
|
+
"tokyo", "paris", "oslo", "berlin", "lagos", "lima", "boston", "vienna",
|
|
6
|
+
"cairo", "kyoto", "delhi", "milan", "rome", "seoul", "dubai", "athens",
|
|
7
|
+
"nairobi", "bali", "oslo", "havana", "lisbon", "tunis", "bogota", "dakar",
|
|
8
|
+
"quito", "darwin", "perth", "bruges", "riga", "minsk", "sofia", "vilna",
|
|
9
|
+
"vaduz", "bern", "accra", "kigali", "abuja", "bamako", "niamey", "lome",
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
COMMON = (
|
|
13
|
+
"river", "stone", "ember", "frost", "harbor", "willow", "copper", "marble",
|
|
14
|
+
"anchor", "lantern", "cedar", "falcon", "drift", "mesa", "grove", "canyon",
|
|
15
|
+
"basin", "fern", "gale", "haven", "peak", "ridge", "shore", "tide",
|
|
16
|
+
"vale", "bluff", "brook", "crest", "delta", "flint", "glen", "helm",
|
|
17
|
+
"inlet", "jetty", "knoll", "loft", "moor", "notch", "orbit", "prism",
|
|
18
|
+
)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# this_file: src/namzy/cli.py
|
|
2
|
+
"""CLI entrypoint for namzy."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import time
|
|
8
|
+
|
|
9
|
+
from . import generate
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main() -> None:
|
|
13
|
+
parser = argparse.ArgumentParser(
|
|
14
|
+
prog="namzy",
|
|
15
|
+
description="Generate fun human-friendly project names.",
|
|
16
|
+
)
|
|
17
|
+
parser.add_argument(
|
|
18
|
+
"--online",
|
|
19
|
+
action="store_true",
|
|
20
|
+
default=False,
|
|
21
|
+
help="Fetch words from a public API (falls back to offline on error)",
|
|
22
|
+
)
|
|
23
|
+
parser.add_argument(
|
|
24
|
+
"--count",
|
|
25
|
+
type=int,
|
|
26
|
+
default=1,
|
|
27
|
+
metavar="N",
|
|
28
|
+
help="Number of names to generate (default: 1)",
|
|
29
|
+
)
|
|
30
|
+
parser.add_argument(
|
|
31
|
+
"--seed",
|
|
32
|
+
type=int,
|
|
33
|
+
default=None,
|
|
34
|
+
metavar="INT",
|
|
35
|
+
help="Random seed for reproducible output",
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
args = parser.parse_args()
|
|
39
|
+
|
|
40
|
+
base_seed = args.seed if args.seed is not None else time.time_ns()
|
|
41
|
+
|
|
42
|
+
for i in range(args.count):
|
|
43
|
+
print(generate(online=args.online, seed=base_seed + i))
|