dey 0.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.
dey-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,6 @@
1
+ Metadata-Version: 2.4
2
+ Name: dey
3
+ Version: 0.1.0
4
+ Summary: Terminal time tracker
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: pyyaml>=6.0
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1,3 @@
1
+ from dey.cli import main
2
+
3
+ main()
dey-0.1.0/dey/cli.py ADDED
@@ -0,0 +1,207 @@
1
+ """
2
+ This time tracker is named after Alexander A. Dey
3
+ (https://americanhistory.si.edu/collections/object/nmah_856741).
4
+ """
5
+
6
+ import os
7
+ import sys
8
+ import re
9
+ from pathlib import Path
10
+ from datetime import date, datetime
11
+ import yaml
12
+
13
+ def print_status():
14
+ print("(status not yet implemented)")
15
+
16
+
17
+ def report_day(data, tails):
18
+ print(f"(day report: {tails})")
19
+
20
+
21
+ def report_week(data, tails):
22
+ print(f"(week report: {tails})")
23
+
24
+
25
+ def latest_entry(data):
26
+ """
27
+ Return (date_key, entry_dict) for the most recent session, or (None, None).
28
+ """
29
+ dates = [k for k in data if isinstance(k, date)]
30
+ if not dates:
31
+ return None, None
32
+ latest = max(dates)
33
+ entries = data[latest]
34
+ if not entries:
35
+ return None, None
36
+ return latest, entries[-1]
37
+
38
+
39
+ def toggle(data, tails):
40
+ # Resolve time and job from tails (order-independent)
41
+ time_str = None
42
+ job_name = None
43
+ for tail in tails:
44
+ if re.fullmatch(r"\d{1,2}:\d{2}", tail):
45
+ time_str = tail
46
+ else:
47
+ job_name = tail
48
+
49
+ if time_str is None:
50
+ time_str = datetime.now().strftime("%H:%M")
51
+
52
+ # Find the most recent session
53
+ latest_date, last_entry = latest_entry(data)
54
+
55
+ # Get the job ID, default to last.
56
+ if job_name is None:
57
+ if last_entry is None:
58
+ print("No job specified and no previous session.")
59
+ return
60
+ job_id = last_entry["job"]
61
+ else:
62
+ jobs = data.get("jobs", {})
63
+ job_id = jobs.get(job_name)
64
+ if job_id is None:
65
+ print(f"Job {job_name} is undefined.")
66
+ return
67
+ if job_id < 0:
68
+ print(f"Cannot use disabled job: {job_name}.")
69
+ return
70
+
71
+ # Toggle: stop active session or start a new one.
72
+ if last_entry is not None and last_entry["stop"] is None:
73
+ # If active session exists, then stop it.
74
+ last_entry["stop"] = time_str
75
+ else:
76
+ # If no active session, then start a new one.
77
+ today = date.today()
78
+ data.setdefault(today, []).append({
79
+ "job": job_id,
80
+ "start": time_str,
81
+ "stop": None,
82
+ })
83
+
84
+
85
+ def adjust(data, tails):
86
+ print(f"(adjust: {tails})")
87
+
88
+
89
+ def name_job(data, tails):
90
+ if not tails:
91
+ return
92
+ new_name = tails[0]
93
+ jobs = data.setdefault("jobs", {})
94
+
95
+ if len(tails) > 1:
96
+ # Rename: find old name, update key
97
+ old_name = tails[1]
98
+ if old_name not in jobs:
99
+ print(f"Job {old_name} is undefined.")
100
+ return # reject
101
+ jobs[new_name] = jobs.pop(old_name)
102
+ return
103
+
104
+ next_id = max((abs(v) for v in jobs.values()), default=0) + 1
105
+ jobs[new_name] = next_id
106
+
107
+
108
+ def disable_job(data, tails):
109
+ jobs = data.setdefault("jobs", {})
110
+ job = tails[0]
111
+ if job in jobs:
112
+ jobs[job] = -abs(jobs[job])
113
+ else:
114
+ print(f"Job {job} is undefined.")
115
+
116
+
117
+ def enable_job(data, tails):
118
+ jobs = data.setdefault("jobs", {})
119
+ job = tails[0]
120
+ if job in jobs:
121
+ jobs[job] = abs(jobs[job])
122
+ else:
123
+ print(f"Job {job} is undefined.")
124
+
125
+
126
+ def undo(data, tails):
127
+ print(f"(undo: {tails})")
128
+
129
+
130
+ def print_help(data, tails):
131
+ print("You've chosen poorly!")
132
+
133
+
134
+ FLAGS = {
135
+ "-r": (report_day, 2),
136
+ "-R": (report_week, 1),
137
+ "-c": (toggle, 2),
138
+ "-C": (adjust, 2),
139
+ "-j": (name_job, 2),
140
+ "-d": (disable_job, 1),
141
+ "-e": (enable_job, 1),
142
+ "-u": (undo, 1),
143
+ "-h": (print_help, 0),
144
+ }
145
+
146
+
147
+ def data_path() -> Path:
148
+ if sys.platform == "win32":
149
+ base = Path(os.environ["APPDATA"]) / "dey"
150
+ else:
151
+ base = Path(os.environ.get(
152
+ "XDG_CONFIG_HOME", Path.home() / ".config")) / "dey"
153
+ return base / "log.yaml"
154
+
155
+
156
+ def load_data() -> dict:
157
+ path = data_path()
158
+ if not path.exists():
159
+ path.parent.mkdir(parents=True, exist_ok=True)
160
+ path.touch()
161
+ return {}
162
+ with open(path) as f:
163
+ return yaml.safe_load(f) or {}
164
+
165
+
166
+ def save_data(data: dict) -> None:
167
+ path = data_path()
168
+ with open(path, "w") as f:
169
+ yaml.safe_dump(data, f,
170
+ default_flow_style=False, sort_keys=False)
171
+
172
+
173
+ #def search_enabled(data: dict):
174
+
175
+
176
+ def parse(argv):
177
+ """Returns list of (flag, [tails]) in order."""
178
+ commands = []
179
+ i = 0
180
+ while i < len(argv):
181
+ token = argv[i]
182
+ if token not in FLAGS:
183
+ raise SystemExit(f"Unknown flag: {token}")
184
+ max_tails = FLAGS[token][1]
185
+ tails = []
186
+ i += 1
187
+ while i < len(argv) and len(tails) < max_tails \
188
+ and not argv[i].startswith("-"):
189
+ tails.append(argv[i])
190
+ i += 1
191
+ commands.append((token, tails))
192
+ return commands
193
+
194
+
195
+ def main():
196
+ data = load_data()
197
+ commands = parse(sys.argv[1:])
198
+ if not commands:
199
+ print_status()
200
+ return
201
+ for flag, tails in commands:
202
+ FLAGS[flag][0](data, tails)
203
+ save_data(data)
204
+
205
+
206
+ if __name__ == "__main__":
207
+ main()
@@ -0,0 +1,6 @@
1
+ Metadata-Version: 2.4
2
+ Name: dey
3
+ Version: 0.1.0
4
+ Summary: Terminal time tracker
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: pyyaml>=6.0
@@ -0,0 +1,10 @@
1
+ pyproject.toml
2
+ dey/__init__.py
3
+ dey/__main__.py
4
+ dey/cli.py
5
+ dey.egg-info/PKG-INFO
6
+ dey.egg-info/SOURCES.txt
7
+ dey.egg-info/dependency_links.txt
8
+ dey.egg-info/entry_points.txt
9
+ dey.egg-info/requires.txt
10
+ dey.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ dey = dey.cli:main
@@ -0,0 +1 @@
1
+ pyyaml>=6.0
@@ -0,0 +1 @@
1
+ dey
@@ -0,0 +1,16 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "dey"
7
+ version = "0.1.0"
8
+ description = "Terminal time tracker"
9
+ requires-python = ">=3.10"
10
+
11
+ dependencies = [
12
+ "pyyaml>=6.0",
13
+ ]
14
+
15
+ [project.scripts]
16
+ dey = "dey.cli:main"
dey-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+