Skip to content

Commit 489e6aa

Browse files
committed
refactor(ducklake): implement abstract classes on the ducklake api classes
1 parent 17f431a commit 489e6aa

11 files changed

Lines changed: 114 additions & 92 deletions

File tree

pysus/api/dadosgov/databases.py

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,18 @@ class CNES(Dataset):
1919
"9455b341-b06e-408e-8e10-54b32b3d74ec",
2020
)
2121

22-
def describe(self, file: Resource): ...
22+
def describe(self, file: Resource):
23+
...
2324

24-
def format(self, file: Resource) -> tuple: ...
25+
def format(self, file: Resource) -> tuple:
26+
...
2527

2628
def get_files(
2729
self,
2830
year: Optional[Union[list, str, int]] = None,
2931
month: Optional[Union[list, str, int]] = None,
30-
) -> List[Resource]: ...
32+
) -> List[Resource]:
33+
...
3134

3235

3336
class PNI(Dataset):
@@ -42,32 +45,38 @@ class PNI(Dataset):
4245
"9a25b796-80e3-444a-a4e7-405f5596d8ab",
4346
)
4447

45-
def describe(self, file: Resource): ...
48+
def describe(self, file: Resource):
49+
...
4650

47-
def format(self, file: Resource) -> tuple: ...
51+
def format(self, file: Resource) -> tuple:
52+
...
4853

4954
def get_files(
5055
self,
5156
year: Optional[Union[list, str, int]] = None,
5257
month: Optional[Union[list, str, int]] = None,
53-
) -> List[Resource]: ...
58+
) -> List[Resource]:
59+
...
5460

5561

5662
class SIA(Dataset):
5763
name = "SIA"
5864
ids = ("9a335cb7-2b4f-4fce-8947-e8441b4a90af",)
5965

60-
def describe(self, file: Resource): ...
66+
def describe(self, file: Resource):
67+
...
6168

62-
def format(self, file: Resource) -> tuple: ...
69+
def format(self, file: Resource) -> tuple:
70+
...
6371

6472
def get_files(
6573
self,
6674
group: Union[List[str], str],
6775
uf: Optional[Union[List[str], str]] = None,
6876
year: Optional[Union[list, str, int]] = None,
6977
month: Optional[Union[list, str, int]] = None,
70-
) -> List[Resource]: ...
78+
) -> List[Resource]:
79+
...
7180

7281

7382
class SINAN(Dataset):
@@ -79,12 +88,15 @@ class SINAN(Dataset):
7988
"740ce8f4-7a5d-4351-aad4-7623f2490ada",
8089
)
8190

82-
def describe(self, file: Resource): ...
91+
def describe(self, file: Resource):
92+
...
8393

84-
def format(self, file: Resource) -> tuple: ...
94+
def format(self, file: Resource) -> tuple:
95+
...
8596

8697
def get_files(
8798
self,
8899
dis_code: Optional[Union[str, list]] = None,
89100
year: Optional[Union[str, int, list]] = None,
90-
) -> List[Resource]: ...
101+
) -> List[Resource]:
102+
...

pysus/api/dadosgov/models.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
1-
import zipfile
21
import pathlib
3-
import httpx
4-
import anyio
2+
import zipfile
53
from datetime import datetime as dt
64
from typing import Annotated, Any, List, Optional
75

8-
from pydantic import BaseModel, BeforeValidator, Field, ConfigDict
9-
from pysus.api.models import (
10-
BaseRemoteFile,
11-
BaseRemoteDataset,
12-
)
6+
import anyio
7+
import httpx
8+
from pydantic import BaseModel, BeforeValidator, ConfigDict, Field
9+
from pysus.api.models import BaseRemoteDataset, BaseRemoteFile
1310

1411

1512
def to_datetime(value: Any) -> Optional[dt]:
@@ -112,7 +109,9 @@ def describe(self, resource: Resource):
112109
group=self.slug,
113110
year=0,
114111
size=resource.api_size,
115-
last_update=resource.last_modified or self.file_updated or dt.now(),
112+
last_update=resource.last_modified
113+
or self.file_updated
114+
or dt.now(),
116115
uf=None,
117116
month=None,
118117
disease=self.title,

pysus/api/ducklake/catalog.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
Index,
1010
Integer,
1111
String,
12+
Table,
1213
)
1314
from sqlalchemy.orm import declarative_base, relationship
14-
from sqlalchemy import Table
1515

1616
Base = declarative_base()
1717

pysus/api/ducklake/client.py

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
1-
from typing import Optional, Any, List
21
from pathlib import Path
3-
import httpx
4-
import duckdb
2+
from typing import Any, List, Optional
53

64
import anyio
75
import boto3
6+
import duckdb
7+
import httpx
88
from botocore.config import Config
9+
from pydantic import BaseModel, PrivateAttr, SecretStr
10+
from pysus import CACHEPATH
11+
from pysus.api.models import BaseLocalFile, BaseRemoteClient
912
from sqlalchemy import create_engine
10-
from sqlalchemy.orm import sessionmaker, joinedload
11-
from pydantic import PrivateAttr, SecretStr, BaseModel
13+
from sqlalchemy.orm import joinedload, sessionmaker
1214

13-
from pysus import CACHEPATH
14-
from pysus.api.models import (
15-
BaseLocalFile,
16-
BaseRemoteClient,
17-
)
18-
from .models import CatalogDataset, CatalogFile
1915
from .catalog import Dataset, DatasetGroup
16+
from .models import CatalogDataset, CatalogFile
2017

2118

2219
class DuckLakeCredentials(BaseModel):
@@ -63,7 +60,8 @@ def _fetch():
6360
.options(
6461
joinedload(Dataset.dataset_metadata),
6562
joinedload(Dataset.groups).joinedload(
66-
DatasetGroup.files),
63+
DatasetGroup.files
64+
),
6765
)
6866
.all()
6967
)
@@ -90,7 +88,9 @@ async def login(
9088
self._con = await anyio.to_thread.run_sync(self._create_connection)
9189

9290
if self._is_authenticated:
93-
self._s3_client = await anyio.to_thread.run_sync(self._get_s3_client)
91+
self._s3_client = await anyio.to_thread.run_sync(
92+
self._get_s3_client
93+
)
9494

9595
async def connect(self, force: bool = False):
9696
if self._con and not force:
@@ -191,23 +191,28 @@ def _create_connection(self):
191191
}
192192

193193
if self._is_authenticated:
194-
s3_cfg["s3_access_key_id"] = self.credentials.access_key.get_secret_value()
195-
s3_cfg["s3_secret_access_key"] = (
196-
self.credentials.secret_key.get_secret_value()
197-
)
194+
s3_cfg[
195+
"s3_access_key_id"
196+
] = self.credentials.access_key.get_secret_value()
197+
s3_cfg[
198+
"s3_secret_access_key"
199+
] = self.credentials.secret_key.get_secret_value()
198200

199201
for key, value in s3_cfg.items():
200202
con.execute(f"SET {key}='{value}';")
201203

202204
mode = "" if self._is_authenticated else "(READ_ONLY)"
203-
con.execute(f"ATTACH 'ducklake:{self._catalog_local}' AS pysus {mode};")
205+
con.execute(
206+
f"ATTACH 'ducklake:{self._catalog_local}' AS pysus {mode};"
207+
)
204208
con.execute("USE pysus;")
205209
return con
206210

207211
async def _upload_catalog(self):
208212
if not self._is_authenticated:
209213
raise PermissionError(
210-
"Admin credentials required to upload catalog.")
214+
"Admin credentials required to upload catalog."
215+
)
211216

212217
def _upload():
213218
self._s3_client.upload_file(

pysus/api/ducklake/models.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
import hashlib
2-
from typing import List, Optional, Union
32
from datetime import datetime
43
from pathlib import Path
4+
from typing import List, Optional, Union
55

66
import anyio
77
from pydantic import Field
8-
98
from pysus.api.models import (
109
BaseRemoteClient,
11-
BaseRemoteGroup,
12-
BaseRemoteFile,
1310
BaseRemoteDataset,
11+
BaseRemoteFile,
12+
BaseRemoteGroup,
1413
)
15-
from .catalog import File, Dataset, DatasetGroup
14+
15+
from .catalog import Dataset, DatasetGroup, File
1616

1717

1818
class CatalogFile(BaseRemoteFile):
@@ -86,7 +86,9 @@ def long_name(self) -> str:
8686
@property
8787
def description(self) -> str:
8888
return (
89-
self.record.group_metadata.description if self.record.group_metadata else ""
89+
self.record.group_metadata.description
90+
if self.record.group_metadata
91+
else ""
9092
)
9193

9294
async def files(self, **kwargs) -> List[CatalogFile]:
@@ -118,7 +120,9 @@ def description(self) -> str:
118120
)
119121

120122
async def groups(self) -> List[CatalogGroup]:
121-
return [CatalogGroup(record=g, dataset=self) for g in self.record.groups]
123+
return [
124+
CatalogGroup(record=g, dataset=self) for g in self.record.groups
125+
]
122126

123127
async def files(self, **kwargs) -> List[CatalogFile]:
124128
return [CatalogFile(record=f, parent=self) for f in self.record.files]

pysus/api/extensions.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,21 @@
88
from pathlib import Path
99
from typing import AsyncGenerator, Dict, List, Optional, Type, Union
1010

11-
from pydantic import Field
1211
import anyio
1312
import chardet
1413
import fastparquet
1514
import magic
1615
import pandas as pd
1716
import pyarrow.parquet as pq
18-
17+
from pydantic import Field
1918
from pysus import CACHEPATH
20-
from pysus.api.models import (
21-
BaseCompressedFile,
22-
BaseLocalFile,
23-
BaseTabularFile,
24-
)
19+
from pysus.api.models import BaseCompressedFile, BaseLocalFile, BaseTabularFile
20+
2521
from .types import FileType
2622

2723
try:
28-
from pyreaddbc import read_dbc, dbc2dbf
2924
from dbfread import DBF as DBFReader
25+
from pyreaddbc import dbc2dbf, read_dbc
3026

3127
FTP_IMPORT = True
3228
except ImportError:

pysus/api/ftp/models.py

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,13 @@
99
from ftplib import FTP
1010
from typing import Any, Dict, List, Optional, Tuple, TypedDict, Union
1111

12-
from typing_extensions import Self
1312
from aioftp import Client
1413
from loguru import logger
15-
from tqdm import tqdm
16-
1714
from pysus import CACHEPATH
18-
from pysus.api.models import (
19-
BaseRemoteFile,
20-
BaseRemoteDataset,
21-
)
15+
from pysus.api.models import BaseRemoteDataset, BaseRemoteFile
2216
from pysus.utils import to_list
17+
from tqdm import tqdm
18+
from typing_extensions import Self
2319

2420
from .client import FTPSingleton
2521

@@ -274,13 +270,17 @@ def load_directory_content(path: str) -> FileContent:
274270
def line_parser(line: str):
275271
if "<DIR>" in line:
276272
date, time, _, name = line.strip().split(maxsplit=3)
277-
modify = datetime.strptime(f"{date} {time}", "%m-%d-%y %I:%M%p")
273+
modify = datetime.strptime(
274+
f"{date} {time}", "%m-%d-%y %I:%M%p"
275+
)
278276
info = {"size": 0, "type": "dir", "modify": modify}
279277
xpath = f"{path}/{name}"
280278
content[name] = Directory(xpath)
281279
else:
282280
date, time, size, name = line.strip().split(maxsplit=3)
283-
modify = datetime.strptime(f"{date} {time}", "%m-%d-%y %I:%M%p")
281+
modify = datetime.strptime(
282+
f"{date} {time}", "%m-%d-%y %I:%M%p"
283+
)
284284
info: FileInfo = {
285285
"size": size,
286286
"type": "file",
@@ -353,7 +353,8 @@ def content(self) -> List[Union[Directory, FTPFile]]:
353353
"""
354354
if not self.__content__:
355355
logger.info(
356-
"content is not loaded, use `load()` to load default paths")
356+
"content is not loaded, use `load()` to load default paths"
357+
)
357358
return []
358359
return sorted(list(self.__content__.values()), key=str)
359360

@@ -418,7 +419,9 @@ def get_files(self, *args, **kwargs) -> list[FTPFile]:
418419
"""
419420
...
420421

421-
def download(self, files: List[FTPFile], local_dir: str = CACHEPATH) -> List[str]:
422+
def download(
423+
self, files: List[FTPFile], local_dir: str = CACHEPATH
424+
) -> List[str]:
422425
"""
423426
Downloads a list of Files.
424427
"""
@@ -433,7 +436,9 @@ def download(self, files: List[FTPFile], local_dir: str = CACHEPATH) -> List[str
433436
return dfiles[0]
434437
return dfiles
435438

436-
async def async_download(self, files: List[FTPFile], local_dir: str = CACHEPATH):
439+
async def async_download(
440+
self, files: List[FTPFile], local_dir: str = CACHEPATH
441+
):
437442
"""
438443
Asynchronously downloads a list of files
439444
"""

0 commit comments

Comments
 (0)