mirror of https://github.com/caronc/apprise
fixed test case
parent
96ee18298b
commit
7ad812694e
|
@ -898,19 +898,15 @@ class ConfigBase(URLBase):
|
||||||
# Acquire our asset tokens
|
# Acquire our asset tokens
|
||||||
tokens = result.get("asset", None)
|
tokens = result.get("asset", None)
|
||||||
if tokens and isinstance(tokens, dict):
|
if tokens and isinstance(tokens, dict):
|
||||||
|
raw_tz = tokens.get("timezone", tokens.get("tz"))
|
||||||
# Prepare our default timezone (if specified)
|
timezone = raw_tz.strip() if isinstance(raw_tz, str) else ""
|
||||||
timezone = str(tokens.get("timezone", tokens.get("tz", "")))
|
|
||||||
if timezone:
|
if timezone:
|
||||||
default_timezone = zoneinfo(re.sub(r"[^\w/-]+", "", timezone))
|
default_timezone = zoneinfo(re.sub(r"[^\w/-]+", "", timezone))
|
||||||
if not default_timezone:
|
if not default_timezone:
|
||||||
ConfigBase.logger.warning(
|
ConfigBase.logger.warning(
|
||||||
'Ignored invalid timezone "%s"', timezone)
|
'Ignored invalid timezone "%s"', raw_tz)
|
||||||
# Restore our timezone back to what was found in the
|
|
||||||
# asset object
|
|
||||||
default_timezone = asset.tzinfo
|
default_timezone = asset.tzinfo
|
||||||
else:
|
else:
|
||||||
# Set our newly specified timezone
|
|
||||||
asset._tzinfo = default_timezone
|
asset._tzinfo = default_timezone
|
||||||
|
|
||||||
# Iterate over remaining tokens
|
# Iterate over remaining tokens
|
||||||
|
|
|
@ -31,7 +31,6 @@ from datetime import tzinfo
|
||||||
from functools import partial
|
from functools import partial
|
||||||
import re
|
import re
|
||||||
from typing import Any, ClassVar, Optional, TypedDict, Union
|
from typing import Any, ClassVar, Optional, TypedDict, Union
|
||||||
from zoneinfo import ZoneInfo
|
|
||||||
|
|
||||||
from ..apprise_attachment import AppriseAttachment
|
from ..apprise_attachment import AppriseAttachment
|
||||||
from ..common import (
|
from ..common import (
|
||||||
|
@ -298,7 +297,6 @@ class NotifyBase(URLBase):
|
||||||
# automatically initialized by specifying ?tz= on the Apprise URLs
|
# automatically initialized by specifying ?tz= on the Apprise URLs
|
||||||
__tzinfo = None
|
__tzinfo = None
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
"""Initialize some general configuration that will keep things
|
"""Initialize some general configuration that will keep things
|
||||||
consistent when working with the notifiers that will inherit this
|
consistent when working with the notifiers that will inherit this
|
||||||
|
@ -350,17 +348,13 @@ class NotifyBase(URLBase):
|
||||||
|
|
||||||
if "tz" in kwargs:
|
if "tz" in kwargs:
|
||||||
value = kwargs["tz"]
|
value = kwargs["tz"]
|
||||||
if isinstance(value, ZoneInfo):
|
self.__tzinfo = zoneinfo(value)
|
||||||
self.__tzinfo = kwargs["tz"]
|
if not self.__tzinfo:
|
||||||
|
err = (
|
||||||
else:
|
f"An invalid notification timezone ({value}) was "
|
||||||
self.__tzinfo = zoneinfo(value)
|
"specified.")
|
||||||
if not self.__tzinfo:
|
self.logger.warning(err)
|
||||||
err = (
|
raise TypeError(err) from None
|
||||||
f"An invalid notification timezone ({value}) was "
|
|
||||||
"specified.")
|
|
||||||
self.logger.warning(err)
|
|
||||||
raise TypeError(err) from None
|
|
||||||
|
|
||||||
if "overflow" in kwargs:
|
if "overflow" in kwargs:
|
||||||
value = kwargs["overflow"]
|
value = kwargs["overflow"]
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
# POSSIBILITY OF SUCH DAMAGE.
|
# POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
from datetime import tzinfo
|
from datetime import datetime, timezone as _tz, tzinfo
|
||||||
from inspect import cleandoc
|
from inspect import cleandoc
|
||||||
|
|
||||||
# Disable logging for a cleaner testing output
|
# Disable logging for a cleaner testing output
|
||||||
|
@ -34,7 +34,7 @@ import logging
|
||||||
import pytest
|
import pytest
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from apprise import Apprise, AppriseAsset, ConfigFormat
|
from apprise import Apprise, AppriseAsset, AppriseConfig, ConfigFormat
|
||||||
from apprise.config import ConfigBase
|
from apprise.config import ConfigBase
|
||||||
from apprise.plugins.email import NotifyEmail
|
from apprise.plugins.email import NotifyEmail
|
||||||
from apprise.utils.time import zoneinfo
|
from apprise.utils.time import zoneinfo
|
||||||
|
@ -1592,3 +1592,77 @@ include: [file:///absolute/path/, relative/path, http://test.com]
|
||||||
assert "file:///absolute/path/" in config
|
assert "file:///absolute/path/" in config
|
||||||
assert "relative/path" in config
|
assert "relative/path" in config
|
||||||
assert "http://test.com" in config
|
assert "http://test.com" in config
|
||||||
|
|
||||||
|
|
||||||
|
def test_yaml_asset_timezone_and_asset_tokens(tmpdir):
|
||||||
|
"""
|
||||||
|
Covers: valid tz, reserved keys, invalid key, bool coercion, None->"",
|
||||||
|
invalid type for string, and %z formatting path used later by plugins.
|
||||||
|
"""
|
||||||
|
cfg = tmpdir.join("asset-tz.yml")
|
||||||
|
cfg.write(
|
||||||
|
"""
|
||||||
|
version: 1
|
||||||
|
asset:
|
||||||
|
tz: " america/toronto " # case-insensitive + whitespace cleanup
|
||||||
|
_private: "ignored" # reserved (starts with _)
|
||||||
|
name_: "ignored" # reserved (ends with _)
|
||||||
|
not_a_field: "ignored" # invalid asset key
|
||||||
|
secure_logging: "yes" # string -> bool via parse_bool
|
||||||
|
app_id: null # None becomes empty string
|
||||||
|
app_desc: [ "list" ] # invalid type for string -> warning path
|
||||||
|
urls:
|
||||||
|
- json://localhost
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
ac = AppriseConfig(paths=str(cfg))
|
||||||
|
# Force a fresh parse and get the loaded plugin
|
||||||
|
servers = ac.servers()
|
||||||
|
assert len(servers) == 1
|
||||||
|
|
||||||
|
plugin = servers[0]
|
||||||
|
asset = plugin.asset
|
||||||
|
|
||||||
|
# tz was accepted and normalised
|
||||||
|
assert getattr(asset.tzinfo, "key", None) == "America/Toronto"
|
||||||
|
# boolean coercion applied
|
||||||
|
assert asset.secure_logging is True
|
||||||
|
# None -> ""
|
||||||
|
assert asset.app_id == ""
|
||||||
|
|
||||||
|
|
||||||
|
def test_yaml_asset_timezone_invalid_and_precedence(tmpdir):
|
||||||
|
"""
|
||||||
|
If 'timezone' is present but invalid, it takes precedence over 'tz'
|
||||||
|
and MUST NOT set the asset to the 'tz' value. We assert that London
|
||||||
|
was not applied. We deliberately avoid asserting the exact fallback,
|
||||||
|
since environments may surface a system tz (datetime.timezone) that
|
||||||
|
lacks a `.key` attribute.
|
||||||
|
"""
|
||||||
|
cfg = tmpdir.join("asset-tz-invalid.yml")
|
||||||
|
cfg.write(
|
||||||
|
"""
|
||||||
|
version: 1
|
||||||
|
asset:
|
||||||
|
timezone: null # invalid (will be seen as "None")
|
||||||
|
tz: Europe/London # would be valid, but 'timezone' wins
|
||||||
|
urls:
|
||||||
|
- json://localhost
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
base_asset = AppriseAsset(timezone="UTC")
|
||||||
|
ac = AppriseConfig(paths=str(cfg))
|
||||||
|
servers = ac.servers(asset=base_asset)
|
||||||
|
assert len(servers) == 1
|
||||||
|
|
||||||
|
tzinfo = servers[0].asset.tzinfo
|
||||||
|
|
||||||
|
# The key assertion: 'tz' MUST NOT have been applied
|
||||||
|
assert getattr(tzinfo, "key", "").lower() != "europe/london"
|
||||||
|
|
||||||
|
# Sanity check that something sensible is set
|
||||||
|
# Compare offsets at a fixed instant instead of object identity
|
||||||
|
dt = datetime(2024, 1, 1, 12, 0, tzinfo=_tz.utc)
|
||||||
|
assert tzinfo.utcoffset(dt) is not None
|
||||||
|
|
Loading…
Reference in New Issue