Endelig 1
This commit is contained in:
50
README.md
50
README.md
@@ -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) |
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
Reference in New Issue
Block a user