Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Add Jupyter Notebook Tooling #168

Merged
merged 6 commits into from
May 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions {{cookiecutter.project_slug}}/.pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ repos:
rev: v.0.8.0
hooks:
- id: flakehell
exclude_types: [jupyter]

# Docstring coverage tool
- repo: https://github.com/econchick/interrogate
Expand Down Expand Up @@ -65,6 +66,59 @@ repos:
args: [--cache-dir=/dev/null, --config-file=tox.ini]
types: [python]

- repo: https://github.com/nbQA-dev/nbQA
rev: 0.8.0
hooks:
- id: nbqa-black
args: [--nbqa-mutate]
additional_dependencies: [black==21.5b0]
- id: nbqa-isort
args: [--nbqa-mutate]
additional_dependencies: [isort==5.8.0]
- id: nbqa-pyupgrade
args: [--nbqa-mutate]
additional_dependencies: [pyupgrade==v2.14.0]

- repo: local
hooks:
- id: nbqa-bandit
name: nbqa-bandit
description: "Run tox env `bandit` on a Jupyter Notebook"
entry: .tox/precommit/bin/nbqa bandit
language: system
types: [jupyter]

## Override nbqa pre-packaged hooks to preempt spurious "Module not found"
## errors

# See: https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports
- repo: local
hooks:
- id: nbqa-mypy
name: nbqa-mypy
description: "Run tox env `mypy` on a Jupyter Notebook"
entry: .tox/precommit/bin/nbqa mypy
# yamllint disable-line rule:line-length
args: [--cache-dir=/dev/null, --config-file=tox.ini]
language: system
types: [jupyter]

# Note: submit docs for this to nbqa?
# ex. https://nbqa.readthedocs.io/en/latest/pre-commit.html
# referencing:
# yamllint disable-line rule:line-length
# [Remove pylint config E0401 and make pylint a local pre-commit hook #229](https://github.com/nbQA-dev/nbQA/pull/229/files)

# E0401: import-error
- repo: local
hooks:
- id: nbqa-pylint
name: nbqa-pylint
description: "Run tox env `pylint` on a Jupyter Notebook"
entry: .tox/precommit/bin/nbqa pylint
language: system
types: [jupyter]

- repo: local
hooks:
- id: pylint
Expand Down
1 change: 1 addition & 0 deletions {{cookiecutter.project_slug}}/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ typer-cli = { version = "^0.0.11", optional = true}

[tool.poetry.dev-dependencies]
# Testing
nbqa = "^0.8.0"
pytest = "^6.2.1"
pytest-benchmark = {extras = ["histogram"], version = "^3.4.1"}
pytest-cov = "^2.10.1"
Expand Down
33 changes: 29 additions & 4 deletions {{cookiecutter.project_slug}}/tox.ini
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
[gh-actions]
python =
3.7: py37
3.8: py38
3.9: py39, coverage
3.7: py37, nbqaxdoctest
3.8: py38, nbqaxdoctest
3.9: py39, coverage, nbqaxdoctest

[tox]
skip_missing_interpreters = true
isolated_build = true
envlist =
py3{7,8,9},
coverage,
nbqaxdoctest,
package

[testenv]
Expand Down Expand Up @@ -83,7 +84,7 @@ commands =
--paths-to-mutate={{cookiecutter.package_name}}/ \
--runner="{[testenv]commands}" \
--tests-dir=tests/ || \
MUTMUT_EXIT_CODE="$\{?\}"; \
MUTMUT_EXIT_CODE=$?; \
if [[ "$\{MUTMUT_EXIT_CODE\}" -eq 1 ]]; \
then \
exit "$\{MUTMUT_EXIT_CODE\}"; \
Expand Down Expand Up @@ -134,14 +135,38 @@ depends =
py3{7,8,9}
parallel_show_output = {[testenv]parallel_show_output}

[testenv:nbqaxdoctest]
description = Run notebook doctests directly via `xdoctest` (more efficient and
less error-prone than using the built-in `doctest` library or
running `xdoctest` via the `pytest` plugin). Note: if any test
fails, the test environment command fails with the FIRST non-zero
exit code encountered in the output job log.
deps = -r requirements-dev.txt
allowlist_externals = bash
commands =
bash -c '\
find {toxinidir}/{{cookiecutter.package_name}} -type f -name "*.ipynb" \
| parallel --joblog {toxworkdir}/{envname}.log -j 0 -k nbqa xdoctest \{\} --colored true; \
NUM_FAILED_JOBS=$?; \
echo "*****************$NUM_FAILED_JOBS FAILED JOBS*****************"; \
cat {toxworkdir}/{envname}.log| awk "\$7 != 0"; \
FAILURE_EXIT_CODES=$(cat {toxworkdir}/{envname}.log | awk "NR>1 && \$7 != 0 \{print \$7 \}") && \
exit $\{FAILURE_EXIT_CODES:0:1\}'
# Run after testenv since auto-generated temp `.py` files interfere with pytest
depends =
py3{7,8,9}
parallel_show_output = {[testenv]parallel_show_output}

[testenv:precommit]
description = Run `pre-commit` hooks to auto-format and lint the codebase
deps =
bandit # `nbqa-bandit`
pre-commit
hypothesis
icontract
icontract_hypothesis
mypy
nbqa
pylint
pytest
sphinx
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"outputs": [],
"source": [
"import operator"
],
"metadata": {
"collapsed": false,
"pycharm": {
"name": "#%%\n"
}
}
},
{
"cell_type": "code",
"execution_count": 2,
"outputs": [],
"source": [
"def my_sum(nums: list[int]) -> int:\n",
" \"\"\"Returns the sum of a given list of integers\n",
"\n",
" Without using the `+` operator\n",
"\n",
" Args:\n",
" nums:\n",
"\n",
" Examples:\n",
" >>> my_sum([1, 1])\n",
" 2\n",
" >>> my_sum([])\n",
" 0\n",
"\n",
" \"\"\"\n",
" running_sum = 0\n",
" for num in nums:\n",
" running_sum = operator.add(running_sum, num)\n",
" return running_sum"
],
"metadata": {
"collapsed": false,
"pycharm": {
"name": "#%%\n"
}
}
},
{
"cell_type": "code",
"execution_count": 3,
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1 + 1 + 1 + 1 = 4\n"
]
}
],
"source": [
"test_nums = [1] * 4\n",
"print(f\"{' + '.join(str(x) for x in test_nums)} = {my_sum(test_nums)}\")"
],
"metadata": {
"collapsed": false,
"pycharm": {
"name": "#%%\n"
}
}
},
{
"cell_type": "code",
"execution_count": 3,
"outputs": [],
"source": [],
"metadata": {
"collapsed": false,
"pycharm": {
"name": "#%%\n"
}
}
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 0
}