add my custom boilerplate (#50)

This commit is contained in:
Dr. Marina Souza, PhD 2023-07-06 17:38:31 -07:00 committed by GitHub
parent 1cfd785c73
commit 79b56abc7c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 418 additions and 0 deletions

View file

@ -0,0 +1,2 @@
# Options are: 'error' < 'info' < 'debug'
LOG_LEVEL=info

View file

@ -0,0 +1,160 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
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
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
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.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
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/

View file

@ -0,0 +1,30 @@
.PHONY: clean
clean:
@find . -iname '*.py[co]' -delete
@find . -iname '__pycache__' -delete
@rm -rf '.pytest_cache'
@rm -rf dist/
@rm -rf build/
@rm -rf *.egg-info
@rm -rf .tox
@rm -rf venv/lib/python*/site-packages/*.egg
.PHONY: install
install:
@PYTHONPATH=$(pwd) python3 setup.py install
.PHONY: install_deps
install_deps:
@PYTHONPATH=$(pwd) pip3 install -r requirements.txt
.PHONY: install_dev
install_deps:
@PYTHONPATH=$(pwd) pip3 install -r requirements_dev.txt
.PHONY: lint
lint:
@PYTHONPATH=$(pwd) tox -e lint
.PHONY: test
test:
@PYTHONPATH=$(pwd) tox

View file

@ -0,0 +1,6 @@
## python boilerplate
<br>
#### a customized boilerplate to make it quicker starting new projects.

View file

@ -0,0 +1,2 @@
python-dotenv==1.0.0

View file

@ -0,0 +1,2 @@
pytest==7.4.0
tox==4.6.4

View file

@ -0,0 +1,13 @@
from setuptools import setup, find_packages
setup(
name="my_package",
version='0.1',
packages=find_packages(include=['src', \
'src.utils']),
author="bt3gl",
install_requires=['python-dotenv'],
entry_points={
'console_scripts': ['my_package=src.main:run']
},
)

View file

@ -0,0 +1 @@
# -*- encoding: utf-8 -*-

View file

@ -0,0 +1,33 @@
#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
# src/main.py
import argparse
def run_menu() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description='Run my project')
parser.add_argument('-t', dest='test', nargs=1,
help="Run test method. \
Example: <my project> -t <argument>")
return parser
def run() -> None:
"""Entry point for this module."""
parser = run_menu()
args = parser.parse_args()
if args.test:
pass
else:
parser.print_help()
if __name__ == "__main__":
run()

View file

@ -0,0 +1 @@
# -*- encoding: utf-8 -*-

View file

@ -0,0 +1,130 @@
# -*- encoding: utf-8 -*-
# utils/os.py
# This class implements OS/file system util methods used by the other classes.
import os
import sys
import json
import copy
import logging
from pathlib import Path
from dotenv import load_dotenv
def set_logging(log_level) -> None:
"""Set logging level according to .env config."""
if log_level == 'info':
logging.basicConfig(level=logging.INFO, format='%(message)s')
elif log_level == 'error':
logging.basicConfig(level=logging.ERROR, format='%(message)s')
elif log_level == 'debug':
logging.basicConfig(level=logging.DEBUG, format='%(message)s')
else:
print(f'Logging level {log_level} is not available. Setting to ERROR')
logging.basicConfig(level=logging.ERROR, format='%(message)s')
def load_config() -> dict:
"""Load and set environment variables."""
env_file = Path('.') / '.env'
if not os.path.isfile(env_file):
exit_with_error('Please create an .env file')
env_vars = {}
load_dotenv(env_file)
try:
env_vars['OUTPUT_DIR'] = os.getenv("OUTPUT_DIR")
set_logging(os.getenv("LOG_LEVEL"))
return env_vars
except KeyError as e:
exit_with_error(f'Cannot extract env variables: {e}. Exiting.')
def log_error(string) -> None:
"""Print STDOUT error using the logging library."""
logging.error('🚨 %s', string)
def log_info(string) -> None:
"""Print STDOUT info using the logging library."""
logging.info('🙌🏼 %s', string)
def log_debug(string) -> None:
"""Print STDOUT debug using the logging library."""
logging.debug('🟨 %s', string)
def open_json(filepath) -> dict:
"""Load and parse a file."""
try:
with open(filepath, 'r', encoding='utf-8') as infile:
return json.load(infile)
except (IOError, FileNotFoundError, TypeError) as e:
exit_with_error(f'Failed to parse: "{filepath}": {e}')
def format_path(dir_path, filename) -> str:
"""Format a OS full filepath."""
return os.path.join(dir_path, filename)
def format_output_file(name) -> str:
"""Format the name for the result file."""
return f'{name}.json'
def save_output(destination, data) -> None:
"""Save data from memory to a destination in disk."""
try:
with open(destination, 'w', encoding='utf-8') as outfile:
json.dump(data, outfile, indent=4)
except (IOError, TypeError) as e:
log_error(f'Could not save {destination}: {e}')
def create_dir(result_dir) -> None:
"""Check whether a directory exists and create it if needed."""
try:
if not os.path.isdir(result_dir):
os.mkdir(result_dir)
except OSError as e:
log_error(f'Could not create {result_dir}: {e}')
def deep_copy(dict_to_clone) -> dict:
"""Deep copy (not reference copy) to a dict."""
return copy.deepcopy(dict_to_clone)
def exit_with_error(message) -> None:
"""Log an error message and halt the program."""
log_error(message)
sys.exit(1)
def print_pid() -> None:
"""Print the PID of the current process."""
log_info(f'Starting process main os.getpid() = {os.getpid()}')

View file

@ -0,0 +1,14 @@
# -*- encoding: utf-8 -*-
# utils/strings.py
# This class implements string methods used by the other classes.
from pprint import PrettyPrinter
def pprint(data, indent=None) -> None:
"""Print dicts and data in a suitable format"""
print()
indent = indent or 4
pp = PrettyPrinter(indent=indent)
pp.pprint(data)
print()

View file

@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
import unittest
class TestMyFunction(unittest.TestCase):
def setUp(self):
pass
def test_one(self):
pass
if __name__ == '__main__':
unittest.main()

View file

@ -0,0 +1,8 @@
[tox]
envlist = py36, py37, py38, py39, py10
skip_missing_interpreters = true
[testenv:lint]
skip_install = true
deps = flake8
commands = flake8 src/