diff options
-rw-r--r-- | .gitignore | 21 | ||||
-rw-r--r-- | .nojekyll | 0 | ||||
-rw-r--r-- | MANIFEST.in | 1 | ||||
-rw-r--r-- | Makefile | 31 | ||||
-rw-r--r-- | README.md | 32 | ||||
-rw-r--r-- | classifiers.txt | 12 | ||||
-rw-r--r-- | codecov.yml | 7 | ||||
-rw-r--r-- | project_dummy/__init__.py | 3 | ||||
-rw-r--r-- | project_dummy/db.py | 26 | ||||
-rw-r--r-- | project_dummy/hemlo_world.py | 15 | ||||
-rw-r--r-- | pyproject.toml | 121 | ||||
-rw-r--r-- | requirements.txt | 0 | ||||
-rw-r--r-- | setup.py.bak | 88 | ||||
-rw-r--r-- | tests/dummy_test.py | 44 | ||||
l--------- | tests/project_dummy | 1 | ||||
-rw-r--r-- | tox.ini | 20 |
16 files changed, 422 insertions, 0 deletions
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 --- /dev/null +++ b/.nojekyll 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 --- /dev/null +++ b/requirements.txt 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 @@ -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 |