nui-python-shared-utils 2.3__tar.gz → 2.4.1__tar.gz

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.
Files changed (104) hide show
  1. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/.github/workflows/ci.yml +1 -1
  2. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/.github/workflows/publish.yml +1 -1
  3. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/.github/workflows/test.yml +1 -1
  4. nui_python_shared_utils-2.4.1/.markdownlint-base.yaml +66 -0
  5. nui_python_shared_utils-2.4.1/.markdownlint-cli2.yaml +17 -0
  6. nui_python_shared_utils-2.4.1/CHANGELOG.md +265 -0
  7. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/CONTRIBUTING.md +1 -1
  8. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/PKG-INFO +3 -4
  9. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/README.md +1 -1
  10. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/decisions/ADR-008-stdlib-zoneinfo-over-pytz.md +4 -3
  11. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/getting-started/installation.md +3 -3
  12. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/guides/powertools-integration.md +46 -1
  13. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/guides/shared-types.md +15 -0
  14. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/mypy.ini +1 -1
  15. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_python_shared_utils.egg-info/SOURCES.txt +2 -0
  16. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/logging/binding.py +0 -1
  17. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/powertools_helpers.py +18 -9
  18. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/timezone.py +4 -4
  19. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/pyproject.toml +3 -4
  20. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/redirect/pyproject.toml +1 -1
  21. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/setup.py +1 -2
  22. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_powertools_helpers.py +75 -1
  23. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_slack_client.py +66 -51
  24. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_timezone.py +37 -0
  25. nui_python_shared_utils-2.3/.markdownlint-cli2.yaml +0 -47
  26. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/.editorconfig +0 -0
  27. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/AGENTS.md +0 -0
  28. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/CLAUDE.md +0 -0
  29. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/LICENSE +0 -0
  30. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/MANIFEST.in +0 -0
  31. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/README.md +0 -0
  32. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/decisions/ADR-001-structured-logging-field-vocabulary.md +0 -0
  33. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/decisions/ADR-002-keep-shared-utilities-generic.md +0 -0
  34. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/decisions/ADR-003-lazy-load-integrations.md +0 -0
  35. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/decisions/ADR-004-credential-resolution-precedence.md +0 -0
  36. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/decisions/ADR-005-explicit-secrets-manager-region.md +0 -0
  37. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/decisions/ADR-006-snowflake-sql-api-client.md +0 -0
  38. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/decisions/ADR-007-elasticsearch-client-version-range.md +0 -0
  39. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/decisions/README.md +0 -0
  40. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/development/testing.md +0 -0
  41. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/getting-started/configuration.md +0 -0
  42. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/getting-started/quickstart.md +0 -0
  43. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/guides/cli-tools.md +0 -0
  44. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/guides/elasticsearch-integration.md +0 -0
  45. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/guides/jwt-authentication.md +0 -0
  46. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/guides/lambda-utilities.md +0 -0
  47. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/guides/llm-integration.md +0 -0
  48. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/guides/log-processing.md +0 -0
  49. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/guides/slack-integration.md +0 -0
  50. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/guides/snowflake-integration.md +0 -0
  51. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/docs/guides/structured-logging-contract.md +0 -0
  52. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/__init__.py +0 -0
  53. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/base_client.py +0 -0
  54. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/cli.py +0 -0
  55. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/cloudwatch_metrics.py +0 -0
  56. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/config.py +0 -0
  57. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/db_client.py +0 -0
  58. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/error_handler.py +0 -0
  59. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/es_client.py +0 -0
  60. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/es_query_builder.py +0 -0
  61. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/jwt_auth.py +0 -0
  62. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/lambda_helpers.py +0 -0
  63. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/llm.py +0 -0
  64. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/log_processors.py +0 -0
  65. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/logging/__init__.py +0 -0
  66. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/logging/fields.py +0 -0
  67. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/logging/redaction.py +0 -0
  68. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/secrets_helper.py +0 -0
  69. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/slack_client.py +0 -0
  70. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/slack_formatter.py +0 -0
  71. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/slack_setup/__init__.py +0 -0
  72. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/slack_setup/channel_creator.py +0 -0
  73. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/slack_setup/channel_definitions.py +0 -0
  74. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/slack_setup/setup_helpers.py +0 -0
  75. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/snowflake_client.py +0 -0
  76. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/nui_shared_utils/utils.py +0 -0
  77. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/pytest.ini +0 -0
  78. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/redirect/README.md +0 -0
  79. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/redirect/setup.py +0 -0
  80. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/requirements-test.txt +0 -0
  81. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/scripts/bench_imports.py +0 -0
  82. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/setup.cfg +0 -0
  83. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/__init__.py +0 -0
  84. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_aws_utils.py +0 -0
  85. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_base_client.py +0 -0
  86. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_cloudwatch_metrics.py +0 -0
  87. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_config.py +0 -0
  88. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_db_client.py +0 -0
  89. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_error_handler.py +0 -0
  90. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_es_client.py +0 -0
  91. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_es_client_compat.py +0 -0
  92. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_es_query_builder.py +0 -0
  93. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_jwt_auth.py +0 -0
  94. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_lambda_helpers.py +0 -0
  95. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_lazy_imports.py +0 -0
  96. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_llm.py +0 -0
  97. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_log_processors.py +0 -0
  98. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_logging_binding.py +0 -0
  99. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_logging_fields.py +0 -0
  100. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_redaction.py +0 -0
  101. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_secrets_helper.py +0 -0
  102. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_slack_formatter.py +0 -0
  103. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_snowflake_client.py +0 -0
  104. {nui_python_shared_utils-2.3 → nui_python_shared_utils-2.4.1}/tests/test_utils.py +0 -0
@@ -15,7 +15,7 @@ jobs:
15
15
  runs-on: ubuntu-latest
16
16
  strategy:
17
17
  matrix:
18
- python-version: ['3.9', '3.10', '3.11', '3.12']
18
+ python-version: ['3.10', '3.11', '3.12']
19
19
 
20
20
  steps:
21
21
  - uses: actions/checkout@v5
@@ -12,7 +12,7 @@ jobs:
12
12
  runs-on: ubuntu-latest
13
13
  strategy:
14
14
  matrix:
15
- python-version: ['3.9', '3.10', '3.11', '3.12']
15
+ python-version: ['3.10', '3.11', '3.12']
16
16
 
17
17
  steps:
18
18
  - uses: actions/checkout@v5
@@ -11,7 +11,7 @@ jobs:
11
11
  runs-on: ubuntu-latest
12
12
  strategy:
13
13
  matrix:
14
- python-version: ['3.9', '3.10', '3.11']
14
+ python-version: ['3.10', '3.11']
15
15
 
16
16
  steps:
17
17
  - uses: actions/checkout@v5
@@ -0,0 +1,66 @@
1
+ # === managed by sync-markdownlint.sh — DO NOT EDIT ===
2
+ # Source of truth: shared tooling config/markdownlint-base.yaml
3
+ # Change rules in the source, then run: sync-markdownlint.sh --update
4
+ # stamp: e9f1a3abeab6
5
+ # === end managed header (sync-markdownlint.sh) ===
6
+ # Shared markdownlint ruleset (FLAT format).
7
+ # See: https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md
8
+ #
9
+ # SOURCE OF TRUTH. Repos adopt this by vendoring a stamped copy as
10
+ # `.markdownlint-base.yaml` (via sync-markdownlint.sh) and pointing their own
11
+ # `.markdownlint-cli2.yaml` at it with `config: { extends: .markdownlint-base.yaml }`,
12
+ # then adding repo-specific `globs`/`ignores` (and any rare repo-only rule tweaks).
13
+ #
14
+ # This file is FLAT (rules at top level, no `config:` wrapper) because that is
15
+ # the format markdownlint's `extends` requires. Keep it rules-only: file
16
+ # selection (globs) and exclusions (ignores) are per-repo.
17
+
18
+ # Enable all rules by default; disables/customisations follow.
19
+ default: true
20
+
21
+ # MD013: Line length - off. Code blocks, tables, and URLs routinely exceed any
22
+ # sane width; wrapping prose to a column is not a standard we enforce.
23
+ MD013: false
24
+
25
+ # MD033: Inline HTML - allowed. Needed for details/summary, anchors, and the
26
+ # HTML comment markers some docs use (companions metadata, stay markers).
27
+ MD033: false
28
+
29
+ # MD034: Bare URLs - off. Bare URLs in reference docs are intentional.
30
+ MD034: false
31
+
32
+ # MD041: First line in file should be a top-level heading - off. Many docs open
33
+ # with YAML frontmatter or a metadata block, not an H1.
34
+ MD041: false
35
+
36
+ # MD024: Multiple headings with the same content - allowed when not siblings
37
+ # (e.g. a repeated "Example" under different sections).
38
+ MD024:
39
+ siblings_only: true
40
+
41
+ # MD046: Code block style - require fenced (not indented) blocks.
42
+ MD046:
43
+ style: "fenced"
44
+
45
+ # MD026: Trailing punctuation in headings - off. "Note:" / "Warning!" are fine.
46
+ MD026: false
47
+
48
+ # MD029: Ordered list item prefix - off. Docs mix "1. 1. 1." and "1. 2. 3." and
49
+ # both render correctly; not worth churning.
50
+ MD029: false
51
+
52
+ # MD036: Emphasis used instead of a heading - off. Bold-as-label
53
+ # ("**Root cause:**", date stamps) is an accepted convention here.
54
+ MD036: false
55
+
56
+ # MD040: Fenced code language - off. Not every code block has (or needs) a
57
+ # language tag; forcing one produces noise on output samples and snippets.
58
+ MD040: false
59
+
60
+ # MD051: Link fragments should be valid - off. Cross-doc anchor validation is
61
+ # unreliable across the workspace's mixed heading styles and generated pages.
62
+ MD051: false
63
+
64
+ # MD060: Table column style - off. Minor pipe-alignment preference; the corpus
65
+ # has always mixed styles.
66
+ MD060: false
@@ -0,0 +1,17 @@
1
+ # Markdownlint configuration for nui-python-shared-utils
2
+ # Shared rules are vendored by sync-markdownlint.sh.
3
+
4
+ config:
5
+ extends: .markdownlint-base.yaml
6
+
7
+ # File patterns to check
8
+ globs:
9
+ - "**/*.md"
10
+
11
+ # Exclusions
12
+ ignores:
13
+ - "node_modules/**"
14
+ - "vendor/**"
15
+ - ".git/**"
16
+ - "venv/**"
17
+ - ".venv/**"
@@ -0,0 +1,265 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and breaking changes are called out explicitly below, including historical minor releases
7
+ that contained them.
8
+
9
+ ## [Unreleased]
10
+
11
+ ### Changed
12
+
13
+ - **BREAKING**: require Python 3.10 or newer in both the main package and the legacy
14
+ redirect package. Python 3.9 is no longer supported or included in CI test matrices.
15
+
16
+ ### Fixed
17
+
18
+ - Use canonical IANA names `America/New_York` and `America/Los_Angeles` for US timezone
19
+ constants and option labels, so importing timezone utilities and Slack formatting works
20
+ on systems without legacy timezone links.
21
+
22
+ ## [2.4] - 2026-10-20
23
+
24
+ ### Added
25
+
26
+ - Add an opt-in `reraise_exceptions` parameter to `powertools_handler`. When enabled,
27
+ handler failures are logged and alerted before the original exception is re-raised so
28
+ stream and asynchronous event sources can apply their configured failure handling.
29
+ The default remains the existing 500 response, while SQS events continue to re-raise
30
+ unconditionally.
31
+
32
+ ## [2.3] - 2026-10-12
33
+
34
+ ### Fixed
35
+
36
+ - `powertools_handler` re-raises exceptions for SQS event-source mappings after logging and
37
+ alerting, so failed batches are redelivered and can reach a configured DLQ instead of
38
+ being acknowledged by the wrapper's 500 response.
39
+
40
+ ## [2.2] - 2026-09-14
41
+
42
+ ### Added
43
+
44
+ - Add response-returning Slack write methods (`post_message`, `post_thread_reply`,
45
+ `post_update`, and `post_file`) for callers that need message timestamps, channel IDs,
46
+ or the raw upload response. The existing bool-returning `send_*` methods retain their
47
+ error-swallowing behavior.
48
+ - Add `SentMessage` as the result type for posted messages and thread replies.
49
+
50
+ ### Changed
51
+
52
+ - `send_file` and `post_file` accept bytes and can upload into a thread with `thread_ts`.
53
+
54
+ ## [2.1] - 2026-08-03
55
+
56
+ ### Changed
57
+
58
+ - **BREAKING**: replace `pytz` with the standard-library `zoneinfo` API and remove `pytz`
59
+ from the base dependencies. Code importing timezone constants must replace `.localize()`
60
+ with `tzinfo=...`, passing `fold=1` for repeated wall times where the old `is_dst=False`
61
+ default mattered, and replace `.zone` with `.key`. Declare `pytz` directly if application
62
+ code still imports it. The `[timezone]` extra supplies `tzdata` for minimal images without
63
+ a system IANA database.
64
+ - Allow Elasticsearch client majors 7.17, 8.x, and 9.x through the `[elasticsearch]` and
65
+ `all` extras. See
66
+ [ADR-007](docs/decisions/ADR-007-elasticsearch-client-version-range.md).
67
+
68
+ ### Fixed
69
+
70
+ - Send Elasticsearch search `size` inside a copied request body, avoiding caller-dict
71
+ mutation and duplicate-value errors on client majors 8.x and 9.x.
72
+ - Return a plain `list` from `ElasticsearchClient.get_indices_info()` on every supported
73
+ Elasticsearch client major.
74
+ - Make no-argument `slack_formatter.format_nz_time()` independent of the host timezone.
75
+
76
+ ### Added
77
+
78
+ - Add an Elasticsearch compatibility test matrix for client majors 7.17, 8.x, and 9.x.
79
+ - Add ADRs covering Elasticsearch version support and the move to `zoneinfo`.
80
+
81
+ ## [2.0] - 2026-07-13
82
+
83
+ ### Removed
84
+
85
+ - **BREAKING**: the `nui_lambda_shared_utils` import shim. Import from `nui_shared_utils` instead (`from nui_shared_utils import ...`). The shim forwarded to `nui_shared_utils` with a `DeprecationWarning` since the 1.3.1 import-root rename and was always slated for removal in 2.0.0.
86
+ - The old distribution name still installs: `pip install nui-lambda-shared-utils` continues to resolve via the redirect package (which depends on `nui-python-shared-utils`). Only the old import root is gone.
87
+
88
+ ### Added
89
+
90
+ - Add ADRs for the package's generic scope, lazy integrations, credential precedence,
91
+ explicit Secrets Manager region resolution, and Snowflake SQL API choice.
92
+
93
+ ## [1.6.0] - 2026-07-13
94
+
95
+ ### Added
96
+
97
+ - Add a backend-neutral structured logging field registry, request-scoped Powertools and
98
+ stdlib binders, binding helpers, field validation, and recursive payload redaction.
99
+ - Add the structured logging contract guide and ADR-001.
100
+
101
+ ## [1.5.0] - 2026-07-02
102
+
103
+ ### Added
104
+
105
+ - Add optional `unfurl_links` and `unfurl_media` controls to `SlackClient.send_message`.
106
+ Unset values preserve Slack's existing defaults.
107
+
108
+ ## [1.4.1] - 2026-06-29
109
+
110
+ ### Fixed
111
+
112
+ - Replace the Snowflake extra's direct Git dependency with the published
113
+ `snowflake-sql-api>=0.1.1,<0.2.0` range so PyPI accepts the package metadata.
114
+
115
+ ## [1.4.0] - 2026-06-29
116
+
117
+ ### Added
118
+
119
+ - Add the pure-Python Snowflake SQL API client behind the optional `[snowflake]` extra,
120
+ including sync and async factories, key-pair credential resolution, query logging, and
121
+ offline tests.
122
+ - Add a generic Anthropic client helper behind the optional `[llm]` extra, with API-key and
123
+ Bedrock authentication, forced tool-use calls, and text calls.
124
+ - Add Snowflake and LLM integration guides.
125
+
126
+ ### Changed
127
+
128
+ - **BREAKING**: resolve the Secrets Manager region from the boto3 session, `AWS_REGION`, or
129
+ `AWS_DEFAULT_REGION`, and fail explicitly instead of silently defaulting to
130
+ `ap-southeast-2`.
131
+
132
+ ## [1.3.3] - 2026-05-06
133
+
134
+ ### Performance
135
+
136
+ - Cold-start init for Lambda consumers reduced by ~400ms.
137
+ - `boto3` and `botocore` are no longer imported at module load. They are deferred to first use inside `secrets_helper.get_secret`, `utils.create_aws_client`/`resolve_aws_region`, and `cloudwatch_metrics.MetricsPublisher` (now lazy-constructs its boto3 client on first metric publish).
138
+ - The package `__init__` uses PEP 562 `__getattr__` so submodules (`slack_client`, `es_client`, `db_client`, `jwt_auth`, `powertools_helpers`, etc.) only load when their attributes are first accessed. `import nui_shared_utils` is ~10ms, down from ~700ms+.
139
+ - Public API is unchanged. Optional integrations still resolve to `None` when their backing dependency is not installed (matching the previous behaviour).
140
+
141
+ ### Added
142
+
143
+ - `scripts/bench_imports.py` for measuring `python -X importtime` cumulative cost across common entry points.
144
+ - `tests/test_lazy_imports.py` regression tests (boto3 must not appear in `sys.modules` after a bare package import or after importing `jwt_auth`/`powertools_helpers`).
145
+
146
+ ## [1.3.2] - 2026-04-10
147
+
148
+ ### Fixed
149
+
150
+ - `get_elasticsearch_credentials()` now checks env vars (`ES_PASSWORD`/`ES_PASS`) before Secrets Manager, aligning with `BaseServiceClient` credential precedence
151
+ - `ESClient._resolve_credentials_from_env()` accepts both `ES_PASSWORD`/`ES_USERNAME` and `ES_PASS`/`ES_USER` conventions
152
+
153
+ ## [1.3.1] - 2026-04-05
154
+
155
+ ### Changed
156
+
157
+ - Renamed internal import from `nui_lambda_shared_utils` to `nui_shared_utils`
158
+
159
+ ## [1.3.0] - 2026-04-05
160
+
161
+ ### Changed
162
+
163
+ - Renamed PyPI package from `nui-lambda-shared-utils` to `nui-python-shared-utils`
164
+ - Added explicit license field for twine 6.x compatibility
165
+ - Updated CI publish workflow for new package name and tag pattern
166
+
167
+ ## [1.0.0 - 1.2.3] - 2025-11 to 2026-03
168
+
169
+ ### Added
170
+
171
+ - **Log Processors Module** - `log_processors` for Kinesis/CloudWatch log extraction
172
+ - **AWS Powertools Integration** - `powertools_helpers` module with `get_powertools_logger()` and `powertools_handler()`
173
+ - **JWT Authentication** - RS256 token validation for API Gateway Lambdas
174
+ - **Slack Block Kit improvements** - Enhanced block builder patterns
175
+ - **`slack-channel-setup` CLI tool** for Slack workspace automation
176
+ - `service_name` parameter to `SlackClient` for custom display names
177
+ - `[powertools]` optional dependency group
178
+ - Streaming bulk operations for Elasticsearch
179
+ - Environment-based credential resolution in `BaseServiceClient`
180
+ - Pass-through account names support
181
+
182
+ ### Changed
183
+
184
+ - Rebranded as generic production-ready package (not NUI-specific)
185
+ - Improved Slack Lambda header formatting (cleaner 2-line layout)
186
+ - Documentation reorganization and expansion
187
+
188
+ ### Breaking Changes
189
+
190
+ - Removed `SERVICE_EMOJI` from public API exports
191
+ - Removed `get_entity_stats()` and `get_record_stats()` from `DatabaseClient`
192
+ - `format_currency()` now requires explicit currency parameter
193
+
194
+ ## [0.0.6] - 2025-11-16
195
+
196
+ ### Added
197
+
198
+ - Configuration YAML support for account info
199
+ - RabbitMQ integration utilities
200
+
201
+ ### Changed
202
+
203
+ - Enhanced configuration system
204
+
205
+ ## [0.0.5] - 2025-09-29
206
+
207
+ ### Added
208
+
209
+ - Comprehensive test improvements
210
+ - Better test coverage across modules
211
+
212
+ ### Fixed
213
+
214
+ - Various test fixes and improvements
215
+
216
+ ## [0.0.4] - 2025-09-05
217
+
218
+ ### Changed
219
+
220
+ - Minor improvements and fixes
221
+
222
+ ## [0.0.3] - 2025-09-05
223
+
224
+ ### Changed
225
+
226
+ - Initial improvements
227
+
228
+ ## [0.0.2] - 2025-09-05
229
+
230
+ ### Added
231
+
232
+ - Initial package structure
233
+ - Core client implementations (Slack, Elasticsearch, Database)
234
+ - Metrics publishing utilities
235
+ - Error handling decorators
236
+ - Timezone utilities for NZ timezone handling
237
+
238
+ ## [0.0.1] - 2025-09-05
239
+
240
+ ### Added
241
+
242
+ - Initial release
243
+ - Basic project structure
244
+ - Python package configuration
245
+
246
+ [Unreleased]: https://github.com/nuimarkets/nui-python-shared-utils/compare/2.4...HEAD
247
+ [2.4]: https://github.com/nuimarkets/nui-python-shared-utils/compare/2.3...2.4
248
+ [2.3]: https://github.com/nuimarkets/nui-python-shared-utils/compare/2.2...2.3
249
+ [2.2]: https://github.com/nuimarkets/nui-python-shared-utils/compare/2.1...2.2
250
+ [2.1]: https://github.com/nuimarkets/nui-python-shared-utils/compare/2.0...2.1
251
+ [2.0]: https://github.com/nuimarkets/nui-python-shared-utils/compare/1.6.0...2.0
252
+ [1.6.0]: https://github.com/nuimarkets/nui-python-shared-utils/compare/1.5.0...1.6.0
253
+ [1.5.0]: https://github.com/nuimarkets/nui-python-shared-utils/compare/1.4.1...1.5.0
254
+ [1.4.1]: https://github.com/nuimarkets/nui-python-shared-utils/compare/1.4.0...1.4.1
255
+ [1.4.0]: https://github.com/nuimarkets/nui-python-shared-utils/compare/1.3.3...1.4.0
256
+ [1.3.3]: https://github.com/nuimarkets/nui-python-shared-utils/compare/1.3.2...1.3.3
257
+ [1.3.2]: https://github.com/nuimarkets/nui-python-shared-utils/compare/1.3.1...1.3.2
258
+ [1.3.1]: https://github.com/nuimarkets/nui-python-shared-utils/compare/1.3.0...1.3.1
259
+ [1.3.0]: https://github.com/nuimarkets/nui-python-shared-utils/compare/0.0.6...1.3.0
260
+ [0.0.6]: https://github.com/nuimarkets/nui-python-shared-utils/compare/0.0.5...0.0.6
261
+ [0.0.5]: https://github.com/nuimarkets/nui-python-shared-utils/compare/0.0.4...0.0.5
262
+ [0.0.4]: https://github.com/nuimarkets/nui-python-shared-utils/compare/0.0.3...0.0.4
263
+ [0.0.3]: https://github.com/nuimarkets/nui-python-shared-utils/compare/0.0.2...0.0.3
264
+ [0.0.2]: https://github.com/nuimarkets/nui-python-shared-utils/compare/0.0.1...0.0.2
265
+ [0.0.1]: https://github.com/nuimarkets/nui-python-shared-utils/releases/tag/0.0.1
@@ -6,7 +6,7 @@ We welcome contributions to the NUI Python Shared Utilities project! This docume
6
6
 
7
7
  ### Prerequisites
8
8
 
9
- - Python 3.9 or higher
9
+ - Python 3.10 or higher
10
10
  - Git
11
11
  - Virtual environment tool (venv, virtualenv, etc.)
12
12
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nui-python-shared-utils
3
- Version: 2.3
3
+ Version: 2.4.1
4
4
  Summary: Shared Python utilities for AWS Lambda, CLI tools, and agents with Slack, Elasticsearch, and monitoring integrations
5
5
  Home-page: https://github.com/nuimarkets/nui-python-shared-utils
6
6
  Author: NUI Markets
@@ -36,7 +36,6 @@ Classifier: Intended Audience :: Developers
36
36
  Classifier: License :: OSI Approved :: MIT License
37
37
  Classifier: Operating System :: OS Independent
38
38
  Classifier: Programming Language :: Python :: 3
39
- Classifier: Programming Language :: Python :: 3.9
40
39
  Classifier: Programming Language :: Python :: 3.10
41
40
  Classifier: Programming Language :: Python :: 3.11
42
41
  Classifier: Programming Language :: Python :: 3.12
@@ -45,7 +44,7 @@ Classifier: Topic :: System :: Monitoring
45
44
  Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
46
45
  Classifier: Environment :: Console
47
46
  Classifier: Framework :: AWS CDK
48
- Requires-Python: >=3.9
47
+ Requires-Python: >=3.10
49
48
  Description-Content-Type: text/markdown
50
49
  License-File: LICENSE
51
50
  Requires-Dist: boto3>=1.20.0
@@ -102,7 +101,7 @@ Dynamic: requires-python
102
101
  # NUI Python Shared Utilities
103
102
 
104
103
  [![PyPI version](https://badge.fury.io/py/nui-python-shared-utils.svg)](https://badge.fury.io/py/nui-python-shared-utils)
105
- [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
104
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
106
105
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
107
106
 
108
107
  Production-ready shared Python utilities for AWS Lambda functions, CLI tools, and agents. Provides standardized integrations for Slack, Elasticsearch, database, and monitoring. Built and battle-tested on the NUI platform with sensible defaults configurable for any environment.
@@ -1,7 +1,7 @@
1
1
  # NUI Python Shared Utilities
2
2
 
3
3
  [![PyPI version](https://badge.fury.io/py/nui-python-shared-utils.svg)](https://badge.fury.io/py/nui-python-shared-utils)
4
- [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
4
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
6
 
7
7
  Production-ready shared Python utilities for AWS Lambda functions, CLI tools, and agents. Provides standardized integrations for Slack, Elasticsearch, database, and monitoring. Built and battle-tested on the NUI platform with sensible defaults configurable for any environment.
@@ -11,7 +11,7 @@ that wanted only the logging contract or the metrics helper still shipped it.
11
11
 
12
12
  The cost is not the code. `pytz` bundles its own copy of the Olson/IANA database (0.86 MB of a
13
13
  1.0 MB installed package, measured on `pytz==2025.2`), and that copy is redundant on
14
- every interpreter this package supports: `requires-python = ">=3.9"`, and `zoneinfo` has been in
14
+ every interpreter this package supports: `requires-python = ">=3.10"`, and `zoneinfo` has been in
15
15
  the standard library since 3.9, reading the system database that Linux, macOS, and the AWS Lambda
16
16
  runtimes all ship.
17
17
 
@@ -82,8 +82,9 @@ a database to everyone:
82
82
 
83
83
  ## Load-bearing premises (supersede triggers)
84
84
 
85
- - **The interpreter floor stays at 3.9+.** `zoneinfo` is stdlib from 3.9. A drop below that
86
- would need `backports.zoneinfo`, at which point the calculus changes.
85
+ - **All supported interpreters include stdlib `zoneinfo`.** The package requires Python 3.10
86
+ or higher. Supporting an interpreter older than 3.9 would need `backports.zoneinfo`, at
87
+ which point the calculus changes.
87
88
  - **Target runtimes ship a system IANA database.** True of Linux, macOS, and the AWS Lambda
88
89
  runtimes today. If the primary deployment target became one that does not, `tzdata` belongs in
89
90
  the base dependencies unconditionally and this ADR's marker split is obsolete.
@@ -4,7 +4,7 @@ This guide covers installation, dependency management, and environment setup for
4
4
 
5
5
  ## Requirements
6
6
 
7
- - Python 3.9 or higher
7
+ - Python 3.10 or higher
8
8
  - AWS credentials configured for Secrets Manager access
9
9
  - Optional: AWS CLI for credential management
10
10
 
@@ -139,7 +139,7 @@ pip install nui-python-shared-utils[all]
139
139
 
140
140
  ```bash
141
141
  # Create environment
142
- conda create -n nui-utils python=3.9
142
+ conda create -n nui-utils python=3.10
143
143
 
144
144
  # Activate environment
145
145
  conda activate nui-utils
@@ -209,7 +209,7 @@ aws lambda publish-layer-version \
209
209
  --layer-name nui-python-shared-utils \
210
210
  --description "NUI Lambda Shared Utilities" \
211
211
  --zip-file fileb://nui-utils-layer.zip \
212
- --compatible-runtimes python3.9 python3.10 python3.11
212
+ --compatible-runtimes python3.10 python3.11
213
213
  ```
214
214
 
215
215
  ### Using in Lambda Function
@@ -168,6 +168,9 @@ def powertools_handler(
168
168
  service_name: str,
169
169
  metrics_namespace: Optional[str] = None,
170
170
  slack_alert_channel: Optional[str] = None,
171
+ slack_account_names: Optional[Dict[str, str]] = None,
172
+ slack_account_names_config: Optional[str] = None,
173
+ reraise_exceptions: bool = False,
171
174
  ):
172
175
  """
173
176
  Decorator for Lambda handlers with logging, metrics, and error handling.
@@ -176,6 +179,9 @@ def powertools_handler(
176
179
  service_name: Service identifier for logging and metrics dimensions
177
180
  metrics_namespace: CloudWatch namespace (e.g., "NUI/TenderAnalyser")
178
181
  slack_alert_channel: Slack channel for error alerts (e.g., "#alerts")
182
+ slack_account_names: AWS account ID to display-name mapping for alerts
183
+ slack_account_names_config: YAML file containing account-name defaults
184
+ reraise_exceptions: Re-raise after logging and alerting. Defaults to False.
179
185
  """
180
186
  ```
181
187
 
@@ -193,7 +199,46 @@ The decorator logs the exception and sends the Slack alert (if configured), then
193
199
  group waits until the batch succeeds or redrives, and the Slack alert fires on every
194
200
  receive. For per-record retries, enable `ReportBatchItemFailures` on the mapping and
195
201
  return `{"batchItemFailures": [...]}` from the handler; the decorator passes it through.
196
- - **Every other event**: returns `{"statusCode": 500, "body": "Internal Server Error"}`.
202
+ - **Every other event, by default**: returns
203
+ `{"statusCode": 500, "body": "Internal Server Error"}` to preserve existing behavior.
204
+ - **Every other event with `reraise_exceptions=True`**: re-raises after logging the
205
+ exception and sending the configured Slack alert. Use this for Kinesis and DynamoDB
206
+ Streams, where a raised exception prevents the checkpoint from advancing, and for
207
+ asynchronous sources such as SNS, S3, and EventBridge, where Lambda failure handling
208
+ depends on the invocation failing.
209
+
210
+ The option is handler-wide rather than an event-source list because the handler's trigger
211
+ configuration determines whether Lambda failure semantics are appropriate. SQS does not
212
+ require the option and continues to re-raise unconditionally.
213
+
214
+ For synchronous triggers such as API Gateway, enabling this option changes failures from
215
+ the decorator's 500 response into an unhandled Lambda invocation error. Enable it only when
216
+ that caller-visible behavior is intended.
217
+
218
+ ### Re-raise Failures for Stream and Async Sources
219
+
220
+ ```python
221
+ from nui_shared_utils import powertools_handler
222
+
223
+
224
+ @powertools_handler(
225
+ service_name="event-processor",
226
+ slack_alert_channel="#production-alerts",
227
+ reraise_exceptions=True,
228
+ )
229
+ def handler(event, context):
230
+ records = event.get("Records", [])
231
+ for record in records:
232
+ print(record)
233
+ return {"processed": len(records)}
234
+ ```
235
+
236
+ Logging and Slack alerting run before the original exception is re-raised. Configure the
237
+ trigger's retry, bisect, failure destination, or dead-letter behavior separately in AWS.
238
+ Every retry invokes the decorator again, so a configured Slack alert can be sent once per
239
+ attempt. For Kinesis and DynamoDB Streams, maximum retry attempts and maximum record age
240
+ bound retries. Bisect-on-error isolates a failing record by adding invocations, which do not
241
+ consume the retry quota and can produce additional alerts.
197
242
 
198
243
  ### Basic Usage (Logging Only)
199
244
 
@@ -103,6 +103,7 @@ client.get_connection_info() -> Dict
103
103
  ```
104
104
 
105
105
  **Connection Pool Entry Structure:**
106
+
106
107
  ```python
107
108
  {
108
109
  "connection": pymysql.Connection,
@@ -111,6 +112,7 @@ client.get_connection_info() -> Dict
111
112
  ```
112
113
 
113
114
  **Connection Info Response:**
115
+
114
116
  ```python
115
117
  {
116
118
  "host": str,
@@ -169,6 +171,7 @@ client.get_indices_info(pattern="*") -> List[Dict]
169
171
  ```
170
172
 
171
173
  **Service Stats Response:**
174
+
172
175
  ```python
173
176
  {
174
177
  "service": str,
@@ -183,6 +186,7 @@ client.get_indices_info(pattern="*") -> List[Dict]
183
186
  ```
184
187
 
185
188
  **Cluster Info Response:**
189
+
186
190
  ```python
187
191
  {
188
192
  "version": str,
@@ -222,6 +226,7 @@ client.get_bot_info() -> Dict
222
226
  ```
223
227
 
224
228
  **Lambda Context Structure:**
229
+
225
230
  ```python
226
231
  {
227
232
  "function_name": str,
@@ -240,6 +245,7 @@ client.get_bot_info() -> Dict
240
245
  ```
241
246
 
242
247
  **Bot Info Response:**
248
+
243
249
  ```python
244
250
  {
245
251
  "bot_id": str,
@@ -274,6 +280,7 @@ result = matcher.categorize_error(exception)
274
280
  ```
275
281
 
276
282
  **Categorized Error Response:**
283
+
277
284
  ```python
278
285
  {
279
286
  "error": str,
@@ -286,6 +293,7 @@ result = matcher.categorize_error(exception)
286
293
  ```
287
294
 
288
295
  **Built-in Error Categories:**
296
+
289
297
  - `data_format` - JSON parsing errors
290
298
  - `authentication` - Auth failures
291
299
  - `database` - DB timeouts
@@ -310,6 +318,7 @@ summary = aggregator.get_summary()
310
318
  ```
311
319
 
312
320
  **Error Summary Response:**
321
+
313
322
  ```python
314
323
  {
315
324
  "total_errors": int,
@@ -360,6 +369,7 @@ publisher.flush() -> bool
360
369
  ```
361
370
 
362
371
  **Metric Data Structure (internal buffer):**
372
+
363
373
  ```python
364
374
  {
365
375
  "MetricName": str,
@@ -429,6 +439,7 @@ with TimedMetric(publisher, "DatabaseQuery", unit="Milliseconds", dimensions=Non
429
439
  ### Credential Structures
430
440
 
431
441
  **Database Credentials:**
442
+
432
443
  ```python
433
444
  {
434
445
  "host": str,
@@ -440,6 +451,7 @@ with TimedMetric(publisher, "DatabaseQuery", unit="Milliseconds", dimensions=Non
440
451
  ```
441
452
 
442
453
  **Elasticsearch Credentials:**
454
+
443
455
  ```python
444
456
  {
445
457
  "host": str, # With port (e.g., "elastic:9200")
@@ -449,6 +461,7 @@ with TimedMetric(publisher, "DatabaseQuery", unit="Milliseconds", dimensions=Non
449
461
  ```
450
462
 
451
463
  **Slack Credentials:**
464
+
452
465
  ```python
453
466
  {
454
467
  "bot_token": str,
@@ -492,6 +505,7 @@ stats = get_pool_stats()
492
505
  ```
493
506
 
494
507
  **Pool Stats Response:**
508
+
495
509
  ```python
496
510
  {
497
511
  "total_pools": int,
@@ -514,6 +528,7 @@ response = handle_lambda_error(error, context)
514
528
  ```
515
529
 
516
530
  **Lambda Error Response:**
531
+
517
532
  ```python
518
533
  {
519
534
  "statusCode": 500,
@@ -1,5 +1,5 @@
1
1
  [mypy]
2
- python_version = 3.9
2
+ python_version = 3.10
3
3
  warn_return_any = False
4
4
  warn_unused_configs = True
5
5
  ignore_missing_imports = True