pytodo-qt 0.2.8__tar.gz → 0.3.8__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.
- pytodo_qt-0.3.8/PKG-INFO +199 -0
- pytodo_qt-0.3.8/README.md +169 -0
- pytodo_qt-0.3.8/pyproject.toml +90 -0
- pytodo_qt-0.3.8/src/pytodo_qt/__init__.py +18 -0
- pytodo_qt-0.3.8/src/pytodo_qt/__main__.py +167 -0
- pytodo_qt-0.3.8/src/pytodo_qt/core/__init__.py +104 -0
- pytodo_qt-0.3.8/src/pytodo_qt/core/config.py +313 -0
- pytodo_qt-0.3.8/src/pytodo_qt/core/database.py +421 -0
- pytodo_qt-0.3.8/src/pytodo_qt/core/logger.py +143 -0
- pytodo_qt-0.3.8/src/pytodo_qt/core/migration.py +258 -0
- pytodo_qt-0.3.8/src/pytodo_qt/core/models.py +323 -0
- pytodo_qt-0.3.8/src/pytodo_qt/core/paths.py +166 -0
- pytodo_qt-0.3.8/src/pytodo_qt/core/settings.py +41 -0
- pytodo_qt-0.3.8/src/pytodo_qt/core/sync_engine.py +327 -0
- pytodo_qt-0.3.8/src/pytodo_qt/crypto/__init__.py +91 -0
- pytodo_qt-0.3.8/src/pytodo_qt/crypto/aes_gcm.py +205 -0
- pytodo_qt-0.3.8/src/pytodo_qt/crypto/kdf.py +130 -0
- pytodo_qt-0.3.8/src/pytodo_qt/crypto/key_exchange.py +292 -0
- pytodo_qt-0.3.8/src/pytodo_qt/crypto/keyring_storage.py +298 -0
- pytodo_qt-0.3.8/src/pytodo_qt/crypto/legacy.py +85 -0
- pytodo_qt-0.3.8/src/pytodo_qt/gui/__init__.py +28 -0
- pytodo_qt-0.3.8/src/pytodo_qt/gui/dialogs/__init__.py +13 -0
- pytodo_qt-0.3.8/src/pytodo_qt/gui/dialogs/add_todo.py +97 -0
- pytodo_qt-0.3.8/src/pytodo_qt/gui/dialogs/peer_manager.py +418 -0
- pytodo_qt-0.3.8/src/pytodo_qt/gui/dialogs/settings.py +330 -0
- pytodo_qt-0.3.8/src/pytodo_qt/gui/dialogs/sync.py +198 -0
- pytodo_qt-0.3.8/src/pytodo_qt/gui/icons/exit.svg +6 -0
- pytodo_qt-0.3.8/src/pytodo_qt/gui/icons/minus.svg +3 -0
- pytodo_qt-0.3.8/src/pytodo_qt/gui/icons/plus.svg +3 -0
- pytodo_qt-0.3.8/src/pytodo_qt/gui/icons/pytodo-qt-1024.png +0 -0
- pytodo_qt-0.3.8/src/pytodo_qt/gui/icons/pytodo-qt-256.png +0 -0
- pytodo_qt-0.3.8/src/pytodo_qt/gui/icons/pytodo-qt.icns +0 -0
- pytodo_qt-0.3.8/src/pytodo_qt/gui/icons/pytodo-qt.svg +18 -0
- pytodo_qt-0.3.8/src/pytodo_qt/gui/icons/toggle.svg +4 -0
- pytodo_qt-0.3.8/src/pytodo_qt/gui/icons/tray.svg +3 -0
- pytodo_qt-0.3.8/src/pytodo_qt/gui/main_window.py +940 -0
- pytodo_qt-0.3.8/src/pytodo_qt/gui/styles/__init__.py +25 -0
- pytodo_qt-0.3.8/src/pytodo_qt/gui/styles/themes.py +475 -0
- pytodo_qt-0.3.8/src/pytodo_qt/gui/widgets/__init__.py +11 -0
- pytodo_qt-0.3.8/src/pytodo_qt/gui/widgets/list_selector.py +158 -0
- pytodo_qt-0.3.8/src/pytodo_qt/gui/widgets/status_bar.py +94 -0
- pytodo_qt-0.3.8/src/pytodo_qt/gui/widgets/todo_table.py +190 -0
- pytodo_qt-0.3.8/src/pytodo_qt/net/__init__.py +47 -0
- pytodo_qt-0.3.8/src/pytodo_qt/net/client.py +439 -0
- pytodo_qt-0.3.8/src/pytodo_qt/net/discovery.py +300 -0
- pytodo_qt-0.3.8/src/pytodo_qt/net/protocol.py +367 -0
- pytodo_qt-0.3.8/src/pytodo_qt/net/server.py +433 -0
- pytodo_qt-0.3.8/src/pytodo_qt.egg-info/PKG-INFO +199 -0
- pytodo_qt-0.3.8/src/pytodo_qt.egg-info/SOURCES.txt +67 -0
- pytodo_qt-0.3.8/src/pytodo_qt.egg-info/requires.txt +14 -0
- pytodo_qt-0.3.8/tests/test_config.py +340 -0
- pytodo_qt-0.3.8/tests/test_crypto.py +545 -0
- pytodo_qt-0.3.8/tests/test_database.py +590 -0
- pytodo_qt-0.3.8/tests/test_discovery.py +415 -0
- pytodo_qt-0.3.8/tests/test_keyring_storage.py +470 -0
- pytodo_qt-0.3.8/tests/test_legacy_crypto.py +234 -0
- pytodo_qt-0.3.8/tests/test_migration.py +492 -0
- pytodo_qt-0.3.8/tests/test_models.py +261 -0
- pytodo_qt-0.3.8/tests/test_net.py +347 -0
- pytodo_qt-0.3.8/tests/test_paths.py +364 -0
- pytodo_qt-0.3.8/tests/test_protocol.py +211 -0
- pytodo_qt-0.3.8/tests/test_settings.py +83 -0
- pytodo_qt-0.3.8/tests/test_sqlite_integration.py +449 -0
- pytodo_qt-0.3.8/tests/test_sync.py +587 -0
- pytodo-qt-0.2.8/PKG-INFO +0 -81
- pytodo-qt-0.2.8/README.md +0 -65
- pytodo-qt-0.2.8/pyproject.toml +0 -36
- pytodo-qt-0.2.8/setup.py +0 -3
- pytodo-qt-0.2.8/src/pytodo_qt/__init__.py +0 -0
- pytodo-qt-0.2.8/src/pytodo_qt/__main__.py +0 -106
- pytodo-qt-0.2.8/src/pytodo_qt/core/Logger.py +0 -62
- pytodo-qt-0.2.8/src/pytodo_qt/core/TodoDatabase.py +0 -243
- pytodo-qt-0.2.8/src/pytodo_qt/core/__init__.py +0 -35
- pytodo-qt-0.2.8/src/pytodo_qt/core/json_helpers.py +0 -90
- pytodo-qt-0.2.8/src/pytodo_qt/core/settings.py +0 -37
- pytodo-qt-0.2.8/src/pytodo_qt/crypto/AESCipher.py +0 -57
- pytodo-qt-0.2.8/src/pytodo_qt/crypto/__init__.py +0 -0
- pytodo-qt-0.2.8/src/pytodo_qt/gui/AddTodoDialog.py +0 -93
- pytodo-qt-0.2.8/src/pytodo_qt/gui/MainWindow.py +0 -969
- pytodo-qt-0.2.8/src/pytodo_qt/gui/SyncDialog.py +0 -106
- pytodo-qt-0.2.8/src/pytodo_qt/gui/__init__.py +0 -0
- pytodo-qt-0.2.8/src/pytodo_qt/gui/icons/minus.png +0 -0
- pytodo-qt-0.2.8/src/pytodo_qt/gui/icons/plus.png +0 -0
- pytodo-qt-0.2.8/src/pytodo_qt/gui/icons/pytodo-qt.png +0 -0
- pytodo-qt-0.2.8/src/pytodo_qt/net/__init__.py +0 -20
- pytodo-qt-0.2.8/src/pytodo_qt/net/sync_operations.py +0 -18
- pytodo-qt-0.2.8/src/pytodo_qt/net/tcp_client_lib.py +0 -134
- pytodo-qt-0.2.8/src/pytodo_qt/net/tcp_server_lib.py +0 -141
- pytodo-qt-0.2.8/src/pytodo_qt.egg-info/PKG-INFO +0 -81
- pytodo-qt-0.2.8/src/pytodo_qt.egg-info/SOURCES.txt +0 -30
- pytodo-qt-0.2.8/src/pytodo_qt.egg-info/requires.txt +0 -2
- {pytodo-qt-0.2.8 → pytodo_qt-0.3.8}/COPYING +0 -0
- {pytodo-qt-0.2.8 → pytodo_qt-0.3.8}/setup.cfg +0 -0
- {pytodo-qt-0.2.8 → pytodo_qt-0.3.8}/src/pytodo_qt.egg-info/dependency_links.txt +0 -0
- {pytodo-qt-0.2.8 → pytodo_qt-0.3.8}/src/pytodo_qt.egg-info/entry_points.txt +0 -0
- {pytodo-qt-0.2.8 → pytodo_qt-0.3.8}/src/pytodo_qt.egg-info/top_level.txt +0 -0
pytodo_qt-0.3.8/PKG-INFO
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pytodo-qt
|
|
3
|
+
Version: 0.3.8
|
|
4
|
+
Summary: A cross-platform to-do list manager with encrypted peer-to-peer synchronization
|
|
5
|
+
Author-email: Michael Berry <trismegustis@gmail.com>
|
|
6
|
+
License: GPLv3
|
|
7
|
+
Project-URL: Homepage, https://github.com/berrym/pytodo-qt
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Requires-Python: >=3.11
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: COPYING
|
|
16
|
+
Requires-Dist: PyQt6>=6.4
|
|
17
|
+
Requires-Dist: cryptography>=41.0
|
|
18
|
+
Requires-Dist: zeroconf>=0.80
|
|
19
|
+
Requires-Dist: keyring>=24.0
|
|
20
|
+
Requires-Dist: qasync>=0.24
|
|
21
|
+
Requires-Dist: rich>=13.0
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
24
|
+
Requires-Dist: pytest-qt>=4.2; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
|
|
26
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
27
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
28
|
+
Requires-Dist: basedpyright>=1.18; extra == "dev"
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
# pytodo-qt
|
|
32
|
+
|
|
33
|
+
[](https://github.com/berrym/pytodo-qt/actions/workflows/ci.yml)
|
|
34
|
+
[](https://codecov.io/gh/berrym/pytodo-qt)
|
|
35
|
+
[](https://www.python.org/downloads/)
|
|
36
|
+
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
37
|
+
[](https://github.com/astral-sh/ruff)
|
|
38
|
+
[](https://github.com/psf/black)
|
|
39
|
+
|
|
40
|
+
A cross-platform to-do list manager with encrypted peer-to-peer synchronization.
|
|
41
|
+
|
|
42
|
+
## Features
|
|
43
|
+
|
|
44
|
+
- **Multiple lists** - Organize tasks into separate lists
|
|
45
|
+
- **Priority levels** - High, normal, and low priority with color coding
|
|
46
|
+
- **Encrypted sync** - AES-256-GCM encryption with Ed25519 key exchange
|
|
47
|
+
- **Auto-discovery** - Find other instances on your network via mDNS/Zeroconf
|
|
48
|
+
- **Dark/light themes** - System-following or manual theme selection
|
|
49
|
+
- **Cross-platform** - Linux, macOS, and Windows support
|
|
50
|
+
|
|
51
|
+
## Requirements
|
|
52
|
+
|
|
53
|
+
- Python 3.11 or later
|
|
54
|
+
- PyQt6
|
|
55
|
+
|
|
56
|
+
## Installation
|
|
57
|
+
|
|
58
|
+
### Pre-built Binaries
|
|
59
|
+
|
|
60
|
+
Download the latest release for your platform from the [Releases page](https://github.com/berrym/pytodo-qt/releases).
|
|
61
|
+
|
|
62
|
+
#### macOS
|
|
63
|
+
|
|
64
|
+
1. Download `pytodo-qt-VERSION-macos-arm64.zip` (Apple Silicon) or `pytodo-qt-VERSION-macos-x86_64.zip` (Intel)
|
|
65
|
+
2. Extract the zip file
|
|
66
|
+
3. Move `pytodo-qt.app` to `/Applications` or `~/Applications`
|
|
67
|
+
4. **First run only:** Right-click the app and select "Open" to bypass Gatekeeper
|
|
68
|
+
- Alternatively, run: `xattr -rd com.apple.quarantine /Applications/pytodo-qt.app`
|
|
69
|
+
5. After the first run, you can open normally by double-clicking
|
|
70
|
+
|
|
71
|
+
> **Note:** The app is ad-hoc signed (not notarized with an Apple Developer ID), so macOS will show an "unidentified developer" warning on first launch. This is normal for open-source software distributed outside the App Store.
|
|
72
|
+
|
|
73
|
+
#### Linux
|
|
74
|
+
|
|
75
|
+
1. Download `pytodo-qt-VERSION-linux-x86_64.tar.gz` or `pytodo-qt-VERSION-linux-arm64.tar.gz`
|
|
76
|
+
2. Extract: `tar -xzf pytodo-qt-VERSION-linux-*.tar.gz`
|
|
77
|
+
3. Run the install script: `cd pytodo-qt-*/ && ./install.sh`
|
|
78
|
+
4. Or run directly: `./pytodo-qt`
|
|
79
|
+
|
|
80
|
+
The install script places the binary in `~/.local/bin/` and creates a desktop entry.
|
|
81
|
+
|
|
82
|
+
To uninstall: `~/.local/lib/pytodo-qt/uninstall.sh` (or run `./uninstall.sh` from the extracted archive)
|
|
83
|
+
|
|
84
|
+
#### Windows
|
|
85
|
+
|
|
86
|
+
1. Download `pytodo-qt-VERSION-windows-x86_64.zip`
|
|
87
|
+
2. Extract the zip file
|
|
88
|
+
3. Run `pytodo-qt.exe`
|
|
89
|
+
|
|
90
|
+
### From PyPI
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
pipx install pytodo-qt # recommended
|
|
94
|
+
pip install pytodo-qt # alternative
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### From source
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
git clone https://github.com/berrym/pytodo-qt.git
|
|
101
|
+
cd pytodo-qt
|
|
102
|
+
pip install .
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Development install
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
pip install -e ".[dev]"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Usage
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
pytodo-qt
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Command-line options
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
Server Options:
|
|
121
|
+
-s, --server {yes,no} enable/disable network server
|
|
122
|
+
--pull {yes,no} allow remote pull requests
|
|
123
|
+
--push {yes,no} allow remote push requests
|
|
124
|
+
-i, --ip IP server bind address
|
|
125
|
+
-p, --port PORT server port
|
|
126
|
+
|
|
127
|
+
Discovery Options:
|
|
128
|
+
-d, --discovery {yes,no} enable/disable mDNS discovery
|
|
129
|
+
|
|
130
|
+
Appearance Options:
|
|
131
|
+
-t, --theme {light,dark,system}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Configuration
|
|
135
|
+
|
|
136
|
+
Configuration is stored in XDG-compliant locations:
|
|
137
|
+
|
|
138
|
+
| Platform | Config | Data |
|
|
139
|
+
|----------|--------|------|
|
|
140
|
+
| Linux | `~/.config/pytodo-qt/` | `~/.local/share/pytodo-qt/` |
|
|
141
|
+
| macOS | `~/Library/Application Support/pytodo-qt/` | same |
|
|
142
|
+
| Windows | `%APPDATA%\pytodo-qt\` | same |
|
|
143
|
+
|
|
144
|
+
### config.toml
|
|
145
|
+
|
|
146
|
+
```toml
|
|
147
|
+
[database]
|
|
148
|
+
active_list = ""
|
|
149
|
+
sort_key = "priority"
|
|
150
|
+
reverse_sort = false
|
|
151
|
+
|
|
152
|
+
[server]
|
|
153
|
+
enabled = true
|
|
154
|
+
address = "0.0.0.0"
|
|
155
|
+
port = 5364
|
|
156
|
+
allow_pull = true
|
|
157
|
+
allow_push = true
|
|
158
|
+
|
|
159
|
+
[discovery]
|
|
160
|
+
enabled = true
|
|
161
|
+
service_name = "" # defaults to pytodo-{hostname}
|
|
162
|
+
|
|
163
|
+
[appearance]
|
|
164
|
+
theme = "system" # light, dark, system
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Synchronization
|
|
168
|
+
|
|
169
|
+
pytodo-qt uses a secure peer-to-peer protocol for syncing between instances:
|
|
170
|
+
|
|
171
|
+
1. **Discovery** - Instances advertise themselves via mDNS (`_pytodo._tcp.local.`)
|
|
172
|
+
2. **Key exchange** - Ed25519 identity keys with X25519 ephemeral session keys
|
|
173
|
+
3. **Encryption** - All data encrypted with AES-256-GCM
|
|
174
|
+
4. **Merge** - Last-write-wins conflict resolution with UUID-based items
|
|
175
|
+
|
|
176
|
+
Identity keys are stored in your system keyring (GNOME Keyring, macOS Keychain, Windows Credential Locker).
|
|
177
|
+
|
|
178
|
+
## Development
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
# Install dev dependencies
|
|
182
|
+
pip install -e ".[dev]"
|
|
183
|
+
|
|
184
|
+
# Run tests
|
|
185
|
+
pytest
|
|
186
|
+
|
|
187
|
+
# Lint and format
|
|
188
|
+
ruff check src/ tests/
|
|
189
|
+
ruff format src/ tests/
|
|
190
|
+
|
|
191
|
+
# Type check
|
|
192
|
+
basedpyright src/
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## License
|
|
196
|
+
|
|
197
|
+
GPLv3 or later. See [COPYING](COPYING) for details.
|
|
198
|
+
|
|
199
|
+
Copyright 2024 Michael Berry <trismegustis@gmail.com>
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# pytodo-qt
|
|
2
|
+
|
|
3
|
+
[](https://github.com/berrym/pytodo-qt/actions/workflows/ci.yml)
|
|
4
|
+
[](https://codecov.io/gh/berrym/pytodo-qt)
|
|
5
|
+
[](https://www.python.org/downloads/)
|
|
6
|
+
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
7
|
+
[](https://github.com/astral-sh/ruff)
|
|
8
|
+
[](https://github.com/psf/black)
|
|
9
|
+
|
|
10
|
+
A cross-platform to-do list manager with encrypted peer-to-peer synchronization.
|
|
11
|
+
|
|
12
|
+
## Features
|
|
13
|
+
|
|
14
|
+
- **Multiple lists** - Organize tasks into separate lists
|
|
15
|
+
- **Priority levels** - High, normal, and low priority with color coding
|
|
16
|
+
- **Encrypted sync** - AES-256-GCM encryption with Ed25519 key exchange
|
|
17
|
+
- **Auto-discovery** - Find other instances on your network via mDNS/Zeroconf
|
|
18
|
+
- **Dark/light themes** - System-following or manual theme selection
|
|
19
|
+
- **Cross-platform** - Linux, macOS, and Windows support
|
|
20
|
+
|
|
21
|
+
## Requirements
|
|
22
|
+
|
|
23
|
+
- Python 3.11 or later
|
|
24
|
+
- PyQt6
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
### Pre-built Binaries
|
|
29
|
+
|
|
30
|
+
Download the latest release for your platform from the [Releases page](https://github.com/berrym/pytodo-qt/releases).
|
|
31
|
+
|
|
32
|
+
#### macOS
|
|
33
|
+
|
|
34
|
+
1. Download `pytodo-qt-VERSION-macos-arm64.zip` (Apple Silicon) or `pytodo-qt-VERSION-macos-x86_64.zip` (Intel)
|
|
35
|
+
2. Extract the zip file
|
|
36
|
+
3. Move `pytodo-qt.app` to `/Applications` or `~/Applications`
|
|
37
|
+
4. **First run only:** Right-click the app and select "Open" to bypass Gatekeeper
|
|
38
|
+
- Alternatively, run: `xattr -rd com.apple.quarantine /Applications/pytodo-qt.app`
|
|
39
|
+
5. After the first run, you can open normally by double-clicking
|
|
40
|
+
|
|
41
|
+
> **Note:** The app is ad-hoc signed (not notarized with an Apple Developer ID), so macOS will show an "unidentified developer" warning on first launch. This is normal for open-source software distributed outside the App Store.
|
|
42
|
+
|
|
43
|
+
#### Linux
|
|
44
|
+
|
|
45
|
+
1. Download `pytodo-qt-VERSION-linux-x86_64.tar.gz` or `pytodo-qt-VERSION-linux-arm64.tar.gz`
|
|
46
|
+
2. Extract: `tar -xzf pytodo-qt-VERSION-linux-*.tar.gz`
|
|
47
|
+
3. Run the install script: `cd pytodo-qt-*/ && ./install.sh`
|
|
48
|
+
4. Or run directly: `./pytodo-qt`
|
|
49
|
+
|
|
50
|
+
The install script places the binary in `~/.local/bin/` and creates a desktop entry.
|
|
51
|
+
|
|
52
|
+
To uninstall: `~/.local/lib/pytodo-qt/uninstall.sh` (or run `./uninstall.sh` from the extracted archive)
|
|
53
|
+
|
|
54
|
+
#### Windows
|
|
55
|
+
|
|
56
|
+
1. Download `pytodo-qt-VERSION-windows-x86_64.zip`
|
|
57
|
+
2. Extract the zip file
|
|
58
|
+
3. Run `pytodo-qt.exe`
|
|
59
|
+
|
|
60
|
+
### From PyPI
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pipx install pytodo-qt # recommended
|
|
64
|
+
pip install pytodo-qt # alternative
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### From source
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
git clone https://github.com/berrym/pytodo-qt.git
|
|
71
|
+
cd pytodo-qt
|
|
72
|
+
pip install .
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Development install
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
pip install -e ".[dev]"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Usage
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
pytodo-qt
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Command-line options
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
Server Options:
|
|
91
|
+
-s, --server {yes,no} enable/disable network server
|
|
92
|
+
--pull {yes,no} allow remote pull requests
|
|
93
|
+
--push {yes,no} allow remote push requests
|
|
94
|
+
-i, --ip IP server bind address
|
|
95
|
+
-p, --port PORT server port
|
|
96
|
+
|
|
97
|
+
Discovery Options:
|
|
98
|
+
-d, --discovery {yes,no} enable/disable mDNS discovery
|
|
99
|
+
|
|
100
|
+
Appearance Options:
|
|
101
|
+
-t, --theme {light,dark,system}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Configuration
|
|
105
|
+
|
|
106
|
+
Configuration is stored in XDG-compliant locations:
|
|
107
|
+
|
|
108
|
+
| Platform | Config | Data |
|
|
109
|
+
|----------|--------|------|
|
|
110
|
+
| Linux | `~/.config/pytodo-qt/` | `~/.local/share/pytodo-qt/` |
|
|
111
|
+
| macOS | `~/Library/Application Support/pytodo-qt/` | same |
|
|
112
|
+
| Windows | `%APPDATA%\pytodo-qt\` | same |
|
|
113
|
+
|
|
114
|
+
### config.toml
|
|
115
|
+
|
|
116
|
+
```toml
|
|
117
|
+
[database]
|
|
118
|
+
active_list = ""
|
|
119
|
+
sort_key = "priority"
|
|
120
|
+
reverse_sort = false
|
|
121
|
+
|
|
122
|
+
[server]
|
|
123
|
+
enabled = true
|
|
124
|
+
address = "0.0.0.0"
|
|
125
|
+
port = 5364
|
|
126
|
+
allow_pull = true
|
|
127
|
+
allow_push = true
|
|
128
|
+
|
|
129
|
+
[discovery]
|
|
130
|
+
enabled = true
|
|
131
|
+
service_name = "" # defaults to pytodo-{hostname}
|
|
132
|
+
|
|
133
|
+
[appearance]
|
|
134
|
+
theme = "system" # light, dark, system
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Synchronization
|
|
138
|
+
|
|
139
|
+
pytodo-qt uses a secure peer-to-peer protocol for syncing between instances:
|
|
140
|
+
|
|
141
|
+
1. **Discovery** - Instances advertise themselves via mDNS (`_pytodo._tcp.local.`)
|
|
142
|
+
2. **Key exchange** - Ed25519 identity keys with X25519 ephemeral session keys
|
|
143
|
+
3. **Encryption** - All data encrypted with AES-256-GCM
|
|
144
|
+
4. **Merge** - Last-write-wins conflict resolution with UUID-based items
|
|
145
|
+
|
|
146
|
+
Identity keys are stored in your system keyring (GNOME Keyring, macOS Keychain, Windows Credential Locker).
|
|
147
|
+
|
|
148
|
+
## Development
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
# Install dev dependencies
|
|
152
|
+
pip install -e ".[dev]"
|
|
153
|
+
|
|
154
|
+
# Run tests
|
|
155
|
+
pytest
|
|
156
|
+
|
|
157
|
+
# Lint and format
|
|
158
|
+
ruff check src/ tests/
|
|
159
|
+
ruff format src/ tests/
|
|
160
|
+
|
|
161
|
+
# Type check
|
|
162
|
+
basedpyright src/
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## License
|
|
166
|
+
|
|
167
|
+
GPLv3 or later. See [COPYING](COPYING) for details.
|
|
168
|
+
|
|
169
|
+
Copyright 2024 Michael Berry <trismegustis@gmail.com>
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[tool.setuptools.packages.find]
|
|
6
|
+
where = ["src"]
|
|
7
|
+
|
|
8
|
+
[tool.setuptools.package-data]
|
|
9
|
+
pytodo_qt = ["*.png", "*.qss"]
|
|
10
|
+
"pytodo_qt.gui.icons" = ["*.png", "*.svg", "*.ico", "*.icns"]
|
|
11
|
+
"pytodo_qt.gui.styles" = ["*.qss"]
|
|
12
|
+
|
|
13
|
+
[tool.basedpyright]
|
|
14
|
+
typeCheckingMode = "standard"
|
|
15
|
+
pythonVersion = "3.11"
|
|
16
|
+
reportMissingImports = "warning"
|
|
17
|
+
reportMissingTypeStubs = false
|
|
18
|
+
|
|
19
|
+
[tool.ruff]
|
|
20
|
+
target-version = "py311"
|
|
21
|
+
line-length = 100
|
|
22
|
+
src = ["src", "tests"]
|
|
23
|
+
|
|
24
|
+
[tool.ruff.format]
|
|
25
|
+
quote-style = "double"
|
|
26
|
+
indent-style = "space"
|
|
27
|
+
skip-magic-trailing-comma = false
|
|
28
|
+
line-ending = "auto"
|
|
29
|
+
docstring-code-format = true
|
|
30
|
+
|
|
31
|
+
[tool.ruff.lint]
|
|
32
|
+
select = [
|
|
33
|
+
"E", # pycodestyle errors
|
|
34
|
+
"W", # pycodestyle warnings
|
|
35
|
+
"F", # Pyflakes
|
|
36
|
+
"I", # isort
|
|
37
|
+
"B", # flake8-bugbear
|
|
38
|
+
"C4", # flake8-comprehensions
|
|
39
|
+
"UP", # pyupgrade
|
|
40
|
+
"SIM", # flake8-simplify
|
|
41
|
+
]
|
|
42
|
+
ignore = [
|
|
43
|
+
"E501", # line too long (handled by formatter)
|
|
44
|
+
"SIM108", # allow if-else instead of ternary
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[tool.ruff.lint.isort]
|
|
48
|
+
known-first-party = ["pytodo_qt"]
|
|
49
|
+
|
|
50
|
+
[project]
|
|
51
|
+
name = "pytodo-qt"
|
|
52
|
+
version = "0.3.8"
|
|
53
|
+
description = "A cross-platform to-do list manager with encrypted peer-to-peer synchronization"
|
|
54
|
+
readme = "README.md"
|
|
55
|
+
authors = [
|
|
56
|
+
{name = "Michael Berry", email = "trismegustis@gmail.com"},
|
|
57
|
+
]
|
|
58
|
+
dependencies = [
|
|
59
|
+
"PyQt6>=6.4",
|
|
60
|
+
"cryptography>=41.0",
|
|
61
|
+
"zeroconf>=0.80",
|
|
62
|
+
"keyring>=24.0",
|
|
63
|
+
"qasync>=0.24",
|
|
64
|
+
"rich>=13.0",
|
|
65
|
+
]
|
|
66
|
+
classifiers = [
|
|
67
|
+
"Programming Language :: Python :: 3",
|
|
68
|
+
"Programming Language :: Python :: 3.11",
|
|
69
|
+
"Programming Language :: Python :: 3.12",
|
|
70
|
+
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
|
|
71
|
+
"Operating System :: OS Independent",
|
|
72
|
+
]
|
|
73
|
+
license = {text = "GPLv3"}
|
|
74
|
+
requires-python = ">=3.11"
|
|
75
|
+
|
|
76
|
+
[project.optional-dependencies]
|
|
77
|
+
dev = [
|
|
78
|
+
"pytest>=7.0",
|
|
79
|
+
"pytest-qt>=4.2",
|
|
80
|
+
"pytest-asyncio>=0.21",
|
|
81
|
+
"pytest-cov>=4.0",
|
|
82
|
+
"ruff>=0.4",
|
|
83
|
+
"basedpyright>=1.18",
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
[project.urls]
|
|
87
|
+
Homepage = "https://github.com/berrym/pytodo-qt"
|
|
88
|
+
|
|
89
|
+
[project.scripts]
|
|
90
|
+
pytodo-qt = "pytodo_qt.__main__:main"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""pytodo-qt - A modern cross-platform to-do application with secure sync.
|
|
2
|
+
|
|
3
|
+
Version 0.3.0 brings:
|
|
4
|
+
- AES-256-GCM authenticated encryption
|
|
5
|
+
- Ed25519/X25519 key exchange for secure connections
|
|
6
|
+
- UUID-based data model with Lamport timestamps
|
|
7
|
+
- Last-Write-Wins sync with conflict tracking
|
|
8
|
+
- Zeroconf/mDNS service discovery
|
|
9
|
+
- TOML configuration with system keyring integration
|
|
10
|
+
- Modern themed UI with light/dark/system mode support
|
|
11
|
+
|
|
12
|
+
Copyright (C) 2024 Michael Berry
|
|
13
|
+
License: GPLv3
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from .core.settings import __version__
|
|
17
|
+
|
|
18
|
+
__all__ = ["__version__"]
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"""__main__.py
|
|
2
|
+
|
|
3
|
+
pytodo-qt
|
|
4
|
+
|
|
5
|
+
A modern to-do list application with secure synchronization.
|
|
6
|
+
|
|
7
|
+
Copyright (C) 2024 Michael Berry <trismegustis@gmail.com>
|
|
8
|
+
|
|
9
|
+
This program is free software: you can redistribute it and/or modify
|
|
10
|
+
it under the terms of the GNU General Public License as published by
|
|
11
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
12
|
+
(at your option) any later version.
|
|
13
|
+
|
|
14
|
+
This program is distributed in the hope that it will be useful,
|
|
15
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
16
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
17
|
+
GNU General Public License for more details.
|
|
18
|
+
|
|
19
|
+
You should have received a copy of the GNU General Public License
|
|
20
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import argparse
|
|
24
|
+
import asyncio
|
|
25
|
+
import sys
|
|
26
|
+
|
|
27
|
+
from PyQt6.QtWidgets import QApplication
|
|
28
|
+
from qasync import QEventLoop
|
|
29
|
+
|
|
30
|
+
from .core import settings
|
|
31
|
+
from .core.logger import Logger
|
|
32
|
+
|
|
33
|
+
logger = Logger(__name__)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def main():
|
|
37
|
+
"""Application entry point."""
|
|
38
|
+
# Initialize configuration system
|
|
39
|
+
config = settings.init_config()
|
|
40
|
+
|
|
41
|
+
# Create command line argument parser
|
|
42
|
+
arg_parser = argparse.ArgumentParser(
|
|
43
|
+
prog="pytodo-qt",
|
|
44
|
+
description="Modern To-Do List Application with Secure Sync",
|
|
45
|
+
epilog="Copyright (C) 2024 Michael Berry",
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# Server options
|
|
49
|
+
server_group = arg_parser.add_argument_group("Server Options")
|
|
50
|
+
|
|
51
|
+
server_group.add_argument(
|
|
52
|
+
"-s",
|
|
53
|
+
"--server",
|
|
54
|
+
action="store",
|
|
55
|
+
type=str,
|
|
56
|
+
choices=["yes", "no"],
|
|
57
|
+
help="enable/disable network server",
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
server_group.add_argument(
|
|
61
|
+
"--pull",
|
|
62
|
+
action="store",
|
|
63
|
+
type=str,
|
|
64
|
+
choices=["yes", "no"],
|
|
65
|
+
help="allow remote pull requests",
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
server_group.add_argument(
|
|
69
|
+
"--push",
|
|
70
|
+
action="store",
|
|
71
|
+
type=str,
|
|
72
|
+
choices=["yes", "no"],
|
|
73
|
+
help="allow remote push requests",
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
server_group.add_argument(
|
|
77
|
+
"-i",
|
|
78
|
+
"--ip",
|
|
79
|
+
type=str,
|
|
80
|
+
help="server bind address",
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
server_group.add_argument(
|
|
84
|
+
"-p",
|
|
85
|
+
"--port",
|
|
86
|
+
type=int,
|
|
87
|
+
help="server port",
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# Discovery options
|
|
91
|
+
discovery_group = arg_parser.add_argument_group("Discovery Options")
|
|
92
|
+
|
|
93
|
+
discovery_group.add_argument(
|
|
94
|
+
"-d",
|
|
95
|
+
"--discovery",
|
|
96
|
+
action="store",
|
|
97
|
+
type=str,
|
|
98
|
+
choices=["yes", "no"],
|
|
99
|
+
help="enable/disable mDNS discovery",
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Appearance options
|
|
103
|
+
appearance_group = arg_parser.add_argument_group("Appearance Options")
|
|
104
|
+
|
|
105
|
+
appearance_group.add_argument(
|
|
106
|
+
"-t",
|
|
107
|
+
"--theme",
|
|
108
|
+
type=str,
|
|
109
|
+
choices=["light", "dark", "system"],
|
|
110
|
+
help="UI theme",
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# General options
|
|
114
|
+
arg_parser.add_argument(
|
|
115
|
+
"-V",
|
|
116
|
+
"--version",
|
|
117
|
+
action="version",
|
|
118
|
+
version=f"%(prog)s v{settings.__version__}",
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Parse arguments
|
|
122
|
+
args = arg_parser.parse_args()
|
|
123
|
+
|
|
124
|
+
# Apply command-line overrides to config
|
|
125
|
+
if args.server is not None:
|
|
126
|
+
config.server.enabled = args.server == "yes"
|
|
127
|
+
if args.pull is not None:
|
|
128
|
+
config.server.allow_pull = args.pull == "yes"
|
|
129
|
+
if args.push is not None:
|
|
130
|
+
config.server.allow_push = args.push == "yes"
|
|
131
|
+
if args.ip is not None:
|
|
132
|
+
config.server.address = args.ip
|
|
133
|
+
if args.port is not None:
|
|
134
|
+
config.server.port = args.port
|
|
135
|
+
if args.discovery is not None:
|
|
136
|
+
config.discovery.enabled = args.discovery == "yes"
|
|
137
|
+
if args.theme is not None:
|
|
138
|
+
config.appearance.theme = args.theme
|
|
139
|
+
|
|
140
|
+
# Create Qt application
|
|
141
|
+
app = QApplication(sys.argv)
|
|
142
|
+
app.setApplicationName("pytodo-qt")
|
|
143
|
+
app.setApplicationVersion(settings.__version__)
|
|
144
|
+
app.setOrganizationName("pytodo-qt")
|
|
145
|
+
|
|
146
|
+
# Set up async event loop with qasync
|
|
147
|
+
loop = QEventLoop(app)
|
|
148
|
+
asyncio.set_event_loop(loop)
|
|
149
|
+
|
|
150
|
+
# Apply theme
|
|
151
|
+
from .gui.styles import apply_current_theme
|
|
152
|
+
|
|
153
|
+
apply_current_theme()
|
|
154
|
+
|
|
155
|
+
# Create main window
|
|
156
|
+
logger.log.info("Starting pytodo-qt v%s", settings.__version__)
|
|
157
|
+
from .gui.main_window import MainWindow
|
|
158
|
+
|
|
159
|
+
_window = MainWindow() # noqa: F841 - window must stay alive for event loop
|
|
160
|
+
|
|
161
|
+
# Run application with async event loop
|
|
162
|
+
with loop:
|
|
163
|
+
sys.exit(loop.run_forever())
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
if __name__ == "__main__":
|
|
167
|
+
main()
|