Add async pieces.
This commit is contained in:
parent
79e06ea46f
commit
32f9588e26
11 changed files with 241 additions and 37 deletions
46
${REPO_NAME_SNAKE}/__init__.py
Normal file
46
${REPO_NAME_SNAKE}/__init__.py
Normal file
|
@ -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 ${REPO_NAME_SNAKE}'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))
|
44
${REPO_NAME_SNAKE}/cli.py
Normal file
44
${REPO_NAME_SNAKE}/cli.py
Normal file
|
@ -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 ${REPO_NAME_SNAKE}.
|
||||||
|
|
||||||
|
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="${REPO_DESCRIPTION}")
|
||||||
|
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)
|
4
${REPO_NAME_SNAKE}/logger.py
Normal file
4
${REPO_NAME_SNAKE}/logger.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logging.basicConfig(format="%(asctime)s - %(message)s", datefmt="%d-%b-%y %H:%M:%S")
|
||||||
|
logger = logging.getLogger(__name__)
|
12
${REPO_NAME_SNAKE}/validation.py
Normal file
12
${REPO_NAME_SNAKE}/validation.py
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from aiopath import AsyncPath
|
||||||
|
|
||||||
|
|
||||||
|
def validate_file_folder(value: str) -> Path:
|
||||||
|
file_folder_path = Path(value)
|
||||||
|
if not file_folder_path.exists():
|
||||||
|
raise FileNotFoundError(f"No such file or folder: {value}")
|
||||||
|
if not file_folder_path.is_file() and not file_folder_path.is_dir():
|
||||||
|
raise TypeError(f"Not a file or directory: {value}")
|
||||||
|
return AsyncPath(value)
|
3
.flake8
Normal file
3
.flake8
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[flake8]
|
||||||
|
max-line-length = 160
|
||||||
|
exclude = docs/*, build/*, .git, __pycache__, build
|
40
.gitignore
vendored
40
.gitignore
vendored
|
@ -28,8 +28,6 @@ share/python-wheels/
|
||||||
MANIFEST
|
MANIFEST
|
||||||
|
|
||||||
# PyInstaller
|
# 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
|
*.manifest
|
||||||
*.spec
|
*.spec
|
||||||
|
|
||||||
|
@ -83,34 +81,10 @@ target/
|
||||||
profile_default/
|
profile_default/
|
||||||
ipython_config.py
|
ipython_config.py
|
||||||
|
|
||||||
# pyenv
|
# PDM
|
||||||
# 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.toml
|
.pdm.toml
|
||||||
|
|
||||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
# PEP 582
|
||||||
__pypackages__/
|
__pypackages__/
|
||||||
|
|
||||||
# Celery stuff
|
# Celery stuff
|
||||||
|
@ -154,11 +128,7 @@ dmypy.json
|
||||||
cython_debug/
|
cython_debug/
|
||||||
|
|
||||||
# PyCharm
|
# PyCharm
|
||||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
.idea/
|
||||||
# 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/
|
|
||||||
|
|
||||||
# ---> macOS
|
# ---> macOS
|
||||||
# General
|
# General
|
||||||
|
@ -167,7 +137,8 @@ cython_debug/
|
||||||
.LSOverride
|
.LSOverride
|
||||||
|
|
||||||
# Icon must end with two \r
|
# Icon must end with two \r
|
||||||
Icon
|
Icon
|
||||||
|
|
||||||
|
|
||||||
# Thumbnails
|
# Thumbnails
|
||||||
._*
|
._*
|
||||||
|
@ -228,4 +199,3 @@ $RECYCLE.BIN/
|
||||||
|
|
||||||
# .nfs files are created when an open file is removed but is still being accessed
|
# .nfs files are created when an open file is removed but is still being accessed
|
||||||
.nfs*
|
.nfs*
|
||||||
|
|
||||||
|
|
35
.pre-commit-config.yaml
Normal file
35
.pre-commit-config.yaml
Normal file
|
@ -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, '.:${REPO_NAME_SNAKE}', --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'
|
34
README.md
34
README.md
|
@ -1,3 +1,33 @@
|
||||||
# python-module
|
<div align="center">
|
||||||
|
# ${REPO_NAME_SNAKE}
|
||||||
|
|
||||||
Template for a new Python project.
|
**${REPO_NAME_SNAKE}** is a...
|
||||||
|
|
||||||
|
Python project!<br/>
|
||||||
|
|
||||||
|
[Installation](#installation) •
|
||||||
|
[Examples](#examples) •
|
||||||
|
[Contributing](#contributing) •
|
||||||
|
[License](#license)
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Install and run ${REPO_NAME_SNAKE} using the below commands or their equivalents for your environment.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip3 install -U ${REPO_HTTPS_URL}
|
||||||
|
${REPO_NAME_SNAKE}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
21
pre-commit.sh
Executable file
21
pre-commit.sh
Executable file
|
@ -0,0 +1,21 @@
|
||||||
|
#!/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/${REPO_NAME_SNAKE}/${REPO_NAME_SNAKE}/__init__.py"
|
||||||
|
PYPROJECT_FILE="$PROJECT_ROOT/pyproject.toml"
|
||||||
|
|
||||||
|
# Modify the CLI line to remove quotes in pyproject.toml
|
||||||
|
sed -i.bak "s/\"${REPO_NAME_SNAKE}\" = \"${REPO_NAME_SNAKE}\.cli:run\"/${REPO_NAME_SNAKE} = \"${REPO_NAME_SNAKE}\.cli:run\"/" $PYPROJECT_FILE && \
|
||||||
|
rm "$PYPROJECT_FILE.bak"
|
||||||
|
|
||||||
|
# Check if __init__.py file exists for template purposes
|
||||||
|
# This can be removed now that the template is cloned
|
||||||
|
if [ ! -f "$INIT_FILE" ]; then
|
||||||
|
echo "__init__.py does not exist yet, exiting."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Portable workaround for macOS/Linux sed differences
|
||||||
|
sed -i.bak "s/__version__ = .*/__version__ = \"$VERSION\"/" $INIT_FILE && \
|
||||||
|
rm "$INIT_FILE.bak"
|
34
pyproject.toml
Normal file
34
pyproject.toml
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=68.0"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "${REPO_NAME_SNAKE}"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = [{ name = "${REPO_OWNER_SNAKE}", email = "git@nixon.mozmail.com" }]
|
||||||
|
description = "${REPO_DESCRIPTION}"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.9"
|
||||||
|
license = { text = "MIT" }
|
||||||
|
dependencies = [
|
||||||
|
"loguru>=0.7.0",
|
||||||
|
"uvloop>=0.17.0",
|
||||||
|
"aiopath>=0.6.11",
|
||||||
|
"asyncstdlib>=3.10.8",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
"${REPO_NAME_SNAKE}" = "${REPO_NAME_SNAKE}.cli:run"
|
||||||
|
|
||||||
|
[project.urls]
|
||||||
|
homepage = "${REPO_LINK}"
|
||||||
|
repository = "${REPO_LINK}"
|
||||||
|
|
||||||
|
[tool.setuptools]
|
||||||
|
py-modules = ["${REPO_NAME_SNAKE}"]
|
||||||
|
|
||||||
|
[tool.bandit]
|
||||||
|
exclude_dirs = ["/docs", "/build"]
|
||||||
|
|
||||||
|
[tool.black]
|
||||||
|
line-length = 120
|
5
template
Normal file
5
template
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
**.py
|
||||||
|
.pre-commit-config.yaml
|
||||||
|
README.md
|
||||||
|
pyproject.toml
|
||||||
|
pre-commit.sh
|
Loading…
Reference in a new issue