From 79b56abc7c00358d68ae97b7001c862e89979ad6 Mon Sep 17 00:00:00 2001
From: "Dr. Marina Souza, PhD" <1130416+bt3gl@users.noreply.github.com>
Date: Thu, 6 Jul 2023 17:38:31 -0700
Subject: [PATCH] add my custom boilerplate (#50)
---
boilerplates/project_boilerplate/.env.example | 2 +
boilerplates/project_boilerplate/.gitignore | 160 ++++++++++++++++++
boilerplates/project_boilerplate/Makefile | 30 ++++
boilerplates/project_boilerplate/README.md | 6 +
.../project_boilerplate/requirements.txt | 2 +
.../project_boilerplate/requirements_dev.txt | 2 +
boilerplates/project_boilerplate/setup.py | 13 ++
.../project_boilerplate/src/__init__.py | 1 +
boilerplates/project_boilerplate/src/main.py | 33 ++++
.../project_boilerplate/src/utils/__init__.py | 1 +
.../project_boilerplate/src/utils/os.py | 130 ++++++++++++++
.../project_boilerplate/src/utils/strings.py | 14 ++
.../tests/test_utils_aes_cipher.py | 16 ++
boilerplates/project_boilerplate/tox.ini | 8 +
14 files changed, 418 insertions(+)
create mode 100644 boilerplates/project_boilerplate/.env.example
create mode 100644 boilerplates/project_boilerplate/.gitignore
create mode 100644 boilerplates/project_boilerplate/Makefile
create mode 100644 boilerplates/project_boilerplate/README.md
create mode 100644 boilerplates/project_boilerplate/requirements.txt
create mode 100644 boilerplates/project_boilerplate/requirements_dev.txt
create mode 100644 boilerplates/project_boilerplate/setup.py
create mode 100644 boilerplates/project_boilerplate/src/__init__.py
create mode 100644 boilerplates/project_boilerplate/src/main.py
create mode 100644 boilerplates/project_boilerplate/src/utils/__init__.py
create mode 100644 boilerplates/project_boilerplate/src/utils/os.py
create mode 100644 boilerplates/project_boilerplate/src/utils/strings.py
create mode 100644 boilerplates/project_boilerplate/tests/test_utils_aes_cipher.py
create mode 100644 boilerplates/project_boilerplate/tox.ini
diff --git a/boilerplates/project_boilerplate/.env.example b/boilerplates/project_boilerplate/.env.example
new file mode 100644
index 0000000..d0df79a
--- /dev/null
+++ b/boilerplates/project_boilerplate/.env.example
@@ -0,0 +1,2 @@
+# Options are: 'error' < 'info' < 'debug'
+LOG_LEVEL=info
\ No newline at end of file
diff --git a/boilerplates/project_boilerplate/.gitignore b/boilerplates/project_boilerplate/.gitignore
new file mode 100644
index 0000000..68bc17f
--- /dev/null
+++ b/boilerplates/project_boilerplate/.gitignore
@@ -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/
diff --git a/boilerplates/project_boilerplate/Makefile b/boilerplates/project_boilerplate/Makefile
new file mode 100644
index 0000000..655d196
--- /dev/null
+++ b/boilerplates/project_boilerplate/Makefile
@@ -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
\ No newline at end of file
diff --git a/boilerplates/project_boilerplate/README.md b/boilerplates/project_boilerplate/README.md
new file mode 100644
index 0000000..2584f0c
--- /dev/null
+++ b/boilerplates/project_boilerplate/README.md
@@ -0,0 +1,6 @@
+## python boilerplate
+
+
+
+#### a customized boilerplate to make it quicker starting new projects.
+
diff --git a/boilerplates/project_boilerplate/requirements.txt b/boilerplates/project_boilerplate/requirements.txt
new file mode 100644
index 0000000..e8c0169
--- /dev/null
+++ b/boilerplates/project_boilerplate/requirements.txt
@@ -0,0 +1,2 @@
+python-dotenv==1.0.0
+
diff --git a/boilerplates/project_boilerplate/requirements_dev.txt b/boilerplates/project_boilerplate/requirements_dev.txt
new file mode 100644
index 0000000..80f4bc9
--- /dev/null
+++ b/boilerplates/project_boilerplate/requirements_dev.txt
@@ -0,0 +1,2 @@
+pytest==7.4.0
+tox==4.6.4
\ No newline at end of file
diff --git a/boilerplates/project_boilerplate/setup.py b/boilerplates/project_boilerplate/setup.py
new file mode 100644
index 0000000..7c655f2
--- /dev/null
+++ b/boilerplates/project_boilerplate/setup.py
@@ -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']
+ },
+)
\ No newline at end of file
diff --git a/boilerplates/project_boilerplate/src/__init__.py b/boilerplates/project_boilerplate/src/__init__.py
new file mode 100644
index 0000000..dae354a
--- /dev/null
+++ b/boilerplates/project_boilerplate/src/__init__.py
@@ -0,0 +1 @@
+# -*- encoding: utf-8 -*-
diff --git a/boilerplates/project_boilerplate/src/main.py b/boilerplates/project_boilerplate/src/main.py
new file mode 100644
index 0000000..7bd34b6
--- /dev/null
+++ b/boilerplates/project_boilerplate/src/main.py
@@ -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: -t ")
+
+ 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()
diff --git a/boilerplates/project_boilerplate/src/utils/__init__.py b/boilerplates/project_boilerplate/src/utils/__init__.py
new file mode 100644
index 0000000..dae354a
--- /dev/null
+++ b/boilerplates/project_boilerplate/src/utils/__init__.py
@@ -0,0 +1 @@
+# -*- encoding: utf-8 -*-
diff --git a/boilerplates/project_boilerplate/src/utils/os.py b/boilerplates/project_boilerplate/src/utils/os.py
new file mode 100644
index 0000000..9ca3659
--- /dev/null
+++ b/boilerplates/project_boilerplate/src/utils/os.py
@@ -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()}')
+
diff --git a/boilerplates/project_boilerplate/src/utils/strings.py b/boilerplates/project_boilerplate/src/utils/strings.py
new file mode 100644
index 0000000..057fdff
--- /dev/null
+++ b/boilerplates/project_boilerplate/src/utils/strings.py
@@ -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()
diff --git a/boilerplates/project_boilerplate/tests/test_utils_aes_cipher.py b/boilerplates/project_boilerplate/tests/test_utils_aes_cipher.py
new file mode 100644
index 0000000..9c4f4b1
--- /dev/null
+++ b/boilerplates/project_boilerplate/tests/test_utils_aes_cipher.py
@@ -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()
diff --git a/boilerplates/project_boilerplate/tox.ini b/boilerplates/project_boilerplate/tox.ini
new file mode 100644
index 0000000..d86ade9
--- /dev/null
+++ b/boilerplates/project_boilerplate/tox.ini
@@ -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/
\ No newline at end of file