Compare commits

...

3 commits

Author SHA1 Message Date
b0c1cab95a docker compose entrypoint 2026-01-08 19:45:38 +00:00
2a1762083b update python notes 2026-01-08 19:45:25 +00:00
5d37a1efb2 additional notes on python testing 2026-01-08 19:44:37 +00:00
5 changed files with 130 additions and 16 deletions

View file

@ -0,0 +1,30 @@
---
tags:
- docker
---
The `entrypoint` key in a Docker compose file is useful for running any advanced
scripts before the the main `cmd` is executed.
```sh
app:
image: python:3.11-slim
entrypoint: ["./entrypoint.sh"]
command: ["python", "src/app.py"]
```
I used it recently to inject a `.pem` certificate into the container before the
main execution.
The script must conclude with `exec "$@"` because it receives the value of the
`command` key in the Compose file as its argument. E.g.
```sh
cat /etc/ssl/certs/ca-certificates.crt /zscaler.pem > /tmp/combined-certs.pem
export REQUESTS_CA_BUNDLE=/tmp/combined-certs.pem
export SSL_CERT_FILE=/tmp/combined-certs.pem
pip install -r requirements.txt
exec "$@"
```

88
zk/Pytest_fixtures.md Normal file
View file

@ -0,0 +1,88 @@
---
tags: [python, pytest]
---
Fixtures are a way to provide data or state to your tests. Typically, although
not exclusively, for processes that you want to reuse accross different `test_`
functions. They are defined at the "arrange" stage of testing.
## Example: testing class methods under test
```py
class Person:
def __init__(self, name):
self.name = name
def print_name(self):
return f"Your name is {self.name}"
```
To create a fixture of this class:
```py
@pytest.fixture
def my_person():
person = new Person('Thomas')
return person.name()
test_print_name(my_person):
assert(my_person) == 'Thomas'
```
> Note we define our fixture and then inject it into our test function.
> Functions request fixtures they require by declaring them as arguments.
Alternatively you could just return the class from the fixture and test the
methods individually within the test function.
## Integrating with `@patch` to provide mock fixtures
Say we wanted to mock reading a JSON file.
We could create a fixture:
```py
@pytest fixture
def raw_json():
return json.dumps({"key": "value"})
```
And pass it in to the mock of the global `open` method:
```py
from unittest.mock import mock_open, patch
def test_json_parsing(raw_json):
with patch("builtins.open", mock_open(read_data=raw_json))
# Then assert etc
```
This fixture could then be re-used to test any other method that relies on
incoming JSON from a file.
## Example: setup and teardown - before each and after each
Fixtures can be leveraged to setup 'before each...' and 'after each...' logic:
```py
@pytest.fixture(scope="function")
def setup():
os.environ["POCKET_LAMBDA_ENDPOINT"] = "https://some_endpoint.com/{article_type}"
yield
del os.environ["POCKET_LAMBDA_ENDPOINT"]
```
Here `yield` is a placeholder for the tests that run in between the setup and
teardown.
We use `scope="function"` to signal that this will run before/after any tests
that inject the fixture.
Then to specify the units that will run as the `yield` we just inject `setup`:
```py
def some_function(setup_function):
pass
```

View file

@ -1,18 +1,16 @@
--- ---
tags: [python, testing] tags: [python, testing, pytest]
--- ---
# Testing Python code
## `pytest` ## `pytest`
Pytest is the most popular testing library for Python. It is not included with Pytest is the most popular testing library for Python. It is not included with
the Python standard library so it must be installed with the Python standard library so it must be installed with
[pip](Python_package_management.md). [pip](Python_package_management.md). While it does not include a declaration
While it does not include a declaration library, it is robust enough to handle library, it is robust enough to handle most scenarios having a rich and
most scenarios having a rich and expressive set of constructs and decorators expressive set of constructs and decorators that let you declare what your tests
that let you declare what your tests should do, under what conditions they should do, under what conditions they should run, and how they should interact
should run, and how they should interact with the rest of your system. with the rest of your system.
### Using `pytest` ### Using `pytest`

View file

@ -2,10 +2,6 @@
tags: [python, data-structures] tags: [python, data-structures]
--- ---
# Tuples in Python
TODO: Exapand tuple notes - give more use cases
Tuples are one of the main data-structures or containers in Python. Tuples are Tuples are one of the main data-structures or containers in Python. Tuples are
useful in cases where you want to group related data and ensure that it will not useful in cases where you want to group related data and ensure that it will not
change. change.
@ -31,9 +27,13 @@ tup1 = (1, 3, 5, 7)
print(tup1[2]) print(tup1[2])
# 5 # 5
"""
``` ```
> Really you should know in advance how long your tuple is going to be but if
> you just do `tup = ('shoe')` this will be processed by Python as a single
> string. Instead if you want to indicate that the tuple may be expanded later
> use `tup = ('shoe',)`. The comma converts it from a string to a tuple.
## Slicing ## Slicing
```python ```python

View file

@ -4,8 +4,6 @@ tags:
- data-types - data-types
--- ---
# Type hinting in Python
With type hinting we can add type information to variables, functions, and With type hinting we can add type information to variables, functions, and
classes. This is not enforced by the Python interpreter but can be used by classes. This is not enforced by the Python interpreter but can be used by
external tools like `mypy` to check the code. external tools like `mypy` to check the code.
@ -109,7 +107,7 @@ def find_index(numbers: list[int], target: int) -> Optional[int]:
The function above returns an `int` or `None`. The function above returns an `int` or `None`.
Post 3.10, we don't need to use `Optional`, we can use a union to cover the From 3.11, we don't need to use `Optional`, we can use a union to cover the
`None` case. Refactoring the previous example: `None` case. Refactoring the previous example:
```py ```py