Skip to content

Commit

Permalink
Release 3.9.3, Merge pull request #489 from sentinel-hub/develop
Browse files Browse the repository at this point in the history
Release 3.9.3
  • Loading branch information
zigaLuksic authored Nov 3, 2023
2 parents 7760095 + 7fbdcd7 commit 2df6028
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 11 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ repos:
language_version: python3

- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: "v0.1.1"
rev: "v0.1.3"
hooks:
- id: ruff

Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
## [Version 3.9.3] - 2023-11-03

- `SHConfig` now correctly initializes a default profile in the file even if the first initialization call is done with a custom profile.
- Save and load methods of `SHConfig` adjusted to work with the environmental variable `SH_PROFILE`
- CLI command `sentinelhub.config --show` works with the environmental variable `SH_PROFILE`


## [Version 3.9.2] - 2023-10-24

- Adjusted how user credentials are passed to the OAuth service.
- Added `QUALITY_FLAGS` band to `S3_OLCI`
- Batch statistical API now supports IAM role style credentials.
- Various minor improvements


## [Version 3.9.1] - 2023-05-04

- The parameter `sh_auth_base_url` has been replaced with `sh_token_url` to allow authentication on endpoints with suffixes other than `oauth/token`. For the new parameter the address must be provided in full, e.g. `https://services.sentinel-hub.com/oauth/token` instead of `https://services.sentinel-hub.com`. The change only affects users who manually adjusted this field.
Expand Down
2 changes: 1 addition & 1 deletion sentinelhub/_version.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Version of the sentinelhub package."""

__version__ = "3.9.2"
__version__ = "3.9.3"
6 changes: 3 additions & 3 deletions sentinelhub/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import click

from .config import DEFAULT_PROFILE, SHConfig
from .config import SHConfig
from .download import DownloadClient, DownloadRequest

FC = TypeVar("FC", bound=Callable[..., Any])
Expand Down Expand Up @@ -40,9 +40,9 @@ def _config_options(func: FC) -> FC:

@click.command()
@click.option("--show", is_flag=True, default=False, help="Show current configuration")
@click.option("--profile", default=DEFAULT_PROFILE, help="Selects profile to show/configure.")
@click.option("--profile", default=None, help="Selects profile to show/configure.")
@_config_options
def config(show: bool, profile: str, **params: Any) -> None:
def config(show: bool, profile: str | None, **params: Any) -> None:
"""Inspect and configure parameters in your local sentinelhub configuration file
\b
Expand Down
17 changes: 11 additions & 6 deletions sentinelhub/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,7 @@ def __init__(self, profile: str | None = None, *, use_defaults: bool = False, **
:param use_defaults: Does not load the configuration file, returns config object with defaults only.
:param kwargs: Any fields of `SHConfig` to be updated. Overrides settings from `config.toml` and environment.
"""
if profile is None:
profile = os.environ.get(SH_PROFILE_ENV_VAR, default=DEFAULT_PROFILE)
profile = self._get_profile(profile)

if not use_defaults:
env_kwargs = {
Expand All @@ -141,29 +140,35 @@ def __repr__(self) -> str:
content = ",\n ".join(f"{key}={value!r}" for key, value in config_dict.items())
return f"{self.__class__.__name__}(\n {content},\n)"

@staticmethod
def _get_profile(profile: str | None) -> str:
return profile if profile is not None else os.environ.get(SH_PROFILE_ENV_VAR, default=DEFAULT_PROFILE)

@classmethod
def load(cls, profile: str = DEFAULT_PROFILE) -> SHConfig:
def load(cls, profile: str | None = None) -> SHConfig:
"""Loads configuration parameters from the config file at `SHConfig.get_config_location()`.
:param profile: Which profile to load from the configuration file.
"""
profile = cls._get_profile(profile)
filename = cls.get_config_location()
if not os.path.exists(filename):
cls(use_defaults=True).save(profile) # store default configuration to standard location
cls(use_defaults=True).save() # store default configuration to standard location

with open(filename, "rb") as cfg_file:
configurations_dict = tomli.load(cfg_file)

if profile not in configurations_dict:
raise KeyError(f"Profile {profile} not found in configuration file.")
raise KeyError(f"Profile `{profile}` not found in configuration file.")

return cls(use_defaults=True, **configurations_dict[profile])

def save(self, profile: str = DEFAULT_PROFILE) -> None:
def save(self, profile: str | None = None) -> None:
"""Saves configuration parameters to the config file at `SHConfig.get_config_location()`.
:param profile: Under which profile to save the configuration.
"""
profile = self._get_profile(profile)
file_path = Path(self.get_config_location())
file_path.parent.mkdir(parents=True, exist_ok=True)

Expand Down
22 changes: 22 additions & 0 deletions tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,20 @@ def test_profiles() -> None:
assert SHConfig(profile="beep").sh_client_id == "bap"


@pytest.mark.dependency(depends=["test_user_config_is_masked"])
@pytest.mark.usefixtures("_restore_config_file")
def test_initialize_nondefault_profile() -> None:
"""Since there is no config, loading a non-default profile should fail."""
config = SHConfig()
os.remove(config.get_config_location())

SHConfig() # works for default

os.remove(config.get_config_location())
with pytest.raises(KeyError):
SHConfig("mr_president")


@pytest.mark.dependency(depends=["test_user_config_is_masked"])
@pytest.mark.usefixtures("_restore_config_file")
def test_profiles_from_env(monkeypatch: pytest.MonkeyPatch) -> None:
Expand All @@ -147,8 +161,16 @@ def test_profiles_from_env(monkeypatch: pytest.MonkeyPatch) -> None:

monkeypatch.setenv(SH_PROFILE_ENV_VAR, "beekeeper")
assert SHConfig().instance_id == "bee", "Environment profile is not used."
assert SHConfig.load().instance_id == "bee", "The load method does not respect the environment profile."
assert SHConfig(profile=DEFAULT_PROFILE).instance_id == "", "Explicit profile overrides environment."

config = SHConfig()
config.instance_id = "many bee"
config.save()

assert SHConfig(profile="beekeeper").instance_id == "many bee", "Save method does not respect the env profile."
assert SHConfig(profile=DEFAULT_PROFILE).instance_id == "", "Saving with env profile changed default profile."


def test_loading_unknown_profile_fails() -> None:
with pytest.raises(KeyError):
Expand Down

0 comments on commit 2df6028

Please sign in to comment.