Implement config file loader

Changes:

* Implement config file loader

* Add config-based database connector
This commit is contained in:
XANTRONIX 2025-04-03 21:47:45 -04:00
parent 86ca31b445
commit f40c1d14c6
9 changed files with 79 additions and 25 deletions

View file

@ -2,22 +2,24 @@
import argparse
from xmet.db import Database
from xmet.afos import AFOSMessageParser
from xmet.util import each_chunk
from xmet.config import Config
from xmet.db import Database
from xmet.afos import AFOSMessageParser
from xmet.util import each_chunk
parser = argparse.ArgumentParser(
description = 'Ingest National Weather Service text bulletin products'
)
parser.add_argument('--quiet', action='store_true', help='Suppress output')
parser.add_argument('--dry-run', action='store_true', help='Do not actually ingest products')
parser.add_argument('db', help='XMET SQLite3 database')
parser.add_argument('afos-text-file', help='AFOS text bulletin product file')
args = parser.parse_args()
db = Database.connect(args.db)
config = Config.load()
db = Database.from_config(config)
db.execute('begin transaction')
parser = AFOSMessageParser()

View file

@ -2,8 +2,9 @@
import argparse
from xmet.db import Database
from xmet.storm import StormEvent
from xmet.config import Config
from xmet.db import Database
from xmet.storm import StormEvent
parser = argparse.ArgumentParser(
description = 'Ingest events from StormEvent_details_*.csv.gz files'
@ -11,12 +12,12 @@ parser = argparse.ArgumentParser(
parser.add_argument('--quiet', action='store_true', help='Suppress output')
parser.add_argument('--dry-run', action='store_true', help='Do not actually ingest events')
parser.add_argument('db', help='XMET SQLite3 database')
parser.add_argument('csv-event-details', nargs='+', help='Compressed storm event details CSV file')
args = parser.parse_args()
db = Database.connect(args.db)
config = Config.load()
db = Database.from_config(config)
if not args.dry_run:
db.execute('begin transaction')

View file

@ -2,8 +2,9 @@
import argparse
from xmet.db import Database
from xmet.igra import IGRAReader
from xmet.config import Config
from xmet.db import Database
from xmet.igra import IGRAReader
parser = argparse.ArgumentParser(
description = 'Ingest IGRA soundings'
@ -17,7 +18,8 @@ parser.add_argument('igra-sounding-file', nargs='+', help='IGRA sounding file')
args = parser.parse_args()
db = Database.connect(args.db)
config = Config.load()
db = Database.from_config(config)
if not args.dry_run:
db.execute('begin transaction')

View file

@ -2,6 +2,7 @@
import argparse
from xmet.config import Config
from xmet.db import Database
from xmet.s3 import S3Bucket
from xmet.storm import StormEvent
@ -18,13 +19,13 @@ group = parser.add_mutually_exclusive_group()
group.add_argument('--exclude', action='append', type=str, help='Exclude types of events from ingest')
group.add_argument('--type', action='append', type=str, help='Specify only given types of events to ingest')
parser.add_argument('db', help='XMET SQLite3 database')
parser.add_argument('csv-event-details', nargs='+', help='Compressed storm event details CSV file')
parser.add_argument('archive-dir', help='Target archive directory')
args = parser.parse_args()
db = Database.connect(args.db)
config = Config.load()
db = Database.from_config(config)
bucket = S3Bucket()
archive = Archive(getattr(args, 'archive-dir'), bucket)
exclude = None

View file

@ -2,9 +2,10 @@
import argparse
from xmet.db import Database
from xmet.raob import RAOBReader
from xmet.igra import IGRAStation
from xmet.config import Config
from xmet.db import Database
from xmet.raob import RAOBReader
from xmet.igra import IGRAStation
parser = argparse.ArgumentParser(
description = 'Ingest RAOB soundings'
@ -13,12 +14,12 @@ parser = argparse.ArgumentParser(
parser.add_argument('--quiet', action='store_true', help='Suppress output')
parser.add_argument('--dry-run', action='store_true', help='Do not actually ingest data')
parser.add_argument('db', help='XMET SQLite3 database')
parser.add_argument('raob-sounding-file', nargs='+', help='RAOB sounding file')
args = parser.parse_args()
db = Database.connect(args.db)
config = Config.load()
db = Database.from_config(config)
if not args.dry_run:
db.execute('begin transaction')

View file

@ -4,6 +4,7 @@ import argparse
import cairo
import shapely
from xmet.config import Config
from xmet.db import Database
from xmet.sounding import Sounding
from xmet.skew_t import SkewTGraph, SkewTLegend
@ -60,14 +61,14 @@ parser = argparse.ArgumentParser(
parser.add_argument('--skew-t', type=str, help='Plot a Skew-T chart to the specified SVG file')
parser.add_argument('--hodograph', type=str, help='Plot a hodograph to the specified SVG file')
parser.add_argument('db', help='XMET SQLite3 database')
parser.add_argument('lat', help='Latitude')
parser.add_argument('lon', help='Longitude')
parser.add_argument('timestamp', help='Timestamp in YYYY-MM-DD HH:MM:SS (UTC)')
args = parser.parse_args()
db = Database.connect(args.db)
config = Config.load()
db = Database.from_config(config)
location = shapely.Point(float(args.lon), float(args.lat))
sounding = Sounding.valid_by_location(db, location, args.timestamp)

View file

@ -3,7 +3,8 @@
import argparse
import cairo
from xmet.db import Database
from xmet.config import Config
from xmet.db import Database
from xmet.spc import SPCOutlookParser, \
SPCOutlook, \
@ -25,7 +26,8 @@ ASSETS = {
def render_categorical(conus: SPCOutlookMap,
outlook: SPCOutlook,
args):
db = Database.connect(args.db)
config = Config.load()
db = Database.from_config(config)
assets = ASSETS['dark'] if args.dark else ASSETS['light']
@ -48,7 +50,8 @@ def render_probabilistic(conus: SPCOutlookMap,
hazard: str,
path: str,
args):
db = Database.connect(args.db)
config = Config.load()
db = Database.from_config(config)
assets = ASSETS['dark'] if args.dark else ASSETS['light']
@ -69,7 +72,6 @@ def render_probabilistic(conus: SPCOutlookMap,
conus.draw_annotation(cr, outlook, SPCOutlookType.PROBABILISTIC, hazard)
argparser = argparse.ArgumentParser(description='Render graphical SPC outlooks from text file')
argparser.add_argument('db', help='Spatialite database file')
argparser.add_argument('--dark', action='store_true', help='Output dark mode graphics')
argparser.add_argument('--categorical', type=str, help='Output categorical risk graphic file')
argparser.add_argument('--any-severe', type=str, help='Output probabilistic severe risk graphic file')

36
lib/xmet/config.py Normal file
View file

@ -0,0 +1,36 @@
import os
import configparser
from typing import Optional, Self
class ConfigException(Exception):
...
class ConfigFileException(ConfigException):
...
class Config(configparser.ConfigParser):
SEARCH_PATHS = (
'./xmet.conf',
os.environ['HOME'] + '/.xmet.conf',
'/etc/xmet/xmet.conf',
)
@staticmethod
def find() -> str:
for path in Config.SEARCH_PATHS:
if os.path.isfile(path):
return path
@staticmethod
def load(path: Optional[str]=None) -> Self:
if path is None:
path = Config.find()
if path is None:
raise ConfigFileException("Could not locate xmet configuration file")
config = Config()
config.read(path)
return config

View file

@ -1,6 +1,10 @@
import enum
import sqlite3
from typing import Self
from xmet.config import Config
class DatabaseOrder(enum.Enum):
DEFAULT = 0
ASC = 1
@ -112,6 +116,10 @@ class Database():
return Database(db)
@staticmethod
def from_config(config: Config) -> Self:
return Database.connect(config['database']['path'])
def column_placeholders(self, table, obj) -> list:
ret = list()