Update version to 0.2.2, add DHL tracking provider, and improve config file generation and loading

- Change version in pyproject.toml to 0.2.2
- Add DHL tracking provider to README.md
- Update README.md with instructions for generating a config file
- Improve config file generation in __main__.py
- Load config file in Tracker class
- Update start and start_async methods in Tracker class to accept an optional config file path
This commit is contained in:
Kumi 2023-08-29 18:58:32 +02:00
parent 44fe6a28a2
commit 751a7ad9e5
Signed by: kumi
GPG key ID: ECBCC9082395383F
5 changed files with 59 additions and 17 deletions

View file

@ -12,6 +12,7 @@ Status information is stored in a SQLite database.
- [Austrian Post](https://www.post.at)
- [GLS](https://gls-group.eu)
- [FedEx](https://www.fedex.com) (requires an API key, see [FedEx Developer Resource Center](https://www.fedex.com/en-us/developer.html))
- [DHL](https://www.dhl.com) (requires an API key, see [DHL Developer Portal](https://developer.dhl.com/))
More tracking providers can be added easily by subclassing `trackbert.trackers.base.BaseTracker`. This should be relatively self-explanatory if you look at the existing implementations. Pull requests are welcome!
@ -43,6 +44,10 @@ First, assure that the virtual environment is activated:
source venv/bin/activate
```
If you need to create a new config file, run `trackbert -g`. You need this if
you want to provide API keys required for KeyDelivery or some of the other
tracking providers.
To add a new shipment, run `trackbert --tracking-number <tracking-number> --carrier <carrier-id>`. Find the required carrier ID in the [KeyDelivery API management](https://app.kd100.com/api-management).
To run the main loop, run `trackbert`. This will check the status of all shipments every 5 minutes, and print the status to the console. If the status of a shipment changes, you will get a desktop notification.

View file

@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "trackbert"
version = "0.2.1"
version = "0.2.2"
authors = [
{ name="Kumi Mitterer", email="trackbert@kumi.email" },
]

View file

@ -6,13 +6,18 @@ import subprocess
import argparse
import logging
import asyncio
from typing import Tuple, Never, Optional
from .classes.database import Database
from .classes.tracker import Tracker
def main():
parser = argparse.ArgumentParser()
# Arguments related to the tracker
parser.add_argument("--tracking-number", "-n", type=str, required=False)
parser.add_argument("--carrier", "-c", type=str, required=False)
parser.add_argument("--description", "-d", type=str, required=False)
@ -30,17 +35,37 @@ def main():
required=False,
help="Disable existing shipment",
)
parser.add_argument(
"--timeout",
"-t",
type=int,
required=False,
default=30,
help="Notification timeout in seconds",
)
# Arguments related to the config file
parser.add_argument("--generate-config", action="store_true", required=False)
parser.add_argument("--config-file", "-C", type=str, required=False)
args = parser.parse_args()
# Generate config file if requested
config_file = Path(args.config_file or "config.ini")
if args.generate_config:
if config_file.exists():
print(f"Config file {config_file} already exists.")
exit(1)
with Path(config_file).open("w") as config_file_obj:
template = Path(__file__).parent / "config.dist.ini"
config_file_obj.write(template.read_text())
print(f"Generated config file {config_file}")
exit(0)
# Load config file
if not config_file.exists():
print(f"Config file {config_file} does not exist. Use -g to generate it.")
exit(1)
db = Database("sqlite:///trackbert.db")
if args.tracking_number is not None and args.carrier is not None:
@ -76,5 +101,6 @@ def main():
tracker = Tracker()
asyncio.run(tracker.start_async())
if __name__ == "__main__":
main()

View file

@ -3,8 +3,11 @@ import subprocess
import time
import importlib
import asyncio
from pathlib import Path
from typing import Optional, Tuple, Never
from os import PathLike
from configparser import ConfigParser
from .database import Database
from ..trackers.base import BaseTracker
@ -46,7 +49,7 @@ class Tracker:
for carrier, priority in carriers:
self.apis.append((carrier, priority, api))
except:
logging.exception(f"Error loading tracker {name}")
logging.exception(f"Error loading tracker {api.stem}")
def query_api(self, tracking_number: str, carrier: str) -> list:
logging.debug(f"Querying API for {tracking_number} with carrier {carrier}")
@ -173,12 +176,20 @@ class Tracker:
await asyncio.sleep(self.loop_interval)
def start(self):
self.db = Database("sqlite:///trackbert.db")
def _pre_start(self, config: Optional[PathLike] = None):
parser = ConfigParser()
parser.read(config or [])
self.database_uri = parser.get("Trackbert", "database", fallback="sqlite:///trackbert.db")
self.db = Database(self.database_uri)
self.loop_interval = parser.getint("Trackbert", "interval", fallback=60)
self.notify("Trackbert", "Starting up")
def start(self, config: Optional[PathLike] = None):
self._pre_start(config)
self.start_loop()
async def start_async(self):
self.db = Database("sqlite:///trackbert.db")
self.notify("Trackbert", "Starting up")
async def start_async(self, config: Optional[PathLike] = None):
self._pre_start(config)
await self.start_loop_async()