From 865e3aabe2d1f46a9c3692e8d51eb4379d7cc970 Mon Sep 17 00:00:00 2001 From: Harald Pfeiffer Date: Wed, 20 Aug 2025 09:59:42 +0200 Subject: Initial Commit --- .gitignore | 21 ++++++++ .nojekyll | 0 MANIFEST.in | 1 + Makefile | 31 +++++++++++ README.md | 32 ++++++++++++ classifiers.txt | 12 +++++ codecov.yml | 7 +++ project_dummy/__init__.py | 3 ++ project_dummy/db.py | 26 ++++++++++ project_dummy/hemlo_world.py | 15 ++++++ pyproject.toml | 121 +++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 0 setup.py.bak | 88 +++++++++++++++++++++++++++++++ tests/dummy_test.py | 44 ++++++++++++++++ tests/project_dummy | 1 + tox.ini | 20 +++++++ 16 files changed, 422 insertions(+) create mode 100644 .gitignore create mode 100644 .nojekyll create mode 100644 MANIFEST.in create mode 100644 Makefile create mode 100644 README.md create mode 100644 classifiers.txt create mode 100644 codecov.yml create mode 100644 project_dummy/__init__.py create mode 100644 project_dummy/db.py create mode 100644 project_dummy/hemlo_world.py create mode 100644 pyproject.toml create mode 100644 requirements.txt create mode 100644 setup.py.bak create mode 100644 tests/dummy_test.py create mode 120000 tests/project_dummy create mode 100644 tox.ini diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..221da88 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +coverage.xml +packages/ +__pycache__ +poetry.lock +*.pyc +.tox/ +doc/build +dist +doc/html +*.swp +build + +# Testing clutter +.coverage +.mypy_cache/ +.pytest_cache/ + +# IDE and framework garbage +.idea +.hypothesis +.ropeproject/ diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..2b0b5ab --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..42b0160 --- /dev/null +++ b/Makefile @@ -0,0 +1,31 @@ +PYTHON ?= python + +all: + +test: + $(MAKE) test-noclean + $(MAKE) clean + +test-noclean: + python3 -m pytest --benchmark-disable --tb=short + +typecheck: + $(MAKE) typecheck-noclean + $(MAKE) clean + +typecheck-noclean: + mypy -p project-dummy --warn-redundant-casts + +coverage: + $(MAKE) coverage-noclean + $(MAKE) clean + +coverage-noclean: + python3 -m pytest --cov project-dummy --benchmark-disable --tb=short + +clean: + @rm -rf ./dist/ ./__pycache__/ ./tests/__pycache__/ + @rm -rf ./.benchmarks ./.pytest_cache ./.mypy_cache + @rm -rf ./packages/ + +.PHONY: all clean test typecheck coverage diff --git a/README.md b/README.md new file mode 100644 index 0000000..0e2de4d --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# project-dummy + +## Explanation + +This is a project dummy. It serves (me, maybe you?) as a "template" for the basic structure of +a Python project. As simple as it can be - copy and adjust. + +## Structure + +This is a project folder containing the folders and files for creating a Python module called +"project-dummy". + +## Credits + +This setup was kicked off while reading Jeff Knupp's ideas[^1] on how to set up a python project. + +Changes since then will be incorporated, like: + +- Define metadata in pyproject.toml which setuptools have adapted since 61.0.0[^2] + +# Resources + +This will list some useful resources to fill in pyproject.toml etc. + +- [Writing pyproject.toml](https://packaging.python.org/en/latest/guides/writing-pyproject-toml/) +- [Setuptools-specific pyproject.toml configuration](https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html) +- [PyPi classifiers](https://pypi.org/classifiers/) + +# Sources + +[^1] [Internet Archive Wayback Machine, 2024-01-05](https://web.archive.org/web/20240105220829/https://www.jeffknupp.com/blog/2013/08/16/open-sourcing-a-python-project-the-right-way/) +[^2] [Setuptools, pyproject_config](https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html) diff --git a/classifiers.txt b/classifiers.txt new file mode 100644 index 0000000..1d953e4 --- /dev/null +++ b/classifiers.txt @@ -0,0 +1,12 @@ +Development Status :: 2 - Pre-Alpha +Environment :: Console +Framework :: Pytest +Framework :: Sphinx +Intended Audience :: Developers +License :: Other/Proprietary License :: WTFPL +Natural Language :: English +Operating System :: OS Independent +Programming Language :: Python :: 3 +Topic :: Software Development +Recommendation :: Useless for Developers :: Windows +Recommendation :: Useless for Administrators :: PowerShell diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..79fafb0 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,7 @@ +comment: + layout: "condensed_header, diff, condensed_files, condensed_footer" + behavior: default + require_changes: false # if true: only post the comment if coverage changes + require_base: false # [true :: must have a base report to post] + require_head: true # [true :: must have a head report to post] + hide_project_coverage: false # [true :: only show coverage on the git diff] diff --git a/project_dummy/__init__.py b/project_dummy/__init__.py new file mode 100644 index 0000000..5693b97 --- /dev/null +++ b/project_dummy/__init__.py @@ -0,0 +1,3 @@ +#!/usr/bin/env python3 + +__all__ = [ "hemlo_world" ] diff --git a/project_dummy/db.py b/project_dummy/db.py new file mode 100644 index 0000000..5b67af4 --- /dev/null +++ b/project_dummy/db.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +"""DBaaS - DB as a String.""" + + +class Db: + """Here's your db.""" + + @property + def dbt(self): + """Here's a string.""" + mystr = '⠀⠀⠀⠀⠀⣠⠶⠚⠛⠛⠛⠲⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⣴⠟⠁⠀⠀⠀⠀⠀⠀⠀⠻⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀' + mystr += '⠀⠀⠀⠀⠀⠀\n⠀⣠⣾⣷⣄⠀⠀⠀⢀⣠⣤⣤⡀⠀⢿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⢸⣿⡿⢃⣸⡶⠂⢠⣿⣿⡿⠁⣱⠀⢸' + mystr += '⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⢸⡏⠉⠩⣏⣐⣦⠀⠛⠦⠴⠚⠁⠀⣸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⣼⠧⠶⠶⠶⠿' + mystr += '⠶⠶⠖⠚⠛⠉⠁⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⠶⠶⡄⠀⠀\n⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⢠⡟⠀⠀⢹⠀' + mystr += '⠀\n⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⢤⢠⡆⠀⢸⡄⠀⠀⠀⠀⠀⠀⢀⡿⠁⠀⠀⡾⠀⠀\n⢹⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠈⡇⠀⠸⣧⣠⠴⠶⠖' + mystr += '⠲⢶⡞⠁⠀⢈⡼⢃⠀⠀\n⠸⡆⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⡇⠀⠀⢿⠁⠄⣲⡶⠶⠿⢤⣄⡀⠛⢛⠉⢻⠀\n⠀⢿⡀⠀⠀⠀⠀⠀⠀⠀⢸' + mystr += '⠠⣇⠀⠀⠀⠀⠊⠁⠀⠀⠀⠀⠀⠙⢦⠈⠙⠓⣆\n⠀⠈⢷⡀⠀⠀⠀⠀⠀⢠⠏⡀⣬⣹⣦⠀⠀⠀⠀⠀⠁⠀⠀⠀⠀⠈⡿⠶⠶⠋\n⠀⠀' + mystr += '⠈⢷⡀⠀⠀⠀⠀⠘⠛⠛⠋⠀⠀⠀⠀⠀⠀⠄⠀⠀⠀⠀⠀⣼⠃⠀⠀⠀\n⠀⠀⠀⠀⠙⢦⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠄⠀⠀⣠⡞' + mystr += '⠁⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠈⠛⣷⢶⣦⣤⣄⣀⣠⣤⣤⠀⣶⠶⠶⠶⠛⠁⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⣀⡀⠀⣰⠇⣾⠀⠀⠈⣩⣥⣄' + mystr += '⣿⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⢿⡉⠳⡟⣸⠃⠀⠀⠀⠘⢷⣌⠉⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠙⢦' + mystr += '⣴⠏⠀⠀⠀⠀⠀⠀⠉⠳⠶⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n' + return mystr + + def print_db(self): + """Output.""" + print(f'{self.dbt}') diff --git a/project_dummy/hemlo_world.py b/project_dummy/hemlo_world.py new file mode 100644 index 0000000..44f4fb9 --- /dev/null +++ b/project_dummy/hemlo_world.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 +"""Hello.""" + + +def hemlo(): + """Hello!. + + Yeah, there's your fucking period, 's if an exclamation + mark were not the end of a sentence!!1!eleven + """ + return 'hemlo world (づ^•ω•^)づ' + + +if __name__ == '__main__': + print(hemlo()) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..803a5cd --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,121 @@ +[build-system] +requires = ["setuptools >= 61.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "project-dummy" +description = "A dummy as base directory for actual projects" +authors = [ + { name = "Glenn Matthews", email = "janitor@sacredheart.com" } +] +license = { text = "License :: OSI Approved :: GNU General Public License v2 (GPLv2)" } +readme = "README.md" +requires-python = ">=3.6.0" +dependencies = [ + "ansible", + "ansible-compat", + "ansible-core>=2.12.0" +] +dynamic = ["version"] + +[project.scripts] +# install a command as part of the package +hemlo = "project_dummy:hemlo_world" + +[project.urls] +Source = "https://git.lirion.de/python-project-dummy" +Documentation = "https://wiki.lirion.example.com/python-project-dummy" + +[tool.pytest.ini_options] +# both mode and loop fixture see https://github.com/pytest-dev/pytest-asyncio/issues/924 +asyncio_mode = "auto" +# Valid fixture loop scopes are: "function", "class", "module", "package", "session" +# Caution: This works only on "more recent" versions of pytest (7.2.1 doesn't know this, 8.3.3 does) +asyncio_default_fixture_loop_scope = "function" + +[tool.ruff] +# Assume Python 3.6. +target-version = "py36" +fix = true +show-fixes = true +preview = true + +[tool.ruff.lint] +select = [ + "E", # pycodestyle + "F", # Pyflakes + "I001", # isort + "UP", # pyupgrade + "ASYNC", # flake8-async + "C4", # flake8-comprehensions + "T10", # flake8-debugger + "FA", # flake8-future-annotations + "PT", # flake8-pytest-style + "RSE", # flake8-raise + "PERF", # Perflint + "FURB", # refurb +] +ignore = [ + "E501" # https://www.flake8rules.com/rules/E501.html - Let `black` handle this. +] +# Allow autofix for all enabled rules (when `--fix`) is provided. +fixable = ["ALL"] +unfixable = [] +# Exclude a variety of commonly ignored directories. +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".git-rewrite", + ".hg", + ".mypy_cache", + ".nox", + ".pants.d", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "venv", + "venv*", + "tests" +] + +[tool.ruff.lint.per-file-ignores] +"__init__.py" = [ + "I001", +] + +[tool.ruff.lint.pyupgrade] +# Preserve types, even if a file imports `from __future__ import annotations`. +# Needed for python < 3.10, should be removed afterward. +keep-runtime-typing = true + +[tools.setuptools.dynamic] +version = {attr = 'project_dummy.__version__'} +readme = {file = ['README.md', 'README.rst', 'USAGE.rst']} +classifiers = {file = ['classifiers.txt']} +# # dependencies supports "file" but does not support comments in requirements.txt ... :| +# dependencies = {file = ['requirements.txt']} +# # ...same for optional dependencies... +# optional-dependencies = {file = ['requirements.txt']} + +# look for packages: +[tools.setuptools.packages.find] +# Not using "src/" for now. I'm starting with /package_name folders, using "src" as a folder +# feels redundant. May change when I use larger projects. +# where = ["src"] # list of folders that contain the packages (["."] by default) +include = ["project_*"] # package names should match these glob patterns (["*"] by default) +exclude = ["project_*.tests*"] # exclude packages matching these glob patterns (empty by default) +namespaces = false # to disable scanning PEP 420 namespaces (true by default) + +# ...or list the packages explicitly: +# [tool.setuptools] +# packages = ["my_package"] # use [] for meta-dists that just collect dependencies diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/setup.py.bak b/setup.py.bak new file mode 100644 index 0000000..d72fff4 --- /dev/null +++ b/setup.py.bak @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +"""Install this beautiful module to your python ecosystem (づ。•◡ •。)づ ᯓᡣ𐭩. + +This is vastly derived from Jeff Knupp's python project ideas. +""" + +from __future__ import print_function + +import io +import os +import sys + +import project_dummy + +from setuptools import setup, find_packages +from setuptools.command.test import test as TestCommand + + +print('This file is obsolete, it should be replaced by pyproject.toml et al.') +sys.exit(0) + +here = os.path.abspath(os.path.dirname(__file__)) + + +def read(*filenames, **kwargs): + """Read project files.""" + encoding = kwargs.get('encoding', 'utf-8') + sep = kwargs.get('sep', '\n') + buf = [] + for filename in filenames: + with io.open(filename, encoding=encoding) as f: + buf.append(f.read()) + return sep.join(buf) + + +long_description = read('README.md', 'CHANGES.md') + + +class PyTest(TestCommand): + """Use pytest for testing.""" + + def finalize_options(self): + """Finalise options.""" + TestCommand.finalize_options(self) + self.test_args = [] + self.test_suite = True + + def run_tests(self): + """Run tests.""" + import pytest + errcode = pytest.main(self.test_args) + sys.exit(errcode) + + +setup( + name='project_dummy', + version=project_dummy.__version__, + url='https://git.lirion.de/python-project-dummy/', + license='LGPLv3', + author='Glenn Matthews', + tests_require=['pytest'], + install_requires=['ansible', + 'ansible-compat', + 'ansible-core>=2.12.0', + ], + cmdclass={'test': PyTest}, + author_email='janitor@sacredheart.com', + description='A dummy as base directory for actual projects', + long_description=long_description, + packages=['project_dummy'], + include_package_data=True, + platforms='any', + test_suite='project_dummy.tests.dummy_test', + classifiers=[ + 'Programming Language :: Python', + 'Development Status :: 2 - Pre-Alpha', + 'Natural Language :: English', + 'Environment :: Console', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: GNU General Public License v2 (GPLv2)', + 'Operating System :: OS Independent', + 'Topic :: Software Development :: Libraries :: Python Modules', + 'Topic :: Software Development :: Libraries :: Application Frameworks', + ], + extras_require={ + 'testing': ['pytest'], + } +) diff --git a/tests/dummy_test.py b/tests/dummy_test.py new file mode 100644 index 0000000..2320f8b --- /dev/null +++ b/tests/dummy_test.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +"""Test some shtuffs.""" + +import pytest + +from project_dummy import db, hemlo_world + + +@pytest.fixture +def test_fix_to_true(): + """A fixture.""" + return True + + +def test_assert_true(): + """A simple assertion.""" + assert True + + +def test_hello_world(): + """Just check that we can import and run this.""" + assert isinstance(hemlo_world.hemlo(), str) + + +def test_db(): + """A string.""" + assert isinstance(db.Db().dbt, str) + db.Db().print_db() + + +if __name__ == '__main__': + hemlo_world.hemlo() + + +# Some random things +# Async fixtures and tests: +# +# @pytest.mark.asyncio +# async def test_async_part(): +# ... +# +# @pytest.fixture +# async def create_x(): +# ... diff --git a/tests/project_dummy b/tests/project_dummy new file mode 120000 index 0000000..d758124 --- /dev/null +++ b/tests/project_dummy @@ -0,0 +1 @@ +../project_dummy \ No newline at end of file diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..6f4ef0a --- /dev/null +++ b/tox.ini @@ -0,0 +1,20 @@ +[tox] +envlist = coverage +isolated_build = True + +[testenv] +passenv = + CI +commands = pytest --benchmark-disable + +[testenv:coverage] +commands = + coverage erase + pytest --cov={envsitepackagesdir}/nio --cov-report term-missing --benchmark-disable + coverage xml + coverage report --show-missing +deps = + .[dev] + coverage +setenv = + COVERAGE_FILE=.coverage -- cgit v1.2.3