11#!/usr/bin/env python
22# -*- coding: utf-8; -*-
33
4- # Copyright (c) 2022 Oracle and/or its affiliates.
4+ # Copyright (c) 2022, 2023 Oracle and/or its affiliates.
55# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
66
77import os
88from collections import defaultdict
99from configparser import ConfigParser
1010from copy import copy
1111from enum import Enum
12- from typing import Callable , Dict , List , Optional , Tuple , Union , Any
12+ from typing import Any , Callable , Dict , List , Optional , Tuple , Union
13+ from urllib .parse import urlparse
1314
1415import fsspec
1516import yaml
17+
1618from ads .common import auth as authutil
1719from ads .common .decorator .argument_to_case import ArgumentCase , argument_to_case
1820
@@ -287,6 +289,7 @@ def __init__(
287289 self ._config_parser = ExtendedConfigParser (uri = self .uri , auth = self .auth )
288290
289291 def _on_change (self ):
292+ """This method will be called when config modified."""
290293 pass
291294
292295 def default (self ) -> ConfigSection :
@@ -345,7 +348,7 @@ def section_set(
345348 The new config section will be added in case if it doesn't exist.
346349 Otherwise the existing config section will be merged with the new fields.
347350
348- Paramaters
351+ Parameters
349352 ----------
350353 key: str
351354 A key of a config section.
@@ -362,7 +365,7 @@ def section_set(
362365 Raises
363366 ------
364367 ValueError
365- If section with goven key is already exist and `replace` flag set to False.
368+ If section with given key is already exist and `replace` flag set to False.
366369 TypeError
367370 If input `info` has a wrong format.
368371 """
@@ -389,7 +392,7 @@ def section_set(
389392 return self ._config [key ]
390393
391394 @argument_to_case (case = ArgumentCase .UPPER , arguments = ["key" ])
392- def section_remove (self , key : str ) -> None :
395+ def section_remove (self , key : str ) -> "Config" :
393396 """Removes config section form config.
394397
395398 Parameters
@@ -404,26 +407,62 @@ def section_remove(self, key: str) -> None:
404407 """
405408 self ._config .pop (key , None )
406409 self ._on_change ()
410+ return self
411+
412+ def save (
413+ self ,
414+ uri : Optional [str ] = None ,
415+ auth : Optional [Dict ] = None ,
416+ force_overwrite : Optional [bool ] = False ,
417+ ) -> "Config" :
418+ """Saves config to a config file.
407419
408- def save (self ) -> None :
409- """Saves config data to a config file.
420+ Parameters
421+ ----------
422+ uri: (str, optional). Defaults to `~/.ads/config`.
423+ The path to the config file. Can be local or Object Storage file.
424+ auth: (Dict, optional). Defaults to None.
425+ The default authentication is set using `ads.set_auth` API. If you need to override the
426+ default, use the `ads.common.auth.api_keys` or `ads.common.auth.resource_principal` to create appropriate
427+ authentication signer and kwargs required to instantiate IdentityClient object.
428+ force_overwrite: (bool, optional). Defaults to `False`.
429+ Overwrites the config if exists.
410430
411431 Returns
412432 -------
413433 None
414434 Nothing
415435 """
416- self ._config_parser .with_dict (self .to_dict ()).save ()
436+ uri = uri or self .uri
437+ auth = auth or self .auth or authutil .default_signer ()
438+ self ._config_parser .with_dict (self .to_dict ()).save (
439+ uri = uri , auth = auth , force_overwrite = force_overwrite
440+ )
441+ return self
442+
443+ def load (self , uri : Optional [str ] = None , auth : Optional [Dict ] = None ) -> "Config" :
444+ """Loads config from a config file.
417445
418- def load (self ) -> "Config" :
419- """Loads config data from a config file.
446+ Parameters
447+ ----------
448+ uri: (str, optional). Defaults to `~/.ads/config`.
449+ The path where the config file needs to be saved. Can be local or Object Storage file.
450+ auth: (Dict, optional). Defaults to None.
451+ The default authentication is set using `ads.set_auth` API. If you need to override the
452+ default, use the `ads.common.auth.api_keys` or `ads.common.auth.resource_principal` to create appropriate
453+ authentication signer and kwargs required to instantiate IdentityClient object.
420454
421455 Returns
422456 -------
423457 Config
424458 A config object.
425459 """
426- return self .with_dict (self ._config_parser .read ().to_dict ())
460+ uri = uri or self .uri
461+ auth = auth or self .auth or authutil .default_signer ()
462+
463+ return self .with_dict (
464+ self ._config_parser .read (uri = uri , auth = auth ).to_dict (), replace = True
465+ )
427466
428467 def with_dict (
429468 self ,
@@ -507,23 +546,54 @@ def __init__(
507546 uri: (str, optional). Defaults to `~/.ads/config`.
508547 The path to the config file. Can be local or Object Storage file.
509548 auth: (Dict, optional). Defaults to None.
510- The default authetication is set using `ads.set_auth` API. If you need to override the
549+ The default authentication is set using `ads.set_auth` API. If you need to override the
511550 default, use the `ads.common.auth.api_keys` or `ads.common.auth.resource_principal` to create appropriate
512551 authentication signer and kwargs required to instantiate IdentityClient object.
513552 """
514553 super ().__init__ (default_section = "EXCLUDE_DEFAULT_SECTION" )
515554 self .auth = auth or authutil .default_signer ()
516555 self .uri = uri
517556
518- def save (self ) -> None :
557+ def save (
558+ self ,
559+ uri : Optional [str ] = None ,
560+ auth : Optional [Dict ] = None ,
561+ force_overwrite : Optional [bool ] = False ,
562+ ) -> None :
519563 """Saves the config to the file.
520564
565+ Parameters
566+ ----------
567+ uri: (str, optional). Defaults to `~/.ads/config`.
568+ The path to the config file. Can be local or Object Storage file.
569+ auth: (Dict, optional). Defaults to None.
570+ The default authentication is set using `ads.set_auth` API. If you need to override the
571+ default, use the `ads.common.auth.api_keys` or `ads.common.auth.resource_principal` to create appropriate
572+ authentication signer and kwargs required to instantiate IdentityClient object.
573+ force_overwrite: (bool, optional). Defaults to `False`.
574+ Overwrites the config if exists.
575+
521576 Returns
522577 -------
523578 None
524- nothing
579+
580+ Raise
581+ -----
582+ FileExistsError
583+ In case if file exists and force_overwrite is false.
525584 """
526- with fsspec .open (self .uri , mode = "w" , ** self .auth ) as f :
585+ uri = uri or self .uri
586+ auth = auth or self .auth or authutil .default_signer ()
587+
588+ if not force_overwrite :
589+ dst_path_scheme = urlparse (uri ).scheme or "file"
590+ if fsspec .filesystem (dst_path_scheme , ** auth ).exists (uri ):
591+ raise FileExistsError (
592+ f"The `{ uri } ` exists. Set `force_overwrite` to True "
593+ "if you wish to overwrite."
594+ )
595+
596+ with fsspec .open (uri , mode = "w" , ** auth ) as f :
527597 self .write (f )
528598
529599 def to_dict (self ) -> Dict [str , Any ]:
@@ -532,19 +602,31 @@ def to_dict(self) -> Dict[str, Any]:
532602 Returns
533603 -------
534604 Dict[str, Any]
535- Cofig in a dictionary format.
605+ Config in a dictionary format.
536606 """
537607 return {s : dict (self [s ]) for s in self .keys () if self [s ]}
538608
539- def read (self ) -> "ExtendedConfigParser" :
609+ def read (
610+ self , uri : Optional [str ] = None , auth : Optional [Dict ] = None
611+ ) -> "ExtendedConfigParser" :
540612 """Reads config file.
541613
614+ uri: (str, optional). Defaults to `~/.ads/config`.
615+ The path to the config file. Can be local or Object Storage file.
616+ auth: (Dict, optional). Defaults to None.
617+ The default authentication is set using `ads.set_auth` API. If you need to override the
618+ default, use the `ads.common.auth.api_keys` or `ads.common.auth.resource_principal` to create appropriate
619+ authentication signer and kwargs required to instantiate IdentityClient object.
620+
542621 Returns
543622 -------
544623 ExtendedConfigParser
545624 Config parser object.
546625 """
547- with fsspec .open (self .uri , "r" , ** self .auth ) as f :
626+ uri = uri or self .uri
627+ auth = auth or self .auth or authutil .default_signer ()
628+
629+ with fsspec .open (uri , "r" , ** auth ) as f :
548630 self .read_string (f .read ())
549631 return self
550632
0 commit comments