psycache 26.1.0__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 (46) hide show
  1. psycache-26.1.0/.github/AI_POLICY.md +71 -0
  2. psycache-26.1.0/.github/CODE_OF_CONDUCT.md +16 -0
  3. psycache-26.1.0/.github/CONTRIBUTING.md +241 -0
  4. psycache-26.1.0/.github/FUNDING.yml +5 -0
  5. psycache-26.1.0/.github/PULL_REQUEST_TEMPLATE.md +34 -0
  6. psycache-26.1.0/.github/dependabot.yml +14 -0
  7. psycache-26.1.0/.github/workflows/ci.yml +226 -0
  8. psycache-26.1.0/.github/workflows/codeql-analysis.yml +42 -0
  9. psycache-26.1.0/.github/workflows/pypi-package.yml +82 -0
  10. psycache-26.1.0/.github/workflows/zizmor.yml +33 -0
  11. psycache-26.1.0/.gitignore +12 -0
  12. psycache-26.1.0/.pre-commit-config.yaml +35 -0
  13. psycache-26.1.0/.python-version +1 -0
  14. psycache-26.1.0/CHANGELOG.md +16 -0
  15. psycache-26.1.0/LICENSE +19 -0
  16. psycache-26.1.0/PKG-INFO +381 -0
  17. psycache-26.1.0/README.md +343 -0
  18. psycache-26.1.0/conftest.py +137 -0
  19. psycache-26.1.0/pyproject.toml +195 -0
  20. psycache-26.1.0/src/psycache/__init__.py +18 -0
  21. psycache-26.1.0/src/psycache/__main__.py +57 -0
  22. psycache-26.1.0/src/psycache/_async.py +203 -0
  23. psycache-26.1.0/src/psycache/_durations.py +55 -0
  24. psycache-26.1.0/src/psycache/_sql.py +33 -0
  25. psycache-26.1.0/src/psycache/_sync.py +198 -0
  26. psycache-26.1.0/src/psycache/_tables.py +24 -0
  27. psycache-26.1.0/src/psycache/instrumentation/__init__.py +12 -0
  28. psycache-26.1.0/src/psycache/instrumentation/_spans.py +173 -0
  29. psycache-26.1.0/src/psycache/instrumentation/prometheus.py +156 -0
  30. psycache-26.1.0/src/psycache/instrumentation/sentry.py +142 -0
  31. psycache-26.1.0/src/psycache/psycopg_pool.py +56 -0
  32. psycache-26.1.0/src/psycache/py.typed +0 -0
  33. psycache-26.1.0/src/psycache/sqlalchemy.py +51 -0
  34. psycache-26.1.0/src/psycache/typing.py +154 -0
  35. psycache-26.1.0/tests/__init__.py +3 -0
  36. psycache-26.1.0/tests/test_cli.py +45 -0
  37. psycache-26.1.0/tests/test_maintenance.py +379 -0
  38. psycache-26.1.0/tests/test_psycopg_pool.py +166 -0
  39. psycache-26.1.0/tests/test_raw.py +63 -0
  40. psycache-26.1.0/tests/test_raw_async.py +103 -0
  41. psycache-26.1.0/tests/test_sqlalchemy.py +85 -0
  42. psycache-26.1.0/tests/typing/README.md +4 -0
  43. psycache-26.1.0/tests/typing/core.py +37 -0
  44. psycache-26.1.0/tests/typing/psycopg_pool.py +20 -0
  45. psycache-26.1.0/tests/typing/sqlalchemy.py +21 -0
  46. psycache-26.1.0/tox.ini +86 -0
@@ -0,0 +1,71 @@
1
+ # Generative AI / LLM Policy
2
+
3
+ We appreciate that we can't realistically police how you author your pull requests, which includes whether you employ large-language model (LLM)-based development tools.
4
+ So, we don't.
5
+
6
+ However, due to both legal and human reasons, we have to establish boundaries.
7
+
8
+ > [!CAUTION]
9
+ > **TL;DR:**
10
+ > - We take the responsibility for this project very seriously and we expect you to take your responsibility for your contributions seriously, too.
11
+ > This used to be a given, but it changed now that a pull request is just one prompt away.
12
+ >
13
+ > - Every contribution has to be backed by a human who unequivocally owns the copyright for all changes.
14
+ > No LLM bots in `Co-authored-by:`s.
15
+ >
16
+ > - DoS-by-slop leads to a permanent ban.
17
+ >
18
+ > - Absolutely **no** unsupervised agentic tools like OpenClaw.
19
+ >
20
+ > ---
21
+ >
22
+ > By submitting a pull request, you certify that:
23
+ >
24
+ > - You are the author of the contribution or have the legal right to submit it.
25
+ > - You either hold the copyright to the changes or have explicit legal authorization to contribute them under this project's license.
26
+ > - You understand the code.
27
+ > - You accept full responsibility for it.
28
+
29
+
30
+ ## Legal
31
+
32
+ There is ongoing legal uncertainty regarding the copyright status of LLM-generated works and their provenance.
33
+ Since we do not have a formal [Contributor License Agreement](https://en.wikipedia.org/wiki/Contributor_license_agreement) (CLA), you retain your copyright to your changes to this project.
34
+
35
+ Therefore, allowing contributions by LLMs has unpredictable consequences for the copyright status of this project – even when leaving aside possible copyright violations due to plagiarism.
36
+
37
+
38
+ ## Human
39
+
40
+ As the makers of software that is used by millions of people worldwide and with a reputation for high-quality maintenance, we take our responsibility to our users very seriously.
41
+ No matter what LLM vendors or boosters on LinkedIn tell you, we have to manually review every change before merging, because it's **our responsibility** to keep the project stable.
42
+
43
+ Please understand that by opening low-quality pull requests you're not helping anyone.
44
+ Worse, you're [poisoning the open source ecosystem](https://lwn.net/Articles/1058266/) that was precarious even before the arrival of LLM tools.
45
+ Having to wade through plausible-looking-but-low-quality pull requests and trying to determine which ones are legit is extremely demoralizing and has already burned out many good maintainers.
46
+
47
+ Put bluntly, we have no time or interest to become part of your vibe coding loop where you drop LLM slop at our door, we spend time and energy to review it, and you just feed it back into the LLM for another iteration.
48
+
49
+ This dynamic is especially pernicious because it poisons the well for mentoring new contributors which we are committed to.
50
+
51
+
52
+ ## Summary
53
+
54
+ In practice, this means:
55
+
56
+ - Pull requests that have an LLM product listed as co-author can't be merged and will be closed without further discussion.
57
+ We cannot risk the copyright status of this project.
58
+
59
+ If you used LLM tools during development, you may still submit – but you must remove any LLM co-author tags and take full ownership of every line.
60
+
61
+ - By submitting a pull request, **you** take full **technical and legal** responsibility for the contents of the pull request and promise that **you** hold the copyright for the changes submitted.
62
+
63
+ "An LLM wrote it" is **not** an acceptable response to questions or critique.
64
+ **If you cannot explain and defend the changes you submit, do not submit them** and open a high-quality bug report/feature request instead.
65
+
66
+ - Accounts that exercise bot-like behavior – like automated mass pull requests – will be permanently banned, whether they belong to a human or not.
67
+
68
+ - Do **not** post LLM-generated review comments – we can prompt LLMs ourselves should we desire their wisdom.
69
+ Do **not** post summaries unless you've fact-checked them and take responsibility for 100% of their content.
70
+ Remember that *all* LLM output *looks* **plausible**.
71
+ When using these tools, it's **your** responsibility to ensure that it's also **correct** and has a reasonable signal-to-noise ratio.
@@ -0,0 +1,16 @@
1
+ # Code of Conduct
2
+
3
+ While not being a [Python Software Foundation](https://www.python.org/psf-landing/) project, everyone interacting in this project is expected to follow the [PSF Code of Conduct](https://policies.python.org/python.org/code-of-conduct/).
4
+
5
+ In general, this means that everyone is expected to be **open**, **considerate**, and **respectful** of others no matter what their position is within the project.
6
+
7
+
8
+ ## Enforcement
9
+
10
+ We take Code of Conduct violations seriously, and will act to ensure our spaces are welcoming, inclusive, and professional environments to communicate in.
11
+
12
+ If you need to raise a Code of Conduct report, you may do so privately by email to [Hynek Schlawack](mailto:hs@ox.cx).
13
+
14
+ Reports will be treated confidentially.
15
+
16
+ Alternately you can make a [report to the Python Software Foundation](https://policies.python.org/python.org/code-of-conduct/Procedures-for-Reporting-Incidents/).
@@ -0,0 +1,241 @@
1
+ # How To Contribute
2
+
3
+ > [!IMPORTANT]
4
+ > - This document is mainly to help you to get started by codifying tribal knowledge and expectations and make it more accessible to everyone.
5
+ > But don't be afraid to open half-finished PRs and ask questions if something is unclear!
6
+ >
7
+ > - If you use LLM / "AI" tools for your contributions, please read and follow our [_Generative AI / LLM Policy_][llm].
8
+
9
+
10
+ ## Workflow
11
+
12
+ > [!WARNING]
13
+ > Before starting to work on **feature** pull requests, **please** discuss your idea with us on the [Ideas board](https://github.com/hynek/psycache/discussions/categories/ideas) to save you time and effort!
14
+
15
+ First off, thank you for considering to contribute!
16
+ It's people like *you* who make this project such a great tool for everyone.
17
+
18
+ - No contribution is too small!
19
+ Please submit as many fixes for typos and grammar bloopers as you can!
20
+
21
+ - **Only contribute code that you fully understand.**
22
+ See also our [AI policy][llm].
23
+
24
+ - Very relatedly, our pull request check list is our mandatory [Van Halen test](https://en.wikipedia.org/wiki/Van_Halen_test).
25
+ Sadly, the current state of the world has forced us into being stricter about policies -- sorry fellow humans!
26
+
27
+ - Try to limit each pull request to *one* change only.
28
+
29
+ - Since we squash on merge, it's up to you how you handle updates to the `main` branch.
30
+ Whether you prefer to rebase on `main` or merge `main` into your branch, do whatever is more comfortable for you.
31
+
32
+ - *Always* add tests and docs for your code.
33
+ This is a hard rule; patches with missing tests or documentation won't be merged.
34
+
35
+ - Consider updating [`CHANGELOG.md`](../CHANGELOG.md) to reflect the changes as observed by people using this library.
36
+
37
+ - Make sure your changes pass our [CI](https://github.com/hynek/psycache/actions).
38
+ You won't get any feedback until it's green unless you ask for it.
39
+ For the CI to pass, the coverage must be 100%.
40
+ If you have problems to test something, open anyway and ask for advice.
41
+ In some situations, we may agree to add an `# pragma: no cover`.
42
+
43
+ - Once you've addressed review feedback, make sure to bump the pull request with a short note, so we know you're done.
44
+
45
+ - Don't break [backwards-compatibility](SECURITY.md).
46
+
47
+
48
+ ## Local development environment
49
+
50
+ ### Postgres
51
+
52
+ The test suite requires a running Postgres database that is accessible via the `postgresql://postgres@127.0.0.1/postgres` DSN (no password).
53
+ It will use it only to create a database `psycache` with a no-password user `psycache` that is used for the actual tests.
54
+
55
+
56
+ ### Python
57
+
58
+ First, **fork** the repository on GitHub.
59
+ Make sure to **uncheck** the `Copy the main branch only` radio button on the `Create a new fork` page.
60
+ If you don't, our test suite will fail because we use Git tags for packaging.
61
+
62
+ Finally, **clone** it using one of the alternatives that you can copy-paste by pressing the big green button labeled `<> Code`.
63
+
64
+ You can (and should) run our test suite using [*tox*](https://tox.wiki/).
65
+ However, you'll probably want a more traditional environment as well.
66
+
67
+ We recommend using the Python version from the `.python-version` file in the project's root directory, because that's the one that is used in the CI by default, too.
68
+
69
+ If you're using [*direnv*](https://direnv.net), you can automate the creation of the project virtual environment with the correct Python version by adding the following `.envrc` to the project root:
70
+
71
+ ```bash
72
+ layout python python$(cat .python-version)
73
+ ```
74
+
75
+ or, if you like [*uv*](https://github.com/astral-sh/uv):
76
+
77
+ ```bash
78
+ test -d .venv || (uv venv && uv pip install -e . --group dev)
79
+ . .venv/bin/activate
80
+ ```
81
+
82
+ > [!WARNING]
83
+ > - **Before** you start working on a new pull request, use the "*Sync fork*" button in GitHub's web UI to ensure your fork is up to date.
84
+ > - **Always create a new branch off `main` for each new pull request.**
85
+ > Yes, you can work on `main` in your fork and submit pull requests.
86
+ > But this will *inevitably* lead to you not being able to synchronize your fork with upstream and having to start over.
87
+
88
+ Change into the newly created directory and after activating a virtual environment, install an editable version of this project along with its tests requirements:
89
+
90
+ ```console
91
+ $ pip install -e . --group dev # or `uv pip install -e . --group dev`
92
+ ```
93
+
94
+ Now you can run the test suite:
95
+
96
+ ```console
97
+ $ python -Im pytest
98
+ ```
99
+
100
+ To run doctests:
101
+
102
+ ```console
103
+ $ tox run -e docs-doctests
104
+ ```
105
+
106
+
107
+ ## Code
108
+
109
+ - Obey [PEP 8](https://peps.python.org/pep-0008/) and [PEP 257](https://peps.python.org/pep-0257/).
110
+ We use the `"""`-on-separate-lines style for docstrings with [Napoleon](https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html)-style API documentation:
111
+
112
+ ```python
113
+ def func(x: str, y: int) -> str:
114
+ """
115
+ Do something.
116
+
117
+ Args:
118
+ x: A very important argument.
119
+
120
+ y:
121
+ Another very important argument, but its description is so long
122
+ that it doesn't fit on one line. So, we start the whole block on a
123
+ fresh new line to keep the block together.
124
+
125
+ Returns:
126
+ The result of doing something.
127
+ """
128
+ ```
129
+
130
+ Please note that unlike everything else, the API docstrings are still reStructuredText.
131
+
132
+ - If you add or change public APIs, tag the docstring using `.. versionadded:: 26.1.0 WHAT` or `.. versionchanged:: 26.1.0 WHAT`.
133
+ We follow [Calendar Versioning](https://calver.org/), so the next version will be the current with with the middle number incremented (for example, `26.1.0` -> `26.2.0`).
134
+
135
+ - We use [Ruff](https://ruff.rs/) to sort our imports and format our code with a line length of 79 characters.
136
+ As long as you run our full *tox* suite before committing, or install our [*pre-commit*](https://pre-commit.com/) hooks (ideally you'll do both -- see [*Local Development Environment*](#local-development-environment) above), you won't have to spend any time on formatting your code at all.
137
+ If you don't, CI will catch it for you -- but that seems like a waste of your time!
138
+
139
+
140
+ ## Tests
141
+
142
+ - Write your asserts as `expected == actual` to line them up nicely, and leave an empty line before them:
143
+
144
+ ```python
145
+ x = f()
146
+
147
+ assert 42 == x.some_attribute
148
+ assert "foo" == x._a_private_attribute
149
+ ```
150
+
151
+ - You can run the test suite runs with all (optional) dependencies against all supported Python versions just as it will in our CI by running `tox`.
152
+
153
+ - Write [good test docstrings](https://jml.io/test-docstrings/).
154
+
155
+
156
+ ## Documentation
157
+
158
+ - Use [semantic newlines] in [reStructuredText](https://www.sphinx-doc.org/en/stable/usage/restructuredtext/basics.html) (`*.rst`) and [Markdown](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax) (`*.md`) files:
159
+
160
+ ```markdown
161
+ This is a sentence.
162
+ This is another sentence.
163
+
164
+ This is a new paragraph.
165
+ ```
166
+
167
+ - If you start a new section, add two blank lines before and one blank line after the header except if two headers follow immediately after each other:
168
+
169
+ ```markdown
170
+ # Main Header
171
+
172
+ Last line of previous section.
173
+
174
+
175
+ ## Header of New Top Section
176
+
177
+ ### Header of New Section
178
+
179
+ First line of new section.
180
+ ```
181
+
182
+
183
+ ### Changelog
184
+
185
+ If your change is interesting to end-users, there needs to be an entry in our `CHANGELOG.md`, so they can learn about it.
186
+
187
+ - The changelog follows the [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) standard.
188
+ Add the best-fitting section if it's missing for the current release.
189
+ We use the following order: `Security`, `Removed`, `Deprecated`, `Added`, `Changed`, `Fixed`.
190
+
191
+ - As with other docs, please use [semantic newlines] in the changelog.
192
+
193
+ - Make the last line a link to your pull request.
194
+ You probably have to open it first to know the number.
195
+
196
+ - Leave an empty line between entries, so it doesn't look like a wall of text.
197
+
198
+ - Refer to all symbols by their fully-qualified names.
199
+ For example, `psycache.Foo` -- not just `Foo`.
200
+
201
+ - Wrap symbols like modules, functions, or classes into backticks, so they are rendered in a `monospace font`.
202
+
203
+ - Wrap arguments into asterisks so they are *italicized* like in API documentation:
204
+ `Added new argument *an_argument*.`
205
+
206
+ - If you mention functions or methods, add parentheses at the end of their names:
207
+ `psycache.func()` or `psycache.Class.method()`.
208
+ This makes the changelog a lot more readable.
209
+
210
+ - Prefer simple past tense or constructions with "now".
211
+ In the `Added` section, you can leave out the "Added" prefix:
212
+
213
+ ```markdown
214
+ ### Added
215
+
216
+ - `psycache.func()` that does foo.
217
+ It's pretty cool.
218
+ [#1](https://github.com/hynek/psycache/pull/1)
219
+
220
+
221
+ ### Fixed
222
+
223
+ - `psycache.func()` now doesn't crash the Large Hadron Collider anymore.
224
+ That was a nasty bug!
225
+ [#2](https://github.com/hynek/psycache/pull/2)
226
+ ```
227
+
228
+
229
+ ## See you on GitHub!
230
+
231
+ Again, this whole file is mainly to help you to get started by codifying tribal knowledge and expectations to save you time and turnarounds.
232
+ It is **not** meant to be a barrier to entry, so don't be afraid to open half-finished PRs and ask questions if something is unclear!
233
+
234
+ Please note that this project is released with a Contributor [Code of Conduct](CODE_OF_CONDUCT.md).
235
+ By participating in this project you agree to abide by its terms.
236
+ Please report any harm to [Hynek Schlawack](https://hynek.me/about/) in any way you find appropriate.
237
+
238
+
239
+ [semantic newlines]: https://rhodesmill.org/brandon/2012/one-sentence-per-line/
240
+ [llm]: AI_POLICY.md
241
+ [install *uv*]: https://docs.astral.sh/uv/getting-started/installation/
@@ -0,0 +1,5 @@
1
+ ---
2
+ github: hynek
3
+ tidelift: pypi/psycache
4
+ thanks_dev: u/gh/hynek
5
+ custom: https://hynek.me/say-thanks/
@@ -0,0 +1,34 @@
1
+ # Summary
2
+
3
+ <!-- Please tell us what your pull request is about here. -->
4
+
5
+
6
+ # Pull Request Check List
7
+
8
+ <!--
9
+ This list is our brown M&M test:
10
+ Ignoring -- or even deleting -- leads to instant closing of this pull request.
11
+ The only exceptions are pure documentation fixes.
12
+
13
+ Please read our [contribution guide](https://github.com/hynek/psycache/blob/main/.github/CONTRIBUTING.md) at least once; it will save you unnecessary review cycles!
14
+
15
+ You may check boxes that don't apply to your pull request to indicate that there isn't anything left to do.
16
+ -->
17
+
18
+ - [ ] I acknowledge this project's [**AI policy**](https://github.com/hynek/psycache/blob/main/.github/AI_POLICY.md).
19
+ - [ ] Typos aside (please, always submit typo fixes!), I understand that this pull request may be **closed** in case there was **no [previous discussion](https://github.com/hynek/psycache/discussions/categories/ideas)**.
20
+ - [ ] This pull request is [**not** from my `main` branch](https://hynek.me/articles/pull-requests-branch/).
21
+ - Consider granting [push permissions to the PR branch](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork), so maintainers can fix minor issues themselves without pestering you.
22
+ - [ ] There's **tests** for all new and changed code.
23
+ - [ ] **New APIs** are added to our typing tests at <https://github.com/hynek/psycache/blob/main/tests/typing/>.
24
+ - [ ] Updated **documentation** for changed code.
25
+ - [ ] New functions/classes have to be added to `docs/core-concepts.md` or one of the integration guides by hand.
26
+ - [ ] Changed/added classes/methods/functions have appropriate `versionadded`, `versionchanged`, or `deprecated` [directives](http://www.sphinx-doc.org/en/stable/markup/para.html#directive-versionadded).
27
+ - The next version is the second number in the current release + 1. The first number represents the current year. So if the current version on PyPI is 26.1.0, the next version is gonna be 26.2.0. If the next version is the first in the new year, it'll be 27.1.0.
28
+ - [ ] Documentation in `.md` files is written using [**semantic newlines**](https://rhodesmill.org/brandon/2012/one-sentence-per-line/).
29
+ - [ ] Changes (and possible deprecations) are documented in the [**changelog**](https://github.com/hynek/psycache/blob/main/CHANGELOG.md).
30
+
31
+ <!--
32
+ If you have *any* questions to *any* of the points above, just **submit and ask**!
33
+ Given the ongoing AI slop wave we need to be strict about policies, but we're happy to help out fellow humans.
34
+ -->
@@ -0,0 +1,14 @@
1
+ ---
2
+ version: 2
3
+ updates:
4
+ - package-ecosystem: github-actions
5
+ directory: /
6
+ schedule:
7
+ interval: monthly
8
+ cooldown:
9
+ # https://blog.yossarian.net/2025/11/21/We-should-all-be-using-dependency-cooldowns
10
+ default-days: 7
11
+ groups:
12
+ github-actions:
13
+ patterns:
14
+ - "*"
@@ -0,0 +1,226 @@
1
+ ---
2
+ name: CI
3
+
4
+ on:
5
+ push:
6
+ branches: [main]
7
+ pull_request:
8
+ workflow_dispatch:
9
+
10
+ env:
11
+ FORCE_COLOR: "1" # Make tools pretty.
12
+ PIP_DISABLE_PIP_VERSION_CHECK: "1"
13
+ PIP_NO_PYTHON_VERSION_WARNING: "1"
14
+
15
+ concurrency:
16
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
17
+ cancel-in-progress: true
18
+
19
+ permissions: {}
20
+
21
+ jobs:
22
+ build-package:
23
+ name: Build & verify package
24
+ runs-on: ubuntu-latest
25
+
26
+ steps:
27
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
28
+ with:
29
+ fetch-depth: 0
30
+ persist-credentials: false
31
+
32
+ - uses: hynek/build-and-inspect-python-package@d44ca7d91762de7a7d5436ddae667c6da6d1c3df # v2.18.0
33
+ id: baipp
34
+
35
+ outputs:
36
+ # Used to define the matrix for tests below. The value is based on
37
+ # packaging metadata (trove classifiers).
38
+ python-versions: ${{ steps.baipp.outputs.supported_python_classifiers_json_array }}
39
+
40
+ tests:
41
+ name: Tests on ${{ matrix.python-version }}
42
+ runs-on: ubuntu-24.04 # the version affects postgres paths!
43
+ needs: build-package
44
+
45
+ strategy:
46
+ fail-fast: false
47
+ matrix:
48
+ # Created by the build-and-inspect-python-package action above.
49
+ python-version: ${{ fromJson(needs.build-package.outputs.python-versions) }}
50
+
51
+ env:
52
+ PYTHON: ${{ matrix.python-version }}
53
+
54
+ steps:
55
+ - name: Download pre-built packages
56
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
57
+ with:
58
+ name: Packages
59
+ path: dist
60
+ - run: |
61
+ tar xf dist/*.tar.gz --strip-components=1
62
+ rm -rf src
63
+ - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
64
+ with:
65
+ python-version: ${{ matrix.python-version }}
66
+ allow-prereleases: true
67
+ - uses: hynek/setup-cached-uv@4300ec2180bc77d705e626a34e381b81a4772c51 # v2.5.0
68
+
69
+ - name: Start PostgreSQL
70
+ run: |
71
+ printf '%s\n' \
72
+ 'local all all trust' \
73
+ 'host all all 127.0.0.1/32 trust' \
74
+ 'host all all ::1/128 trust' \
75
+ | sudo tee /etc/postgresql/16/main/pg_hba.conf >/dev/null
76
+
77
+ sudo systemctl start postgresql.service
78
+
79
+ until sudo -u postgres pg_isready -q; do sleep 1; done
80
+
81
+ - name: Run tests
82
+ run: >
83
+ uvx --with tox-uv tox run
84
+ --installpkg dist/*.whl
85
+ -f ${PYTHON}-tests
86
+
87
+ - name: Upload coverage data
88
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
89
+ with:
90
+ name: coverage-data-${{ matrix.python-version }}
91
+ path: .coverage.*
92
+ include-hidden-files: true
93
+ if-no-files-found: ignore
94
+
95
+ coverage:
96
+ name: Ensure 100% test coverage
97
+ runs-on: ubuntu-latest
98
+ needs: tests
99
+ if: always()
100
+
101
+ steps:
102
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
103
+ with:
104
+ persist-credentials: false
105
+ - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
106
+ with:
107
+ python-version-file: .python-version
108
+ - uses: hynek/setup-cached-uv@4300ec2180bc77d705e626a34e381b81a4772c51 # v2.5.0
109
+
110
+ - name: Download coverage data
111
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
112
+ with:
113
+ pattern: coverage-data-*
114
+ merge-multiple: true
115
+
116
+ - name: Combine coverage and fail if it's <100%.
117
+ run: |
118
+ uv tool install coverage
119
+
120
+ coverage combine
121
+ coverage html --skip-covered --skip-empty
122
+
123
+ # Report and write to summary.
124
+ coverage report --format=markdown >> $GITHUB_STEP_SUMMARY
125
+
126
+ # Report again and fail if under 100%.
127
+ coverage report --fail-under=100
128
+
129
+ - name: Upload HTML report if check failed.
130
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
131
+ with:
132
+ name: html-report
133
+ path: htmlcov
134
+ if: ${{ failure() }}
135
+
136
+ typing:
137
+ name: Check types using supported type checkers
138
+ runs-on: ubuntu-latest
139
+ needs: build-package
140
+
141
+ steps:
142
+ - name: Download pre-built packages
143
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
144
+ with:
145
+ name: Packages
146
+ path: dist
147
+ - run: tar xf dist/*.tar.gz --strip-components=1
148
+ - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
149
+ with:
150
+ python-version-file: .python-version
151
+ - uses: hynek/setup-cached-uv@4300ec2180bc77d705e626a34e381b81a4772c51 # v2.5.0
152
+
153
+ - run: >
154
+ uvx --with tox-uv
155
+ tox run -f typing
156
+
157
+ docs:
158
+ name: Run doctests
159
+ needs: build-package
160
+ runs-on: ubuntu-latest
161
+ steps:
162
+ - name: Download pre-built packages
163
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
164
+ with:
165
+ name: Packages
166
+ path: dist
167
+ - run: tar xf dist/*.tar.gz --strip-components=1
168
+ - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
169
+ with:
170
+ # Keep in sync with tox.ini's base_python_file.
171
+ python-version-file: .python-version
172
+ - uses: hynek/setup-cached-uv@4300ec2180bc77d705e626a34e381b81a4772c51 # v2.5.0
173
+
174
+ - name: Start PostgreSQL
175
+ # The README examples connect to a real database, so the doctests need
176
+ # a running PostgreSQL with password-less local access.
177
+ run: |
178
+ printf '%s\n' \
179
+ 'local all all trust' \
180
+ 'host all all 127.0.0.1/32 trust' \
181
+ 'host all all ::1/128 trust' \
182
+ | sudo tee /etc/postgresql/16/main/pg_hba.conf >/dev/null
183
+
184
+ sudo systemctl start postgresql.service
185
+
186
+ until sudo -u postgres pg_isready -q; do sleep 1; done
187
+
188
+ - run: >
189
+ uvx --with tox-uv
190
+ tox run -e docs-doctests
191
+
192
+ install-dev:
193
+ name: Verify dev env
194
+ runs-on: ubuntu-latest
195
+
196
+ steps:
197
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
198
+ with:
199
+ persist-credentials: false
200
+ - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
201
+ with:
202
+ python-version-file: .python-version
203
+ - uses: hynek/setup-cached-uv@4300ec2180bc77d705e626a34e381b81a4772c51 # v2.5.0
204
+
205
+ - run: uv venv
206
+ - run: uv pip install -e . --group dev
207
+
208
+ - run: .venv/bin/python -Ic 'from importlib.metadata import version; print(version("psycache"))'
209
+
210
+ required-checks-pass:
211
+ name: Ensure everything required is passing for branch protection
212
+ if: always()
213
+
214
+ needs:
215
+ - coverage
216
+ - install-dev
217
+ - typing
218
+ - docs
219
+
220
+ runs-on: ubuntu-latest
221
+
222
+ steps:
223
+ - name: Decide whether the needed jobs succeeded or failed
224
+ uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2
225
+ with:
226
+ jobs: ${{ toJSON(needs) }}
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: CodeQL
3
+
4
+ on:
5
+ schedule:
6
+ - cron: "41 3 * * 6"
7
+ workflow_dispatch:
8
+
9
+ concurrency:
10
+ group: ${{ github.workflow }}
11
+ cancel-in-progress: true
12
+
13
+ permissions: {}
14
+
15
+ jobs:
16
+ analyze:
17
+ name: Analyze
18
+ runs-on: ubuntu-latest
19
+ permissions:
20
+ security-events: write # necessary according to docs
21
+
22
+ strategy:
23
+ fail-fast: false
24
+ matrix:
25
+ language: [python]
26
+
27
+ steps:
28
+ - name: Checkout repository
29
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
30
+ with:
31
+ persist-credentials: false
32
+
33
+ - name: Initialize CodeQL
34
+ uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
35
+ with:
36
+ languages: ${{ matrix.language }}
37
+
38
+ - name: Autobuild
39
+ uses: github/codeql-action/autobuild@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
40
+
41
+ - name: Perform CodeQL Analysis
42
+ uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2