xocto 4.9.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- xocto/__init__.py +4 -0
- xocto/events/__init__.py +2 -0
- xocto/events/core.py +88 -0
- xocto/events/utils.py +19 -0
- xocto/exceptions.py +4 -0
- xocto/health.py +28 -0
- xocto/localtime.py +785 -0
- xocto/numbers.py +150 -0
- xocto/pact_testing.py +105 -0
- xocto/ranges.py +925 -0
- xocto/settlement_periods.py +151 -0
- xocto/storage/__init__.py +0 -0
- xocto/storage/files.py +213 -0
- xocto/storage/s3_select.py +188 -0
- xocto/storage/storage.py +1858 -0
- xocto/tracing.py +36 -0
- xocto/types.py +69 -0
- xocto/urls.py +146 -0
- xocto-4.9.0.dist-info/LICENSE +27 -0
- xocto-4.9.0.dist-info/METADATA +68 -0
- xocto-4.9.0.dist-info/RECORD +23 -0
- xocto-4.9.0.dist-info/WHEEL +5 -0
- xocto-4.9.0.dist-info/top_level.txt +1 -0
xocto/__init__.py
ADDED
xocto/events/__init__.py
ADDED
xocto/events/core.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Protocol
|
|
4
|
+
|
|
5
|
+
import structlog
|
|
6
|
+
from django import http
|
|
7
|
+
from django.conf import settings
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
logger = structlog.get_logger("events")
|
|
11
|
+
|
|
12
|
+
__all__ = ["publish"]
|
|
13
|
+
|
|
14
|
+
METADATA = {
|
|
15
|
+
"release": "GIT_SHA",
|
|
16
|
+
"aws_private_ip": "AWS_LOCAL_IP",
|
|
17
|
+
"aws_instance_id": "AWS_INSTANCE_ID",
|
|
18
|
+
"aws_availability_zone": "AWS_AVAILABILITY_ZONE",
|
|
19
|
+
"aws_auto_scaling_group": "AWS_AUTO_SCALING_GROUP",
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Account(Protocol):
|
|
24
|
+
number: str
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def publish(
|
|
28
|
+
event: str,
|
|
29
|
+
params: dict[str, Any] | None = None,
|
|
30
|
+
meta: dict[str, Any] | None = None,
|
|
31
|
+
account: Account | None = None,
|
|
32
|
+
request: http.HttpRequest | None = None,
|
|
33
|
+
) -> None:
|
|
34
|
+
"""
|
|
35
|
+
Publish an event.
|
|
36
|
+
|
|
37
|
+
- `params` are values that were used to create the event (eg the path of a
|
|
38
|
+
request)
|
|
39
|
+
- `meta` are contextual values around the event (eg the IP address of the
|
|
40
|
+
person making the request)
|
|
41
|
+
|
|
42
|
+
Note, structlog will add a timestamp.
|
|
43
|
+
"""
|
|
44
|
+
payload: dict[str, Any] = {"event": event}
|
|
45
|
+
if params is not None:
|
|
46
|
+
payload["params"] = params
|
|
47
|
+
if meta is None:
|
|
48
|
+
meta = {}
|
|
49
|
+
|
|
50
|
+
# If the event relates to a single account, we include its number so it's easy to filter down
|
|
51
|
+
# to events that affect one account in Loggly.
|
|
52
|
+
if account is not None:
|
|
53
|
+
payload["account"] = account.number
|
|
54
|
+
|
|
55
|
+
# Add static metadata from settings.
|
|
56
|
+
for key, setting in METADATA.items():
|
|
57
|
+
value = getattr(settings, setting, "")
|
|
58
|
+
if value:
|
|
59
|
+
meta[key] = value
|
|
60
|
+
|
|
61
|
+
# Add metadata from request
|
|
62
|
+
if request is not None:
|
|
63
|
+
meta.update(_request_meta(request))
|
|
64
|
+
|
|
65
|
+
payload["meta"] = meta
|
|
66
|
+
|
|
67
|
+
_log(payload)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _log(event: dict[str, Any]) -> None:
|
|
71
|
+
"""
|
|
72
|
+
Log the event.
|
|
73
|
+
"""
|
|
74
|
+
event_ = event.copy()
|
|
75
|
+
name = event_.pop("event")
|
|
76
|
+
logger.info(name, **event_)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _request_meta(request: http.HttpRequest) -> dict[str, Any]:
|
|
80
|
+
"""
|
|
81
|
+
Extract relevant meta information from a request instance.
|
|
82
|
+
"""
|
|
83
|
+
meta = {"ip_address": request.META["REMOTE_ADDR"]}
|
|
84
|
+
if "HTTP_USER_AGENT" in request.META:
|
|
85
|
+
meta["user_agent"] = request.META["HTTP_USER_AGENT"]
|
|
86
|
+
if hasattr(request, "session") and request.session.session_key:
|
|
87
|
+
meta["session"] = request.session.session_key
|
|
88
|
+
return meta
|
xocto/events/utils.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import time
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
__all__ = ["Timer"]
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Timer(object):
|
|
9
|
+
"""
|
|
10
|
+
Context manager to allow easy timing of events.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __enter__(self) -> "Timer":
|
|
14
|
+
self.start = time.time()
|
|
15
|
+
return self
|
|
16
|
+
|
|
17
|
+
def __exit__(self, *args: Any) -> None:
|
|
18
|
+
self.end = time.time()
|
|
19
|
+
self.duration_in_ms = (self.end - self.start) * 1000
|
xocto/exceptions.py
ADDED
xocto/health.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from django.db import DEFAULT_DB_ALIAS, connections
|
|
2
|
+
from django.db.migrations.loader import MigrationLoader
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def check_migrations() -> bool:
|
|
6
|
+
"""
|
|
7
|
+
Check if there are any migrations that haven't been applied yet.
|
|
8
|
+
"""
|
|
9
|
+
return _num_unapplied_migrations() == 0
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _num_unapplied_migrations() -> int:
|
|
13
|
+
"""
|
|
14
|
+
Return the number of unapplied migrations.
|
|
15
|
+
"""
|
|
16
|
+
connection = connections[DEFAULT_DB_ALIAS]
|
|
17
|
+
loader = MigrationLoader(connection)
|
|
18
|
+
graph = loader.graph
|
|
19
|
+
|
|
20
|
+
# Count unapplied migrations
|
|
21
|
+
num_unapplied_migrations = 0
|
|
22
|
+
for app_name in loader.migrated_apps:
|
|
23
|
+
for node in graph.leaf_nodes(app_name):
|
|
24
|
+
for plan_node in graph.forwards_plan(node):
|
|
25
|
+
if plan_node not in loader.applied_migrations:
|
|
26
|
+
num_unapplied_migrations += 1
|
|
27
|
+
|
|
28
|
+
return num_unapplied_migrations
|