Skip to content

Commit 9361d59

Browse files
committed
docs: improve examples safety and structure
- Remove potentially confusing raw_events.py example that performed destructive operations - Create comprehensive working-with-data.rst guide with safety best practices - Add proper redirects for moved pages using sphinxext-rediraffe - Restructure examples section with clearer progression from basic to advanced - Point users to production-ready examples in aw-client repository - Emphasize testing modes and dry-run practices throughout Addresses #1171
1 parent b3210e5 commit 9361d59

11 files changed

Lines changed: 411 additions & 208 deletions

Makefile

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ help:
5656
@echo " linkcheck to check all external links for integrity"
5757
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
5858
@echo " coverage to run coverage check of the documentation (if enabled)"
59+
@echo " redirectcheck to check that deleted files have proper redirects"
5960
@echo " dummy to check syntax errors of document sources"
6061

6162
.PHONY: clean
@@ -243,8 +244,14 @@ pseudoxml:
243244
@echo
244245
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
245246

247+
.PHONY: redirectcheck
248+
redirectcheck:
249+
$(SPHINXBUILD) -b rediraffecheckdiff $(ALLSPHINXOPTS) $(BUILDDIR)/rediraffe
250+
@echo
251+
@echo "Redirect check complete."
252+
246253
.PHONY: dummy
247254
dummy:
248255
$(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy
249256
@echo
250-
@echo "Build finished. Dummy builder generates no files."
257+
@echo "Build finished. Dummy builder generates no files."

poetry.lock

Lines changed: 114 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ m2r2 = "*"
2525
myst-parser = "*"
2626
recommonmark = "^0.7.0"
2727
setuptools = "*" # needed in Python 3.12+: https://github.com/CrossNox/m2r2/issues/72
28+
sphinxext-rediraffe = "^0.2.7"
2829

2930
[build-system]
3031
requires = ["poetry-core"]

src/conf.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"sphinx.ext.extlinks",
4242
"sphinx_tabs.tabs",
4343
"sphinx_click",
44+
"sphinxext.rediraffe",
4445
]
4546

4647
extlinks = {
@@ -50,6 +51,10 @@
5051
"gh-aw": ("https://github.com/ActivityWatch/%s", ""),
5152
}
5253

54+
# Redirects for moved pages
55+
rediraffe_redirects = "redirects.txt"
56+
rediraffe_branch = "HEAD~1"
57+
5358
# Add any paths that contain templates here, relative to this directory.
5459
templates_path = ["_templates"]
5560

@@ -391,4 +396,4 @@
391396

392397
# If true, do not generate a @detailmenu in the "Top" node's menu.
393398
#
394-
# texinfo_no_detailmenu = False
399+
# texinfo_no_detailmenu = False

src/examples.rst

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,54 @@
11
Examples
22
========
33

4-
For more examples, see the examples in the aw-client repo: https://github.com/ActivityWatch/aw-client
4+
This section provides practical examples for working with ActivityWatch, from retrieving your data to extending functionality with custom watchers.
5+
6+
Getting Your Data Out
7+
----------------------
8+
9+
**Most users should start here:**
10+
11+
.. toctree::
12+
:maxdepth: 1
13+
14+
examples/working-with-data
15+
16+
This comprehensive guide covers:
17+
18+
* **Canonical Events** - Get processed activity data (what the web UI uses)
19+
* **Custom Queries** - Write your own analysis using the query language
20+
* **Raw Events** - Advanced direct access to bucket data
21+
* **Safety Best Practices** - Avoiding data corruption with proper testing and dry-run modes
22+
23+
The guide includes links to production-ready examples from the `aw-client repository <https://github.com/ActivityWatch/aw-client/tree/master/examples>`_.
24+
25+
Writing Your Own Watchers
26+
-------------------------
27+
28+
Want to collect custom data? **See:**
529

630
.. toctree::
7-
examples/querying-data
31+
:maxdepth: 1
32+
833
examples/writing-watchers
9-
examples/extending
34+
35+
These guides cover:
36+
37+
* **Minimal watcher example** - Get started with a simple template
38+
* **Full-featured watcher** - Complete example with heartbeats and proper structure
39+
* **Best practices** - Error handling, bucket management, and testing modes
40+
* **Rust examples** - Alternative implementation for performance-critical watchers
41+
42+
Watchers are small programs that collect data and send it to ActivityWatch. You can track anything with a timestamp!
43+
44+
Example Code Repository
45+
-----------------------
46+
47+
The `aw-client examples <https://github.com/ActivityWatch/aw-client/tree/master/examples>`_ contain comprehensive, well-documented examples including:
48+
49+
* **Time analysis** - ``time_spent_today.py``, ``working_hours.py``
50+
* **Data export** - ``load_dataframe.py`` for pandas integration
51+
* **Data management** - ``redact_sensitive.py`` with safe dry-run mode
52+
* **Advanced analysis** - ``suggest_categories.py`` with AI categorization
53+
54+
All examples follow safety best practices with testing modes and error handling.

src/examples/extending.rst

Lines changed: 0 additions & 27 deletions
This file was deleted.

src/examples/querying-data.rst

Lines changed: 19 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,27 @@
1-
Querying Data
2-
=============
3-
4-
There are a couple of ways to query data in ActivityWatch.
5-
6-
aw-server supplies a "/query" endpoint (also accessible via aw-client's query method) which supplies a basic scripting language which you can utilize to do transformations on the server-side.
7-
This option is good for basic analysis and for lightweight clients (such as aw-webui).
8-
9-
Another option is to fetch events from the "/buckets/bucketname/events" endpoint (also accessible via aw-client's get_events method) and either program your own transformations or use transformation methods available in the aw-analysis python library (which includes all transformations available in the query endpoint). This requires a lot of more work since you will likely have to reprogram transformations already available in the query API, but on the other hand it is much more flexible.
10-
11-
12-
Writing a Query
13-
---------------
1+
Querying Data (Moved)
2+
====================
143

154
.. note::
16-
This section is still WIP.
17-
There is still no documentation of all the transform functions, but for most simple queries these examples should be enough.
18-
19-
Queries are the easiest yet advanced way to get events from aw-server buckets in a format which fits most needs.
20-
Queries can be done by doing a POST request to aw-server either manually or with the aw-client library.
21-
22-
For an incomplete API reference of the transform functions, see the API reference for :py:mod:`aw_transform` and :py:mod:`aw_query`.
23-
24-
In a query you start by getting events from a bucket and assign that collection of events to a variable, then there are multiple transform functions which you can use to for example filter, limit, sort, and merge events from a bucket.
25-
After that you assign what you want to receive from the request to the RETURN variable.
26-
27-
Magic Variables:
28-
There is a magic variable ``__CATEGORIES__`` you can use in the web UI's Query Explorer to include your configured categories in your query.
29-
30-
Here's an example of using this variable to find all events categorized as "Web Browsing"
31-
32-
.. code-block:: python
33-
34-
events = flood(query_bucket(find_bucket("aw-watcher-window_")));
35-
not_afk = flood(query_bucket(find_bucket("aw-watcher-afk_")));
36-
not_afk = filter_keyvals(not_afk, "status", ["not-afk"]);
37-
events = filter_period_intersect(events, not_afk);
38-
events = categorize(events, __CATEGORIES__);
39-
events = filter_keyvals(events, "$category", [["Work"]]);
40-
RETURN = sort_by_duration(events);
41-
42-
Minimal example:
43-
Minimal query which only gets events from a bucket and returns it:
44-
45-
.. code-block:: bash
46-
47-
events = query_bucket("my_bucket");
48-
RETURN = events;
49-
50-
51-
Example which arranges a hierarchy:
52-
A query which merges events from a bucket in a key1->key2 hierarchy:
53-
54-
.. code-block:: bash
55-
56-
events = query_bucket("my_bucket");
57-
events = merge_events_by_keys(events, "merged_key1", "merged_key2");
58-
RETURN = events;
59-
60-
61-
Example combining window and AFK events:
62-
A simplified query example of how to summarize what programs used while not afk.
63-
The query intersects the not-afk events from the afk bucket with the events from the window bucket, merges keys from the result and sorts by duration.
64-
65-
.. code-block:: bash
66-
67-
afk_events = query_bucket(find_bucket("aw-watcher-afk_"));
68-
window_events = query_bucket(find_bucket("aw-watcher-window_"));
69-
window_events = filter_period_intersect(window_events, filter_keyvals(afk_events, "status", ["not-afk"]));
70-
merged_events = merge_events_by_keys(window_events, ["app", "title"]);
71-
RETURN = sort_by_duration(merged_events);
72-
73-
Example including aw-client:
74-
This is an example of how you can do analysis and aggregation with the query method in Python with aw-client.
75-
You probably need to install the client library by following the instructions in its `repository <https://github.com/ActivityWatch/aw-client>`_.
76-
77-
.. note:: This example runs the client in *testing* mode, which means that it will try to connect to an aw-server in testing mode on the port 5666 instead of the normal 5600.
5+
This page has been moved and significantly improved.
6+
7+
**Please update your bookmarks to:** :doc:`working-with-data`
788

79-
.. literalinclude:: query_client.py
9+
This page has been replaced by a more comprehensive guide: :doc:`working-with-data`
8010

81-
Fetching Raw Events
82-
-------------------
83-
It is possible to fetch the raw events from a bucket. This is useful if you want to do your own analysis on the data, or if you want to use the aw-analysis library to do transformations on the data.
11+
The new page covers:
8412

85-
Example fetching raw events from the "aw-watcher-window_" bucket:
86-
This is an example that you can run in a Python to fetch raw events posted by the window watcher.
87-
The scripts sums the time spent on each window title and showcases a data redaction use case.
13+
* **Canonical Events** (recommended) - Get processed activity data like the web UI
14+
* **Custom Queries** - Write your own analysis queries
15+
* **Raw Events** (advanced) - Direct bucket access for maximum flexibility
16+
* **Comprehensive Examples** - Safe, up-to-date examples from the aw-client repository
8817

89-
.. literalinclude:: raw_events.py
18+
**Automatic redirect:** You will be redirected in 5 seconds.
9019

20+
.. raw:: html
9121

92-
.. TODO `Bucket REST API <./rest.html#get-events>`_
22+
<script>
23+
setTimeout(function() {
24+
window.location.href = 'working-with-data.html';
25+
}, 5000);
26+
</script>
27+
<meta http-equiv="refresh" content="5;url=working-with-data.html">

src/examples/raw_events.py

Lines changed: 0 additions & 68 deletions
This file was deleted.

0 commit comments

Comments
 (0)