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:
parent
44fe6a28a2
commit
751a7ad9e5
5 changed files with 59 additions and 17 deletions
|
@ -12,6 +12,7 @@ Status information is stored in a SQLite database.
|
||||||
- [Austrian Post](https://www.post.at)
|
- [Austrian Post](https://www.post.at)
|
||||||
- [GLS](https://gls-group.eu)
|
- [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))
|
- [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!
|
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
|
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 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.
|
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.
|
||||||
|
|
|
@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "trackbert"
|
name = "trackbert"
|
||||||
version = "0.2.1"
|
version = "0.2.2"
|
||||||
authors = [
|
authors = [
|
||||||
{ name="Kumi Mitterer", email="trackbert@kumi.email" },
|
{ name="Kumi Mitterer", email="trackbert@kumi.email" },
|
||||||
]
|
]
|
||||||
|
|
|
@ -6,13 +6,18 @@ import subprocess
|
||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from typing import Tuple, Never, Optional
|
from typing import Tuple, Never, Optional
|
||||||
|
|
||||||
from .classes.database import Database
|
from .classes.database import Database
|
||||||
from .classes.tracker import Tracker
|
from .classes.tracker import Tracker
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
|
|
||||||
|
# Arguments related to the tracker
|
||||||
|
|
||||||
parser.add_argument("--tracking-number", "-n", type=str, required=False)
|
parser.add_argument("--tracking-number", "-n", type=str, required=False)
|
||||||
parser.add_argument("--carrier", "-c", type=str, required=False)
|
parser.add_argument("--carrier", "-c", type=str, required=False)
|
||||||
parser.add_argument("--description", "-d", type=str, required=False)
|
parser.add_argument("--description", "-d", type=str, required=False)
|
||||||
|
@ -30,17 +35,37 @@ def main():
|
||||||
required=False,
|
required=False,
|
||||||
help="Disable existing shipment",
|
help="Disable existing shipment",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
|
||||||
"--timeout",
|
# Arguments related to the config file
|
||||||
"-t",
|
|
||||||
type=int,
|
parser.add_argument("--generate-config", action="store_true", required=False)
|
||||||
required=False,
|
parser.add_argument("--config-file", "-C", type=str, required=False)
|
||||||
default=30,
|
|
||||||
help="Notification timeout in seconds",
|
|
||||||
)
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
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")
|
db = Database("sqlite:///trackbert.db")
|
||||||
|
|
||||||
if args.tracking_number is not None and args.carrier is not None:
|
if args.tracking_number is not None and args.carrier is not None:
|
||||||
|
@ -76,5 +101,6 @@ def main():
|
||||||
tracker = Tracker()
|
tracker = Tracker()
|
||||||
asyncio.run(tracker.start_async())
|
asyncio.run(tracker.start_async())
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -3,8 +3,11 @@ import subprocess
|
||||||
import time
|
import time
|
||||||
import importlib
|
import importlib
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional, Tuple, Never
|
from typing import Optional, Tuple, Never
|
||||||
|
from os import PathLike
|
||||||
|
from configparser import ConfigParser
|
||||||
|
|
||||||
from .database import Database
|
from .database import Database
|
||||||
from ..trackers.base import BaseTracker
|
from ..trackers.base import BaseTracker
|
||||||
|
@ -46,7 +49,7 @@ class Tracker:
|
||||||
for carrier, priority in carriers:
|
for carrier, priority in carriers:
|
||||||
self.apis.append((carrier, priority, api))
|
self.apis.append((carrier, priority, api))
|
||||||
except:
|
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:
|
def query_api(self, tracking_number: str, carrier: str) -> list:
|
||||||
logging.debug(f"Querying API for {tracking_number} with carrier {carrier}")
|
logging.debug(f"Querying API for {tracking_number} with carrier {carrier}")
|
||||||
|
@ -173,12 +176,20 @@ class Tracker:
|
||||||
|
|
||||||
await asyncio.sleep(self.loop_interval)
|
await asyncio.sleep(self.loop_interval)
|
||||||
|
|
||||||
def start(self):
|
def _pre_start(self, config: Optional[PathLike] = None):
|
||||||
self.db = Database("sqlite:///trackbert.db")
|
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")
|
self.notify("Trackbert", "Starting up")
|
||||||
|
|
||||||
|
def start(self, config: Optional[PathLike] = None):
|
||||||
|
self._pre_start(config)
|
||||||
self.start_loop()
|
self.start_loop()
|
||||||
|
|
||||||
async def start_async(self):
|
async def start_async(self, config: Optional[PathLike] = None):
|
||||||
self.db = Database("sqlite:///trackbert.db")
|
self._pre_start(config)
|
||||||
self.notify("Trackbert", "Starting up")
|
await self.start_loop_async()
|
||||||
await self.start_loop_async()
|
|
Loading…
Reference in a new issue