commit ebf2864e61caacddad59f0484ad96f4de07114b4 Author: Holger Frey Date: Tue Aug 22 15:23:10 2023 +0200 import of project template diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d5f79e1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,65 @@ +# ---> Python +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +.venv +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# 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/ +.nox/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Mac Stuff +.DS_Store + diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..b438489 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,28 @@ +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v2.4.0 + hooks: + - id: check-added-large-files + - id: check-byte-order-marker + - id: check-json + - id: check-merge-conflict + - id: check-toml + - id: debug-statements + - id: detect-private-key +- repo: local + hooks: + - id: black + name: Auto formatting code with "black" + entry: black src tests + language: system + pass_filenames: false + - id: ruff + name: Linting code with "ruff" + entry: ruff src tests + language: system + pass_filenames: false + - id: pytest + name: Running tests with "pytest" + entry: pytest tests + language: system + pass_filenames: false diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..2fd3f54 --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,4 @@ +0.0.1 - first version +---------------------- + + - setting up the project diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..220198f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,117 @@ +Contributing +============ + +Contributions are welcome, and they are greatly appreciated! Every little bit +helps, and credit will always be given. + +You can contribute in many ways: + +Types of Contributions +---------------------- + +### Report Bugs + +Report bugs at https://git.cpi.imtek.uni-freiburg.de/holgi/conda_helpers.git/issues. + +If you are reporting a bug, please include: + +* Your operating system name and version. +* Any details about your local setup that might be helpful in troubleshooting. +* Detailed steps to reproduce the bug. + +### Fix Bugs + +Look through the GitHub issues for bugs. Anything tagged with "bug" and "help +wanted" is open to whoever wants to implement it. + +### Implement Features + +Look through the GitHub issues for features. Anything tagged with "enhancement" +and "help wanted" is open to whoever wants to implement it. + +### Write Documentation + +conda helpers could always use more documentation, whether as part of the +official conda helpers docs, in docstrings, or even on the web in blog posts, +articles, and such. + +### Submit Feedback + +The best way to send feedback is to file an issue at https://git.cpi.imtek.uni-freiburg.de/holgi/conda_helpers.git/issues. + +If you are proposing a feature: + +* Explain in detail how it would work. +* Keep the scope as narrow as possible, to make it easier to implement. +* Remember that this is a volunteer-driven project, and that contributions + are welcome :) + +Get Started! +------------ + +Ready to contribute? Here's how to set up `conda_helpers` for local development. + +1. Fork the `conda_helpers` repo on GitHub. +2. Clone your fork locally:: + + `$ git clone git@github.com:your_name_here/conda_helpers.git` + +3. Install your local copy into a virtualenv. + + `$ cd conda_helpers/` + `$ make devenv` + +4. Create a branch for local development:: + + `$ git checkout -b name-of-your-bugfix-or-feature` + + Now you can make your changes locally. + +5. When you're done making changes, check that your changes passes the linters and the + tests, including testing other Python versions with tox:: + + ``` + $ make lint + $ make coverage + $ make tox + ``` + +6. Commit your changes and push your branch to GitHub:: + + ``` + $ git add . + $ git commit -m "Your detailed description of your changes." + $ git push origin name-of-your-bugfix-or-feature + ``` + +7. Submit a pull request through the GitHub website. + +Pull Request Guidelines +----------------------- + +Before you submit a pull request, check that it meets these guidelines: + +1. The pull request should include tests. +2. If the pull request adds functionality, the docs should be updated. Put + your new functionality into a function with a docstring, and add the + feature to the list in README.md and CHANGES.md + +Tips +---- + +To run a quick set of tests without coverage report + + $ make test + +Deploying +--------- + +A reminder for the maintainers on how to deploy. +Bump the version in `conda_helpers/__init__.py` and +make sure all your changes are committed (including an entry in CHANGES.md). + + $ git tag + $ git push + $ git push --tags + $ flit publish + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a3dfb3e --- /dev/null +++ b/LICENSE @@ -0,0 +1,10 @@ +/* +* ---------------------------------------------------------------------------- +* "THE BEER-WARE LICENSE" (Revision 42): +* frey@imtek.de wrote this file. As long as you retain this notice you +* can do whatever you want with this stuff. If we meet some day, and you think +* this stuff is worth it, you can buy me a beer in return. Holger Frey +* ---------------------------------------------------------------------------- +*/ + + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..14c1ae4 --- /dev/null +++ b/Makefile @@ -0,0 +1,118 @@ +.PHONY: clean clean-build clean-docs clean-pyc clean-test coverage coverall devenv docs help install lint nox prepareenv repo serve-docs test testall testfunctional tox venvexists +.DEFAULT_GOAL := help + +define BROWSER_PYSCRIPT +import os, webbrowser, sys + +try: + from urllib import pathname2url +except: + from urllib.request import pathname2url + +webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1]))) +endef +export BROWSER_PYSCRIPT + +define PRINT_HELP_PYSCRIPT +import re, sys + +for line in sys.stdin: + match = re.match(r'^([a-zA-Z_-]+):.*?## (.*)$$', line) + if match: + target, help = match.groups() + print("%-20s %s" % (target, help)) +endef +export PRINT_HELP_PYSCRIPT + +BROWSER := python -c "$$BROWSER_PYSCRIPT" + +help: + @python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST) + + +venvexists: ## helper to check if a virtual environment exists + @test -x .venv/bin/python || { echo "No virtual environment found, please run 'make devenv'"; exit 1; } + +clean: clean-build clean-docs clean-pyc clean-test ## remove all build, test, coverage and Python artifacts + +clean-build: ## remove build artifacts + rm -fr build/ + rm -fr dist/ + rm -fr .eggs/ + find . -name '*.egg-info' -exec rm -fr {} + + find . -name '*.egg' -exec rm -f {} + + +clean-docs: ## remove documentation artifacts + rm -fr site/ + +clean-pyc: ## remove Python file artifacts + find . -name '*.pyc' -exec rm -f {} + + find . -name '*.pyo' -exec rm -f {} + + find . -name '*~' -exec rm -f {} + + find . -name '__pycache__' -exec rm -fr {} + + +clean-test: ## remove test and coverage artifacts + rm -fr .mypy_cache/ + rm -fr .pytest_cache/ + rm -fr .ruff_cache/ + rm -fr .nox/ + rm -fr .tox/ + rm -f .coverage + rm -fr htmlcov/ + +lint: venvexists ## reformat with black and check style with flake8 + .venv/bin/black src tests noxfile.py + .venv/bin/ruff src tests noxfile.py + +test: lint ## run tests quickly, stop on first error + .venv/bin/pytest tests --stepwise --disable-warnings -m "not functional" + +testfunctional: lint ## run functional tests, stop on first error + .venv/bin/pytest tests --stepwise -m "functional" + +testall: lint ## run all tests + .venv/bin/pytest tests + +coverage: lint ## functional test suite, check code coverage and open coverage report + .venv/bin/pytest tests --cov=conda_helpers --cov=tests -m "functional" + .venv/bin/coverage html + $(BROWSER) htmlcov/index.html + +coverall: lint ## full test suite, check code coverage and open coverage report + .venv/bin/pytest tests --cov=conda_helpers --cov=tests + .venv/bin/coverage html + $(BROWSER) htmlcov/index.html + +nox: venvexists ## run fully isolated tests with nox + .venv/bin/nox + +tox: venvexists ## old habits die hard: typo-squatting to use nox + .venv/bin/nox + +docs: venvexists ## build the documentation using mkdocs + .venv/bin/mkdocs build + +serve-docs: docs ## build the documentation and serve them in a web server + .venv/bin/mkdocs serve + +install: venvexists ## install updated project.toml + .venv/bin/pip3 install -e ".[dev,docs,test]" + +prepareenv: ## helper to create virtual environment and install basic packages + rm -fr .venv/ + python3 -m venv --prompt conda_helpers .venv + .venv/bin/pip3 install --upgrade pip wheel + .venv/bin/pip3 install -e ".[dev,docs,test]" + +devenv: prepareenv ## setup development environment including precommit hooks + .venv/bin/pre-commit install --install-hooks + +repo: prepareenv ## complete project setup with development environment and git repo + git init . + git add . + git commit -m "import of project template" + git branch -m main + git remote add origin https://git.cpi.imtek.uni-freiburg.de/holgi/conda_helpers.git + git push -u origin main --no-verify + + .venv/bin/pre-commit install --install-hooks diff --git a/README.md b/README.md new file mode 100644 index 0000000..746ffbe --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +conda helpers +============= + +Helpers for working with data frames in a conda environment + +## Example: + +```python + + import conda_helpers + + conda_helpers.run() +``` + + +## Development + +To install the development version of conda helpers: + + git clone https://git.cpi.imtek.uni-freiburg.de/holgi/conda_helpers.git + + # create a virtual environment and install all required dev dependencies + cd conda_helpers + make devenv + +To run the tests, use `make tests` or `make coverage` for a complete report. + +To generate the documentation pages use `make docs` or `make serve-docs` for +starting a webserver with the generated documentation diff --git a/docs/explanation.md b/docs/explanation.md new file mode 100644 index 0000000..71077ee --- /dev/null +++ b/docs/explanation.md @@ -0,0 +1,18 @@ +# Explanation + +This part of the project documentation focuses on a +**learning-oriented** approach. You'll learn how to +get started with the code in this project. + +> **Note:** Expand this section by considering the +> following points: + +- Help newcomers with getting started +- Teach readers about your library by making them + write code +- Inspire confidence through examples that work for + everyone, repeatably +- Give readers an immediate sense of achievement +- Show concrete examples, no abstractions +- Provide the minimum necessary explanation +- Avoid any distractions diff --git a/docs/how-to-guides.md b/docs/how-to-guides.md new file mode 100644 index 0000000..54df9be --- /dev/null +++ b/docs/how-to-guides.md @@ -0,0 +1,6 @@ +# How-To Guides + +This part of the project documentation focuses on a +**problem-oriented** approach. You'll tackle common +tasks that you might have, with the help of the code +provided in this project. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..3bacd80 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,20 @@ +# conda helpers Documentation + +This site contains the project documentation for the +`conda_helpers` project. + + +## Table Of Contents + +The documentation follows the best practice for +project documentation as described by Daniele Procida +in the [Diátaxis documentation framework](https://diataxis.fr/) +and consists of four separate parts: + +1. [Tutorials](tutorials.md) +2. [How-To Guides](how-to-guides.md) +3. [Reference](reference.md) +4. [Explanation](explanation.md) + +Quickly find what you're looking for depending on +your use case by looking at the different pages. diff --git a/docs/reference.md b/docs/reference.md new file mode 100644 index 0000000..fb6f50a --- /dev/null +++ b/docs/reference.md @@ -0,0 +1,9 @@ +# Reference + +This part of the project documentation focuses on +an **information-oriented** approach. Use it as a +reference for the technical implementation of the +` conda_helpers` project code. + + +::: conda_helpers diff --git a/docs/tutorials.md b/docs/tutorials.md new file mode 100644 index 0000000..fba5682 --- /dev/null +++ b/docs/tutorials.md @@ -0,0 +1,17 @@ +# Tutorials + +This part of the project documentation focuses on an +**understanding-oriented** approach. You'll get a +chance to read about the background of the project, +as well as reasoning about how it was implemented. + +> **Note:** Expand this section by considering the +> following points: + +- Give context and background on your library +- Explain why you created it +- Provide multiple examples and approaches of how + to work with it +- Help the reader make connections +- Avoid writing instructions or technical descriptions + here diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..1a4b70b --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,17 @@ +site_name: conda helpers Docs + +nav: + - Introduction: index.md + - Tutorials: tutorials.md + - How-To Guides: how-to-guides.md + - Reference: reference.md + - Explanation: explanation.md + +repo_url: https://git.cpi.imtek.uni-freiburg.de/holgi/conda_helpers.git + +theme: + name: readthedocs + highlightjs: true + +plugins: + - mkdocstrings diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 0000000..0687c84 --- /dev/null +++ b/noxfile.py @@ -0,0 +1,61 @@ +import pathlib +import tempfile +import typing + +import nox + + +class RepoCache: + """class for caching checkouts of downstream repos + + By caching the checkouts for downstream test runs, + the nox invokation is faster and there is less load + on the git server and network. + """ + + _checkouts: typing.ClassVar = {} + + @classmethod + def clone(cls, session: nox.Session, repo: str) -> str: + """clones a git repo only once + + Arguments: + session: the nox session in use + repo: a git repo url + + Returns: + path to a temporary directory containing the + cloned git repo + """ + tmpdir = cls._checkouts.get(repo, None) + + if tmpdir is None: + tmpdir = tempfile.TemporaryDirectory() + session.run("git", "clone", repo, tmpdir.name, external=True) + cls._checkouts[repo] = tmpdir + + return tmpdir.name + + +@nox.session(python=["3.9", "3.10", "3.11"]) +def tests(session): + session.install(".[test]") + + session.run("pytest", *session.posargs) + + +@nox.session(python=["3.9", "3.10", "3.11"]) +@nox.parametrize( + "repo", + [ + "https://git.example.com/user/repo", + ], +) +def downstream(session, repo): + tmpdir = RepoCache.clone(session, repo) + + session.install(".") + session.install(f"{tmpdir}[test]") + + test_path = pathlib.Path(tmpdir) / "tests" + session.run("pytest", test_path) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..7e701fe --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,118 @@ + + +[build-system] +requires = ["flit_core>=3.2,<4"] +build-backend = "flit_core.buildapi" + +[project] +name = "conda_helpers" +readme = "README.md" +license = { file = "LICENSE" } +requires-python = ">=3.9" +dynamic = ["version", "description"] + +authors = [ + {name = "Holger Frey", email = "frey@imtek.de"}, +] + +# see https://pypi.org/classifiers/ +classifiers = [ + "Development Status :: 2 - Pre-Alpha", + "Intended Audience :: Developers", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3 :: Only", + "License :: Freely Distributable", +] + +dependencies = [ + "pandas", +] + +[project.urls] +Source = "https://git.cpi.imtek.uni-freiburg.de/holgi/conda_helpers.git" + +# [project.scripts] +# script_name = "conda_helpers:function" + +[project.optional-dependencies] +dev = [ + "black", + "flit", + "keyring", + "pre-commit", + "ruff", +] +docs = [ + "mkdocs", + "mkdocstrings[python]", +] +test = [ + "nox", + "pytest >=4.0.0", + "pytest-cov", + "pytest-icdiff", + "pytest-mock", + "pytest-randomly", +] + + +[tool.pytest.ini_options] +markers = [ + "functional: marks tests as functional (deselect with '-m \"not functional\"')", +] +addopts = [ + "--strict-markers", + "--strict-config", + "--showlocals", + "-ra", +] + + +[tool.black] +line-length = 79 +target-version = ['py39', 'py310'] +include = '\.pyi?$' +extend-exclude = ''' +# A regex preceded with ^/ will apply only to files and directories +# in the root of the project. +^/.git +^/.tox +^/.venv +^/.build +^/.dist +''' + + +[tool.ruff] +# see https://github.com/charliermarsh/ruff +select = ["ALL"] +ignore = [ + # ignored for now, should be activated in the future + # docstrings + "D", + # flake8-annotations + "ANN", + # flake8-type-checking + "TCH", + + # ignored, "black" will handle this + # flake8-commas + "COM", + + # ignored, due to Windows / WSL2 setup + # flake8-executable + "EXE", +] +fixable = ["I"] +fix = true +line-length=79 +target-version = "py38" + +[tool.ruff.per-file-ignores] +# see https://github.com/charliermarsh/ruff +"tests/*" = ["FBT003", "INP001", "PLR2004", "S101", "SLF001"] + +[tool.ruff.pydocstyle] +convention = "pep257" # Accepts: "google", "numpy", or "pep257". diff --git a/src/conda_helpers/__init__.py b/src/conda_helpers/__init__.py new file mode 100644 index 0000000..33c8aae --- /dev/null +++ b/src/conda_helpers/__init__.py @@ -0,0 +1,6 @@ +""" conda helpers + +Helpers for working with data frames in a conda environment +""" + +__version__ = "0.0.1" diff --git a/tests/test_conda_helpers.py b/tests/test_conda_helpers.py new file mode 100644 index 0000000..2eacc3f --- /dev/null +++ b/tests/test_conda_helpers.py @@ -0,0 +1,45 @@ +""" Stub file for testing the project + +There are three predefined ways to run tests: + +make test: + runs only unit tests, that are not marked with "fun" (for functional test) + in a random order. If a test failed before, only the failed tests will be + run. This is intended to be the default testing method while developing. + +make testall: + runs unit tests and functional tests in random order. Will give a complete + overview of the test suite. + +make coverage: + runs only tests marked with "fun" (for functional tests) and generates a + coverage report for the test run. The idea is to check the test coverage + only on functinal tests to see if a) everything is as much covered as + possible and b) to find dead code that is not called in end-to-end tests. + +all three test strategies will run "make lint" before to catch easily made +mistakes. +""" + +import pytest + + +def test_example_unittest(): + """example unittest - try importing the project + + will be run by 'make test' and 'make testall' but not 'make coverage' + """ + import conda_helpers # noqa: F401 + + assert True + + +@pytest.mark.functional() +def test_example_functional_test(): + """example unittest + + will be by 'make coverage' and 'make testall' but not 'make test' + """ + import conda_helpers # noqa: F401 + + assert True