Testing
Focus here is on:
Styling flake8
Formatting black
Unit Test pytest
Debugger debugpy
Local testing
The gateway will be the Makefile for various test/build/deploy/run/validation needs
make test
# reference repo specific `Makefile` for additional info
# but common patterns will be
make pytest
make flake8
make black_check
We'll use tox for easily running multiple tests in a single command
tox
tox -e py3
tox -e flake8
tox -e black
Styling and Formatting
Usage of flake8 and black together will ensure code is written in a opinionated manner
In addition to the make and tox methods can be ran individually like
# flake8
flake8 --max-line-length 120 ./
# black
black --check --line-length 120 ./
black --diff --line-length 120 ./
black --line-length 120 ./
Unit Test
Commmand Line
Additional options to make and tox methods
# file or directory
pytest -vv ./<target>
# specific test
pytest -vv ./<target>::<function_name>
# test pattern name
pytest -vv ./<target> -k "pattern_name"
Skip a test with a decorator
@pytest.mark.skip(reason="Something")
vscode Unit Test integration
via settings.json
"python.testing.nosetestsEnabled": false,
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true,
"python.testing.pytestArgs": [
"linecaspy"
],
TODO: refine further, been leveraging tox and pytest directly
Debugger
The preferred method is using launch.json but to invoke debugpy manually use a pattern
# local file
python -m debugpy --listen 5678 ~/code/lambda-functions/health_check_py/lambda_function.py
# docker example
docker-compose exec -T pyfunctions python -m debugpy --listen 0.0.0.0:5678 --wait-for-client /git/health_check_py/lambda_function.py
# docker-compose flask command
python -m debugpy --listen 0.0.0.0:5678 --wait-for-client -m flask run --host=0.0.0.0 --port=5005
# linecaspy debugger (requires env var DEBUGGER=True)
from linecaspy.helpers.generic import HelperFunctions as PyHelpers
PyHelpers().enable_debugger()
Using the below code references for integrating debugpy will help when mount/path issues occur with breakpoints set in vscode
import debugpy # noqa: F401
debugpy.wait_for_client()
debugpy.breakpoint()
vscode configurations
Local Python Project
via launch.json include:
* NOTE: no method to support console_script CLI projects directly, must call direct file
{
"name": "on-aws",
"type": "python",
"request": "launch",
"python": "/home/andrew/virtualenvs/py/bin/python",
"program": "${workspaceFolder}/linecaspy/linecaspy/clients/cli_aws.py",
"console": "integratedTerminal",
"justMyCode": false,
"args": [
"--instances"
],
"env": {
"DEBUGGER": "True"
}
},
{
"name": "on-slack",
"type": "python",
"request": "launch",
"python": "/home/andrew/virtualenvs/py/bin/python",
"program": "${workspaceFolder}/linecaspy/linecaspy/clients/cli_slack.py",
"console": "integratedTerminal",
"justMyCode": false,
"args": [
"--channel", "sandbox", "--message", "Using debugger"
],
"env": {
"DEBUGGER": "True"
},
"envFile": "${workspaceFolder}/.vscode/.env"
},
Lambda Functions
Diffent debugger techniques are needed for different projects like lambda-functions
In that project, there are a few key integrations
# docker-compose.yml
ports:
- 5365:5678
# Makefile (sample for each respective function)
health_check_py_debugpy:
docker-compose exec -T pyfunctions python -m debugpy --listen 0.0.0.0:5678 --wait-for-client /git/health_check_py/lambda_function.py
Enable Docker and Makefile integration via launch.json like below:
{
"name": "lambda:funcions",
"type": "python",
"request": "attach",
"port": 5365,
"host": "localhost",
"pathMappings": [
{
"localRoot": "${workspaceFolder}/lambda-functions",
"remoteRoot": "."
}
]
},
In this workflow we would
* Set our breakpoints in vscode
* Pend the lambda function for analysis
make health_check_py_debugpy
make http_handler_py_debugpy
make pass_fail_py_debugpy
- Run debugger
lambda:functions
Attest - Docker
Similar to the Lambda Functions repo above, the attest repo also has different debug needs for the various dockerized services.
The workflow here can be a combination of the previous items. Where we start with the docker-compose.yml with relevant portion
command: python ./orbit.py
# command: python -m debugpy --listen 0.0.0.0:5678 --wait-for-client ./orbit.py
working_dir: /git/attest/src
volumes:
- ./:/git
environment:
- DEBUGGER=True
ports:
- 5577:5678
Notes:
* On the port configuration, we always bind to :5678, but the external port remain differnt
* Then comes the volumes and working_dir mounts that
* Which allows for specific command (more on this later) or the application to be called directly
* If the linecaspy debugger option is enabled, need to set environment variables DEBUGGER=True
Commands (samples)
# dependent upon your needs, the direct debugger command could look like
command: python ./app.py
command: python ./orbit.py
command: python -m debugpy --listen 0.0.0.0:5678 --wait-for-client ./orbit.py
command: python -m debugpy --listen 0.0.0.0:5678 --wait-for-client -m flask run --host=0.0.0.0 --port=5005
If the file is called directly, the debugger can still be integrated like
from linecaspy.helpers.generic import HelperFunctions as PyHelpers
PyHelpers().enable_debugger()
Which then makes my local debugger enablement process of either:
* Edit the command to run python -m debugpy if desired
* Set the environment variable DEBUGGER=True with linecaspy helper
Restart Specific service
make restart_orbit
# or
docker-compose stop orbit && \
docker-compose up -d orbit
Run Debugger via samples in launch.json
{
"name": "attest:api:werkzeug",
"type": "python",
"request": "attach",
"port": 5570,
"host": "localhost",
"pathMappings": [
{
"localRoot": "${workspaceFolder}/attest/attest/src",
"remoteRoot": "/git/attest/src"
}
]
},
{
"name": "attest:orbit",
"type": "python",
"request": "attach",
"port": 5577,
"host": "localhost",
"pathMappings": [
{
"localRoot": "${workspaceFolder}/attest/attest/src",
"remoteRoot": "/git/attest/src"
}
]
},
{
"name": "attest:worker",
"type": "python",
"request": "attach",
"port": 5575,
"host": "localhost",
"pathMappings": [
{
"localRoot": "${workspaceFolder}/attest/attest/src",
"remoteRoot": "/git/attest/src"
}
]
},
vscode Tasks
To understand file paths, create a tasks.json, and then run via Terminal -> Run Task -> echo
{
"version": "2.0.0",
"tasks": [
{
"label": "echo",
"type": "shell",
"command": "echo ${workspaceFolder}"
}
]
}