mirror of
https://github.com/jbranchaud/til
synced 2026-09-02 17:51:47 +00:00
Compare commits
2
Commits
300a22f18b
...
1a0b02168e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a0b02168e | ||
|
|
146274230e |
@@ -10,7 +10,7 @@ working across different projects via [VisualMode](https://www.visualmode.dev/).
|
|||||||
|
|
||||||
For a steady stream of TILs, [sign up for my newsletter](https://visualmode.kit.com/newsletter).
|
For a steady stream of TILs, [sign up for my newsletter](https://visualmode.kit.com/newsletter).
|
||||||
|
|
||||||
_1844 TILs and counting..._
|
_1846 TILs and counting..._
|
||||||
|
|
||||||
See some of the other learning resources I work on:
|
See some of the other learning resources I work on:
|
||||||
|
|
||||||
@@ -486,6 +486,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
- [Capture An Output Value For Use In A Later Step](github-actions/capture-an-output-value-for-use-in-a-later-step.md)
|
- [Capture An Output Value For Use In A Later Step](github-actions/capture-an-output-value-for-use-in-a-later-step.md)
|
||||||
- [Disable A Workflow With The gh CLI](github-actions/disable-a-workflow-with-the-gh-cli.md)
|
- [Disable A Workflow With The gh CLI](github-actions/disable-a-workflow-with-the-gh-cli.md)
|
||||||
- [Reference An Encrypted Secret In An Action](github-actions/reference-an-encrypted-secret-in-an-action.md)
|
- [Reference An Encrypted Secret In An Action](github-actions/reference-an-encrypted-secret-in-an-action.md)
|
||||||
|
- [Run Schedule Action To Commit Regular Updates](github-actions/run-scheduled-action-to-commit-regular-updates.md)
|
||||||
- [Trigger A Workflow Via An API Call](github-actions/trigger-a-workflow-via-an-api-call.md)
|
- [Trigger A Workflow Via An API Call](github-actions/trigger-a-workflow-via-an-api-call.md)
|
||||||
- [Use Labels To Block PR Merge](github-actions/use-labels-to-block-pr-merge.md)
|
- [Use Labels To Block PR Merge](github-actions/use-labels-to-block-pr-merge.md)
|
||||||
|
|
||||||
@@ -1072,6 +1073,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
- [Access Most Recent Return Value In REPL](python/access-most-recent-return-value-in-repl.md)
|
- [Access Most Recent Return Value In REPL](python/access-most-recent-return-value-in-repl.md)
|
||||||
- [Access SQLite Result Values By Name With Row Factory](python/access-sqlite-result-values-by-name-with-row-factory.md)
|
- [Access SQLite Result Values By Name With Row Factory](python/access-sqlite-result-values-by-name-with-row-factory.md)
|
||||||
- [Access Variables Outside Loop Scope](python/access-variables-outside-loop-scope.md)
|
- [Access Variables Outside Loop Scope](python/access-variables-outside-loop-scope.md)
|
||||||
|
- [Another Way To Mark Keyword-Only Dataclass Fields](python/another-way-to-mark-keyword-only-dataclass-fields.md)
|
||||||
- [Argument Defaults Are Evaluated When Function Is Defined](python/argument-defaults-are-evaluated-when-function-is-defined.md)
|
- [Argument Defaults Are Evaluated When Function Is Defined](python/argument-defaults-are-evaluated-when-function-is-defined.md)
|
||||||
- [Assert Is Only A Development Check](python/assert-is-only-a-development-check.md)
|
- [Assert Is Only A Development Check](python/assert-is-only-a-development-check.md)
|
||||||
- [Avoid Modification With Frozen Dataclass](python/avoid-modification-with-frozen-dataclass.md)
|
- [Avoid Modification With Frozen Dataclass](python/avoid-modification-with-frozen-dataclass.md)
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
# Run Scheduled Action To Commit Regular Updates
|
||||||
|
|
||||||
|
The quintessential example of what GitHub Actions are used for is running CI
|
||||||
|
tasks like the test suite, type checker, linter, etc. Each CI step runs to
|
||||||
|
completion and either passes or fails and you see the results in the GitHub PR
|
||||||
|
interface. That's a great use case, but far from the only one. GitHub Actions
|
||||||
|
are a much more general-purpose execution environment that can be used for much
|
||||||
|
more.
|
||||||
|
|
||||||
|
Here is a recent example that expanded my mind a bit on what is possible with
|
||||||
|
GitHub actions. Imagine a GitHub Action that is scheduled to run once a day, it
|
||||||
|
executes a script that might make changes to the repo itself (e.g. the
|
||||||
|
`README.md`), and then commits those changes (self-updating the repo).
|
||||||
|
|
||||||
|
Here is a minimal version of a workflow that does that:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '17 11 * * *' # daily at 11:17 UTC (06:17 CT)
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4 # get the repo + push credentials
|
||||||
|
|
||||||
|
- run: ./bin/regenerate_readme.sh # apply updates to README
|
||||||
|
|
||||||
|
- run: |
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
git add -A README.md
|
||||||
|
git diff --staged --quiet || {
|
||||||
|
git commit -m "chore: regenerate README with latest updates"
|
||||||
|
git push
|
||||||
|
} # commit updates to README if there are any, otherwise no-op
|
||||||
|
```
|
||||||
|
|
||||||
|
Once a day at 11:17 UTC, GitHub Actions will run this workflow which is made up
|
||||||
|
of a single job with permissions to write to the repo.
|
||||||
|
|
||||||
|
- First, it checks out the repo in the job container which includes push
|
||||||
|
credentials.
|
||||||
|
- Then it runs a script that might update the README (e.g. maybe based on other
|
||||||
|
things that have since been committed to the repo).
|
||||||
|
- Last, it attempts to stage any changes the script made to the README. If there
|
||||||
|
are any, then it will commit them with that generic commit message. Finally it
|
||||||
|
will push that commit to the main branch.
|
||||||
|
|
||||||
|
If this all sounds a bit untethered from a real-world example, then take a look
|
||||||
|
at how I use this exact pattern to [apply daily updates to my GitHub Profile
|
||||||
|
README](https://github.com/jbranchaud/jbranchaud/blob/main/.github/workflows/update-tils.yml)
|
||||||
|
based on the latest [TILs](https://github.com/jbranchaud/til) I have written.
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# Another Way To Mark Keyword-Only Dataclass Fields
|
||||||
|
|
||||||
|
In [Configure Other Attributes Of Dataclass
|
||||||
|
Field](configure-other-attributes-of-dataclass-field), I showed how the
|
||||||
|
[`dataclasses.field`](https://docs.python.org/3/library/dataclasses.html#dataclasses.field)
|
||||||
|
constructor function can be used. One of the parameters I demonstrated was
|
||||||
|
`kw_only`. Each field constructed with `kw_only=True` will be required to be
|
||||||
|
passed as a keyword-only parameter when constructing an instance of that
|
||||||
|
`dataclass`.
|
||||||
|
|
||||||
|
Another way to specify keyword-only parameters with `dataclass` fields is to
|
||||||
|
segment them with `KW_ONLY`. This sentinel value can be included as a
|
||||||
|
pseudo-field where all fields that come after it are treated as keyword-only.
|
||||||
|
|
||||||
|
Translating the example from that other post would look like this:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from dataclasses import dataclass, field, KW_ONLY
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Session:
|
||||||
|
start_time: datetime
|
||||||
|
project_name: str
|
||||||
|
_: KW_ONLY
|
||||||
|
tags: list[str] = field(default_factory=list, kw_only=True)
|
||||||
|
end_time: datetime | None = None
|
||||||
|
|
||||||
|
# ...
|
||||||
|
|
||||||
|
sesh1 = Session(start1, "my-project", tags=["pytorch", "numpy"])
|
||||||
|
sesh2 = Session(start2, "other-project", end_time=datetime.now())
|
||||||
|
```
|
||||||
|
|
||||||
|
The field whose value is `KW_ONLY` is only used to signal that keyword-only
|
||||||
|
boundary. It does not itself become a field of the dataclass.
|
||||||
|
|
||||||
|
On the one hand I like this approach because it feels closer to [the way this is
|
||||||
|
signaled in standard function definition
|
||||||
|
syntax](force-remaining-arguments-to-be-named.md).
|
||||||
|
|
||||||
|
```python
|
||||||
|
def build_session(start_time, project_name, *, tags, end_time=None)
|
||||||
|
```
|
||||||
|
|
||||||
|
On the other hand, it feels like magic `dataclass` syntax whereas the
|
||||||
|
`kw_only=True` parameter is more explicit.
|
||||||
Reference in New Issue
Block a user