made pylint happy and added enviorment files
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -163,3 +163,4 @@ cython_debug/
|
||||
things2reclaim/config/.toggl.toml
|
||||
things2reclaim/config/.things2reclaim.toml
|
||||
things2reclaim/data/tasks.db
|
||||
api/ReclaimAI/collection.bru
|
||||
|
||||
6
.pylintrc
Normal file
6
.pylintrc
Normal file
@@ -0,0 +1,6 @@
|
||||
[MASTER]
|
||||
disable=
|
||||
C0114, #missing-module-docstring
|
||||
C0115, #missing-class-docstring
|
||||
C0116, #missing-function-docstring
|
||||
init-hook='import sys; sys.path.append(".")'
|
||||
18
api/ReclaimAI/Get Events.bru
Normal file
18
api/ReclaimAI/Get Events.bru
Normal file
@@ -0,0 +1,18 @@
|
||||
meta {
|
||||
name: Get Events
|
||||
type: http
|
||||
seq: 3
|
||||
}
|
||||
|
||||
get {
|
||||
url: https://api.app.reclaim.ai/api/events?start=2024-06-13&end=2024-06-14&sourceDetails=true&allConnected=true
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
params:query {
|
||||
start: 2024-06-13
|
||||
end: 2024-06-14
|
||||
sourceDetails: true
|
||||
allConnected: true
|
||||
}
|
||||
11
api/ReclaimAI/Get Tasks.bru
Normal file
11
api/ReclaimAI/Get Tasks.bru
Normal file
@@ -0,0 +1,11 @@
|
||||
meta {
|
||||
name: Get Tasks
|
||||
type: http
|
||||
seq: 2
|
||||
}
|
||||
|
||||
get {
|
||||
url: https://api.app.reclaim.ai/api/tasks
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
13
api/ReclaimAI/bruno.json
Normal file
13
api/ReclaimAI/bruno.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": "1",
|
||||
"name": "ReclaimAI",
|
||||
"type": "collection",
|
||||
"ignore": [
|
||||
"node_modules",
|
||||
".git"
|
||||
],
|
||||
"presets": {
|
||||
"requestType": "http",
|
||||
"requestUrl": ""
|
||||
}
|
||||
}
|
||||
41
environment.yml
Normal file
41
environment.yml
Normal file
@@ -0,0 +1,41 @@
|
||||
name: things-automation
|
||||
channels:
|
||||
- conda-forge
|
||||
- defaults
|
||||
dependencies:
|
||||
- astroid=3.2.2=py312hca03da5_0
|
||||
- brotli-python=1.0.9=py312h313beb8_8
|
||||
- bzip2=1.0.8=h80987f9_6
|
||||
- ca-certificates=2024.3.11=hca03da5_0
|
||||
- certifi=2024.6.2=py312hca03da5_0
|
||||
- charset-normalizer=2.0.4=pyhd3eb1b0_0
|
||||
- click=8.1.7=py312hca03da5_0
|
||||
- dill=0.3.8=py312hca03da5_0
|
||||
- expat=2.6.2=h313beb8_0
|
||||
- isort=5.13.2=py312hca03da5_0
|
||||
- libcxx=14.0.6=h848a8c0_0
|
||||
- libffi=3.4.4=hca03da5_1
|
||||
- mccabe=0.7.0=pyhd3eb1b0_0
|
||||
- ncurses=6.4=h313beb8_0
|
||||
- openssl=3.0.13=h1a28f6b_2
|
||||
- pip=23.3.1=py312hca03da5_0
|
||||
- pylint=3.2.2=py312hca03da5_0
|
||||
- pysocks=1.7.1=py312hca03da5_0
|
||||
- python=3.12.1=h99e199e_0
|
||||
- python-dateutil=2.9.0post0=py312hca03da5_2
|
||||
- python-dotenv=0.21.0=pyhd8ed1ab_0
|
||||
- pytz=2024.1=py312hca03da5_0
|
||||
- readline=8.2=h1a28f6b_0
|
||||
- requests=2.31.0=py312hca03da5_1
|
||||
- setuptools=69.5.1=py312hca03da5_0
|
||||
- six=1.16.0=pyhd3eb1b0_1
|
||||
- sqlite=3.45.3=h80987f9_0
|
||||
- tk=8.6.14=h6ba3021_0
|
||||
- tzdata=2024a=h04d1e81_0
|
||||
- urllib3=2.2.1=py312hca03da5_0
|
||||
- wheel=0.43.0=py312hca03da5_0
|
||||
- xz=5.4.6=h80987f9_1
|
||||
- zlib=1.2.13=h18a0788_1
|
||||
- pip:
|
||||
- -r file:requirements.txt
|
||||
prefix: /opt/homebrew/Caskroom/miniconda/base/envs/things-automation
|
||||
77
requirements.txt
Normal file
77
requirements.txt
Normal file
@@ -0,0 +1,77 @@
|
||||
annotated-types==0.7.0
|
||||
anyio==4.4.0
|
||||
astroid @ file:///private/var/folders/nz/j6p8yfhx1mv_0grj5xl4650h0000gp/T/abs_b7z3htqpm1/croot/astroid_1717618370968/work
|
||||
better-rich-prompts==1.0.2
|
||||
black==24.4.2
|
||||
Brotli @ file:///private/var/folders/k1/30mswbxs7r1g6zwn8y4fyt500000gp/T/abs_27zk0eqdh0/croot/brotli-split_1714483157007/work
|
||||
build==1.2.1
|
||||
CacheControl==0.14.0
|
||||
certifi==2024.6.2
|
||||
cffi==1.16.0
|
||||
charset-normalizer @ file:///tmp/build/80754af9/charset-normalizer_1630003229654/work
|
||||
cleo==2.1.0
|
||||
click==8.1.7
|
||||
crashtest==0.4.1
|
||||
dill @ file:///private/var/folders/k1/30mswbxs7r1g6zwn8y4fyt500000gp/T/abs_28zwy_olqk/croot/dill_1715094676263/work
|
||||
distlib==0.3.8
|
||||
dnspython==2.6.1
|
||||
dulwich==0.21.7
|
||||
email_validator==2.1.1
|
||||
fastjsonschema==2.19.1
|
||||
filelock==3.14.0
|
||||
h11==0.14.0
|
||||
h2==4.1.0
|
||||
hpack==4.0.0
|
||||
httpcore==1.0.5
|
||||
httpx==0.27.0
|
||||
hyperframe==6.0.1
|
||||
idna==3.7
|
||||
installer==0.7.0
|
||||
isort @ file:///private/var/folders/k1/30mswbxs7r1g6zwn8y4fyt500000gp/T/abs_1bnvhw7_ex/croot/isort_1718291367347/work
|
||||
jaraco.classes==3.4.0
|
||||
keyring==24.3.1
|
||||
markdown-it-py==3.0.0
|
||||
mccabe @ file:///opt/conda/conda-bld/mccabe_1644221741721/work
|
||||
mdurl==0.1.2
|
||||
more-itertools==10.2.0
|
||||
msgpack==1.0.8
|
||||
mypy-extensions==1.0.0
|
||||
packaging==24.0
|
||||
pathspec==0.12.1
|
||||
pexpect==4.9.0
|
||||
pkginfo==1.10.0
|
||||
platformdirs @ file:///Users/builder/cbouss/perseverance-python-buildout/croot/platformdirs_1701803010714/work
|
||||
poetry==1.8.3
|
||||
poetry-core==1.9.0
|
||||
poetry-plugin-export==1.8.0
|
||||
ptyprocess==0.7.0
|
||||
pycparser==2.22
|
||||
pydantic==2.7.3
|
||||
pydantic_core==2.18.4
|
||||
Pygments==2.18.0
|
||||
pylint @ file:///private/var/folders/nz/j6p8yfhx1mv_0grj5xl4650h0000gp/T/abs_b623auwyzd/croot/pylint_1717622581741/work
|
||||
pyproject_hooks==1.1.0
|
||||
PySocks @ file:///Users/builder/cbouss/perseverance-python-buildout/croot/pysocks_1699237568675/work
|
||||
python-dateutil==2.9.0.post0
|
||||
python-dotenv @ file:///home/conda/feedstock_root/build_artifacts/python-dotenv_1662230030282/work
|
||||
pytz @ file:///private/var/folders/k1/30mswbxs7r1g6zwn8y4fyt500000gp/T/abs_a4b76c83ik/croot/pytz_1713974318928/work
|
||||
rapidfuzz==3.9.1
|
||||
reclaim-sdk @ git+https://github.com/cato447/reclaim-sdk.git@dd1bd0792be24b06fe57f40633a197699f7888c0
|
||||
requests @ file:///private/var/folders/nz/j6p8yfhx1mv_0grj5xl4650h0000gp/T/abs_b3tnputioh/croot/requests_1707355573919/work
|
||||
requests-toolbelt==1.0.0
|
||||
rich==13.7.1
|
||||
setuptools==69.5.1
|
||||
shellingham==1.5.4
|
||||
six==1.16.0
|
||||
sniffio==1.3.1
|
||||
things.py @ git+https://github.com/cato447/things.py.git@10fa2c8a07142cd149ef59bff22931ae0856c114
|
||||
toggl_python @ file:///Users/cato/Code/Cato447/toggl-python
|
||||
toml==0.10.2
|
||||
tomlkit @ file:///Users/builder/cbouss/perseverance-python-buildout/croot/tomlkit_1699238737474/work
|
||||
trove-classifiers==2024.5.22
|
||||
typer==0.12.3
|
||||
typing_extensions==4.12.2
|
||||
urllib3 @ file:///private/var/folders/nz/j6p8yfhx1mv_0grj5xl4650h0000gp/T/abs_22oz53beet/croot/urllib3_1715635830593/work
|
||||
virtualenv==20.26.2
|
||||
wheel==0.43.0
|
||||
xattr==1.1.0
|
||||
@@ -1,7 +1,7 @@
|
||||
import sqlite3
|
||||
|
||||
|
||||
class UploadedTasksDB(object):
|
||||
class UploadedTasksDB:
|
||||
def __init__(self, filename):
|
||||
self.conn: sqlite3.Connection = sqlite3.connect(filename)
|
||||
self.__create_tables()
|
||||
@@ -9,7 +9,7 @@ class UploadedTasksDB(object):
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
def __exit__(self, *exc):
|
||||
self.conn.close()
|
||||
|
||||
def __create_tables(self):
|
||||
|
||||
@@ -1,25 +1,26 @@
|
||||
#!/opt/homebrew/Caskroom/miniconda/base/envs/things-automation/bin/python3
|
||||
|
||||
from datetime import datetime
|
||||
from dateutil import tz
|
||||
from typing import Optional, List, Dict
|
||||
import tomllib
|
||||
from pathlib import Path
|
||||
|
||||
import sqlite3
|
||||
import typer
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional
|
||||
import tomllib
|
||||
|
||||
from dateutil import tz
|
||||
from rich import print as rprint
|
||||
from rich.console import Console
|
||||
from rich.prompt import Confirm
|
||||
from rich.table import Table
|
||||
from rich.text import Text
|
||||
from rich.prompt import Confirm
|
||||
from typing_extensions import Annotated
|
||||
import typer
|
||||
|
||||
from things2reclaim import reclaim_handler
|
||||
from things2reclaim import things_handler
|
||||
from things2reclaim import toggl_handler
|
||||
from things2reclaim import utils
|
||||
from things2reclaim.database_handler import UploadedTasksDB
|
||||
|
||||
import utils
|
||||
import things_handler
|
||||
import reclaim_handler
|
||||
from database_handler import UploadedTasksDB
|
||||
import toggl_handler
|
||||
|
||||
CONFIG_PATH = Path("config/.things2reclaim.toml")
|
||||
|
||||
@@ -138,18 +139,18 @@ def list_reclaim_tasks(subject: Annotated[Optional[str], typer.Argument()] = Non
|
||||
reclaim_tasks = reclaim_handler.filter_for_subject(subject, reclaim_tasks)
|
||||
current_date = datetime.now(tz.tzutc())
|
||||
table = Table("Index", "Task", "Days left", title="Task list")
|
||||
for id, task in enumerate(reclaim_tasks):
|
||||
for index, task in enumerate(reclaim_tasks):
|
||||
if current_date > task.due_date:
|
||||
days_behind = (current_date - task.due_date).days
|
||||
table.add_row(
|
||||
f"({id + 1})",
|
||||
f"({index + 1})",
|
||||
task.name,
|
||||
Text(f"{days_behind} days overdue", style="bold red"),
|
||||
)
|
||||
else:
|
||||
days_left = (task.due_date - current_date).days
|
||||
table.add_row(
|
||||
f"({id + 1})",
|
||||
f"({index + 1})",
|
||||
task.name,
|
||||
Text(f"{days_left} days left", style="bold white"),
|
||||
)
|
||||
@@ -223,7 +224,8 @@ def stop_task():
|
||||
time_format = "%H:%M"
|
||||
local_zone = tz.gettz()
|
||||
rprint(
|
||||
f"Logged work from {current_task.start.astimezone(local_zone).strftime(time_format)} to {stop_time.astimezone(local_zone).strftime(time_format)} for {stopped_task.name}"
|
||||
f"""Logged work from {current_task.start.astimezone(local_zone).strftime(time_format)}
|
||||
to {stop_time.astimezone(local_zone).strftime(time_format)} for {stopped_task.name}"""
|
||||
)
|
||||
|
||||
|
||||
@@ -278,7 +280,8 @@ def print_time_needed():
|
||||
today = datetime.now(tz.tzutc())
|
||||
|
||||
print(
|
||||
f"Last task is scheduled for {last_task_date.strftime('%d.%m.%Y')} ({last_task_date - today} till completion)"
|
||||
f"""Last task is scheduled for {last_task_date.strftime('%d.%m.%Y')}
|
||||
({last_task_date - today} till completion)"""
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -32,6 +32,10 @@ def get_project(task: ReclaimTask):
|
||||
return task.name.split(" ")[0]
|
||||
|
||||
|
||||
def get_events(since_days: int = 1):
|
||||
return ReclaimTaskEvent.search()
|
||||
|
||||
|
||||
def start_task(task: ReclaimTask):
|
||||
task.prioritize()
|
||||
|
||||
@@ -61,7 +65,7 @@ def log_work_for_task(task: ReclaimTask, start: datetime, end: datetime):
|
||||
|
||||
last_event.start = start.astimezone(utc)
|
||||
last_event.end = end.astimezone(utc)
|
||||
last_event._update()
|
||||
last_event.save()
|
||||
|
||||
|
||||
def finish_task(task: ReclaimTask):
|
||||
|
||||
@@ -4,7 +4,7 @@ import tomllib
|
||||
|
||||
import things
|
||||
|
||||
from database_handler import UploadedTasksDB
|
||||
from things2reclaim.database_handler import UploadedTasksDB
|
||||
|
||||
_config = {}
|
||||
CONFIG_PATH = Path("config/.things2reclaim.toml")
|
||||
@@ -49,7 +49,7 @@ def get_all_uploaded_things_tasks() -> List:
|
||||
|
||||
|
||||
def get_task_tags(things_task: Dict) -> Dict[str, str]:
|
||||
return {k: v for (k, v) in [tag.split(": ") for tag in things_task["tags"]]}
|
||||
return dict([tag.split(": ") for tag in things_task["tags"]])
|
||||
|
||||
|
||||
def full_name(things_task) -> str:
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
from toggl_python.entities import TimeEntry
|
||||
import toggl_python
|
||||
import tomllib
|
||||
from pathlib import Path
|
||||
from dateutil import tz
|
||||
import difflib
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from better_rich_prompts.prompt import ListPrompt
|
||||
from pathlib import Path
|
||||
import tomllib
|
||||
|
||||
import toggl_python
|
||||
from better_rich_prompts.prompt import ListPrompt
|
||||
from dateutil import tz
|
||||
from toggl_python.entities import TimeEntry
|
||||
|
||||
_config = {}
|
||||
|
||||
@@ -29,8 +28,8 @@ time_entry_editor = toggl_python.WorkspaceTimeEntries(
|
||||
)
|
||||
|
||||
|
||||
def get_time_entry(id: int):
|
||||
return toggl_python.TimeEntries(auth=auth).retrieve(id)
|
||||
def get_time_entry(time_entry_id: int):
|
||||
return toggl_python.TimeEntries(auth=auth).retrieve(time_entry_id)
|
||||
|
||||
|
||||
def get_time_entries(since_days: int = 30):
|
||||
@@ -65,14 +64,13 @@ def get_approriate_tag(description: str) -> str | None:
|
||||
|
||||
if not possible_tags:
|
||||
print("Found no matching tags")
|
||||
return
|
||||
return None
|
||||
|
||||
possible_tags = list(possible_tags)
|
||||
|
||||
if len(possible_tags) == 1:
|
||||
return possible_tags[0]
|
||||
else:
|
||||
return ListPrompt.ask("Select the best fitting tag", possible_tags)
|
||||
return ListPrompt.ask("Select the best fitting tag", possible_tags)
|
||||
|
||||
|
||||
def create_task_time_entry(
|
||||
@@ -95,9 +93,8 @@ def create_task_time_entry(
|
||||
if start is not None:
|
||||
if start.tzinfo is None:
|
||||
raise ValueError("start has to be timezone aware")
|
||||
else:
|
||||
start = start.astimezone(tz.tzutc())
|
||||
time_entry.start = start
|
||||
start = start.astimezone(tz.tzutc())
|
||||
time_entry.start = start
|
||||
|
||||
tag = get_approriate_tag(description)
|
||||
if tag:
|
||||
|
||||
@@ -3,14 +3,15 @@ import re
|
||||
from typing import Union, Dict, Any, List
|
||||
import difflib
|
||||
|
||||
from rich import print as rprint
|
||||
import things_handler
|
||||
from better_rich_prompts.prompt import ListPrompt
|
||||
from rich import print as rprint
|
||||
|
||||
regex = (
|
||||
from things2reclaim import things_handler
|
||||
|
||||
TIME_PATTERN = (
|
||||
r"((\d+\.?\d*) (hours|hrs|hour|hr|h))? ?((\d+\.?\d*) (mins|min|minutes|minute|m))?"
|
||||
)
|
||||
pattern = re.compile(regex)
|
||||
pattern = re.compile(TIME_PATTERN)
|
||||
|
||||
|
||||
def calculate_time_on_unit(tag_value: str) -> float:
|
||||
@@ -65,8 +66,8 @@ def get_closest_match(name: str, candidates: Dict[str, Any]) -> Any | None:
|
||||
return None
|
||||
if len(possible_candidates) == 1:
|
||||
return candidates[possible_candidates[0]]
|
||||
else:
|
||||
return candidates[ListPrompt.ask("Select a candidate", possible_candidates)]
|
||||
|
||||
return candidates[ListPrompt.ask("Select a candidate", possible_candidates)]
|
||||
|
||||
|
||||
def pinfo(msg: str):
|
||||
|
||||
Reference in New Issue
Block a user