Setech utilities
Project description
Setech Utilities
Python utility library for API clients, logging, and various development tasks.
Installation
Install the package using pip:
pip install setech
Or with virtualenv (recommended):
python -m venv .venv
source .venv/bin/activate # On Linux/macOS
Extra Dependencies
The following optional dependencies are available:
| Extra | Description |
|---|---|
django |
Django support (>=5.2, django-crum, django-model-utils) |
drf |
Django REST Framework with full Django stack |
dns |
DNS utilities (dnspython with dnssec, doh, idna support) |
dns-redis |
DNS cache using Redis backend |
Install extras:
pip install "setech[django]" # Django support
pip install "setech[drf]" # Django REST Framework
pip install "setech[dns]" # DNS utilities
pip install "setech[dns-redis]" # DNS cache with Redis
Core Dependencies
The package requires the following core dependencies:
httpx2[http2]num2wordsphonenumberslitepydanticunidecode
Development Setup
The repository uses uv as the package manager and dependency resolver.
Follow these steps to get a fully‑featured development environment with one command.
# 1. Create and activate a virtual environment (recommended)
python -m venv .venv
source .venv/bin/activate # On Windows use `.venv\Scripts\activate`
# 2. Install uv (if you don’t already have it)
curl -LsSf [https://astral.sh/uv/install.sh](https://astral.sh/uv/install.sh) | sh
# 3. Sync all base, dev and optional extras in a single command
uv sync --dev
# 4. Verify everything is installed
uv run python -m pip list | grep setech
What the --dev flag does
- Installs the core dependencies listed under
[project]. - Adds the optional extras
django,drfanddns‑redis(viasetech[... ]). - Installs the development tooling (
ipython,ruff,mypy, test runners, etc.) from the[dependency-groups] devsection. - Resolves transitive dependencies only once, so no duplication occurs.
Tip: If you ever need to refresh the lockfile after a dependency bump, run:
uv sync --dev --upgrade
Example code
API Clients
# integration/client.py
from setech import SyncClient
class LocalClient(SyncClient):
name = "local"
_base_url = "https://obligari.serveo.net/ping/local"
def __init__(self, nonce=None):
super().__init__(nonce)
self._session.headers.update(
{"User-Agent": "Mozilla/5.0 (Windows NT 10.0; rv:123.0) Gecko/20100101 Firefox/123.0"}
)
def send_post_ping(self, var1: str, var2: int) -> bool:
res = self.post("/some-post", json={"variable_one": var1, "second_variable": var2})
return res.json().get("status")
def send_put_ping(self, var1: str, var2: int) -> bool:
res = self.put("/some-put", data={"variable_one": var1, "second_variable": var2})
return res.json().get("status")
def send_get_ping(self, var1: str, var2: int) -> bool:
res = self.get("/some-get", params={"variable_one": var1, "second_variable": var2})
return res.json().get("status")
def send_patch_ping(self, var1: str, var2: int) -> bool:
res = self.put("/some-patch", data=(("variable_one", var1), ("variable_one", var2)))
return res.json().get("status")
def send_trace_ping(self, var1: str, var2: int) -> bool:
res = self.trace("/some-trace", params=(("variable_one", var1), ("variable_one", var2)))
return res.json().get("status")
# integration/main.py
from integration.client import LocalClient
client = LocalClient()
client.send_post_ping("asd", 123)
client.send_put_ping("asd", 123)
client.send_get_ping("asd", 123)
client.send_patch_ping("asd", 123)
client.send_trace_ping("asd", 123)
Log output
Simple
[14d709e02c0c] Preparing POST request to "https://obligari.serveo.net/ping/local/some-post"
[14d709e02c0c] Sending request with payload=b'{"variable_one": "asd", "second_variable": 123}'
[14d709e02c0c] Response response.status_code=200 str_repr_content='{"status":true,"request_id":62}'
[14d709e02c0c] Preparing GET request to "https://obligari.serveo.net/ping/local/some-get"
[14d709e02c0c] Sending request with payload=None
[14d709e02c0c] Response response.status_code=200 str_repr_content='{"status":true,"request_id":63}'
Structured
{"app": "dev", "level": "DEBUG", "name": "APIClient", "date_time": "2024-03-09 22:59:24", "location": "api_client/client.py:_request:71", "message": "[cfbdadc56f53] Preparing POST request to \"https://obligari.serveo.net/ping/local/some-post\"", "extra_data": {"hooks": {"response": []}, "method": "POST", "url": "https://obligari.serveo.net/ping/local/some-post", "headers": {}, "files": [], "data": [], "json": {"variable_one": "asd", "second_variable": 123}, "params": {}, "auth": null, "cookies": null}}
{"app": "dev", "level": "INFO", "name": "APIClient", "date_time": "2024-03-09 22:59:24", "location": "api_client/client.py:_request:74", "message": "[cfbdadc56f53] Sending request with payload=b'{\"variable_one\": \"asd\", \"second_variable\": 123}'", "extra_data": {"payload": "{\"variable_one\": \"asd\", \"second_variable\": 123}"}}
{"app": "dev", "level": "INFO", "name": "APIClient", "date_time": "2024-03-09 22:59:25", "location": "api_client/client.py:_request:81", "message": "[cfbdadc56f53] Response response.status_code=200 str_repr_content='{\"status\":true,\"request_id\":72}'", "extra_data": {"status_code": 200, "content": "{\"status\":true,\"request_id\":72}"}}
{"app": "dev", "level": "DEBUG", "name": "APIClient", "date_time": "2024-03-09 22:59:25", "location": "api_client/client.py:_request:71", "message": "[cfbdadc56f53] Preparing GET request to \"https://obligari.serveo.net/ping/local/some-get\"", "extra_data": {"hooks": {"response": []}, "method": "GET", "url": "https://obligari.serveo.net/ping/local/some-get", "headers": {}, "files": [], "data": [], "json": null, "params": {"variable_one": "asd", "second_variable": 123}, "auth": null, "cookies": null}}
{"app": "dev", "level": "INFO", "name": "APIClient", "date_time": "2024-03-09 22:59:25", "location": "api_client/client.py:_request:74", "message": "[cfbdadc56f53] Sending request with payload=None", "extra_data": {"payload": "{}"}}
{"app": "dev", "level": "INFO", "name": "APIClient", "date_time": "2024-03-09 22:59:25", "location": "api_client/client.py:_request:81", "message": "[cfbdadc56f53] Response response.status_code=200 str_repr_content='{\"status\":true,\"request_id\":74}'", "extra_data": {"status_code": 200, "content": "{\"status\":true,\"request_id\":73}"}}
django features
Using the setech.django in a Django project
Models
The library ships two abstract base models that can be inherited to get timestamping, UUID and audit fields.
# myapp/models.py
from django.db import models
from setech.django.models import TimeStampedUUIDModel, UserTimeStampedUUIDModel
class Article(TimeStampedUUIDModel):
title = models.CharField()
content = models.TextField()
class Comment(UserTimeStampedUUIDModel):
article = models.ForeignKey(Article, on_delete=models.CASCADE)
text = models.TextField()
What each base class provides
| Base model | Fields added | Notes |
|---|---|---|
TimeStampedUUIDModel |
uid, created_at, updated_at |
UUID (v4 or v7 if available) and timestamps |
UserTimeStampedUUIDModel |
created_by, modified_by |
Populated automatically from the current request when using Django‑CRUM |
Validators
setech.django.validators contains a handful of reusable validator functions that can be dropped straight into Django model fields or form/serializer validations.
They wrap common checks such as phone numbers, personal IDs and MX‑record validation for e‑mail addresses.
# myapp/models.py
from django.db import models
from setech.django.models import TimeStampedUUIDModel
from setech.django.validators import django_phone_number_validator, django_personal_code_validator, django_validate_email_mx_domain, validate_image_and_svg_file_extension
class UserProfile(TimeStampedUUIDModel):
# Phone number in international format, e.g. "+44 20 7946 0958"
phone = models.CharField(validators=[django_phone_number_validator])
# Personal ID (SSN/NRIC/etc.) – the validator automatically uses your
# `settings.COUNTRY_CODE` (e.g. "LV" for Latvia)
personal_id = models.CharField(max_length=20, validators=[django_personal_code_validator])
# Email address – ensures the domain can receive mail
email = models.EmailField(validators=[django_validate_email_mx_domain])
# Image file – ensures the file is either image or svg
picture = models.FileField(validators=[validate_image_and_svg_file_extension])
Customizing the country code
The validators rely on settings.COUNTRY_CODE to decide which format to expect.
Add the following to your Django settings:
# settings.py
from setech.django.constants import Country
...
COUNTRY_CODE = Country.LV # Latvia, change to your locale
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file setech-1.8.0rc2.tar.gz.
File metadata
- Download URL: setech-1.8.0rc2.tar.gz
- Upload date:
- Size: 23.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b7c305543c3e260d65acb00d37f753e91a9c2e497457244ce7ae3186059c0da2
|
|
| MD5 |
d0b98321b98d1142d8050df5e3b2878f
|
|
| BLAKE2b-256 |
631af11401cf9d77857d3d2a68ff046c617a4530c74b81df6a67665acd21f8b8
|
File details
Details for the file setech-1.8.0rc2-py3-none-any.whl.
File metadata
- Download URL: setech-1.8.0rc2-py3-none-any.whl
- Upload date:
- Size: 34.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d185e46bfe46cc213284d252552d957e15b80f7e5a12eb23789d8b9ebb086a53
|
|
| MD5 |
5860316ee24a08b08a65b0e8fe51c9dd
|
|
| BLAKE2b-256 |
50e3daec5955fa788b2a7dff04b730cd8893c16c738f4e7bea77c66b92c5da18
|