Releases: syngenta/acai-python
Release list
v2.8.1 — dedupe equal RedactionFilters
Fixed
- logger:
CommonLogger.register_callbacknow dedupes equal callbacks;RedactionFiltergained value equality (__eq__/__hash__). Registering the same filter from multiple handler entrypoints in one process is idempotent (no stacked redaction passes). Distinct callbacks still stack.
Full changelog: 2.8.0...2.8.1
v2.8.0
Added
- logger: pluggable pre-print callback hook on
CommonLogger(register_callback/reset_callbacks) — records pass through callbacks before emit (#328) - logger:
RedactionFiltercallback — opt-in scrubbing of matching field names (any depth) and regex value matches,redact_withconfigurable (#328)
Changed
- logger:
CommonLoggeris now a singleton — configured once, reused across alllogger.log()calls; callbacks are process-global (#329)
LOG_FORMAT / LOG_LEVEL continue to be read per call (env-driven). Fully backward compatible.
Full changelog: 2.7.0...2.8.0
v2.7.0
Added
- apigateway: map request-contract errors to
400instead of500(#327)
Fixed
- logger: accept canonical Python level names (
WARNING,DEBUG,CRITICAL) — shipped in interim tag 2.6.2
Full changelog: 2.6.1...2.7.0
v2.6.1
Build & CI
- Switch from pipenv to uv
- Tighten uv setup (locked install, pinned uv, setuptools-scm,
[tool.uv]) - Parallelize lint, test, and sonarcloud jobs
- Use full checkout for the sonarcloud-scan job
Full changelog: 2.6.0...2.6.1
v2.6.0
Added
- ALB Router with full API Gateway routing parity
Docs
- Document
alb.Routerfor HTTP routing on ALB Lambda targets
Full changelog: 2.5.1...2.6.0
v2.5.1
Bug Fix
validate_record_body crashed with TypeError when body is non-dict and required_body is a Pydantic model.
When a record body was not a dict (e.g., empty string "", None, or a list) and required_body pointed to a Pydantic BaseModel, the resolved(**body) unpacking raised TypeError instead of producing a validation error.
Now returns {'key_path': 'body', 'message': 'Expected JSON object body'} cleanly, which flows through all failure_mode options correctly.
Found during
Downstream integration with service-payroll-kyc where ALB records can arrive with empty-string bodies.
v2.5.0
What's New
Pydantic BaseModel support for all records events
required_body now accepts a Pydantic BaseModel subclass on every event source (SQS, Kinesis, DynamoDB, MSK, SNS, S3, Firehose, MQ, DocumentDB, ALB) — not just API Gateway.
from pydantic import BaseModel
from acai_aws.sqs.requirements import requirements
class OrderEvent(BaseModel):
order_id: str
amount: float
@requirements(required_body=OrderEvent)
def handler(event):
for record in event.records:
process(record.body)Unified failure_mode enum
Replaces the overlapping raise_body_error / raise_operation_error booleans with a single failure_mode kwarg:
| Mode | Behavior |
|---|---|
FailureMode.SILENT_IGNORE |
Default — invalid records silently filtered (unchanged) |
FailureMode.LOG_WARN |
Filter + structured WARN log per invalid record |
FailureMode.RAISE_ERROR |
First invalid record raises RecordException |
FailureMode.RETURN_FAILURE |
Auto-merge validation failures into batchItemFailures response |
from acai_aws.base.event import FailureMode
@requirements(required_body=OrderEvent, failure_mode=FailureMode.RETURN_FAILURE)
def handler(event):
# Framework auto-merges validation failures into batchItemFailures.
# SQS/Kinesis/DynamoDB retries malformed messages instead of losing them.
...ALB automatic HTTP 400
When required_body is set on an ALB handler, invalid bodies produce an HTTP 400 response matching the API Gateway error shape — handler is never called.
Eager validation
Validation now runs before the handler executes (was lazy on event.records access). All four modes are deterministic regardless of whether the handler accesses records.
Per-source batch_item_identifier
Records expose batch_item_identifier for partial batch response: SQS → messageId, Kinesis/DDB → sequenceNumber, MSK → topic-partition-offset.
100% line coverage
575 tests, pylint 10.00/10, 2382/2382 lines covered.
Deprecations
raise_body_error=True→ usefailure_mode=FailureMode.RAISE_ERRORraise_operation_error=True→ usefailure_mode=FailureMode.RAISE_ERROR
Both still work with a one-time deprecation warning. Will be removed in the next major version.
Internal
validate_record_bodyerror field renamedkey→key_path(internal only, no external consumers)- S3 and MSK Event classes refactored to use
_build_records/_post_operation_hookhooks - Deleted dead
_reset_recordshelper
v2.4.0
What's New
ALB Event Source Support
Added Application Load Balancer as a new event source module (acai_aws.alb).
ALB sends a single Lambda proxy integration event (not a Records array). The new module wraps it for compatibility with the existing base class pattern.
Record properties:
body- JSON-parsed body (handles base64-encoded bodies)operation- Maps HTTP methods to operations (POST=CREATED, PUT/PATCH=UPDATED, DELETE=DELETED)http_method- Raw HTTP methodpath- Request pathheaders- Request headers dictquery_params- Query string parameterssource_ip- x-forwarded-for headertarget_group_arn- ALB target group ARN
Usage:
from acai_aws.alb.requirements import requirements
@requirements()
def handler(records):
for record in records.records:
handle_request(record.http_method, record.body, record.source_ip)Detected automatically via requestContext.elb in the event, registered as aws:elb event source.
v2.3.8
What's Changed
Features
response_codessupport in OpenAPI generator — Endpoints can now declare multiple HTTP status codes (e.g. 200/204) via@requirements(response_codes={200: 'User exists', 204: 'User does not exist'}). The existingrequired_responseschema is applied to non-204 codes; 204 responses are emitted without a body. Fully backwards compatible — falls back to the original behavior whenresponse_codesis not set.
Fixes
- Resolve all pylint issues in openapi module — Added
encoding='utf-8'to file writeropen()calls, fixed missing final newline, removed unnecessaryelifafterreturn, added consistent return statements, and replaced broadExceptionwithValueErrorin input validator. Pylint score now 10.00/10.
Full Changelog: 2.3.7...2.3.8
2.3.7
fix: inline $defs from pydantic model_json_schema in OpenAPI generator. Produces universally compatible output without $defs references.