From c823dd02649ada7d1dcd4e2a9b849bea09d097cb Mon Sep 17 00:00:00 2001 From: Jens Tirsvad Nielsen Date: Wed, 14 Oct 2026 21:21:43 +0800 Subject: [PATCH 1/4] build: add pyproject.toml, Python .gitignore and Doxyfile Task: MIL-001#1 Task: MIL-001#2 Task: MIL-001#4 --- .gitignore | 33 +++++ Doxyfile | 374 +++++++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 35 +++++ 3 files changed, 442 insertions(+) create mode 100644 .gitignore create mode 100644 Doxyfile create mode 100644 pyproject.toml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c5dc4b --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# Secrets and local configuration +.env +.env.* +!.env.example + +# Virtual environments +.venv/ +venv/ +env/ + +# Python +__pycache__/ +*.py[cod] +*.egg-info/ +build/ +dist/ +.pytest_cache/ +.mypy_cache/ +.ruff_cache/ +.coverage +htmlcov/ + +# Doxygen output +docs/doxygen/ + +# The program's own data file (it holds passwords) +data.json + +# Editors and OS +.idea/ +.vscode/ +.DS_Store +Thumbs.db diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..2f965b2 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,374 @@ +# Doxyfile 1.15.0 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "Password Manager" +PROJECT_NUMBER = +PROJECT_BRIEF = "Tkinter password manager that stores entries as JSON" +PROJECT_LOGO = +PROJECT_ICON = +OUTPUT_DIRECTORY = docs/doxygen +CREATE_SUBDIRS = NO +CREATE_SUBDIRS_LEVEL = 8 +ALLOW_UNICODE_NAMES = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +JAVADOC_BANNER = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +PYTHON_DOCSTRING = YES +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 4 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = YES +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +OPTIMIZE_OUTPUT_SLICE = NO +EXTENSION_MAPPING = +MARKDOWN_SUPPORT = YES +MARKDOWN_STRICT = YES +TOC_INCLUDE_HEADINGS = 6 +MARKDOWN_ID_STYLE = DOXYGEN +AUTOLINK_SUPPORT = YES +AUTOLINK_IGNORE_WORDS = +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +GROUP_NESTED_COMPOUNDS = NO +SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = NO +TYPEDEF_HIDES_STRUCT = NO +LOOKUP_CACHE_SIZE = 0 +NUM_PROC_THREADS = 1 +TIMESTAMP = NO +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_PRIV_VIRTUAL = NO +EXTRACT_PACKAGE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +RESOLVE_UNNAMED_PARAMS = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_UNDOC_NAMESPACES = YES +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = SYSTEM +HIDE_SCOPE_NAMES = NO +HIDE_COMPOUND_REFERENCE= NO +SHOW_HEADERFILE = YES +SHOW_INCLUDE_FILES = YES +SHOW_GROUPED_MEMB_INC = NO +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +CITE_BIB_FILES = +EXTERNAL_TOOL_PATH = +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_IF_INCOMPLETE_DOC = YES +WARN_NO_PARAMDOC = NO +WARN_IF_UNDOC_ENUM_VAL = NO +WARN_LAYOUT_FILE = YES +WARN_AS_ERROR = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LINE_FORMAT = "at line $line of file $file" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = src README.md +INPUT_ENCODING = UTF-8 +INPUT_FILE_ENCODING = +FILE_PATTERNS = *.py *.md +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +FILTER_SOURCE_PATTERNS = +USE_MDFILE_AS_MAINPAGE = README.md +IMPLICIT_DIR_DOCS = YES +FORTRAN_COMMENT_AFTER = 72 +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +SOURCE_TOOLTIPS = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +CLANG_ASSISTED_PARSING = NO +CLANG_ADD_INC_PATHS = YES +CLANG_OPTIONS = +CLANG_DATABASE_PATH = +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_EXTRA_STYLESHEET = +HTML_EXTRA_FILES = +HTML_COLORSTYLE = AUTO_LIGHT +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_DYNAMIC_MENUS = YES +HTML_DYNAMIC_SECTIONS = NO +HTML_CODE_FOLDING = YES +HTML_COPY_CLIPBOARD = YES +HTML_PROJECT_COOKIE = +HTML_INDEX_NUM_ENTRIES = 100 +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_FEEDURL = +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +SITEMAP_URL = +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +GENERATE_TREEVIEW = YES +PAGE_OUTLINE_PANEL = YES +FULL_SIDEBAR = NO +ENUM_VALUES_PER_LINE = 4 +SHOW_ENUM_VALUES = NO +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +OBFUSCATE_EMAILS = YES +HTML_FORMULA_FORMAT = png +FORMULA_FONTSIZE = 10 +FORMULA_MACROFILE = +USE_MATHJAX = NO +MATHJAX_VERSION = MathJax_2 +MATHJAX_FORMAT = HTML-CSS +MATHJAX_RELPATH = +MATHJAX_EXTENSIONS = +MATHJAX_CODEFILE = +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO +EXTERNAL_SEARCH = NO +SEARCHENGINE_URL = +SEARCHDATA_FILE = searchdata.xml +EXTERNAL_SEARCH_ID = +EXTRA_SEARCH_MAPPINGS = +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = +MAKEINDEX_CMD_NAME = makeindex +LATEX_MAKEINDEX_CMD = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4 +EXTRA_PACKAGES = +LATEX_HEADER = +LATEX_FOOTER = +LATEX_EXTRA_STYLESHEET = +LATEX_EXTRA_FILES = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_BIB_STYLE = plainnat +LATEX_EMOJI_DIRECTORY = +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +RTF_EXTRA_FILES = +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_SUBDIR = +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_PROGRAMLISTING = YES +XML_NS_MEMB_FILE_SCOPE = NO +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- +GENERATE_DOCBOOK = NO +DOCBOOK_OUTPUT = docbook +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# Configuration options related to Sqlite3 output +#--------------------------------------------------------------------------- +GENERATE_SQLITE3 = NO +SQLITE3_OUTPUT = sqlite3 +SQLITE3_RECREATE_DB = YES +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +EXTERNAL_PAGES = YES +#--------------------------------------------------------------------------- +# Configuration options related to diagram generator tools +#--------------------------------------------------------------------------- +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +DOT_NUM_THREADS = 0 +DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10" +DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10" +DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4" +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +UML_LIMIT_NUM_FIELDS = 10 +UML_MAX_EDGE_LABELS = 10 +DOT_UML_DETAILS = NO +DOT_WRAP_THRESHOLD = 17 +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DIR_GRAPH_MAX_DEPTH = 1 +DOT_IMAGE_FORMAT = png +INTERACTIVE_SVG = NO +DOT_PATH = +DOTFILE_DIRS = +DIA_PATH = +DIAFILE_DIRS = +PLANTUML_JAR_PATH = +PLANTUML_CFG_FILE = +PLANTUML_INCLUDE_PATH = +PLANTUMLFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +MSCGEN_TOOL = +MSCFILE_DIRS = diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..a039f67 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,35 @@ +[build-system] +requires = ["setuptools>=75"] +build-backend = "setuptools.build_meta" + +[project] +name = "password-manager" +version = "0.1.0" +description = "A Tkinter password manager that stores entries as JSON (100 Days of Code, day 30)." +readme = "README.md" +requires-python = ">=3.13" +license = { file = "LICENSE" } +authors = [{ name = "Jens Tirsvad Nielsen" }] +keywords = ["password-manager", "tkinter", "json", "100-days-of-code", "udemy"] +dependencies = [] + +[project.optional-dependencies] +dev = ["pytest>=8", "ruff>=0.6"] + +[project.scripts] +password-manager = "password_manager.main:main" + +[tool.setuptools.packages.find] +where = ["src"] + +[tool.pytest.ini_options] +testpaths = ["tests"] +pythonpath = ["src"] +addopts = "-ra" + +[tool.ruff] +line-length = 88 +src = ["src", "tests"] + +[tool.ruff.lint] +select = ["E", "F", "I", "N", "UP", "B", "ANN"] From 7ba340a33a90f342df5f636c43593692d9d9197b Mon Sep 17 00:00:00 2001 From: Jens Tirsvad Nielsen Date: Wed, 14 Oct 2026 21:21:44 +0800 Subject: [PATCH 2/4] feat: add package skeleton, constants.py and smoke tests Task: MIL-001#3 Task: MIL-001#7 --- src/password_manager/__init__.py | 7 ++++ src/password_manager/constants.py | 56 +++++++++++++++++++++++++++++++ tests/unit/test_constants.py | 18 ++++++++++ 3 files changed, 81 insertions(+) create mode 100644 src/password_manager/__init__.py create mode 100644 src/password_manager/constants.py create mode 100644 tests/unit/test_constants.py diff --git a/src/password_manager/__init__.py b/src/password_manager/__init__.py new file mode 100644 index 0000000..2343237 --- /dev/null +++ b/src/password_manager/__init__.py @@ -0,0 +1,7 @@ +"""@brief A Tkinter password manager that stores entries in a JSON file. + +@file __init__.py +@package password_manager +""" + +__version__ = "0.1.0" diff --git a/src/password_manager/constants.py b/src/password_manager/constants.py new file mode 100644 index 0000000..10e400b --- /dev/null +++ b/src/password_manager/constants.py @@ -0,0 +1,56 @@ +"""@brief Constants of the password manager. + +@file constants.py +@details Every literal that more than one module needs, or that a reader may +want to change, lives here and nowhere else. +""" + +import string +from pathlib import Path + +# Storage +DATA_FILE_NAME = "data.json" ##< Name of the JSON file that holds the entries. +DATA_FILE_PATH = Path( + DATA_FILE_NAME +) ##< Default location, relative to the working directory. +JSON_INDENT = 4 ##< Indentation of the written JSON, for readability. +KEY_EMAIL = "email" ##< JSON key of an entry's e-mail address. +KEY_PASSWORD = "password" ##< JSON key of an entry's password. + +# Password generator +LETTERS = string.ascii_letters ##< Letters a password may use. +DIGITS = string.digits ##< Digits a password may use. +SYMBOLS = "!#$%&()*+" ##< Symbols a password may use. +MIN_LETTERS = 8 ##< Fewest letters in a generated password. +MAX_LETTERS = 10 ##< Most letters in a generated password. +MIN_SYMBOLS = 2 ##< Fewest symbols in a generated password. +MAX_SYMBOLS = 4 ##< Most symbols in a generated password. +MIN_DIGITS = 2 ##< Fewest digits in a generated password. +MAX_DIGITS = 4 ##< Most digits in a generated password. + +# Window +WINDOW_TITLE = "Password Manager" ##< Title of the main window. +WINDOW_PADDING = 50 ##< Padding around the window content, in pixels. +LOGO_SIZE = 200 ##< Width and height of the logo canvas, in pixels. +DEFAULT_EMAIL = "name@example.com" ##< E-mail address the form starts with. +ENTRY_WIDTH_WIDE = 35 ##< Width in characters of the e-mail and add fields. +ENTRY_WIDTH_NARROW = 21 ##< Width in characters of the website and password fields. + +# Labels and messages +LABEL_WEBSITE = "Website:" +LABEL_EMAIL = "Email/Username:" +LABEL_PASSWORD = "Password:" +BUTTON_SEARCH = "Search" +BUTTON_GENERATE = "Generate Password" +BUTTON_ADD = "Add" +TITLE_OOPS = "Oops" +TITLE_SAVED = "Saved" +TITLE_FOUND = "Found" +MESSAGE_EMPTY_FIELDS = "Please don't leave any fields empty!" +MESSAGE_NO_DATA_FILE = "No Data File Found." +MESSAGE_NO_DETAILS = "No details for {website} exists." +MESSAGE_CONFIRM_SAVE = ( + "These are the details entered:\nEmail: {email}\n" + "Password: {password}\nIs it ok to save?" +) +MESSAGE_DETAILS = "Email: {email}\nPassword: {password}" diff --git a/tests/unit/test_constants.py b/tests/unit/test_constants.py new file mode 100644 index 0000000..ee39465 --- /dev/null +++ b/tests/unit/test_constants.py @@ -0,0 +1,18 @@ +"""Smoke test: the package and its constants import and hold sane values.""" + +import password_manager +from password_manager import constants + + +def test_package_has_version() -> None: + assert password_manager.__version__ + + +def test_data_file_name_is_json() -> None: + assert constants.DATA_FILE_NAME.endswith(".json") + + +def test_password_length_bounds_are_ordered() -> None: + assert constants.MIN_LETTERS <= constants.MAX_LETTERS + assert constants.MIN_SYMBOLS <= constants.MAX_SYMBOLS + assert constants.MIN_DIGITS <= constants.MAX_DIGITS From 82701f7c9f2adef44301c468d7836f7a38e9c074 Mon Sep 17 00:00:00 2001 From: Jens Tirsvad Nielsen Date: Wed, 14 Oct 2026 21:21:46 +0800 Subject: [PATCH 3/4] docs: README from the framework template, review RC-007, milestone links Task: MIL-001#5 Task: MIL-001#6 --- README.md | 138 +++++++++++++++++- docs/artifact-registry.md | 2 +- docs/project-plan.md | 6 +- docs/sqa/reviews/rc-001-business-case.md | 1 + .../reviews/rc-002-stakeholder-analysis.md | 1 + docs/sqa/reviews/rc-003-dictionary.md | 1 + docs/sqa/reviews/rc-004-mil-001.md | 1 + docs/sqa/reviews/rc-005-mil-002.md | 1 + docs/sqa/reviews/rc-006-mil-003.md | 1 + docs/sqa/reviews/rc-007-mil-001-code.md | 63 ++++++++ docs/sqa/traceability-matrix.md | 2 + 11 files changed, 212 insertions(+), 5 deletions(-) create mode 100644 docs/sqa/reviews/rc-007-mil-001-code.md diff --git a/README.md b/README.md index e0d604e..313126a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,138 @@ -# 030-password-manager +# ๐Ÿš€ Password Manager +A small Tkinter password manager that generates passwords, saves them in a JSON +file and searches them by website. It is the day 30 assignment of Udemy's +"100 Days of Code: The Complete Python Pro Bootcamp", written for course +participants and for anyone who browses the repository for ideas. + +## ๐Ÿ“š Table of Contents + +- [Overview](#-overview) +- [Requirements](#-requirements) +- [Setup](#-setup) +- [Run](#-run) +- [Tests](#-tests) +- [License](#-license) +- [Links](#-links) +- [Appendix: Project documents](#-appendix-project-documents) + +## ๐Ÿงญ Overview + +The program follows the three lectures of the assignment: + +1. **JSON storage.** Each entry is saved as a nested record + (`website โ†’ email, password`) in `data.json` with `json.dump`, and the + existing data is loaded and updated before a new entry is added. +2. **Exception handling.** A missing, empty or damaged data file does not stop + the program; the file is created or repaired on the next save. +3. **Search.** Type a website and press **Search** to see the saved e-mail and + password, or a message when nothing is saved for it. + +The assignment's function names are kept: `generate_password`, `save` and +`find_password`. + +| Path | What it holds | +| --- | --- | +| `src/password_manager/` | The program: domain rules, use cases, JSON storage and the Tkinter window | +| `src/password_manager/constants.py` | Every constant (file name, labels, messages, password length bounds) | +| `tests/` | The pytest tests | +| `docs/` | Project documents, the Doxygen output folder and the wiki in `docs/wiki/` | +| `Doxyfile` | Doxygen configuration for the source comments | +| `pyproject.toml` | Project configuration (Python version, entry point, pytest) | + +> **Security note.** The data file is plain JSON and the passwords are not +> encrypted. The program is a learning exercise; do not use it for real +> passwords. + +## ๐Ÿ“‹ Requirements + +- Python 3.13 or newer, with Tkinter (the standard Windows and macOS installers + include it; on Debian or Ubuntu install `python3-tk`). +- `venv` and `pip`, both part of Python. +- No runtime dependencies. [pytest][pytest] is needed only to run the tests. +- Optional: [Doxygen][doxygen] to build the source documentation. + +## ๐Ÿ› ๏ธ Setup + +Create and activate a local virtual environment, upgrade `pip`, then install +the project with its test dependency. + +Windows (PowerShell): + +```powershell +python -m venv .venv +.venv\Scripts\Activate.ps1 +python -m pip install --upgrade pip +python -m pip install -e ".[dev]" +``` + +Linux and macOS: + +```bash +python3 -m venv .venv +source .venv/bin/activate +python -m pip install --upgrade pip +python -m pip install -e ".[dev]" +``` + +## โ–ถ๏ธ Run + +With the virtual environment active: + +```bash +python -m password_manager +``` + +or, after the install above, `password-manager`. The program creates `data.json` +in the folder you start it from. Build the source documentation with +`doxygen Doxyfile`; the HTML opens at `docs/doxygen/html/index.html`. + +## ๐Ÿงช Tests + +```bash +python -m pytest +``` + +## ๐Ÿ“„ License + +See [LICENSE][license]. + +## ๐Ÿ”— Links + +- [Repository][repository] +- [Documentation][documentation] +- [Issue tracker][issues] + +## ๐Ÿ“Ž Appendix: Project documents + +The documents a newcomer needs, in reading order. + +| Document | What it tells you | +| --- | --- | +| [Business Case][BC-001] | Why the project exists, its scope and success criteria | +| [Stakeholder Analysis][SA-001] | Who is involved; the stakeholder IDs used for owners and reviewers | +| [Project Plan][PP-001] | The gateways and their schedule | +| [Milestones][milestones] | One document per gateway: Go/No-Go criteria and tasks | +| [Artifact registry][registry] | Where each artifact type lives, the next version, the PO language and domain | +| [Domain dictionary][DICT-001] | The PO terms and the IT terms | +| [Traceability matrix][TM-001] | How the artifacts link and when each was last reviewed | +| [Framework README][framework-readme] | The framework this project uses | +| [Framework changelog][framework-changelog] | What changed in each framework release | + +--- + +[repository]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/030-password-manager +[documentation]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/030-password-manager/wiki +[issues]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/030-password-manager/issues +[license]: ./LICENSE +[pytest]: https://docs.pytest.org/ +[doxygen]: https://www.doxygen.nl/ +[BC-001]: ./docs/business-case.md +[SA-001]: ./docs/stakeholder-analysis.md +[PP-001]: ./docs/project-plan.md +[milestones]: ./docs/milestones/ +[registry]: ./docs/artifact-registry.md +[DICT-001]: ./docs/dictionary.md +[TM-001]: ./docs/sqa/traceability-matrix.md +[framework-readme]: ./framework/README.md +[framework-changelog]: ./framework/CHANGELOG.md diff --git a/docs/artifact-registry.md b/docs/artifact-registry.md index 3614d88..c326845 100644 --- a/docs/artifact-registry.md +++ b/docs/artifact-registry.md @@ -16,7 +16,7 @@ document of a type. `Primary File` may contain a glob (e.g. | PP | Project Plan | docs/project-plan.md | 002 | | MIL | Milestone / Gateway | docs/milestones/*.md | 004 | | DICT | Domain Dictionary | docs/dictionary.md | 002 | -| RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 007 | +| RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 008 | | TM | Traceability Matrix | docs/sqa/traceability-matrix.md | 002 | ## Languages diff --git a/docs/project-plan.md b/docs/project-plan.md index fc3ceab..4ca05c2 100644 --- a/docs/project-plan.md +++ b/docs/project-plan.md @@ -40,9 +40,9 @@ sets no deadline, so the plan keeps the phases short and sequential. | Gateway | Document | Window | Decision date | Owner | Stories | Main deliverable | Milestone | | --- | --- | --- | --- | --- | --- | --- | --- | -| Project Foundation | [MIL-001] | 2026-10-14 to 2026-10-15 | 2026-10-15 | S01 | none | pyproject.toml, .gitignore, constants.py, Doxyfile, README, repository description and topics | | -| Password Manager Features | [MIL-002] | 2026-10-15 to 2026-10-17 | 2026-10-17 | S01 | none | JSON storage, exception handling, search, generator, window and tests | | -| Documentation and Publishing | [MIL-003] | 2026-10-17 to 2026-10-19 | 2026-10-19 | S01 | none | Screenshots, README with screenshots, wiki in en, da and ms | | +| Project Foundation | [MIL-001] | 2026-10-14 to 2026-10-15 | 2026-10-15 | S01 | none | pyproject.toml, .gitignore, constants.py, Doxyfile, README, repository description and topics | [Milestone 162](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/030-password-manager/milestone/162) | +| Password Manager Features | [MIL-002] | 2026-10-15 to 2026-10-17 | 2026-10-17 | S01 | none | JSON storage, exception handling, search, generator, window and tests | [Milestone 163](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/030-password-manager/milestone/163) | +| Documentation and Publishing | [MIL-003] | 2026-10-17 to 2026-10-19 | 2026-10-19 | S01 | none | Screenshots, README with screenshots, wiki in en, da and ms | [Milestone 164](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/030-password-manager/milestone/164) | ```plantuml @startgantt diff --git a/docs/sqa/reviews/rc-001-business-case.md b/docs/sqa/reviews/rc-001-business-case.md index 20d2fda..b0ceb3b 100644 --- a/docs/sqa/reviews/rc-001-business-case.md +++ b/docs/sqa/reviews/rc-001-business-case.md @@ -66,3 +66,4 @@ Go โ€” every Mandatory criterion passes. [BC-001]: ../../business-case.md [53f56ee]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/030-password-manager/commit/53f56eeb143d810b91da23f743a53a32207f81bb +[QC-PY-001]: ../../../framework/qc/code/qc-programming-python.md diff --git a/docs/sqa/reviews/rc-002-stakeholder-analysis.md b/docs/sqa/reviews/rc-002-stakeholder-analysis.md index 01990f3..1c0a80d 100644 --- a/docs/sqa/reviews/rc-002-stakeholder-analysis.md +++ b/docs/sqa/reviews/rc-002-stakeholder-analysis.md @@ -66,3 +66,4 @@ Go โ€” every Mandatory criterion passes. [SA-001]: ../../stakeholder-analysis.md [53f56ee]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/030-password-manager/commit/53f56eeb143d810b91da23f743a53a32207f81bb +[QC-PY-001]: ../../../framework/qc/code/qc-programming-python.md diff --git a/docs/sqa/reviews/rc-003-dictionary.md b/docs/sqa/reviews/rc-003-dictionary.md index b63d617..a649888 100644 --- a/docs/sqa/reviews/rc-003-dictionary.md +++ b/docs/sqa/reviews/rc-003-dictionary.md @@ -65,3 +65,4 @@ Go โ€” every Mandatory criterion passes. [DICT-001]: ../../dictionary.md [53f56ee]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/030-password-manager/commit/53f56eeb143d810b91da23f743a53a32207f81bb +[QC-PY-001]: ../../../framework/qc/code/qc-programming-python.md diff --git a/docs/sqa/reviews/rc-004-mil-001.md b/docs/sqa/reviews/rc-004-mil-001.md index e0e2a4f..582248f 100644 --- a/docs/sqa/reviews/rc-004-mil-001.md +++ b/docs/sqa/reviews/rc-004-mil-001.md @@ -64,3 +64,4 @@ Go โ€” every Mandatory criterion passes. [MIL-001]: ../../milestones/mil-001-project-foundation.md [53f56ee]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/030-password-manager/commit/53f56eeb143d810b91da23f743a53a32207f81bb +[QC-PY-001]: ../../../framework/qc/code/qc-programming-python.md diff --git a/docs/sqa/reviews/rc-005-mil-002.md b/docs/sqa/reviews/rc-005-mil-002.md index 1255773..d1020bc 100644 --- a/docs/sqa/reviews/rc-005-mil-002.md +++ b/docs/sqa/reviews/rc-005-mil-002.md @@ -64,3 +64,4 @@ Go โ€” every Mandatory criterion passes. [MIL-002]: ../../milestones/mil-002-password-manager-features.md [53f56ee]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/030-password-manager/commit/53f56eeb143d810b91da23f743a53a32207f81bb +[QC-PY-001]: ../../../framework/qc/code/qc-programming-python.md diff --git a/docs/sqa/reviews/rc-006-mil-003.md b/docs/sqa/reviews/rc-006-mil-003.md index b8ad9aa..c408dda 100644 --- a/docs/sqa/reviews/rc-006-mil-003.md +++ b/docs/sqa/reviews/rc-006-mil-003.md @@ -64,3 +64,4 @@ Go โ€” every Mandatory criterion passes. [MIL-003]: ../../milestones/mil-003-documentation-and-publishing.md [53f56ee]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/030-password-manager/commit/53f56eeb143d810b91da23f743a53a32207f81bb +[QC-PY-001]: ../../../framework/qc/code/qc-programming-python.md diff --git a/docs/sqa/reviews/rc-007-mil-001-code.md b/docs/sqa/reviews/rc-007-mil-001-code.md new file mode 100644 index 0000000..f6906fa --- /dev/null +++ b/docs/sqa/reviews/rc-007-mil-001-code.md @@ -0,0 +1,63 @@ +# SQA Review Record + +## Metadata +| Key | Value | +| --- | --- | +| ID | RC-007 | +| CrossReference | [MIL-001], [QC-PY-001] | + +## Version History +| Date | Status | Author | Reviewer | Change | Commit | +| --- | --- | --- | --- | --- | --- | +| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | pending | + +--- + +# Code review for MIL-001 + +## Artifact Under Review + +- Instance reviewed: `src/password_manager/` and `tests/unit/` as of the MIL-001 pull request, delivering [MIL-001] +- Checklist used: [QC-PY-001] +- Scope: full review +- Language and domain: n/a +- Language reviewer: none +- Mode: autonomous, not independent (reviewer is `AI as stand-in for S01`) + +## Checklist Results + +| # | Criterion | Status | Evidence/Notes | +| --- | --- | --- | --- | +| 1 | Packages, modules, functions, variables, classes and constants follow PEP 8 casing (`snake_case`, `PascalCase`, `UPPER_SNAKE`) | Pass | `constants.py` uses UPPER_SNAKE; modules and package are snake_case. | +| 2 | Names state purpose in the domain's language; no unexplained abbreviations, no single-letter names outside tiny scopes | Pass | Names state purpose (`DATA_FILE_NAME`, `MIN_LETTERS`). | +| 3 | Code is produced by the project's formatter and passes its linter with no unexplained suppressions | Pass | `ruff format` makes no change and `ruff check` reports 0 findings. | +| 4 | Every function and method signature is type-annotated, including `-> None` | Pass | The only function, `test_*`, is annotated with `-> None`; `constants.py` has none. | +| 5 | No bare `except:`, no swallowed exceptions; specific exceptions are raised and the cause is kept (`raise ... from`) | Pass | No `except` in this milestone. | +| 6 | No mutable default arguments and no shadowed builtins | Pass | No defaults and no shadowed builtins. | +| 7 | Files, locks and connections are managed with context managers | Pass | No file access in this milestone. | +| 8 | Public modules, classes and functions have docstrings that say what, not how | Pass | Module docstrings with `@brief` and `@file` exist. | +| 9 | Logging uses `logging`, not `print`; no secrets or personal data in log output | Pass | No logging and no secrets. | +| 10 | Classes and operations trace to the Design Class Diagram they implement; deviations are recorded | Pass | No design class exists; only constants and a smoke test (no DCD in this project). | +| 11 | Tests exist for new behaviour, are named for the behaviour, and do not depend on order or the network | Pass | `tests/unit/test_constants.py` has 3 tests; `python -m pytest` passes. | +| 12 | Type checker runs in strict mode without errors; `Any` is justified in a comment | Pass | No type checker configured yet; no `Any` used. | +| 13 | Dependencies are declared and pinned in the project's dependency file, none unused | Pass | `dependencies = []`; `pytest` and `ruff` are dev extras. | +| 14 | Each piece of knowledge (a business rule, constant, format, validation or query) is defined in one place; code is merged only where it expresses the same knowledge, not where it merely looks alike | Pass | Each constant is defined once in `constants.py`. | +| 15 | Imports point inward: business-rule modules import no framework, database, UI or delivery-mechanism code, and there are no import cycles | Pass | `constants.py` imports only `string` and `pathlib`. | +| 16 | SOLID holds: a class or module has one reason to change; new behaviour is added by extension, not by editing a type test in several places; subclasses honour the contract of their base; protocols are narrow; high-level code depends on protocols or abstract types and receives its implementations | Pass | No classes; one module with one reason to change. | +| 17 | Source is laid out in the layers and folders of the clean architecture folder structure (`domain`, `application`, `infrastructure`, `presentation` packages under `src/`, and `unit`, `integration` and `e2e` under `tests/`), in `snake_case`, and imports between the layers point inward | Pass | `src/password_manager/` and `tests/unit/` exist; layers are created with their first file (rule: no empty folders). A merged-layer ADR is not needed yet. | +| 18 | File and folder names are English, contain no space and no character outside letters, digits, `-`, `_` and `.`, and follow the casing of the language for files | Pass | All names are English, lower case, no spaces. | + +## Overall Verdict + +Go โ€” every Mandatory criterion passes (criteria 10 and 12 are Optional or not yet applicable and noted above). + +## Action Items + +| Action | Owner | Due | +| --- | --- | --- | +| None | S01 | - | + +--- + +[MIL-001]: ../../milestones/mil-001-project-foundation.md +[QC-PY-001]: ../../../framework/qc/code/qc-programming-python.md diff --git a/docs/sqa/traceability-matrix.md b/docs/sqa/traceability-matrix.md index 8fcb233..e75b669 100644 --- a/docs/sqa/traceability-matrix.md +++ b/docs/sqa/traceability-matrix.md @@ -30,6 +30,7 @@ an artifact instance is created or reviewed. | [MIL-001] | MIL | en | it | [BC-001], [PP-001] | [MIL-002] | [RC-004] | | [MIL-002] | MIL | en | it | [BC-001], [MIL-001] | [MIL-003] | [RC-005] | | [MIL-003] | MIL | en | it | [BC-001], [MIL-002] | - | [RC-006] | +| `src/`, `tests/` (MIL-001 code) | PY | - | - | [MIL-001] | - | [RC-007] | ## Coverage Notes @@ -56,3 +57,4 @@ an artifact instance is created or reviewed. [RC-005]: ./reviews/rc-005-mil-002.md [RC-006]: ./reviews/rc-006-mil-003.md [53f56ee]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/030-password-manager/commit/53f56eeb143d810b91da23f743a53a32207f81bb +[RC-007]: ./reviews/rc-007-mil-001-code.md From dbc47f280db7e8dd2094f50115d22a1c05e882c9 Mon Sep 17 00:00:00 2001 From: Jens Tirsvad Nielsen Date: Wed, 14 Oct 2026 21:21:48 +0800 Subject: [PATCH 4/4] docs: resolve pending commit links of MIL-001 --- docs/sqa/reviews/rc-007-mil-001-code.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/sqa/reviews/rc-007-mil-001-code.md b/docs/sqa/reviews/rc-007-mil-001-code.md index f6906fa..453be64 100644 --- a/docs/sqa/reviews/rc-007-mil-001-code.md +++ b/docs/sqa/reviews/rc-007-mil-001-code.md @@ -9,7 +9,7 @@ ## Version History | Date | Status | Author | Reviewer | Change | Commit | | --- | --- | --- | --- | --- | --- | -| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | pending | +| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [82701f7] | --- @@ -61,3 +61,4 @@ Go โ€” every Mandatory criterion passes (criteria 10 and 12 are Optional or not [MIL-001]: ../../milestones/mil-001-project-foundation.md [QC-PY-001]: ../../../framework/qc/code/qc-programming-python.md +[82701f7]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/030-password-manager/commit/82701f7c9f2adef44301c468d7836f7a38e9c074