Codebase Knowledge Index¶
Overview¶
afwf_genpass is an Alfred workflow that ships three independent generators —
secure passwords, YouTube-style short IDs, and UUID4s — each wired to its own
Alfred keyword. Under the hood it is a thin layer on top of the
afwf SDK: every Alfred keyword
calls a Python function that returns an afwf.ScriptFilter object, which the
CLI serializes to JSON for Alfred to render.
This page is the knowledge index for the codebase — a one-stop list of the files that define what the workflow does and where to look when you need to change something.
Top-level configuration files¶
The package metadata, dependencies (afwf, fire, diskcache), and the
console-script entry point afwf-genpass = "afwf_genpass.cli:run" are
declared in pyproject.toml. This is the binary that Alfred invokes — and
the same binary you can reach from the shell via uvx --from afwf-genpass.
pyproject.toml
1# ==============================================================================
2# The [project] table defined by Official python.org
3#
4# Read: https://packaging.python.org/en/latest/guides/writing-pyproject-toml/
5# ==============================================================================
6[project]
7name = "afwf_genpass"
8# Increment version before each release - follow `semantic versioning <https://semver.org/>`_
9# Currently, poetry 2.1.X doesn't support dynamic versioning
10# (Read https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#version)
11# So this value has to be aligned with the one in ``afwf_genpass/_version.py``
12version = "0.1.2"
13description = "Alfred Workflow for Random Password."
14# Read https://dev-exp-share.readthedocs.io/en/latest/search.html?q=Pick+An+Open+Source+License+For+Python+Project&check_keywords=yes&area=default
15# To pick a license and update the ``license``, ``classifier`` field in ``pyproject.toml``
16# And also update the ``LICENSE.txt`` file in the git repo.
17license = "MIT"
18license-files = ["LICENSE.txt", "AUTHORS.rst"]
19authors = [
20 { name = "Sanhe Hu", email = "husanhe@email.com" },
21]
22maintainers = [
23 { name = "Sanhe Hu", email = "husanhe@email.com" },
24]
25keywords = []
26readme = "README.rst"
27requires-python = ">=3.10,<4.0"
28# Full list of classifiers: https://pypi.org/classifiers/
29classifiers = [
30 "Development Status :: 4 - Beta",
31 "Intended Audience :: Developers",
32 "Natural Language :: English",
33 "Operating System :: Microsoft :: Windows",
34 "Operating System :: MacOS",
35 "Operating System :: Unix",
36 "Programming Language :: Python :: 3",
37 "Programming Language :: Python :: 3.10",
38 "Programming Language :: Python :: 3.11",
39 "Programming Language :: Python :: 3.12",
40 "Programming Language :: Python :: 3.13",
41 "Programming Language :: Python :: 3.14",
42]
43
44# ------------------------------------------------------------------------------
45# Core Dependencies
46# ------------------------------------------------------------------------------
47dependencies = [
48 "afwf>=1.0.2,<2.0.0",
49 "diskcache>=5.6.3,<6.0.0",
50 "fire>=0.6.0,<1.0.0",
51]
52
53# ------------------------------------------------------------------------------
54# Optional dependency that can be used in ``pip install ${your_project_name}[${feature_name}]``
55# Sometime this is also called "extras"
56# Read: https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#dependencies-optional-dependencies
57#
58# IMPORTANT: all optional dependencies has to be compatible with the "requires-python" field
59# ------------------------------------------------------------------------------
60[project.optional-dependencies]
61
62# ------------------------------------------------------------------------------
63# Local Development dependenceies
64# ------------------------------------------------------------------------------
65dev = [
66 "rich>=13.8.1,<14.0.0", # pretty print
67]
68
69# ------------------------------------------------------------------------------
70# (Unit/Coverage/Integration/Load) Test dependenceies
71# ------------------------------------------------------------------------------
72test = [
73 "pytest>=8.2.2,<9.0.0", # Testing framework
74 "pytest-cov>=6.0.0,<7.0.0", # Coverage reporting
75]
76
77# ------------------------------------------------------------------------------
78# Documentation build dependenceies
79# ------------------------------------------------------------------------------
80doc = [
81 "Sphinx>=7.4.7,<8.0.0",
82 "sphinx-copybutton>=0.5.2,<1.0.0", # add copy button to code block
83 "sphinx-design>=0.6.1,<1.0.0", # add additional design pattern to sphinx
84 "sphinx-jinja>=2.0.2,<3.0.0", # enable jinja syntax in reStructuredText
85 "furo==2024.8.6", # the furo sphinx theme
86 "pygments>=2.18.0,<3.0.0", # syntax highlight
87 "ipython>=8.18.1,<8.19.0", # interactive Python
88 "nbsphinx>=0.8.12,<1.0.0", # add jupyter notebook in sphinx doc
89 "rstobj==2.0.0", # generate reStructuredText from Python code
90 "docfly==3.0.3", # automaticall generate .. toctree directives and API reference doc
91]
92
93# ------------------------------------------------------------------------------
94# Mise task runner dependencies
95# ------------------------------------------------------------------------------
96mise = [
97 "PyGithub>=2.8.0,<3.0.0", # GitHub API client
98 "httpx>=0.28.0,<1.0.0", # HTTP client for ReadTheDocs API
99 "tomli>=2.0.0,<3.0.0; python_version < '3.11'", # TOML parser for Python 3.10
100]
101
102# Quick Links
103[project.urls]
104Homepage = "https://github.com/MacHu-GWU/afwf_genpass-project"
105Documentation = "https://afwf-genpass.readthedocs.io/en/latest/"
106Repository = "https://github.com/MacHu-GWU/afwf_genpass-project"
107Issues = "https://github.com/MacHu-GWU/afwf_genpass-project/issues"
108Changelog = "https://github.com/MacHu-GWU/afwf_genpass-project/blob/main/release-history.rst"
109Download = "https://pypi.org/pypi/afwf-genpass#files"
110
111# For command line interface, read: https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#creating-executable-scripts
112[project.scripts]
113afwf-genpass = "afwf_genpass.cli:run"
114
115[tool.setuptools.packages.find]
116where = ["."]
117include = [
118 "afwf_genpass*"
119]
120exclude = [
121 "afwf_genpass.tests",
122 "afwf_genpass.tests.*",
123 "afwf_genpass.docs",
124 "afwf_genpass.docs.*",
125]
126
127[build-system]
128requires = ["setuptools>=61.0", "wheel"]
129build-backend = "setuptools.build_meta"
The Alfred workflow definition lives in info.plist. It contains three
Script Filter nodes — genpass, genid, genuuid4 — each of which
calls ~/.local/bin/uvx --from "afwf-genpass==X.Y.Z" afwf-genpass <subcommand>.
Keep this file in the repo as the source of truth; the installed copy in
Alfred is a snapshot taken at release time.
info.plist
1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3<plist version="1.0">
4<dict>
5 <key>bundleid</key>
6 <string>MacHu-GWU.generate-secure-password</string>
7 <key>connections</key>
8 <dict>
9 <key>C9643FA2-6BC2-4020-A2D4-4099AF6D58DE</key>
10 <array/>
11 </dict>
12 <key>createdby</key>
13 <string>Sanhe Hu</string>
14 <key>description</key>
15 <string>Generate a Secure Password made easy</string>
16 <key>disabled</key>
17 <false/>
18 <key>name</key>
19 <string>afwf_genpass</string>
20 <key>objects</key>
21 <array>
22 <dict>
23 <key>config</key>
24 <dict>
25 <key>alfredfiltersresults</key>
26 <false/>
27 <key>alfredfiltersresultsmatchmode</key>
28 <integer>0</integer>
29 <key>argumenttreatemptyqueryasnil</key>
30 <false/>
31 <key>argumenttrimmode</key>
32 <integer>0</integer>
33 <key>argumenttype</key>
34 <integer>1</integer>
35 <key>escaping</key>
36 <integer>68</integer>
37 <key>keyword</key>
38 <string>genpass</string>
39 <key>queuedelaycustom</key>
40 <integer>3</integer>
41 <key>queuedelayimmediatelyinitially</key>
42 <true/>
43 <key>queuedelaymode</key>
44 <integer>1</integer>
45 <key>queuemode</key>
46 <integer>1</integer>
47 <key>runningsubtext</key>
48 <string>please wait ...</string>
49 <key>script</key>
50 <string>~/.local/bin/uvx --from "afwf-genpass==0.1.2" afwf-genpass genpass --query '{query}'
51# ~/Documents/GitHub/afwf_genpass-project/.venv/bin/afwf-genpass genpass --query '{query}'</string>
52 <key>scriptargtype</key>
53 <integer>0</integer>
54 <key>scriptfile</key>
55 <string></string>
56 <key>subtext</key>
57 <string>Generate a secure password</string>
58 <key>title</key>
59 <string>genpass</string>
60 <key>type</key>
61 <integer>0</integer>
62 <key>withspace</key>
63 <true/>
64 </dict>
65 <key>type</key>
66 <string>alfred.workflow.input.scriptfilter</string>
67 <key>uid</key>
68 <string>C9643FA2-6BC2-4020-A2D4-4099AF6D58DE</string>
69 <key>version</key>
70 <integer>3</integer>
71 </dict>
72 <dict>
73 <key>config</key>
74 <dict>
75 <key>alfredfiltersresults</key>
76 <false/>
77 <key>alfredfiltersresultsmatchmode</key>
78 <integer>0</integer>
79 <key>argumenttreatemptyqueryasnil</key>
80 <false/>
81 <key>argumenttrimmode</key>
82 <integer>0</integer>
83 <key>argumenttype</key>
84 <integer>1</integer>
85 <key>escaping</key>
86 <integer>68</integer>
87 <key>keyword</key>
88 <string>genid</string>
89 <key>queuedelaycustom</key>
90 <integer>3</integer>
91 <key>queuedelayimmediatelyinitially</key>
92 <true/>
93 <key>queuedelaymode</key>
94 <integer>1</integer>
95 <key>queuemode</key>
96 <integer>1</integer>
97 <key>runningsubtext</key>
98 <string>please wait ...</string>
99 <key>script</key>
100 <string>~/.local/bin/uvx --from "afwf-genpass==0.1.2" afwf-genpass genid --query '{query}'
101# ~/Documents/GitHub/afwf_genpass-project/.venv/bin/afwf-genpass genid --query '{query}'</string>
102 <key>scriptargtype</key>
103 <integer>0</integer>
104 <key>scriptfile</key>
105 <string></string>
106 <key>subtext</key>
107 <string>Generate Random ID</string>
108 <key>title</key>
109 <string>genid</string>
110 <key>type</key>
111 <integer>0</integer>
112 <key>withspace</key>
113 <true/>
114 </dict>
115 <key>type</key>
116 <string>alfred.workflow.input.scriptfilter</string>
117 <key>uid</key>
118 <string>D5C6FAF4-8EC7-4F6E-842A-50587EDA22A9</string>
119 <key>version</key>
120 <integer>3</integer>
121 </dict>
122 <dict>
123 <key>config</key>
124 <dict>
125 <key>alfredfiltersresults</key>
126 <false/>
127 <key>alfredfiltersresultsmatchmode</key>
128 <integer>0</integer>
129 <key>argumenttreatemptyqueryasnil</key>
130 <false/>
131 <key>argumenttrimmode</key>
132 <integer>0</integer>
133 <key>argumenttype</key>
134 <integer>2</integer>
135 <key>escaping</key>
136 <integer>68</integer>
137 <key>keyword</key>
138 <string>genuuid4</string>
139 <key>queuedelaycustom</key>
140 <integer>3</integer>
141 <key>queuedelayimmediatelyinitially</key>
142 <true/>
143 <key>queuedelaymode</key>
144 <integer>1</integer>
145 <key>queuemode</key>
146 <integer>1</integer>
147 <key>runningsubtext</key>
148 <string>please wait ...</string>
149 <key>script</key>
150 <string>~/.local/bin/uvx --from "afwf-genpass==0.1.2" afwf-genpass genuuid4
151# ~/Documents/GitHub/afwf_genpass-project/.venv/bin/afwf-genpass genuuid4</string>
152 <key>scriptargtype</key>
153 <integer>0</integer>
154 <key>scriptfile</key>
155 <string></string>
156 <key>subtext</key>
157 <string>Generate Random UUID 4</string>
158 <key>title</key>
159 <string>genuuid4</string>
160 <key>type</key>
161 <integer>0</integer>
162 <key>withspace</key>
163 <false/>
164 </dict>
165 <key>type</key>
166 <string>alfred.workflow.input.scriptfilter</string>
167 <key>uid</key>
168 <string>7CF84DAD-33A9-408A-8DA3-107AF4FCC927</string>
169 <key>version</key>
170 <integer>3</integer>
171 </dict>
172 </array>
173 <key>readme</key>
174 <string>This workflow can generate secure password that:
175
176- length is between 8, 32 (you can define it)
177- has at least one lowercase letter
178- has at least one upper letter
179- has at least one digital letter
180- has at least one special character
181- avoid characters like ``1lIoO0`` that is hard to distinguish
182
183Dependencies:
184
185- OS Intel / Arm
186- Python3.7+</string>
187 <key>uidata</key>
188 <dict>
189 <key>7CF84DAD-33A9-408A-8DA3-107AF4FCC927</key>
190 <dict>
191 <key>xpos</key>
192 <real>40</real>
193 <key>ypos</key>
194 <real>240</real>
195 </dict>
196 <key>C9643FA2-6BC2-4020-A2D4-4099AF6D58DE</key>
197 <dict>
198 <key>xpos</key>
199 <real>40</real>
200 <key>ypos</key>
201 <real>30</real>
202 </dict>
203 <key>D5C6FAF4-8EC7-4F6E-842A-50587EDA22A9</key>
204 <dict>
205 <key>xpos</key>
206 <real>40</real>
207 <key>ypos</key>
208 <real>135</real>
209 </dict>
210 </dict>
211 <key>userconfigurationconfig</key>
212 <array/>
213 <key>variablesdontexport</key>
214 <array/>
215 <key>version</key>
216 <string>0.1.1</string>
217 <key>webaddress</key>
218 <string>https://github.com/MacHu-GWU/afwf_genpass-project</string>
219</dict>
220</plist>
End-user documentation — what each keyword does, allowed length ranges,
default values, banned visually-confusing characters, and install instructions
— lives in README.rst.
README.rst
1.. image:: https://readthedocs.org/projects/afwf-genpass/badge/?version=latest
2 :target: https://afwf-genpass.readthedocs.io/en/latest/
3 :alt: Documentation Status
4
5.. image:: https://github.com/MacHu-GWU/afwf_genpass-project/actions/workflows/main.yml/badge.svg
6 :target: https://github.com/MacHu-GWU/afwf_genpass-project/actions?query=workflow:CI
7
8.. image:: https://codecov.io/gh/MacHu-GWU/afwf_genpass-project/branch/main/graph/badge.svg
9 :target: https://codecov.io/gh/MacHu-GWU/afwf_genpass-project
10
11.. image:: https://img.shields.io/pypi/v/afwf-genpass.svg
12 :target: https://pypi.python.org/pypi/afwf-genpass
13
14.. image:: https://img.shields.io/pypi/l/afwf-genpass.svg
15 :target: https://pypi.python.org/pypi/afwf-genpass
16
17.. image:: https://img.shields.io/pypi/pyversions/afwf-genpass.svg
18 :target: https://pypi.python.org/pypi/afwf-genpass
19
20.. image:: https://img.shields.io/badge/✍️_Release_History!--None.svg?style=social&logo=github
21 :target: https://github.com/MacHu-GWU/afwf_genpass-project/blob/main/release-history.rst
22
23.. image:: https://img.shields.io/badge/⭐_Star_me_on_GitHub!--None.svg?style=social&logo=github
24 :target: https://github.com/MacHu-GWU/afwf_genpass-project
25
26------
27
28.. image:: https://img.shields.io/badge/Link-API-blue.svg
29 :target: https://afwf-genpass.readthedocs.io/en/latest/py-modindex.html
30
31.. image:: https://img.shields.io/badge/Link-Install-blue.svg
32 :target: `Installation`_
33
34.. image:: https://img.shields.io/badge/Link-GitHub-blue.svg
35 :target: https://github.com/MacHu-GWU/afwf_genpass-project
36
37.. image:: https://img.shields.io/badge/Link-Submit_Issue-blue.svg
38 :target: https://github.com/MacHu-GWU/afwf_genpass-project/issues
39
40.. image:: https://img.shields.io/badge/Link-Request_Feature-blue.svg
41 :target: https://github.com/MacHu-GWU/afwf_genpass-project/issues
42
43.. image:: https://img.shields.io/badge/Link-Download-blue.svg
44 :target: https://pypi.org/pypi/afwf-genpass#files
45
46
47Welcome to ``afwf_genpass`` Documentation
48==============================================================================
49.. image:: https://afwf-genpass.readthedocs.io/en/latest/_static/afwf_genpass-logo.png
50 :target: https://afwf-genpass.readthedocs.io/en/latest/
51
52Use Case
53------------------------------------------------------------------------------
54This Alfred workflow exposes three independent Script Filters, each bound to its own keyword: ``genpass``, ``genid``, and ``genuuid4``.
55
56``genpass`` — Generate Secure Password
57------------------------------------------------------------------------------
58Type ``genpass <length>`` in Alfred to get 8 random passwords of the given ``<length>``. Each password is guaranteed to contain at least one lowercase letter, one uppercase letter, one digit and one symbol (from ``!%@#&^*``), and always starts with a letter.
59
60Allowed length is ``8`` to ``32``; default is ``12`` (just hit Enter on ``genpass``). Tab autocompletes to the default length. Hit ⌘C on any item to copy the password to your clipboard. Visually-confusing characters ``1``, ``l``, ``I``, ``O``, ``0`` are excluded for readability.
61
62``genid`` — Generate Short ID
63------------------------------------------------------------------------------
64Type ``genid <length>`` in Alfred to get 8 random YouTube-style short IDs of the given ``<length>``. Backed by ``secrets.choice`` (cryptographically strong) over a 57-character URL-safe charset, suitable for use as opaque identifiers in URLs, filenames, blog slugs, etc.
65
66Allowed length is ``6`` to ``32``; default is ``16`` (just hit Enter on ``genid``). Tab autocompletes to the default length. Hit ⌘C on any item to copy the ID to your clipboard. Visually-confusing characters ``0``, ``1``, ``l``, ``O``, ``o`` are excluded for readability.
67
68``genuuid4`` — Generate UUID4
69------------------------------------------------------------------------------
70Just type ``genuuid4`` in Alfred to get 8 freshly generated standard RFC 4122 UUID4s, formatted as ``8-4-4-4-12`` lowercase hex (e.g. ``550e8400-e29b-41d4-a716-446655440000``). No parameters — UUID4 has a fixed format. Hit ⌘C on any item to copy the UUID to your clipboard.
71
72For the length-based keywords (``genpass`` / ``genid``), if the value you type is not a valid integer in the allowed range, the workflow shows an inline error item instead of producing garbage results.
73
74Installation
75------------------------------------------------------------------------------
76Go to https://github.com/MacHu-GWU/afwf_genpass-project/releases, download the latest ``afwf-genpass-X.Y.Z.alfredworkflow`` file, double click to install.
Source package — afwf_genpass/¶
afwf_genpass.cli— thefire-based command-line entry point exposed as theafwf-genpassconsole script. Two flavours per generator:gen*— Alfred Script Filter entry, emits JSON viaafwfand routes uncaught errors to a rotating log file at~/.alfred-afwf/afwf_genpass/error.log.gen*-one— plain stdout, prints exactly one value. Independent of Alfred; handy in shell pipelines (e.g.export TOKEN=$(afwf-genpass genid-one)).
afwf_genpass.constants— single source of truth for all configuration knobs: character sets, banned characters, length bounds, default lengths, item-count constants, and the human-readable UI messages shown in Alfred. Change a default length or a banned character here and the rest of the codebase picks it up.afwf_genpass.genpass— secure password generator. Detailed in Section 03.afwf_genpass.genid— YouTube-style short-ID generator. Detailed in Section 04.afwf_genpass.genuuid4— UUID4 generator. Detailed in Section 05.afwf_genpass.paths— centralizedPathEnumof all project paths (project home, cache directory, error log, docs, virtualenv, etc.). All file paths used elsewhere in the codebase should be resolved throughpath_enumrather than hard-coded.
Tests — tests/¶
tests.test_genpasstests.test_genidtests.test_genuuid4tests.test_cli
Pytest-based unit tests covering both the pure main() functions and the
Command class in afwf_genpass.cli (including the _one stdout
variants). Each file can be run standalone — the if __name__ == "__main__":
block invokes pytest with coverage for the matching module.
Reading order¶
If you are new to the codebase, read in this order:
README.rst— what the workflow does from a user’s perspectiveafwf_genpass.constants— every tunable parameter in the projectafwf_genpass.genpass/afwf_genpass.genid/afwf_genpass.genuuid4— the three generatorsafwf_genpass.cli— how the generators are exposed to Alfred and the shellinfo.plist— how Alfred binds keywords to CLI subcommands