Compare commits
No commits in common. "b0c1cab95abd1464dce8cbd5d6cc25a268cebc57" and "52f4420b739ac779d54afcb1e1a7f40352f3a749" have entirely different histories.
b0c1cab95a
...
52f4420b73
5 changed files with 16 additions and 130 deletions
|
|
@ -1,30 +0,0 @@
|
||||||
---
|
|
||||||
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 "$@"
|
|
||||||
```
|
|
||||||
|
|
@ -1,88 +0,0 @@
|
||||||
---
|
|
||||||
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
|
|
||||||
```
|
|
||||||
|
|
@ -1,16 +1,18 @@
|
||||||
---
|
---
|
||||||
tags: [python, testing, pytest]
|
tags: [python, testing]
|
||||||
---
|
---
|
||||||
|
|
||||||
|
# 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). While it does not include a declaration
|
[pip](Python_package_management.md).
|
||||||
library, it is robust enough to handle most scenarios having a rich and
|
While it does not include a declaration library, it is robust enough to handle
|
||||||
expressive set of constructs and decorators that let you declare what your tests
|
most scenarios having a rich and expressive set of constructs and decorators
|
||||||
should do, under what conditions they should run, and how they should interact
|
that let you declare what your tests should do, under what conditions they
|
||||||
with the rest of your system.
|
should run, and how they should interact with the rest of your system.
|
||||||
|
|
||||||
### Using `pytest`
|
### Using `pytest`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,10 @@
|
||||||
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.
|
||||||
|
|
@ -27,13 +31,9 @@ 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
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ 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.
|
||||||
|
|
@ -107,7 +109,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`.
|
||||||
|
|
||||||
From 3.11, we don't need to use `Optional`, we can use a union to cover the
|
Post 3.10, 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
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue