-
-
Notifications
You must be signed in to change notification settings - Fork 0
more utils #10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
more utils #10
Changes from 97 commits
b878c90
4051ab8
c32e36f
bedb464
1bd181f
10dbca9
fdfa17e
e588ca9
f68b13a
710e372
3ab6688
59f2909
4bd5f8f
811966b
7948269
9894062
7e1fbcd
c84bc54
7fde93b
84adfeb
0e55404
4c91c9f
86f9582
823d704
528c4de
017f03e
0b550f2
c144b48
321f2eb
23448b5
d3ba6d0
ad27325
69bb6e5
1feddca
148e53e
8b77455
d19c681
75b01d4
2a68d15
5d8c128
1efd3cf
c5a52ef
f33d04b
aacd810
ccb916a
f90b899
4e864bb
382e6fc
85b24a2
e636771
0474076
10f5827
aaeb456
ebd609b
cd3f541
e8f85b5
e500314
e396037
162cbb7
fea9cdf
5c861d2
4d1de78
385ac32
092da21
469bf52
4e8b686
f400314
71cb689
8397183
1804786
b0dffad
cec3fb0
ee76127
c53e4d1
903375d
9e85908
386de31
f075309
6b06c88
2a29266
da6c659
49bcd99
9b35a92
73dcf48
75fe57d
7012d30
cad71ff
19e51a3
b8a0c7f
c087c80
12ad4e2
a29b992
b9e6b84
26b9ab6
86b7c2a
9ce9b97
ecdd0cb
4e87d9a
cb94d5c
fc4a5e8
c30781f
c21d80f
bb83b6e
d7bbf11
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -20,6 +20,7 @@ A set of functions for the **F**riendly **I**nteractive **Sh**ell (fish). This i | |||||||||||||||||||||||||
| - **`battery`**: print the percentage of the battery; | ||||||||||||||||||||||||||
| - **`between`**: check if the given values are ordered, usually used for three items to check membership of a range; | ||||||||||||||||||||||||||
| - **`biblespeak`**: speak the next verse of the *Bible*; | ||||||||||||||||||||||||||
| - **`blackcp`**: run the *Black* formatter, and if Black made changes, commit and push these; | ||||||||||||||||||||||||||
| - **`blooddonation`**: register a blood donation together with blood metrics; | ||||||||||||||||||||||||||
| - **`bloodresults`**: store blood result measurements; | ||||||||||||||||||||||||||
| - **`bloodpressure`**: register a blood pressure measurement; | ||||||||||||||||||||||||||
|
|
@@ -52,6 +53,7 @@ A set of functions for the **F**riendly **I**nteractive **Sh**ell (fish). This i | |||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### F | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - **`facialmask`**: register the use of a facial mask; | ||||||||||||||||||||||||||
| - **`fill`**: fill the entire screen with a certain color; | ||||||||||||||||||||||||||
| - **`fish_home`**: get the directory where the fish functions are stored; | ||||||||||||||||||||||||||
| - **`frmclip`**: copy from the clipboard to the stdout; | ||||||||||||||||||||||||||
|
|
@@ -69,14 +71,19 @@ A set of functions for the **F**riendly **I**nteractive **Sh**ell (fish). This i | |||||||||||||||||||||||||
| - **`gitacp`**: add items to the repository, commit, and push; | ||||||||||||||||||||||||||
| - **`gitb`**: make a new git branch; | ||||||||||||||||||||||||||
| - **`gitc`**: make a git commit (short for `git commit -am`); | ||||||||||||||||||||||||||
| - **`gitci`**: list the last CI/CD runs on *GitHub*; | ||||||||||||||||||||||||||
| - **`gitclonec`**: clone a repository and chance the directory to that of the cloned repository; | ||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typo: “chance” → “change”. User-facing docs. - - **`gitclonec`**: clone a repository and chance the directory to that of the cloned repository;
+ - **`gitclonec`**: clone a repository and change to the cloned repository’s directory;📝 Committable suggestion
Suggested change
🧰 Tools🪛 markdownlint-cli2 (0.17.2)74-74: Unordered list indentation (MD007, ul-indent) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
| - **`gitcp`**: commit with the given parameters, and push the changes; | ||||||||||||||||||||||||||
| - **`gitcpr`**: commit with the given parameters, push the changes and open a pull request on *GitHub*; | ||||||||||||||||||||||||||
| - **`gitd`**: calculate the git difference and work with a pager to read the full response; | ||||||||||||||||||||||||||
| - **`gitf`**: alias for `git fetch`; | ||||||||||||||||||||||||||
| - **`gith`**: checkout a given branch; | ||||||||||||||||||||||||||
| - **`gitm`**: move a given file in a git repository; | ||||||||||||||||||||||||||
| - **`gitmaster`**: checkout the master branch (and stash work in progress if any); | ||||||||||||||||||||||||||
| - **`gitmastertag`**: checkout the master branch, pull from remote, tag the commit and push the tag to the repository; | ||||||||||||||||||||||||||
| - **`gitp`**: pushes the changes to the remote repository (short for `git push`); | ||||||||||||||||||||||||||
| - **`gitpr`**: open a pull request on *GitHub*; | ||||||||||||||||||||||||||
| - **`gitprv`**: show comments of the active pull request; | ||||||||||||||||||||||||||
| - **`gitremote`**: add the remote as origin with the given `GIT_PREFIX` and the name of the directory as git project; | ||||||||||||||||||||||||||
| - **`gits`**: prints the status of the current Git repository (short for `git status`); | ||||||||||||||||||||||||||
| - **`gitt`**: make a git tag and push the tag; | ||||||||||||||||||||||||||
|
|
@@ -90,13 +97,15 @@ A set of functions for the **F**riendly **I**nteractive **Sh**ell (fish). This i | |||||||||||||||||||||||||
| - **`here_is_the_news`**: beeps a few times to mark a certain event; | ||||||||||||||||||||||||||
| - **`hlint`**: run Haskell lint and use a pager for the results; | ||||||||||||||||||||||||||
| - **`homebattery`**: determine how long it will take to load the battery full; | ||||||||||||||||||||||||||
| - **`hourcolor`**: change the keyboard to the hour color, can be scheduled as cronjob; | ||||||||||||||||||||||||||
| - **`household`**: wait until a household device has finished with info; | ||||||||||||||||||||||||||
| - **`hydrate`**: keep track of the amount of water we drink; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### I | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - **`igrep`**: run grep in a case insensitive way; | ||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add hyphen to compound adjective: "case-insensitive". When compound adjectives precede a noun, they should be hyphenated for proper grammar. Apply this diff: - - **`igrep`**: run grep in a case insensitive way;
+ - **`igrep`**: run grep in a case-insensitive way;📝 Committable suggestion
Suggested change
🧰 Tools🪛 LanguageTool[grammar] ~105-~105: Use a hyphen to join words. (QB_NEW_EN_HYPHEN) 🪛 markdownlint-cli2 (0.18.1)105-105: Unordered list indentation (MD007, ul-indent) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
| - **`import`**: initializes the python shell with `import …`, so `import datetime` for example can be written in the shell as first Python command; | ||||||||||||||||||||||||||
| - **`isortcp`**: run the isort formatter, and if isort made changes, commit and push these; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### J | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
@@ -122,15 +131,23 @@ A set of functions for the **F**riendly **I**nteractive **Sh**ell (fish). This i | |||||||||||||||||||||||||
| - **`measureall`**: start asking for many measures in bulk, used as helper function; | ||||||||||||||||||||||||||
| - **`measurelog`**: add a given measurement at a given time; | ||||||||||||||||||||||||||
| - **`mkdircd`**: make a directory, if it does not yet exist, and move the cd to that directory; | ||||||||||||||||||||||||||
| - **`mkdircdgit`**: make a directory, if it does not yet exist, cd into that directory, and start a git repository; | ||||||||||||||||||||||||||
| - **`mkvim`**: make the directories needed to edit a file; | ||||||||||||||||||||||||||
| - **`mkvimgit`**: make the directories needed to edit a file and add the file to git; | ||||||||||||||||||||||||||
| - **`mynote`**: add a notebook entry to a specific topic; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### N | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - **`natrix`**: the Python interpreter of the fish environment; | ||||||||||||||||||||||||||
| - **`natrix-env`**: run a Python program in the natrix environment; | ||||||||||||||||||||||||||
| - **`note`**: add a notebook entry; | ||||||||||||||||||||||||||
| - **`notes`**: notebook in a loop to log entries; | ||||||||||||||||||||||||||
| - **`numpy`**: start a Python shell with `numpy` imported; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### O | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - **`otp`**: generate/configure One Time Passwords (OTPs) with pass-extension-otp; | ||||||||||||||||||||||||||
|
Comment on lines
+148
to
+150
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix indentation for new section O. The ### O
- - **`otp`**: generate/configure One Time Passwords (OTPs) with pass-extension-otp;
+ - **`otp`**: generate/configure One Time Passwords (OTPs) with pass-extension-otp;📝 Committable suggestion
Suggested change
Suggested change
🧰 Tools🪛 markdownlint-cli2 (0.18.1)144-144: Unordered list indentation (MD007, ul-indent) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### P | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - **`pandas`**: start a Python shell with `numpy` and `pandas` imported; | ||||||||||||||||||||||||||
|
|
@@ -143,6 +160,7 @@ A set of functions for the **F**riendly **I**nteractive **Sh**ell (fish). This i | |||||||||||||||||||||||||
| - **`proofreadedit`**: let vim open the file along with the proofread file; | ||||||||||||||||||||||||||
| - **`proofreadmd`**: proofread Markdown files with Groq to find spelling and grammatical errors; | ||||||||||||||||||||||||||
| - **`pwd`**: list the absolute path for the given files listed or the `pwd` if no arguments were provided; | ||||||||||||||||||||||||||
| - **`pydoc`**: add doc strings to all elements of a Python file; | ||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Terminology: "doc strings" → "docstrings". Use the standard Python term "docstrings" (one word) instead of "doc strings". - - **`pydoc`**: add doc strings to all elements of a Python file;
+ - **`pydoc`**: add docstrings to all elements of a Python file;📝 Committable suggestion
Suggested change
🧰 Tools🪛 markdownlint-cli2 (0.18.1)163-163: Unordered list indentation (MD007, ul-indent) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
| - **`python3`**: overrides normal Python prompt with an IPython shell without banner, no confirmations and matplotlib; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### Q | ||||||||||||||||||||||||||
|
|
@@ -151,6 +169,7 @@ A set of functions for the **F**riendly **I**nteractive **Sh**ell (fish). This i | |||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### R | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - **`rabbitdoc`**: ask [*CodeRabbit*](https://github.com/coderabbitai) to generate docstrings for the latest pull request; | ||||||||||||||||||||||||||
| - **`redo`**: redo a command until the exit code is 0; | ||||||||||||||||||||||||||
| - **`remake`**: a loop to remake certain products with a Makefile; | ||||||||||||||||||||||||||
| - **`rmake`**: walk up the filetree until it finds a Makefile; | ||||||||||||||||||||||||||
|
|
@@ -159,6 +178,7 @@ A set of functions for the **F**riendly **I**nteractive **Sh**ell (fish). This i | |||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### S | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - **`season`**: determine the season for a given day; | ||||||||||||||||||||||||||
| - **`semver`**: convert a given requirements file to its sem-ver equivalent; | ||||||||||||||||||||||||||
| - **`sensors`**: show the temperature measured by sensors updated every second; | ||||||||||||||||||||||||||
| - **`setvar`**: check if a variable with the name exists; if not, query for a value; | ||||||||||||||||||||||||||
|
|
@@ -185,9 +205,11 @@ A set of functions for the **F**riendly **I**nteractive **Sh**ell (fish). This i | |||||||||||||||||||||||||
| - **`taskd`**: set the task with the given id as done; | ||||||||||||||||||||||||||
| - **`taskflush`**: set all expired tasks to done; | ||||||||||||||||||||||||||
| - **`teeth`**: help cleaning teeth; | ||||||||||||||||||||||||||
| - **`timeprompt`**: wait for a given amount of time, or until the person hits a key exits with 1 if the user interrupted; | ||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clarify the description of The current phrasing is awkward: "wait for a given amount of time, or until the person hits a key exits with 1 if the user interrupted." Consider revising for clarity: - - **`timeprompt`**: wait for a given amount of time, or until the person hits a key exits with 1 if the user interrupted;
+ - **`timeprompt`**: wait for a given amount of time or until a key is pressed; exits with 1 if the user interrupted;📝 Committable suggestion
Suggested change
🧰 Tools🪛 markdownlint-cli2 (0.18.1)203-203: Unordered list indentation (MD007, ul-indent) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
| - **`timestamp`**: get a string that specifies date and time, used for filenames mainly; | ||||||||||||||||||||||||||
| - **`todo`**: add or inspect to a todo list; | ||||||||||||||||||||||||||
| - **`truthful`**: check if at least one of the given Python literals or JSON values has truthiness `true`; | ||||||||||||||||||||||||||
| - **`typehintcheck`**: check if all defined functions have type hints; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### U | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
@@ -198,6 +220,7 @@ A set of functions for the **F**riendly **I**nteractive **Sh**ell (fish). This i | |||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - **`videos`**: see random videos; | ||||||||||||||||||||||||||
| - **`vimc`**: create a directory if the directory does not yet exist before running `vim`; | ||||||||||||||||||||||||||
| - **`vimgit`**: edit the given files in the parameters, and add these to git; | ||||||||||||||||||||||||||
| - **`vimo`**: open two or more files in vim next to each other; | ||||||||||||||||||||||||||
| - **`vimp`**: use vim with different tabs, a shortcut for `vim -p`; | ||||||||||||||||||||||||||
| - **`vimpsrc`**: open all the Haskell files in the `src` directory with `vim`; | ||||||||||||||||||||||||||
|
|
@@ -251,6 +274,10 @@ The following emoji aliases can be used as commands: | |||||||||||||||||||||||||
| - **`GROQ_API_TOKEN`**: the API token for *Groq* to make chatbot requests, can be found [here](https://console.groq.com/keys); and | ||||||||||||||||||||||||||
| - **`USER_SLUG`**: the slug used to prepend to file names when adding an author to it, for example `Elon_Musk`. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## Measurements | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| One of the core features is that one can measure all sorts of parameters, like health, activities, notes, etc. These are stored in `assets/Measurements.json`, a JSON file that allows cascading measurements. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## Installation | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| One can install this by downloading (or cloning) and put the files in the `~/.config/fish/functions/` | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| #!/usr/bin/python3 | ||
|
|
||
| import ast | ||
| import os | ||
| import os.path | ||
| import sys | ||
|
|
||
| import astor | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainVerify dependency: astor present if targeting <3.9. If you intend to support Python <3.9, ensure Run to check packaging references: 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "Searching packaging for 'astor'…"
fd -t f -a 'pyproject.toml' 'setup.cfg' 'setup.py' 'requirements*.txt' 2>/dev/null | while read -r f; do
echo "==> $f"
rg -n --fixed-strings "astor" "$f" || true
doneLength of output: 32 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "Listing root directory files:"
ls -1
echo
echo "Finding packaging files:"
find . -maxdepth 2 -type f \( -name 'pyproject.toml' -o -name 'setup.py' -o -name 'setup.cfg' -o -name 'requirements.txt' -o -name 'requirements*.txt' \)
PACK_FILES=$(find . -maxdepth 2 -type f \( -name 'pyproject.toml' -o -name 'setup.py' -o -name 'setup.cfg' -o -name 'requirements.txt' -o -name 'requirements*.txt' \))
if [[ -n "$PACK_FILES" ]]; then
echo
echo "Searching for 'astor' in packaging files:"
echo "$PACK_FILES" | while read -r f; do
echo "==> $f"
rg -n --fixed-strings "astor" "$f" || true
done
fiLength of output: 2739 Add missing astor dependency 🤖 Prompt for AI Agents |
||
|
|
||
|
|
||
| class AddDocString(ast.NodeTransformer): | ||
| def __init__(self, *args, docstring: str, **kwargs): | ||
| """ | ||
| Initialize the AddDocString transformer with the docstring text to insert. | ||
|
|
||
| The provided `docstring` value is stored on the instance as `self.docstring` and will be inserted into any Module, ClassDef, FunctionDef, or AsyncFunctionDef that lacks a docstring. | ||
| Any additional positional and keyword arguments are forwarded to the superclass initializer. | ||
| """ | ||
| super().__init__(*args, **kwargs) | ||
| self.docstring = docstring | ||
|
|
||
| def add_docstring(self, node): | ||
| """ | ||
| Insert the configured docstring into the given AST node if it has no existing docstring. | ||
|
|
||
| If the node (Module, ClassDef, FunctionDef, or AsyncFunctionDef) has no docstring, this function inserts the value of self.docstring as the first statement of node.body. If a docstring already exists, the node is left unchanged. The node is then traversed with generic_visit and returned. | ||
|
|
||
| Parameters: | ||
| node (ast.AST): An AST node that has a `body` sequence (module, class, or function node). | ||
|
|
||
| Returns: | ||
| ast.AST: The (possibly modified) node after applying generic visitation. | ||
| """ | ||
| if ast.get_docstring(node) is None: | ||
| node.body.insert(0, ast.Expr(value=ast.Constant(self.docstring))) | ||
| return self.generic_visit(node) | ||
|
|
||
| def visit_FunctionDef(self, node): | ||
| """ | ||
| Ensure an ast.FunctionDef node has a docstring, inserting the transformer's configured docstring if one is missing, then continue generic traversal. | ||
|
|
||
| Delegates to add_docstring(node) and returns the possibly modified ast.FunctionDef node. | ||
| """ | ||
| return self.add_docstring(node) | ||
|
|
||
| def visit_AsyncFunctionDef(self, node): | ||
| """ | ||
| Visit an async function definition node and ensure it has a docstring. | ||
|
|
||
| If the async function node has no existing docstring, inserts self.docstring | ||
| as the first statement in the node's body. Continues generic AST traversal | ||
| and returns the (possibly modified) node. | ||
|
|
||
| Parameters: | ||
| node (ast.AsyncFunctionDef): The async function AST node to visit. | ||
|
|
||
| Returns: | ||
| ast.AST: The visited (and possibly modified) node. | ||
| """ | ||
| return self.add_docstring(node) | ||
|
|
||
| def visit_ClassDef(self, node): | ||
| """ | ||
| Visit a class definition node and ensure it has a docstring. | ||
|
|
||
| If the class has no docstring, insert the transformer's configured docstring as the first statement. Returns the (possibly modified) AST ClassDef node for further traversal. | ||
|
|
||
| Parameters: | ||
| node (ast.ClassDef): The class definition AST node to visit and potentially modify. | ||
|
|
||
| Returns: | ||
| ast.AST: The transformed ClassDef node. | ||
| """ | ||
| return self.add_docstring(node) | ||
|
|
||
| def visit_Module(self, node): | ||
| """ | ||
| Ensure the given module AST node has a docstring. If the module lacks a docstring, insert the transformer's configured docstring as the first statement, then continue a generic visit of the node's children. | ||
|
|
||
| Parameters: | ||
| node (ast.Module): The module AST node to process. | ||
|
|
||
| Returns: | ||
| ast.AST: The module node after potential modification and traversal. | ||
| """ | ||
| return self.add_docstring(node) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| converter = AddDocString( | ||
| docstring=os.environ.get("PY_DOCSTRING", "@coderabbitai generate docstrings") | ||
| ) | ||
| for file in sys.argv[1:]: | ||
| with open(file, "rb") as f: | ||
| tree = ast.parse(f.read()) | ||
| result = astor.to_source(converter.visit(tree)) | ||
| file, ext = os.path.splitext(file) | ||
| with open(f"{file}_modified{ext}", "w") as f: | ||
| f.write(result) | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -6,66 +6,47 @@ | |||||
| from ast import literal_eval | ||||||
| from datetime import datetime | ||||||
| from shutil import move | ||||||
| import sqlite3 | ||||||
| from peewee import DateTimeField, Model, SqliteDatabase, TextField | ||||||
|
|
||||||
| from color_pprint import cprint | ||||||
| from dateparser import parse | ||||||
| from filelock import FileLock | ||||||
|
|
||||||
| DURATION = re.compile(r"\d{1,2}([:]\d{2})+") | ||||||
| ASSET_PATH = "assets/measurements.json" | ||||||
| ASSET_PATH = "assets/measurements.db" | ||||||
|
|
||||||
| db = SqliteDatabase(ASSET_PATH) | ||||||
|
|
||||||
| def filter_dict(data, dt): | ||||||
| if isinstance(data, dict): | ||||||
| result = {} | ||||||
| for k, v in data.items(): | ||||||
| v = filter_dict(v, dt) | ||||||
| if v: | ||||||
| try: | ||||||
| dt2 = datetime.fromisoformat(k) | ||||||
| except ValueError: | ||||||
| result[k] = v | ||||||
| else: | ||||||
| if dt2 >= dt: | ||||||
| result[k] = v | ||||||
| return result | ||||||
| return data | ||||||
| class Measurement(Model): | ||||||
| key = TextField() | ||||||
| value = TextField() | ||||||
| created_date = DateTimeField(default=datetime.now) | ||||||
|
|
||||||
| class Meta: | ||||||
| database = db | ||||||
|
|
||||||
| if __name__ == "__main__": | ||||||
| n = len(sys.argv) | ||||||
| assert ( | ||||||
| n > 1 | ||||||
| ), "You should provide the name of the measurement and the corresponding value" | ||||||
| with FileLock(f"{ASSET_PATH}.lock"): | ||||||
| try: | ||||||
| with open(ASSET_PATH, "r") as f: | ||||||
| data = json.load(f) | ||||||
| except IOError: | ||||||
| data = {} | ||||||
| timestamp = datetime.now().replace(microsecond=0) | ||||||
| db.connect() | ||||||
| db.create_tables([Measurement]) | ||||||
| key_dt = timestamp = datetime.now() | ||||||
| dt = timestamp.isoformat() | ||||||
| to_sort = {} | ||||||
| _def = {} | ||||||
| for i in range(1, n, 2): | ||||||
| key = sys.argv[i] | ||||||
| try: | ||||||
| key, dt2 = key.rsplit("@", 1) | ||||||
| timefilter = dt2 = parse(dt2) | ||||||
| timefilter = dt2 = parse(dt2).replace(tzinfo=None) | ||||||
| if dt2 is not None: | ||||||
| key_dt = dt2.replace(microsecond=0, tzinfo=None).isoformat() | ||||||
| key_dt = dt2.replace(tzinfo=None) | ||||||
| except ValueError: | ||||||
| # key is already fine | ||||||
| timefilter = datetime.min | ||||||
| key_dt = dt | ||||||
| datum = data | ||||||
| for ky in key.split("."): | ||||||
| _datum = datum.setdefault(ky, _def) | ||||||
| if _datum is _def: | ||||||
| _def = {} # new one | ||||||
| # need to resort datum, new entry | ||||||
| to_sort[id(datum)] = datum | ||||||
| datum = _datum | ||||||
| if n > i + 1: | ||||||
| val = sys.argv[i + 1].strip() | ||||||
| if DURATION.fullmatch(val.strip()): | ||||||
|
|
@@ -83,16 +64,9 @@ def filter_dict(data, dt): | |||||
| except ValueError: | ||||||
| pass # keep it a string | ||||||
| if val: # None, False, etc. are all omitted | ||||||
| datum[key_dt] = val | ||||||
| if key_dt is not dt: | ||||||
| # we add a key from the past | ||||||
| to_sort[id(datum)] = datum | ||||||
| Measurement.create(created_date=key_dt, key=key, value=json.dumps(val)) | ||||||
| else: | ||||||
| cprint(filter_dict(datum, timefilter)) | ||||||
| for datum in to_sort.values(): | ||||||
| datum_sort = {k: v for k, v in sorted(datum.items())} | ||||||
| datum.clear() | ||||||
| datum.update(datum_sort) | ||||||
| with open(f"{ASSET_PATH}.tmp", "w") as f: | ||||||
| json.dump(data, f, indent=4) | ||||||
| move(f"{ASSET_PATH}.tmp", ASSET_PATH) | ||||||
| datum = {} | ||||||
| for entry in Measurement.select().where(Measurement.key == key, Measurement.created_date >= timefilter.isoformat()): | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix type mismatch in database query. The comparison Apply this diff to compare datetime objects directly: - for entry in Measurement.select().where(Measurement.key == key, Measurement.created_date >= timefilter.isoformat()):
+ for entry in Measurement.select().where(Measurement.key == key, Measurement.created_date >= timefilter):📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| datum[parse(entry.created_date).replace(microsecond=0)] = json.loads(entry.value) | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Remove unnecessary datetime parsing.
Apply this diff to use the datetime object directly: - datum[parse(entry.created_date).replace(microsecond=0)] = json.loads(entry.value)
+ datum[entry.created_date.replace(microsecond=0)] = json.loads(entry.value)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| cprint(datum) | ||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,6 +1,12 @@ | ||||||
| measurements*.json | ||||||
| *_measurements.json | ||||||
| *_measurements.json.gz | ||||||
| measurements*.sqlite3 | ||||||
| *_measurements.sqlite3 | ||||||
| *_measurements.slite3.gz | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix typo in file extension. Line 6 contains "slite3" instead of "sqlite3". Apply this diff to fix the typo: -*_measurements.slite3.gz
+*_measurements.sqlite3.gz📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| measurements*.db | ||||||
| *_measurements.db | ||||||
| *_measurements.db.gz | ||||||
| list.json | ||||||
| *_list.json | ||||||
| *.lock | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid executing unpinned remote scripts in CI; replace with a local validator or pin to a commit.
curl-ing and executing a remote script from a moving branch (master) is a supply-chain risk and makes builds non-deterministic. Prefer a local validator (no network), or at minimum fetch a specific commit and verify integrity.
Preferred fix: replace the remote script with a Python-based JSON validation that fails the job on invalid JSON.
Alternative (if you must keep the remote script):
📝 Committable suggestion
🤖 Prompt for AI Agents