Skip to content

Commit

Permalink
docs: eodag.utils
Browse files Browse the repository at this point in the history
  • Loading branch information
sbrunato committed Oct 21, 2024
1 parent 048805b commit 75a6aa7
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 51 deletions.
13 changes: 11 additions & 2 deletions docs/api_reference/utils.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.. module:: eodag.utils
:no-index:

=====
Utils
Expand All @@ -11,13 +12,21 @@ Logging
:members:

Callbacks
-----------------
---------

.. autofunction::eodag.api.product.DownloadedCallback
.. autoclass:: eodag.utils.DownloadedCallback
:special-members: __call__
.. autofunction:: eodag.utils.ProgressCallback

Notebook
--------

.. automodule:: eodag.utils.notebook
:members:

Misc
----

.. automodule:: eodag.utils
:members:
:exclude-members: DownloadedCallback, ProgressCallback, NotebookProgressCallback, get_progress_callback
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@
# https://github.com/psf/requests/issues/6140#issuecomment-1135071992
"python-requests": ("https://requests.readthedocs.io/en/stable/", None),
"shapely": ("https://shapely.readthedocs.io/en/stable/", None),
"click": ("https://click.palletsprojects.com/en/latest/", None),
}

suppress_warnings = ["misc.copy_overwrite"]
Expand Down
2 changes: 1 addition & 1 deletion eodag/api/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2047,7 +2047,7 @@ def download_all(
:param search_result: A collection of EO products resulting from a search
:param downloaded_callback: (optional) A method or a callable object which takes
as parameter the ``product``. You can use the base class
:class:`~eodag.api.product.DownloadedCallback` and override
:class:`~eodag.utils.DownloadedCallback` and override
its ``__call__`` method. Will be called each time a product
finishes downloading
:param progress_callback: (optional) A method or a callable object
Expand Down
2 changes: 1 addition & 1 deletion eodag/plugins/download/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ def download_all(
:param auth: (optional) authenticated object
:param downloaded_callback: (optional) A method or a callable object which takes
as parameter the ``product``. You can use the base class
:class:`~eodag.api.product.DownloadedCallback` and override
:class:`~eodag.utils.DownloadedCallback` and override
its ``__call__`` method. Will be called each time a product
finishes downloading
:param progress_callback: (optional) A progress callback
Expand Down
100 changes: 53 additions & 47 deletions eodag/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
if TYPE_CHECKING:
from jsonpath_ng import JSONPath

from eodag.api.product import EOProduct
from eodag.api.product._product import EOProduct


logger = py_logging.getLogger("eodag.utils")
Expand Down Expand Up @@ -232,9 +232,10 @@ def __repr__(self) -> str:
def slugify(value: Any, allow_unicode: bool = False) -> str:
"""Copied from Django Source code, only modifying last line (no need for safe
strings).
source: https://github.com/django/django/blob/master/django/utils/text.py
Convert to ASCII if 'allow_unicode' is False. Convert spaces to hyphens.
Convert to ASCII if ``allow_unicode`` is ``False``. Convert spaces to hyphens.
Remove characters that aren't alphanumerics, underscores, or hyphens.
Convert to lowercase. Also strip leading and trailing whitespace.
"""
Expand Down Expand Up @@ -293,7 +294,7 @@ def strip_accents(s: str) -> str:

def uri_to_path(uri: str) -> str:
"""
Convert a file URI (e.g. 'file:///tmp') to a local path (e.g. '/tmp')
Convert a file URI (e.g. ``file:///tmp``) to a local path (e.g. ``/tmp``)
"""
if not uri.startswith("file"):
raise ValueError("A file URI must be provided (e.g. 'file:///tmp'")
Expand Down Expand Up @@ -328,23 +329,22 @@ def mutate_dict_in_place(func: Callable[[Any], Any], mapping: Dict[Any, Any]) ->


def merge_mappings(mapping1: Dict[Any, Any], mapping2: Dict[Any, Any]) -> None:
"""Merge two mappings with string keys, values from `mapping2` overriding values
from `mapping1`.
"""Merge two mappings with string keys, values from ``mapping2`` overriding values
from ``mapping1``.
Do its best to detect the key in `mapping1` to override. For example::
Do its best to detect the key in ``mapping1`` to override. For example:
>>> mapping2 = {"keya": "new"}
>>> mapping1 = {"keyA": "obsolete"}
>>> merge_mappings(mapping1, mapping2)
>>> mapping1
{'keyA': 'new'}
If mapping2 has a key that cannot be detected in mapping1, this new key is added
to mapping1 as is.
If ``mapping2`` has a key that cannot be detected in ``mapping1``, this new key is
added to ``mapping1`` as is.
:param mapping1: The mapping containing values to be overridden
:param mapping2: The mapping containing values that will override the
first mapping
:param mapping2: The mapping containing values that will override the first mapping
"""
# A mapping between mapping1 keys as lowercase strings and original mapping1 keys
m1_keys_lowercase = {key.lower(): key for key in mapping1}
Expand Down Expand Up @@ -411,7 +411,7 @@ def get_timestamp(date_time: str) -> float:
If the datetime has no offset, it is assumed to be an UTC datetime.
:param date_time: The datetime string to return as timestamp
:returns: The timestamp corresponding to the date_time string in seconds
:returns: The timestamp corresponding to the ``date_time`` string in seconds
"""
dt = isoparse(date_time)
if not dt.tzinfo:
Expand All @@ -420,7 +420,7 @@ def get_timestamp(date_time: str) -> float:


def datetime_range(start: dt, end: dt) -> Iterator[dt]:
"""Generator function for all dates in-between start and end date."""
"""Generator function for all dates in-between ``start`` and ``end`` date."""
delta = end - start
for nday in range(delta.days + 1):
yield start + datetime.timedelta(days=nday)
Expand All @@ -440,15 +440,15 @@ def __call__(self, product: EOProduct) -> None:
class ProgressCallback(tqdm):
"""A callable used to render progress to users for long running processes.
It inherits from `tqdm.auto.tqdm`, and accepts the same arguments on
instantiation: `iterable`, `desc`, `total`, `leave`, `file`, `ncols`,
`mininterval`, `maxinterval`, `miniters`, `ascii`, `disable`, `unit`,
`unit_scale`, `dynamic_ncols`, `smoothing`, `bar_format`, `initial`,
`position`, `postfix`, `unit_divisor`.
It inherits from :class:`tqdm.auto.tqdm`, and accepts the same arguments on
instantiation: ``iterable``, ``desc``, ``total``, ``leave``, ``file``, ``ncols``,
``mininterval``, ``maxinterval``, ``miniters``, ``ascii``, ``disable``, ``unit``,
``unit_scale``, ``dynamic_ncols``, ``smoothing``, ``bar_format``, ``initial``,
``position``, ``postfix``, ``unit_divisor``.
It can be globally disabled using `eodag.utils.logging.setup_logging(0)` or
`eodag.utils.logging.setup_logging(level, no_progress_bar=True)`, and
individually disabled using `disable=True`.
It can be globally disabled using ``eodag.utils.logging.setup_logging(0)`` or
``eodag.utils.logging.setup_logging(level, no_progress_bar=True)``, and
individually disabled using ``disable=True``.
"""

def __init__(self, *args: Any, **kwargs: Any) -> None:
Expand Down Expand Up @@ -483,8 +483,8 @@ def copy(self, *args: Any, **kwargs: Any) -> ProgressCallback:
"""Returns another progress callback using the same initial
keyword-arguments.
Optional `args` and `kwargs` parameters will be used to create a
new `~eodag.utils.ProgressCallback` instance, overriding initial
Optional ``args`` and ``kwargs`` parameters will be used to create a
new :class:`~eodag.utils.ProgressCallback` instance, overriding initial
`kwargs`.
"""

Expand All @@ -506,7 +506,7 @@ def get_progress_callback() -> tqdm:


def repeatfunc(func: Callable[..., Any], n: int, *args: Any) -> starmap:
"""Call `func` `n` times with `args`"""
"""Call ``func`` ``n`` times with ``args``"""
return starmap(func, repeat(args, n))


Expand All @@ -521,12 +521,12 @@ def makedirs(dirpath: str) -> None:


def rename_subfolder(dirpath: str, name: str) -> None:
"""Rename first subfolder found in dirpath with given name,
raise RuntimeError if no subfolder can be found
"""Rename first subfolder found in ``dirpath`` with given ``name``,
raise :class:`RuntimeError` if no subfolder can be found
:param dirpath: path to the directory containing the subfolder
:param name: new name of the subfolder
:raises: RuntimeError
:raises: :class:`RuntimeError`
Example:
Expand All @@ -540,16 +540,20 @@ def rename_subfolder(dirpath: str, name: str) -> None:
... rename_subfolder(tmpdir, "otherfolder")
... assert not os.path.isdir(somefolder) and os.path.isdir(otherfolder)
Before:
Before::
$ tree <tmp-folder>
<tmp-folder>
└── somefolder
└── somefile
After:
After::
$ tree <tmp-folder>
<tmp-folder>
└── otherfolder
└── somefile
"""
try:
subdir, *_ = (p for p in glob(os.path.join(dirpath, "*")) if os.path.isdir(p))
Expand All @@ -565,7 +569,7 @@ def rename_subfolder(dirpath: str, name: str) -> None:
def format_dict_items(
config_dict: Dict[str, Any], **format_variables: Any
) -> Dict[Any, Any]:
r"""Recursive apply string.format(\**format_variables) to dict elements
r"""Recursively apply :meth:`str.format` to ``**format_variables`` on ``config_dict`` values
>>> format_dict_items(
... {"foo": {"bar": "{a}"}, "baz": ["{b}?", "{b}!"]},
Expand All @@ -583,7 +587,7 @@ def format_dict_items(
def jsonpath_parse_dict_items(
jsonpath_dict: Dict[str, Any], values_dict: Dict[str, Any]
) -> Dict[Any, Any]:
"""Recursive parse jsonpath elements in dict
"""Recursively parse :class:`jsonpath_ng.JSONPath` elements in dict
>>> import jsonpath_ng.ext as jsonpath
>>> jsonpath_parse_dict_items(
Expand All @@ -592,7 +596,7 @@ def jsonpath_parse_dict_items(
... ) == {'foo': {'bar': 'baz'}, 'qux': ['quux', 'quux']}
True
:param jsonpath_dict: Dictionary having values that need to be parsed
:param jsonpath_dict: Dictionary having :class:`jsonpath_ng.JSONPath` values that need to be parsed
:param values_dict: Values dict used as args for parsing
:returns: Updated dict
"""
Expand All @@ -606,7 +610,7 @@ def update_nested_dict(
allow_empty_values: bool = False,
allow_extend_duplicates: bool = True,
) -> Dict[Any, Any]:
"""Update recursively old_dict items with new_dict ones
"""Update recursively ``old_dict`` items with ``new_dict`` ones
>>> update_nested_dict(
... {"a": {"a.a": 1, "a.b": 2}, "b": 3},
Expand Down Expand Up @@ -868,7 +872,7 @@ def list_items_recursive_sort(config_list: List[Any]) -> List[Any]:


def string_to_jsonpath(*args: Any, force: bool = False) -> Union[str, JSONPath]:
"""Get jsonpath for "$.foo.bar" like string
"""Get :class:`jsonpath_ng.JSONPath` for ``$.foo.bar`` like string
>>> string_to_jsonpath(None, "$.foo.bar")
Child(Child(Root(), Fields('foo')), Fields('bar'))
Expand All @@ -882,7 +886,7 @@ def string_to_jsonpath(*args: Any, force: bool = False) -> Union[str, JSONPath]:
Fields('foo')
:param args: Last arg as input string value, to be converted
:param force: force conversion even if input string is not detected as a jsonpath
:param force: force conversion even if input string is not detected as a :class:`jsonpath_ng.JSONPath`
:returns: Parsed value
"""
path_str: str = args[-1]
Expand Down Expand Up @@ -945,7 +949,7 @@ def string_to_jsonpath(*args: Any, force: bool = False) -> Union[str, JSONPath]:


def format_string(key: str, str_to_format: Any, **format_variables: Any) -> Any:
"""Format "{foo}" like string
"""Format ``"{foo}"``-like string
>>> format_string(None, "foo {bar}, {baz} ?", **{"bar": "qux", "baz": "quux"})
'foo qux, quux ?'
Expand Down Expand Up @@ -983,7 +987,7 @@ def format_string(key: str, str_to_format: Any, **format_variables: Any) -> Any:
def parse_jsonpath(
key: str, jsonpath_obj: Union[str, jsonpath.Child], **values_dict: Dict[str, Any]
) -> Optional[str]:
"""Parse jsonpah in jsonpath_obj using values_dict
"""Parse jsonpah in ``jsonpath_obj`` using ``values_dict``
>>> import jsonpath_ng.ext as jsonpath
>>> parse_jsonpath(None, parse("$.foo.bar"), **{"foo": {"bar": "baz"}})
Expand Down Expand Up @@ -1025,10 +1029,10 @@ def nested_pairs2dict(pairs: Union[List[Any], Any]) -> Union[Any, Dict[Any, Any]
def get_geometry_from_various(
locations_config: List[Dict[str, Any]] = [], **query_args: Any
) -> BaseGeometry:
"""Creates a shapely geometry using given query kwargs arguments
"""Creates a ``shapely.geometry`` using given query kwargs arguments
:param locations_config: (optional) EODAG locations configuration
:param query_args: Query kwargs arguments from core.search() method
:param query_args: Query kwargs arguments from :meth:`~eodag.api.core.EODataAccessGateway.search`
:returns: shapely Geometry found
:raises: :class:`ValueError`
"""
Expand Down Expand Up @@ -1158,7 +1162,7 @@ def obj_md5sum(data: Any) -> str:

@functools.lru_cache()
def cached_parse(str_to_parse: str) -> JSONPath:
"""Cached jsonpath_ng.ext.parse
"""Cached :func:`jsonpath_ng.ext.parse`
>>> cached_parse.cache_clear()
>>> cached_parse("$.foo")
Expand All @@ -1174,8 +1178,8 @@ def cached_parse(str_to_parse: str) -> JSONPath:
>>> cached_parse.cache_info()
CacheInfo(hits=1, misses=2, maxsize=128, currsize=2)
:param str_to_parse: string to parse as jsonpath
:returns: parsed jsonpath
:param str_to_parse: string to parse as :class:`jsonpath_ng.JSONPath`
:returns: parsed :class:`jsonpath_ng.JSONPath`
"""
return parse(str_to_parse)

Expand All @@ -1189,7 +1193,7 @@ def _mutable_cached_yaml_load(config_path: str) -> Any:


def cached_yaml_load(config_path: str) -> Dict[str, Any]:
"""Cached yaml.load
"""Cached :func:`yaml.load`
:param config_path: path to the yaml configuration file
:returns: loaded yaml configuration
Expand All @@ -1204,7 +1208,7 @@ def _mutable_cached_yaml_load_all(config_path: str) -> List[Any]:


def cached_yaml_load_all(config_path: str) -> List[Any]:
"""Cached yaml.load_all
"""Cached :func:`yaml.load_all`
Load all configurations stored in the configuration file as separated yaml documents
Expand Down Expand Up @@ -1269,7 +1273,8 @@ def flatten_top_directories(

def deepcopy(sth: Any) -> Any:
"""Customized and faster deepcopy inspired by https://stackoverflow.com/a/45858907
`_copy_list` and `_copy_dict` available for the moment
``_copy_list`` and ``_copy_dict`` dispatchers available for the moment
:param sth: Object to copy
:returns: Copied object
Expand Down Expand Up @@ -1334,7 +1339,7 @@ def cast_scalar_value(value: Any, new_type: Any) -> Any:
:param value: the scalar value to convert
:param new_type: the wanted type
:returns: scalar value converted to new_type
:returns: scalar ``value`` converted to ``new_type``
"""
if isinstance(value, str) and new_type is bool:
# Bool is a type with special meaning in Python, thus the special
Expand Down Expand Up @@ -1380,8 +1385,9 @@ def guess_extension(type: str) -> Optional[str]:

def get_ssl_context(ssl_verify: bool) -> ssl.SSLContext:
"""
Returns an SSL context based on ssl_verify argument.
:param ssl_verify: ssl_verify parameter
Returns an SSL context based on ``ssl_verify`` argument.
:param ssl_verify: :attr:`~eodag.config.PluginConfig.ssl_verify` parameter
:returns: An SSL context object.
"""
ctx = ssl.create_default_context()
Expand Down

0 comments on commit 75a6aa7

Please sign in to comment.