Endelig 1

This commit is contained in:
2026-04-03 01:04:29 +02:00
parent 60fb674c8d
commit 4f27849fd3
3 changed files with 51 additions and 25 deletions

View File

@@ -15,24 +15,27 @@ ETL-værktøj til udtræk og transformation af semistrukturerede data (JSON og X
## Projektstruktur ## Projektstruktur
``` ```
udpak_semistruktur/ uudpak_semistruktur/
├── udpak_semistruktur/ # Python-pakken ├── udpak_semistruktur/ # Python-pakken
│ ├── extract/ # Filindlæsning og JSON/XML-traversering │ ├── extract/ # Filindlæsning og JSON/XML-traversering
│ │ ├── reader.py # Filindlæsning, type- og encoding-detektion │ │ ├── reader.py # Filindlæsning, type- og encoding-detektion
│ │ ── traversal.py # Rekursiv stibaseret udtræk │ │ ── traversal.py # Rekursiv stibaseret navigation i JSON/XML
── transform/ # Datatransformation │ └── extractor.py # Udtræk af rækker baseret på YAML-konfiguration
│ ├── convert.py # Typekonvertering (dato, tal, boolean m.m.) │ ├── transform/ # Datatransformation
│ │ ├── clean.py # Rensning, linjeskift, tag-stripping, case │ │ ├── convert.py # Typekonvertering (dato, tal, boolean m.m.)
│ │ ── reshape.py # Flatten, join, where-filter, id-felt │ │ ── clean.py # Rensning, linjeskift, tag-stripping, case, filnavn
│ ├── load/ # Skrivning til fil og database │ ├── reshape.py # Flatten, join, where-filter, id-felt, sammensat nøgle
│ │ ── file_writer.py # CSV/TSV-skrivning med retry │ │ ── hash.py # Hash-beregning af kolonneværdier
│ └── db_writer.py # Sybase ASE insert via ODBC ├── load/ # Skrivning til fil og database
│ ├── config.py # YAML-konfigurationshåndtering og -validering │ ├── file_writer.py # CSV/TSV-skrivning med retry ved låste filer
├── db.py # Databaseforbindelse og credentials │ └── db_writer.py # Sybase ASE insert via ODBC
│ ├── ddl.py # DDL-generering og flyt-scripts til Sybase ASE │ ├── config.py # YAML-indlæsning, validering og expansion
── utils.py # Fælles hjælpefunktioner ── db.py # Credentials fra pwd.json
├── tests/ # Unit tests │ ├── ddl.py # DDL-generering og flyt-scripts til Sybase ASE
├── udpak_semistruktur.py # CLI entry point │ ├── logger.py # Central logging med konfigurerbart logniveau
│ └── utils.py # Fælles hjælpefunktioner
├── tests/ # Unit tests
├── udpak_semistruktur.py # CLI entry point
├── requirements.txt ├── requirements.txt
└── README.md └── README.md
``` ```
@@ -53,10 +56,11 @@ pip install -r requirements.txt
## Brug ## Brug
```bash ```bash
python udpak_semistruktur.py --config min_config.yaml --input data.json python udpak_semistruktur.py --config min_config.yaml
python udpak_semistruktur.py --config min_config.yaml --input-liste filer.txt python udpak_semistruktur.py --config min_config.yaml --DDL
python udpak_semistruktur.py --config min_config.yaml --input data.xml --DDL python udpak_semistruktur.py --config min_config.yaml --DDL --tmp
python udpak_semistruktur.py --config min_config.yaml --input data.json --DDL --flyt python udpak_semistruktur.py --config min_config.yaml --DDL --flyt
python udpak_semistruktur.py --config min_config.yaml --DDL --flyt_kort
``` ```
### Vigtigste flag ### Vigtigste flag
@@ -64,8 +68,6 @@ python udpak_semistruktur.py --config min_config.yaml --input data.json --DDL --
| Flag | Beskrivelse | | Flag | Beskrivelse |
|---|---| |---|---|
| `--config` | Sti til YAML-konfigurationsfil | | `--config` | Sti til YAML-konfigurationsfil |
| `--input` | Sti til enkelt input-fil (JSON eller XML) |
| `--input-liste` | Sti til tekstfil med én input-fil per linje |
| `--DDL` | Generer CREATE TABLE DDL-filer | | `--DDL` | Generer CREATE TABLE DDL-filer |
| `--tmp` | Generer også `_tmp`-tabelvariant ved DDL | | `--tmp` | Generer også `_tmp`-tabelvariant ved DDL |
| `--flyt` | Generer DELETE + INSERT flyt-scripts (fuld kolonteliste) | | `--flyt` | Generer DELETE + INSERT flyt-scripts (fuld kolonteliste) |

View File

@@ -1,3 +1,4 @@
import sys
import argparse import argparse
from udpak_semistruktur.config import valider_yaml from udpak_semistruktur.config import valider_yaml
@@ -13,7 +14,7 @@ from udpak_semistruktur.transform.hash import beregn_hash
from udpak_semistruktur.load.file_writer import generer_filer_med_overskrifter, skriv_fil_med_retry from udpak_semistruktur.load.file_writer import generer_filer_med_overskrifter, skriv_fil_med_retry
from udpak_semistruktur.load.db_writer import get_ase_connection_windows, insert_rows_ase from udpak_semistruktur.load.db_writer import get_ase_connection_windows, insert_rows_ase
from udpak_semistruktur.db import læs_json_fil from udpak_semistruktur.db import læs_json_fil
from udpak_semistruktur.utils import generer_filnavn from udpak_semistruktur.utils import generer_filnavn, load_env_file
logger = hent_logger(__name__) logger = hent_logger(__name__)
@@ -103,6 +104,11 @@ def _kør_udtræk(config: dict, global_config: dict) -> None:
def main(): def main():
"""Hovedfunktion der eksekveres ved kørsel af scriptet.""" """Hovedfunktion der eksekveres ved kørsel af scriptet."""
# Indlæs lokal .env under udvikling springes over i kompileret .exe
if not getattr(sys, "frozen", False):
load_env_file("testenv.env")
parser = _byg_argument_parser() parser = _byg_argument_parser()
args = parser.parse_args() args = parser.parse_args()

View File

@@ -2,6 +2,9 @@ import os
import re import re
from typing import Any from typing import Any
from udpak_semistruktur.logger import hent_logger
logger = hent_logger(__name__)
EMPTY_SENTINELS = (None, "", [], {}) EMPTY_SENTINELS = (None, "", [], {})
@@ -51,3 +54,18 @@ def parse_value_token(value: Any) -> tuple[str, Any]:
return "prog", prog_match.group(1) return "prog", prog_match.group(1)
return "const", value return "const", value
def load_env_file(filepath: str) -> None:
"""Indlæser miljøvariabler fra en .env-fil. Bruges kun under udvikling."""
if not os.path.exists(filepath):
logger.debug(f"{filepath} blev ikke fundet springer over.")
return
with open(filepath, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line or line.startswith("#"):
continue
if "=" in line:
key, value = line.split("=", 1)
os.environ[key.strip()] = value.strip()