diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..f3d0278 --- /dev/null +++ b/.flake8 @@ -0,0 +1,3 @@ +[flake8] +max-line-length = 160 +exclude = docs/*, build/*, .git, __pycache__, build diff --git a/.gitignore b/.gitignore index 34207bd..fa764ad 100644 --- a/.gitignore +++ b/.gitignore @@ -28,8 +28,6 @@ share/python-wheels/ MANIFEST # PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec @@ -83,34 +81,10 @@ target/ profile_default/ ipython_config.py -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/#use-with-ide +# PDM .pdm.toml -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +# PEP 582 __pypackages__/ # Celery stuff @@ -154,11 +128,7 @@ dmypy.json cython_debug/ # PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ +.idea/ # ---> macOS # General @@ -167,7 +137,8 @@ cython_debug/ .LSOverride # Icon must end with two \r -Icon +Icon + # Thumbnails ._* @@ -228,4 +199,3 @@ $RECYCLE.BIN/ # .nfs files are created when an open file is removed but is still being accessed .nfs* - diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..189b6ea --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,35 @@ +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v3.2.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files +- repo: https://github.com/asottile/reorder_python_imports + rev: v3.9.0 + hooks: + - id: reorder-python-imports + args: [--application-directories, '.:dotgift', --py39-plus] +- repo: https://github.com/psf/black + rev: 23.3.0 + hooks: + - id: black + language_version: python3.11 +- repo: https://github.com/PyCQA/bandit + rev: 1.7.5 + hooks: + - id: bandit + args: ["-c", "pyproject.toml"] + additional_dependencies: ["bandit[toml]"] +- repo: https://github.com/pycqa/flake8 + rev: 6.0.0 + hooks: + - id: flake8 +- repo: local + hooks: + - id: version + name: Update version + entry: ./pre-commit.sh + language: script + files: 'pyproject.toml' \ No newline at end of file diff --git a/README.md b/README.md index 13bbdf1..a2e2b03 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,28 @@ +
# dotgift -Christmas gift list project \ No newline at end of file +**dotgift** is a Christmas manager + +for large double families like mine!
+ +[Installation](#installation) • +[Examples](#examples) • +[Contributing](#contributing) • +[License](#license) +
+ +## Installation + +TBD + +## Examples + +TBD + +## Contributing + +If you would like to contribute to this project, feel free to submit a pull request or open an issue on GitHub. + +## License + +This project is licensed under the current AGPL 3.0+ License. See the `LICENSE` file for details. diff --git a/dotgift/__init__.py b/dotgift/__init__.py new file mode 100644 index 0000000..253e652 --- /dev/null +++ b/dotgift/__init__.py @@ -0,0 +1,46 @@ +import argparse +import asyncio +import sys + +import uvloop + +__version__ = "0.0.1" + + +async def main(args: argparse.Namespace) -> None: + """ + Main function of the program (stub). + + This function serves as dotgift's critical path for primary logic. + It receives an `argparse.Namespace` object as input from invoke_maiun, which includes + the command-line arguments that were defined and parsed in the `run` function. + + Args: + args (argparse.Namespace): The command-line arguments object. + + Returns: + None + """ + pass + + +def invoke_main(args: argparse.Namespace) -> None: + """ + Function to invoke the main function using asyncio and uvloop (stub). + + This function serves as a bridge to run the async main function in + a uvloop event loop. It handles the differences in asyncio API across + different Python versions. + + Args: + args (argparse.Namespace): The command-line arguments object. + + Returns: + None + """ + if sys.version_info >= (3, 11): + with asyncio.Runner(loop_factory=uvloop.new_event_loop) as runner: + runner.run(main(args)) + else: + uvloop.install() + asyncio.run(main(args)) diff --git a/dotgift/cli.py b/dotgift/cli.py new file mode 100644 index 0000000..d28aec8 --- /dev/null +++ b/dotgift/cli.py @@ -0,0 +1,44 @@ +from argparse import ArgumentParser +from pathlib import Path + +from . import __version__ +from .logger import logger +from .validation import validate_file_folder + + +def run() -> None: + """ + Command-line interface for dotgift. + + This function defines and handles command-line arguments for the program. + The available options are: + + --version: Show the version of the program and exit. + --verbose: Enable verbose logging. This will produce detailed output messages. + --output/-o: Specify the output file. This must be a valid file path. + paths: Specify any number of existing files or directories to be processed. + These paths must point to existing files or directories. + + Upon parsing the command-line arguments, the function configures the logger + and invokes the `main` function with the parsed arguments. + + Returns: + None + """ + # your code here + parser = ArgumentParser(description="A Christmas list manager for families like mine!") + parser.add_argument("--version", action="version", version=__version__) + parser.add_argument("--verbose", action="store_true", help="Enable verbose logging") + parser.add_argument("--output", "-o", type=Path, help="Specify output file") + parser.add_argument( + "paths", + nargs="+", + type=validate_file_folder, + help="Specify any number of existing files or directories to be processed.", + ) + args = parser.parse_args() + + if args.verbose: + logger.debug("Verbose logging enabled") + + run(args) diff --git a/dotgift/logger.py b/dotgift/logger.py new file mode 100644 index 0000000..3fe05e6 --- /dev/null +++ b/dotgift/logger.py @@ -0,0 +1,4 @@ +import logging + +logging.basicConfig(format="%(asctime)s - %(message)s", datefmt="%d-%b-%y %H:%M:%S") +logger = logging.getLogger(__name__) diff --git a/pre-commit.sh b/pre-commit.sh new file mode 100644 index 0000000..94399b2 --- /dev/null +++ b/pre-commit.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +PROJECT_ROOT=$(git rev-parse --show-toplevel) +VERSION=$(grep 'version =' $PROJECT_ROOT/pyproject.toml | head -1 | cut -d '"' -f 2) +INIT_FILE="$PROJECT_ROOT/dotgift/dotgift/__init__.py" + +# Portable workaround for macOS/Linux sed differences +sed -i.bak "s/__version__ = .*/__version__ = \"$VERSION\"/" $INIT_FILE && \ + rm "$INIT_FILE.bak" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..79e1b84 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,29 @@ +[build-system] +requires = ["setuptools>=68.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "dotgift" +version = "0.0.1" +authors = [{ name = "pdf", email = "git@nixon.mozmail.com" }] +description = "Another Christmas list manager for families" +readme = "README.md" +requires-python = ">=3.11" +license = { text = "AGPL 3.0" } +dependencies = ["uvloop>=0.17.0", "asyncstdlib>=3.10.8"] + +[project.scripts] +dotgift = "dotgift.cli:run" + +[project.urls] +homepage = "https://sillyhats.mips.uk/pdf/dotgift" +repository = "https://sillyhats.mips.uk/pdf/dotgift" + +[tool.setuptools] +py-modules = ["dotgift"] + +[tool.bandit] +exclude_dirs = ["/docs", "/build"] + +[tool.black] +line-length = 120