77from contextlib import contextmanager
88from datetime import datetime
99from pathlib import Path
10- from typing import Any , Generic , Iterator , Optional , Type , TypeVar
10+ from typing import Annotated , Any , Generic , Iterator , TypeVar
1111from uuid import UUID
1212
1313import httpx
1616 AnyHttpUrl ,
1717 AnyUrl ,
1818 BaseModel ,
19- BaseSettings ,
2019 EmailStr ,
2120 Field ,
2221 NonNegativeInt ,
2322 SecretStr ,
2423 ValidationError ,
25- conint ,
2624)
27- from pydantic . generics import GenericModel
25+ from pydantic_settings import BaseSettings , SettingsConfigDict
2826
2927log = logging .getLogger (__name__ )
3028logging .basicConfig (level = getattr (logging , os .environ .get ("LOG_LEVEL" , "INFO" )))
@@ -46,32 +44,32 @@ class Meta(BaseModel):
4644class PageLinks (BaseModel ):
4745 self : AnyHttpUrl
4846 first : AnyHttpUrl
49- prev : Optional [ AnyHttpUrl ]
50- next : Optional [ AnyHttpUrl ]
47+ prev : AnyHttpUrl | None
48+ next : AnyHttpUrl | None
5149 last : AnyHttpUrl
5250
5351
54- class Page (GenericModel , Generic [ItemT ]):
52+ class Page (BaseModel , Generic [ItemT ]):
5553 meta : Meta = Field (..., alias = "_meta" )
5654 data : list [ItemT ]
5755 links : PageLinks = Field (..., alias = "_links" )
5856
5957
60- class Envelope (GenericModel , Generic [DataT ]):
61- data : Optional [ DataT ]
62- error : Optional [ Any ]
58+ class Envelope (BaseModel , Generic [DataT ]):
59+ data : DataT | None
60+ error : Any | None
6361
6462 @classmethod
6563 def parse_data (cls , obj ):
66- return cls .parse_obj ({"data" : obj })
64+ return cls .model_validate ({"data" : obj })
6765
6866
6967class CheckPoint (BaseModel ):
7068 id : NonNegativeInt
7169 checksum : str
72- tag : Optional [ str ] = None
73- message : Optional [ str ] = None
74- parent : Optional [ NonNegativeInt ] = None
70+ tag : str | None = None
71+ message : str | None = None
72+ parent : NonNegativeInt | None = None
7573 created_at : datetime
7674
7775
@@ -98,7 +96,7 @@ class ProjectIteration(BaseModel):
9896
9997
10098class ExtractedResults (BaseModel ):
101- progress : dict [NodeIDStr , conint (ge = 0 , le = 100 )] = Field (
99+ progress : dict [NodeIDStr , Annotated [ int , Field (ge = 0 , le = 100 )] ] = Field (
102100 ..., description = "Progress in each computational node"
103101 )
104102 labels : dict [NodeIDStr , str ] = Field (
@@ -140,19 +138,19 @@ def login(client: httpx.Client, user: str, password: str):
140138
141139def get_profile (client : httpx .Client ):
142140 r = client .get ("/me" )
143- assert r .status_code == 200
141+ assert r .status_code == httpx . codes . OK
144142 return r .json ()["data" ]
145143
146144
147145def iter_items (
148- client : httpx .Client , url_path : str , item_cls : Type [ItemT ]
146+ client : httpx .Client , url_path : str , item_cls : type [ItemT ]
149147) -> Iterator [ItemT ]:
150148 """iterates items returned by a List std-method
151149
152150 SEE https://google.aip.dev/132
153151 """
154152
155- def _relative_url_path (page_link : Optional [ AnyHttpUrl ] ) -> Optional [ str ] :
153+ def _relative_url_path (page_link : AnyHttpUrl | None ) -> str | None :
156154 if page_link :
157155 return f"{ page_link .path } " .replace (client .base_url .path , "" )
158156 return None
@@ -165,9 +163,8 @@ def _relative_url_path(page_link: Optional[AnyHttpUrl]) -> Optional[str]:
165163 r = client .get (next_url )
166164 r .raise_for_status ()
167165
168- page = Page [item_cls ].parse_raw (r .text )
169- for item in page .data :
170- yield item
166+ page = Page [item_cls ].model_validate_json (r .text )
167+ yield from page .data
171168
172169 next_url = _relative_url_path (page .links .next )
173170 last_url = _relative_url_path (page .links .last )
@@ -198,24 +195,25 @@ def iter_project_iteration(
198195# SETUP ------------------------------------------
199196class ClientSettings (BaseSettings ):
200197
201- OSPARC_API_URL : AnyUrl = Field (default = "http://127.0.0.1.nip.io:9081/v0" ) # NOSONAR
198+ OSPARC_API_URL : AnyUrl = Field (
199+ default = "http://127.0.0.1.nip.io:9081/v0"
200+ ) # NOSONAR
202201 OSPARC_USER_EMAIL : EmailStr
203202 OSPARC_USER_PASSWORD : SecretStr
204203
205- class Config :
206- env_file = ".env-osparc-web.ignore"
204+ model_config = SettingsConfigDict (env_file = ".env-osparc-web.ignore" )
207205
208206
209207def init ():
210- env_file = Path (ClientSettings .Config .env_file )
208+ env_file = Path (ClientSettings .model_config .env_file )
211209 log .info ("Creating %s" , f"{ env_file } " )
212210 kwargs = {}
213211 kwargs ["OSPARC_API_URL" ] = input ("OSPARC_API_URL: " ).strip () or None
214212 kwargs ["OSPARC_USER_EMAIL" ] = (
215213 input ("OSPARC_USER_EMAIL: " ) or getpass .getuser () + "@itis.swiss"
216214 )
217215 kwargs ["OSPARC_USER_PASSWORD" ] = getpass .getpass ()
218- with open (env_file , "wt " ) as fh :
216+ with env_file . open ("w " ) as fh :
219217 for key , value in kwargs .items ():
220218 print (key , value )
221219 if value is not None :
@@ -234,7 +232,7 @@ def query_if_invalid_config():
234232def setup_client () -> Iterator [httpx .Client ]:
235233 settings = ClientSettings ()
236234
237- client = httpx .Client (base_url = settings .OSPARC_API_URL )
235+ client = httpx .Client (base_url = f" { settings .OSPARC_API_URL } " )
238236 try :
239237 # check if online and login
240238 print (ping (client ))
0 commit comments