From 901c484f89cc4e6e91a389063b065c9f4c04ca89 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Thu, 14 Mar 2024 12:15:02 -0700 Subject: [PATCH 01/13] Include deleted usernames in log filter --- plexpy/logger.py | 2 +- plexpy/users.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/plexpy/logger.py b/plexpy/logger.py index 9f44df95..7227ab10 100644 --- a/plexpy/logger.py +++ b/plexpy/logger.py @@ -76,7 +76,7 @@ def filter_usernames(new_users=None): global _FILTER_USERNAMES if new_users is None: - new_users = [user['username'] for user in users.Users().get_users()] + new_users = [user['username'] for user in users.Users().get_users(include_deleted=True)] for username in new_users: if username.lower() not in ('local', 'guest') and len(username) > 3 and username not in _FILTER_USERNAMES: diff --git a/plexpy/users.py b/plexpy/users.py index 0e201791..974d30cd 100644 --- a/plexpy/users.py +++ b/plexpy/users.py @@ -679,15 +679,17 @@ class Users(object): return recently_watched - def get_users(self): + def get_users(self, include_deleted=False): monitor_db = database.MonitorDatabase() + where = '' if include_deleted else 'WHERE deleted_user = 0' + try: query = "SELECT id AS row_id, user_id, username, friendly_name, thumb, custom_avatar_url, email, " \ "is_active, is_admin, is_home_user, is_allow_sync, is_restricted, " \ "do_notify, keep_history, allow_guest, shared_libraries, " \ "filter_all, filter_movies, filter_tv, filter_music, filter_photos " \ - "FROM users WHERE deleted_user = 0" + "FROM users %s" % where result = monitor_db.select(query=query) except Exception as e: logger.warn("Tautulli Users :: Unable to execute database query for get_users: %s." % e) From 344f19c9d6581cddf92ff89dafadf358b1b0e784 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Mar 2024 14:53:10 -0700 Subject: [PATCH 02/13] Bump actions/cache from 3 to 4 (#2261) Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> [skip ci] --- .github/workflows/publish-docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index f0947104..1185e5eb 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -47,7 +47,7 @@ jobs: version: latest - name: Cache Docker Layers - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: /tmp/.buildx-cache key: ${{ runner.os }}-buildx-${{ github.sha }} From d3504e8a3c192f28c12397494857c7b2dcc6e31a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Mar 2024 14:53:44 -0700 Subject: [PATCH 03/13] Bump softprops/action-gh-release from 1 to 2 (#2273) Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 1 to 2. - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/v1...v2) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> [skip ci] --- .github/workflows/publish-installers.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-installers.yml b/.github/workflows/publish-installers.yml index 45610edf..7b79eea6 100644 --- a/.github/workflows/publish-installers.yml +++ b/.github/workflows/publish-installers.yml @@ -129,7 +129,7 @@ jobs: echo "$EOF" >> $GITHUB_OUTPUT - name: Create Release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 id: create_release env: GITHUB_TOKEN: ${{ secrets.GHACTIONS_TOKEN }} From c1b8be0227d2aa47e4092e86a5e4e1e617ff0b13 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Mar 2024 15:20:52 -0700 Subject: [PATCH 04/13] Bump arrow from 1.2.3 to 1.3.0 (#2172) * Bump arrow from 1.2.3 to 1.3.0 Bumps [arrow](https://github.com/arrow-py/arrow) from 1.2.3 to 1.3.0. - [Release notes](https://github.com/arrow-py/arrow/releases) - [Changelog](https://github.com/arrow-py/arrow/blob/master/CHANGELOG.rst) - [Commits](https://github.com/arrow-py/arrow/compare/1.2.3...1.3.0) --- updated-dependencies: - dependency-name: arrow dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Update arrow==1.3.0 --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> [skip ci] --- lib/arrow/_version.py | 2 +- lib/arrow/arrow.py | 31 ++--- lib/arrow/factory.py | 3 - lib/arrow/formatter.py | 4 - lib/arrow/locales.py | 34 ++++-- lib/arrow/parser.py | 20 +-- lib/dateutil-stubs/METADATA.toml | 6 + lib/dateutil-stubs/__init__.pyi | 0 lib/dateutil-stubs/_common.pyi | 9 ++ lib/dateutil-stubs/easter.pyi | 8 ++ lib/dateutil-stubs/parser/__init__.pyi | 67 ++++++++++ lib/dateutil-stubs/parser/isoparser.pyi | 15 +++ lib/dateutil-stubs/py.typed | 1 + lib/dateutil-stubs/relativedelta.pyi | 97 +++++++++++++++ lib/dateutil-stubs/rrule.pyi | 111 +++++++++++++++++ lib/dateutil-stubs/tz/__init__.pyi | 15 +++ lib/dateutil-stubs/tz/_common.pyi | 28 +++++ lib/dateutil-stubs/tz/tz.pyi | 115 ++++++++++++++++++ lib/dateutil-stubs/utils.pyi | 5 + lib/dateutil-stubs/zoneinfo/__init__.pyi | 17 +++ lib/dateutil-stubs/zoneinfo/rebuild.pyi | 11 ++ lib/dateutil/__init__.py | 16 +++ lib/dateutil/_version.py | 5 +- lib/dateutil/parser/isoparser.py | 2 +- lib/dateutil/relativedelta.py | 2 +- lib/dateutil/rrule.py | 2 +- lib/dateutil/tz/tz.py | 2 +- .../zoneinfo/dateutil-zoneinfo.tar.gz | Bin 174394 -> 156400 bytes requirements.txt | 2 +- 29 files changed, 564 insertions(+), 66 deletions(-) create mode 100644 lib/dateutil-stubs/METADATA.toml create mode 100644 lib/dateutil-stubs/__init__.pyi create mode 100644 lib/dateutil-stubs/_common.pyi create mode 100644 lib/dateutil-stubs/easter.pyi create mode 100644 lib/dateutil-stubs/parser/__init__.pyi create mode 100644 lib/dateutil-stubs/parser/isoparser.pyi create mode 100644 lib/dateutil-stubs/py.typed create mode 100644 lib/dateutil-stubs/relativedelta.pyi create mode 100644 lib/dateutil-stubs/rrule.pyi create mode 100644 lib/dateutil-stubs/tz/__init__.pyi create mode 100644 lib/dateutil-stubs/tz/_common.pyi create mode 100644 lib/dateutil-stubs/tz/tz.pyi create mode 100644 lib/dateutil-stubs/utils.pyi create mode 100644 lib/dateutil-stubs/zoneinfo/__init__.pyi create mode 100644 lib/dateutil-stubs/zoneinfo/rebuild.pyi diff --git a/lib/arrow/_version.py b/lib/arrow/_version.py index 10aa336c..67bc602a 100644 --- a/lib/arrow/_version.py +++ b/lib/arrow/_version.py @@ -1 +1 @@ -__version__ = "1.2.3" +__version__ = "1.3.0" diff --git a/lib/arrow/arrow.py b/lib/arrow/arrow.py index 1ede107f..8d329efd 100644 --- a/lib/arrow/arrow.py +++ b/lib/arrow/arrow.py @@ -168,9 +168,9 @@ class Arrow: isinstance(tzinfo, dt_tzinfo) and hasattr(tzinfo, "localize") and hasattr(tzinfo, "zone") - and tzinfo.zone # type: ignore[attr-defined] + and tzinfo.zone ): - tzinfo = parser.TzinfoParser.parse(tzinfo.zone) # type: ignore[attr-defined] + tzinfo = parser.TzinfoParser.parse(tzinfo.zone) elif isinstance(tzinfo, str): tzinfo = parser.TzinfoParser.parse(tzinfo) @@ -495,7 +495,7 @@ class Arrow: yield current values = [getattr(current, f) for f in cls._ATTRS] - current = cls(*values, tzinfo=tzinfo).shift( # type: ignore + current = cls(*values, tzinfo=tzinfo).shift( # type: ignore[misc] **{frame_relative: relative_steps} ) @@ -578,7 +578,7 @@ class Arrow: for _ in range(3 - len(values)): values.append(1) - floor = self.__class__(*values, tzinfo=self.tzinfo) # type: ignore + floor = self.__class__(*values, tzinfo=self.tzinfo) # type: ignore[misc] if frame_absolute == "week": # if week_start is greater than self.isoweekday() go back one week by setting delta = 7 @@ -792,7 +792,6 @@ class Arrow: return self._datetime.isoformat() def __format__(self, formatstr: str) -> str: - if len(formatstr) > 0: return self.format(formatstr) @@ -804,7 +803,6 @@ class Arrow: # attributes and properties def __getattr__(self, name: str) -> int: - if name == "week": return self.isocalendar()[1] @@ -965,7 +963,6 @@ class Arrow: absolute_kwargs = {} for key, value in kwargs.items(): - if key in self._ATTRS: absolute_kwargs[key] = value elif key in ["week", "quarter"]: @@ -1022,7 +1019,6 @@ class Arrow: additional_attrs = ["weeks", "quarters", "weekday"] for key, value in kwargs.items(): - if key in self._ATTRS_PLURAL or key in additional_attrs: relative_kwargs[key] = value else: @@ -1259,11 +1255,10 @@ class Arrow: ) if trunc(abs(delta)) != 1: - granularity += "s" # type: ignore + granularity += "s" # type: ignore[assignment] return locale.describe(granularity, delta, only_distance=only_distance) else: - if not granularity: raise ValueError( "Empty granularity list provided. " @@ -1314,7 +1309,7 @@ class Arrow: def dehumanize(self, input_string: str, locale: str = "en_us") -> "Arrow": """Returns a new :class:`Arrow ` object, that represents - the time difference relative to the attrbiutes of the + the time difference relative to the attributes of the :class:`Arrow ` object. :param timestring: a ``str`` representing a humanized relative time. @@ -1367,7 +1362,6 @@ class Arrow: # Search input string for each time unit within locale for unit, unit_object in locale_obj.timeframes.items(): - # Need to check the type of unit_object to create the correct dictionary if isinstance(unit_object, Mapping): strings_to_search = unit_object @@ -1378,7 +1372,6 @@ class Arrow: # Needs to cycle all through strings as some locales have strings that # could overlap in a regex match, since input validation isn't being performed. for time_delta, time_string in strings_to_search.items(): - # Replace {0} with regex \d representing digits search_string = str(time_string) search_string = search_string.format(r"\d+") @@ -1419,7 +1412,7 @@ class Arrow: # Assert error if string does not modify any units if not any([True for k, v in unit_visited.items() if v]): raise ValueError( - "Input string not valid. Note: Some locales do not support the week granulairty in Arrow. " + "Input string not valid. Note: Some locales do not support the week granularity in Arrow. " "If you are attempting to use the week granularity on an unsupported locale, this could be the cause of this error." ) @@ -1718,7 +1711,6 @@ class Arrow: # math def __add__(self, other: Any) -> "Arrow": - if isinstance(other, (timedelta, relativedelta)): return self.fromdatetime(self._datetime + other, self._datetime.tzinfo) @@ -1736,7 +1728,6 @@ class Arrow: pass # pragma: no cover def __sub__(self, other: Any) -> Union[timedelta, "Arrow"]: - if isinstance(other, (timedelta, relativedelta)): return self.fromdatetime(self._datetime - other, self._datetime.tzinfo) @@ -1749,7 +1740,6 @@ class Arrow: return NotImplemented def __rsub__(self, other: Any) -> timedelta: - if isinstance(other, dt_datetime): return other - self._datetime @@ -1758,42 +1748,36 @@ class Arrow: # comparisons def __eq__(self, other: Any) -> bool: - if not isinstance(other, (Arrow, dt_datetime)): return False return self._datetime == self._get_datetime(other) def __ne__(self, other: Any) -> bool: - if not isinstance(other, (Arrow, dt_datetime)): return True return not self.__eq__(other) def __gt__(self, other: Any) -> bool: - if not isinstance(other, (Arrow, dt_datetime)): return NotImplemented return self._datetime > self._get_datetime(other) def __ge__(self, other: Any) -> bool: - if not isinstance(other, (Arrow, dt_datetime)): return NotImplemented return self._datetime >= self._get_datetime(other) def __lt__(self, other: Any) -> bool: - if not isinstance(other, (Arrow, dt_datetime)): return NotImplemented return self._datetime < self._get_datetime(other) def __le__(self, other: Any) -> bool: - if not isinstance(other, (Arrow, dt_datetime)): return NotImplemented @@ -1865,7 +1849,6 @@ class Arrow: def _get_iteration_params(cls, end: Any, limit: Optional[int]) -> Tuple[Any, int]: """Sets default end and limit values for range method.""" if end is None: - if limit is None: raise ValueError("One of 'end' or 'limit' is required.") diff --git a/lib/arrow/factory.py b/lib/arrow/factory.py index aad4af8b..f35085f1 100644 --- a/lib/arrow/factory.py +++ b/lib/arrow/factory.py @@ -267,11 +267,9 @@ class ArrowFactory: raise TypeError(f"Cannot parse single argument of type {type(arg)!r}.") elif arg_count == 2: - arg_1, arg_2 = args[0], args[1] if isinstance(arg_1, datetime): - # (datetime, tzinfo/str) -> fromdatetime @ tzinfo if isinstance(arg_2, (dt_tzinfo, str)): return self.type.fromdatetime(arg_1, tzinfo=arg_2) @@ -281,7 +279,6 @@ class ArrowFactory: ) elif isinstance(arg_1, date): - # (date, tzinfo/str) -> fromdate @ tzinfo if isinstance(arg_2, (dt_tzinfo, str)): return self.type.fromdate(arg_1, tzinfo=arg_2) diff --git a/lib/arrow/formatter.py b/lib/arrow/formatter.py index 728bea1a..d45f7153 100644 --- a/lib/arrow/formatter.py +++ b/lib/arrow/formatter.py @@ -29,7 +29,6 @@ FORMAT_W3C: Final[str] = "YYYY-MM-DD HH:mm:ssZZ" class DateTimeFormatter: - # This pattern matches characters enclosed in square brackets are matched as # an atomic group. For more info on atomic groups and how to they are # emulated in Python's re library, see https://stackoverflow.com/a/13577411/2701578 @@ -41,18 +40,15 @@ class DateTimeFormatter: locale: locales.Locale def __init__(self, locale: str = DEFAULT_LOCALE) -> None: - self.locale = locales.get_locale(locale) def format(cls, dt: datetime, fmt: str) -> str: - # FIXME: _format_token() is nullable return cls._FORMAT_RE.sub( lambda m: cast(str, cls._format_token(dt, m.group(0))), fmt ) def _format_token(self, dt: datetime, token: Optional[str]) -> Optional[str]: - if token and token.startswith("[") and token.endswith("]"): return token[1:-1] diff --git a/lib/arrow/locales.py b/lib/arrow/locales.py index 3627497f..34b2a098 100644 --- a/lib/arrow/locales.py +++ b/lib/arrow/locales.py @@ -129,7 +129,6 @@ class Locale: _locale_map[locale_name.lower().replace("_", "-")] = cls def __init__(self) -> None: - self._month_name_to_ordinal = None def describe( @@ -174,7 +173,7 @@ class Locale: # Needed to determine the correct relative string to use timeframe_value = 0 - for _unit_name, unit_value in timeframes: + for _, unit_value in timeframes: if trunc(unit_value) != 0: timeframe_value = trunc(unit_value) break @@ -285,7 +284,6 @@ class Locale: timeframe: TimeFrameLiteral, delta: Union[float, int], ) -> str: - if timeframe == "now": return humanized @@ -425,7 +423,7 @@ class ItalianLocale(Locale): "hours": "{0} ore", "day": "un giorno", "days": "{0} giorni", - "week": "una settimana,", + "week": "una settimana", "weeks": "{0} settimane", "month": "un mese", "months": "{0} mesi", @@ -867,14 +865,16 @@ class FinnishLocale(Locale): timeframes: ClassVar[Mapping[TimeFrameLiteral, Union[str, Mapping[str, str]]]] = { "now": "juuri nyt", - "second": "sekunti", - "seconds": {"past": "{0} muutama sekunti", "future": "{0} muutaman sekunnin"}, + "second": {"past": "sekunti", "future": "sekunnin"}, + "seconds": {"past": "{0} sekuntia", "future": "{0} sekunnin"}, "minute": {"past": "minuutti", "future": "minuutin"}, "minutes": {"past": "{0} minuuttia", "future": "{0} minuutin"}, "hour": {"past": "tunti", "future": "tunnin"}, "hours": {"past": "{0} tuntia", "future": "{0} tunnin"}, - "day": "päivä", + "day": {"past": "päivä", "future": "päivän"}, "days": {"past": "{0} päivää", "future": "{0} päivän"}, + "week": {"past": "viikko", "future": "viikon"}, + "weeks": {"past": "{0} viikkoa", "future": "{0} viikon"}, "month": {"past": "kuukausi", "future": "kuukauden"}, "months": {"past": "{0} kuukautta", "future": "{0} kuukauden"}, "year": {"past": "vuosi", "future": "vuoden"}, @@ -1887,7 +1887,7 @@ class GermanBaseLocale(Locale): future = "in {0}" and_word = "und" - timeframes = { + timeframes: ClassVar[Dict[TimeFrameLiteral, str]] = { "now": "gerade eben", "second": "einer Sekunde", "seconds": "{0} Sekunden", @@ -1982,7 +1982,9 @@ class GermanBaseLocale(Locale): return super().describe(timeframe, delta, only_distance) # German uses a different case without 'in' or 'ago' - humanized = self.timeframes_only_distance[timeframe].format(trunc(abs(delta))) + humanized: str = self.timeframes_only_distance[timeframe].format( + trunc(abs(delta)) + ) return humanized @@ -2547,6 +2549,8 @@ class ArabicLocale(Locale): "hours": {"2": "ساعتين", "ten": "{0} ساعات", "higher": "{0} ساعة"}, "day": "يوم", "days": {"2": "يومين", "ten": "{0} أيام", "higher": "{0} يوم"}, + "week": "اسبوع", + "weeks": {"2": "اسبوعين", "ten": "{0} أسابيع", "higher": "{0} اسبوع"}, "month": "شهر", "months": {"2": "شهرين", "ten": "{0} أشهر", "higher": "{0} شهر"}, "year": "سنة", @@ -3709,6 +3713,8 @@ class HungarianLocale(Locale): "hours": {"past": "{0} órával", "future": "{0} óra"}, "day": {"past": "egy nappal", "future": "egy nap"}, "days": {"past": "{0} nappal", "future": "{0} nap"}, + "week": {"past": "egy héttel", "future": "egy hét"}, + "weeks": {"past": "{0} héttel", "future": "{0} hét"}, "month": {"past": "egy hónappal", "future": "egy hónap"}, "months": {"past": "{0} hónappal", "future": "{0} hónap"}, "year": {"past": "egy évvel", "future": "egy év"}, @@ -3934,7 +3940,6 @@ class ThaiLocale(Locale): class LaotianLocale(Locale): - names = ["lo", "lo-la"] past = "{0} ກ່ອນຫນ້ານີ້" @@ -4119,6 +4124,7 @@ class BengaliLocale(Locale): return f"{n}র্থ" if n == 6: return f"{n}ষ্ঠ" + return "" class RomanshLocale(Locale): @@ -4137,6 +4143,8 @@ class RomanshLocale(Locale): "hours": "{0} ura", "day": "in di", "days": "{0} dis", + "week": "in'emna", + "weeks": "{0} emnas", "month": "in mais", "months": "{0} mais", "year": "in onn", @@ -5399,7 +5407,7 @@ class LuxembourgishLocale(Locale): future = "an {0}" and_word = "an" - timeframes = { + timeframes: ClassVar[Dict[TimeFrameLiteral, str]] = { "now": "just elo", "second": "enger Sekonn", "seconds": "{0} Sekonnen", @@ -5487,7 +5495,9 @@ class LuxembourgishLocale(Locale): return super().describe(timeframe, delta, only_distance) # Luxembourgish uses a different case without 'in' or 'ago' - humanized = self.timeframes_only_distance[timeframe].format(trunc(abs(delta))) + humanized: str = self.timeframes_only_distance[timeframe].format( + trunc(abs(delta)) + ) return humanized diff --git a/lib/arrow/parser.py b/lib/arrow/parser.py index e95d78b0..645e3da7 100644 --- a/lib/arrow/parser.py +++ b/lib/arrow/parser.py @@ -159,7 +159,6 @@ class DateTimeParser: _input_re_map: Dict[_FORMAT_TYPE, Pattern[str]] def __init__(self, locale: str = DEFAULT_LOCALE, cache_size: int = 0) -> None: - self.locale = locales.get_locale(locale) self._input_re_map = self._BASE_INPUT_RE_MAP.copy() self._input_re_map.update( @@ -196,7 +195,6 @@ class DateTimeParser: def parse_iso( self, datetime_string: str, normalize_whitespace: bool = False ) -> datetime: - if normalize_whitespace: datetime_string = re.sub(r"\s+", " ", datetime_string.strip()) @@ -236,13 +234,14 @@ class DateTimeParser: ] if has_time: - if has_space_divider: date_string, time_string = datetime_string.split(" ", 1) else: date_string, time_string = datetime_string.split("T", 1) - time_parts = re.split(r"[\+\-Z]", time_string, 1, re.IGNORECASE) + time_parts = re.split( + r"[\+\-Z]", time_string, maxsplit=1, flags=re.IGNORECASE + ) time_components: Optional[Match[str]] = self._TIME_RE.match(time_parts[0]) @@ -303,7 +302,6 @@ class DateTimeParser: fmt: Union[List[str], str], normalize_whitespace: bool = False, ) -> datetime: - if normalize_whitespace: datetime_string = re.sub(r"\s+", " ", datetime_string) @@ -341,12 +339,11 @@ class DateTimeParser: f"Unable to find a match group for the specified token {token!r}." ) - self._parse_token(token, value, parts) # type: ignore + self._parse_token(token, value, parts) # type: ignore[arg-type] return self._build_datetime(parts) def _generate_pattern_re(self, fmt: str) -> Tuple[List[_FORMAT_TYPE], Pattern[str]]: - # fmt is a string of tokens like 'YYYY-MM-DD' # we construct a new string by replacing each # token by its pattern: @@ -498,7 +495,6 @@ class DateTimeParser: value: Any, parts: _Parts, ) -> None: - if token == "YYYY": parts["year"] = int(value) @@ -508,7 +504,7 @@ class DateTimeParser: elif token in ["MMMM", "MMM"]: # FIXME: month_number() is nullable - parts["month"] = self.locale.month_number(value.lower()) # type: ignore + parts["month"] = self.locale.month_number(value.lower()) # type: ignore[typeddict-item] elif token in ["MM", "M"]: parts["month"] = int(value) @@ -588,7 +584,6 @@ class DateTimeParser: weekdate = parts.get("weekdate") if weekdate is not None: - year, week = int(weekdate[0]), int(weekdate[1]) if weekdate[2] is not None: @@ -712,7 +707,6 @@ class DateTimeParser: ) def _parse_multiformat(self, string: str, formats: Iterable[str]) -> datetime: - _datetime: Optional[datetime] = None for fmt in formats: @@ -740,12 +734,11 @@ class DateTimeParser: class TzinfoParser: _TZINFO_RE: ClassVar[Pattern[str]] = re.compile( - r"^([\+\-])?(\d{2})(?:\:?(\d{2}))?$" + r"^(?:\(UTC)*([\+\-])?(\d{2})(?:\:?(\d{2}))?" ) @classmethod def parse(cls, tzinfo_string: str) -> dt_tzinfo: - tzinfo: Optional[dt_tzinfo] = None if tzinfo_string == "local": @@ -755,7 +748,6 @@ class TzinfoParser: tzinfo = tz.tzutc() else: - iso_match = cls._TZINFO_RE.match(tzinfo_string) if iso_match: diff --git a/lib/dateutil-stubs/METADATA.toml b/lib/dateutil-stubs/METADATA.toml new file mode 100644 index 00000000..5f2be1e4 --- /dev/null +++ b/lib/dateutil-stubs/METADATA.toml @@ -0,0 +1,6 @@ +version = "2.9.*" +upstream_repository = "https://github.com/dateutil/dateutil" +partial_stub = true + +[tool.stubtest] +ignore_missing_stub = true diff --git a/lib/dateutil-stubs/__init__.pyi b/lib/dateutil-stubs/__init__.pyi new file mode 100644 index 00000000..e69de29b diff --git a/lib/dateutil-stubs/_common.pyi b/lib/dateutil-stubs/_common.pyi new file mode 100644 index 00000000..75bf74c5 --- /dev/null +++ b/lib/dateutil-stubs/_common.pyi @@ -0,0 +1,9 @@ +from typing_extensions import Self + +class weekday: + def __init__(self, weekday: int, n: int | None = None) -> None: ... + def __call__(self, n: int) -> Self: ... + def __eq__(self, other: object) -> bool: ... + def __hash__(self) -> int: ... + weekday: int + n: int diff --git a/lib/dateutil-stubs/easter.pyi b/lib/dateutil-stubs/easter.pyi new file mode 100644 index 00000000..952d1191 --- /dev/null +++ b/lib/dateutil-stubs/easter.pyi @@ -0,0 +1,8 @@ +from datetime import date +from typing import Literal + +EASTER_JULIAN: Literal[1] +EASTER_ORTHODOX: Literal[2] +EASTER_WESTERN: Literal[3] + +def easter(year: int, method: Literal[1, 2, 3] = 3) -> date: ... diff --git a/lib/dateutil-stubs/parser/__init__.pyi b/lib/dateutil-stubs/parser/__init__.pyi new file mode 100644 index 00000000..c375ff15 --- /dev/null +++ b/lib/dateutil-stubs/parser/__init__.pyi @@ -0,0 +1,67 @@ +from collections.abc import Callable, Mapping +from datetime import datetime, tzinfo +from typing import IO, Any +from typing_extensions import TypeAlias + +from .isoparser import isoparse as isoparse, isoparser as isoparser + +_FileOrStr: TypeAlias = bytes | str | IO[str] | IO[Any] +_TzData: TypeAlias = tzinfo | int | str | None +_TzInfo: TypeAlias = Mapping[str, _TzData] | Callable[[str, int], _TzData] + +class parserinfo: + JUMP: list[str] + WEEKDAYS: list[tuple[str, ...]] + MONTHS: list[tuple[str, ...]] + HMS: list[tuple[str, str, str]] + AMPM: list[tuple[str, str]] + UTCZONE: list[str] + PERTAIN: list[str] + TZOFFSET: dict[str, int] + def __init__(self, dayfirst: bool = False, yearfirst: bool = False) -> None: ... + def jump(self, name: str) -> bool: ... + def weekday(self, name: str) -> int | None: ... + def month(self, name: str) -> int | None: ... + def hms(self, name: str) -> int | None: ... + def ampm(self, name: str) -> int | None: ... + def pertain(self, name: str) -> bool: ... + def utczone(self, name: str) -> bool: ... + def tzoffset(self, name: str) -> int | None: ... + def convertyear(self, year: int) -> int: ... + def validate(self, res: datetime) -> bool: ... + +class parser: + def __init__(self, info: parserinfo | None = None) -> None: ... + def parse( + self, + timestr: _FileOrStr, + default: datetime | None = None, + ignoretz: bool = False, + tzinfos: _TzInfo | None = None, + *, + dayfirst: bool | None = ..., + yearfirst: bool | None = ..., + fuzzy: bool = ..., + fuzzy_with_tokens: bool = ..., + ) -> datetime: ... + +DEFAULTPARSER: parser + +def parse( + timestr: _FileOrStr, + parserinfo: parserinfo | None = None, + *, + dayfirst: bool | None = ..., + yearfirst: bool | None = ..., + ignoretz: bool = ..., + fuzzy: bool = ..., + fuzzy_with_tokens: bool = ..., + default: datetime | None = ..., + tzinfos: _TzInfo | None = ..., +) -> datetime: ... + +class _tzparser: ... + +DEFAULTTZPARSER: _tzparser + +class ParserError(ValueError): ... diff --git a/lib/dateutil-stubs/parser/isoparser.pyi b/lib/dateutil-stubs/parser/isoparser.pyi new file mode 100644 index 00000000..fc5e46d9 --- /dev/null +++ b/lib/dateutil-stubs/parser/isoparser.pyi @@ -0,0 +1,15 @@ +from _typeshed import SupportsRead +from datetime import date, datetime, time, tzinfo +from typing_extensions import TypeAlias + +_Readable: TypeAlias = SupportsRead[str | bytes] +_TakesAscii: TypeAlias = str | bytes | _Readable + +class isoparser: + def __init__(self, sep: str | bytes | None = None): ... + def isoparse(self, dt_str: _TakesAscii) -> datetime: ... + def parse_isodate(self, datestr: _TakesAscii) -> date: ... + def parse_isotime(self, timestr: _TakesAscii) -> time: ... + def parse_tzstr(self, tzstr: _TakesAscii, zero_as_utc: bool = True) -> tzinfo: ... + +def isoparse(dt_str: _TakesAscii) -> datetime: ... diff --git a/lib/dateutil-stubs/py.typed b/lib/dateutil-stubs/py.typed new file mode 100644 index 00000000..b648ac92 --- /dev/null +++ b/lib/dateutil-stubs/py.typed @@ -0,0 +1 @@ +partial diff --git a/lib/dateutil-stubs/relativedelta.pyi b/lib/dateutil-stubs/relativedelta.pyi new file mode 100644 index 00000000..394713db --- /dev/null +++ b/lib/dateutil-stubs/relativedelta.pyi @@ -0,0 +1,97 @@ +from datetime import date, timedelta +from typing import SupportsFloat, TypeVar, overload +from typing_extensions import Self, TypeAlias + +# See #9817 for why we reexport this here +from ._common import weekday as weekday + +_DateT = TypeVar("_DateT", bound=date) +# Work around attribute and type having the same name. +_Weekday: TypeAlias = weekday + +MO: weekday +TU: weekday +WE: weekday +TH: weekday +FR: weekday +SA: weekday +SU: weekday + +class relativedelta: + years: int + months: int + days: int + leapdays: int + hours: int + minutes: int + seconds: int + microseconds: int + year: int | None + month: int | None + weekday: _Weekday | None + day: int | None + hour: int | None + minute: int | None + second: int | None + microsecond: int | None + def __init__( + self, + dt1: date | None = None, + dt2: date | None = None, + years: int | None = 0, + months: int | None = 0, + days: int | None = 0, + leapdays: int | None = 0, + weeks: int | None = 0, + hours: int | None = 0, + minutes: int | None = 0, + seconds: int | None = 0, + microseconds: int | None = 0, + year: int | None = None, + month: int | None = None, + day: int | None = None, + weekday: int | _Weekday | None = None, + yearday: int | None = None, + nlyearday: int | None = None, + hour: int | None = None, + minute: int | None = None, + second: int | None = None, + microsecond: int | None = None, + ) -> None: ... + @property + def weeks(self) -> int: ... + @weeks.setter + def weeks(self, value: int) -> None: ... + def normalized(self) -> Self: ... + # TODO: use Union when mypy will handle it properly in overloaded operator + # methods (#2129, #1442, #1264 in mypy) + @overload + def __add__(self, other: relativedelta) -> Self: ... + @overload + def __add__(self, other: timedelta) -> Self: ... + @overload + def __add__(self, other: _DateT) -> _DateT: ... + @overload + def __radd__(self, other: relativedelta) -> Self: ... + @overload + def __radd__(self, other: timedelta) -> Self: ... + @overload + def __radd__(self, other: _DateT) -> _DateT: ... + @overload + def __rsub__(self, other: relativedelta) -> Self: ... + @overload + def __rsub__(self, other: timedelta) -> Self: ... + @overload + def __rsub__(self, other: _DateT) -> _DateT: ... + def __sub__(self, other: relativedelta) -> Self: ... + def __neg__(self) -> Self: ... + def __bool__(self) -> bool: ... + def __nonzero__(self) -> bool: ... + def __mul__(self, other: SupportsFloat) -> Self: ... + def __rmul__(self, other: SupportsFloat) -> Self: ... + def __eq__(self, other: object) -> bool: ... + def __ne__(self, other: object) -> bool: ... + def __div__(self, other: SupportsFloat) -> Self: ... + def __truediv__(self, other: SupportsFloat) -> Self: ... + def __abs__(self) -> Self: ... + def __hash__(self) -> int: ... diff --git a/lib/dateutil-stubs/rrule.pyi b/lib/dateutil-stubs/rrule.pyi new file mode 100644 index 00000000..f091cfbd --- /dev/null +++ b/lib/dateutil-stubs/rrule.pyi @@ -0,0 +1,111 @@ +import datetime +from _typeshed import Incomplete +from collections.abc import Iterable, Iterator, Sequence +from typing_extensions import TypeAlias + +from ._common import weekday as weekdaybase + +YEARLY: int +MONTHLY: int +WEEKLY: int +DAILY: int +HOURLY: int +MINUTELY: int +SECONDLY: int + +class weekday(weekdaybase): ... + +weekdays: tuple[weekday, weekday, weekday, weekday, weekday, weekday, weekday] +MO: weekday +TU: weekday +WE: weekday +TH: weekday +FR: weekday +SA: weekday +SU: weekday + +class rrulebase: + def __init__(self, cache: bool = False) -> None: ... + def __iter__(self) -> Iterator[datetime.datetime]: ... + def __getitem__(self, item): ... + def __contains__(self, item): ... + def count(self): ... + def before(self, dt, inc: bool = False): ... + def after(self, dt, inc: bool = False): ... + def xafter(self, dt, count: Incomplete | None = None, inc: bool = False): ... + def between(self, after, before, inc: bool = False, count: int = 1): ... + +class rrule(rrulebase): + def __init__( + self, + freq, + dtstart: datetime.date | None = None, + interval: int = 1, + wkst: weekday | int | None = None, + count: int | None = None, + until: datetime.date | int | None = None, + bysetpos: int | Iterable[int] | None = None, + bymonth: int | Iterable[int] | None = None, + bymonthday: int | Iterable[int] | None = None, + byyearday: int | Iterable[int] | None = None, + byeaster: int | Iterable[int] | None = None, + byweekno: int | Iterable[int] | None = None, + byweekday: int | weekday | Iterable[int] | Iterable[weekday] | None = None, + byhour: int | Iterable[int] | None = None, + byminute: int | Iterable[int] | None = None, + bysecond: int | Iterable[int] | None = None, + cache: bool = False, + ) -> None: ... + def replace(self, **kwargs): ... + +_RRule: TypeAlias = rrule + +class _iterinfo: + rrule: _RRule + def __init__(self, rrule: _RRule) -> None: ... + yearlen: int | None + nextyearlen: int | None + yearordinal: int | None + yearweekday: int | None + mmask: Sequence[int] | None + mdaymask: Sequence[int] | None + nmdaymask: Sequence[int] | None + wdaymask: Sequence[int] | None + mrange: Sequence[int] | None + wnomask: Sequence[int] | None + nwdaymask: Sequence[int] | None + eastermask: Sequence[int] | None + lastyear: int | None + lastmonth: int | None + def rebuild(self, year, month): ... + def ydayset(self, year, month, day): ... + def mdayset(self, year, month, day): ... + def wdayset(self, year, month, day): ... + def ddayset(self, year, month, day): ... + def htimeset(self, hour, minute, second): ... + def mtimeset(self, hour, minute, second): ... + def stimeset(self, hour, minute, second): ... + +class rruleset(rrulebase): + class _genitem: + dt: Incomplete + genlist: list[Incomplete] + gen: Incomplete + def __init__(self, genlist, gen) -> None: ... + def __next__(self) -> None: ... + next = __next__ + def __lt__(self, other) -> bool: ... + def __gt__(self, other) -> bool: ... + def __eq__(self, other) -> bool: ... + def __ne__(self, other) -> bool: ... + + def __init__(self, cache: bool = False) -> None: ... + def rrule(self, rrule: _RRule): ... + def rdate(self, rdate): ... + def exrule(self, exrule): ... + def exdate(self, exdate): ... + +class _rrulestr: + def __call__(self, s, **kwargs) -> rrule | rruleset: ... + +rrulestr: _rrulestr diff --git a/lib/dateutil-stubs/tz/__init__.pyi b/lib/dateutil-stubs/tz/__init__.pyi new file mode 100644 index 00000000..334ca482 --- /dev/null +++ b/lib/dateutil-stubs/tz/__init__.pyi @@ -0,0 +1,15 @@ +from .tz import ( + datetime_ambiguous as datetime_ambiguous, + datetime_exists as datetime_exists, + gettz as gettz, + resolve_imaginary as resolve_imaginary, + tzfile as tzfile, + tzical as tzical, + tzlocal as tzlocal, + tzoffset as tzoffset, + tzrange as tzrange, + tzstr as tzstr, + tzutc as tzutc, +) + +UTC: tzutc diff --git a/lib/dateutil-stubs/tz/_common.pyi b/lib/dateutil-stubs/tz/_common.pyi new file mode 100644 index 00000000..4e64822f --- /dev/null +++ b/lib/dateutil-stubs/tz/_common.pyi @@ -0,0 +1,28 @@ +import abc +from datetime import datetime, timedelta, tzinfo +from typing import ClassVar + +def tzname_in_python2(namefunc): ... +def enfold(dt: datetime, fold: int = 1): ... + +class _DatetimeWithFold(datetime): + @property + def fold(self): ... + +# Doesn't actually have ABCMeta as the metaclass at runtime, +# but mypy complains if we don't have it in the stub. +# See discussion in #8908 +class _tzinfo(tzinfo, metaclass=abc.ABCMeta): + def is_ambiguous(self, dt: datetime) -> bool: ... + def fromutc(self, dt: datetime) -> datetime: ... + +class tzrangebase(_tzinfo): + def __init__(self) -> None: ... + def utcoffset(self, dt: datetime | None) -> timedelta | None: ... + def dst(self, dt: datetime | None) -> timedelta | None: ... + def tzname(self, dt: datetime | None) -> str: ... + def fromutc(self, dt: datetime) -> datetime: ... + def is_ambiguous(self, dt: datetime) -> bool: ... + __hash__: ClassVar[None] # type: ignore[assignment] + def __ne__(self, other): ... + __reduce__ = object.__reduce__ diff --git a/lib/dateutil-stubs/tz/tz.pyi b/lib/dateutil-stubs/tz/tz.pyi new file mode 100644 index 00000000..6addba65 --- /dev/null +++ b/lib/dateutil-stubs/tz/tz.pyi @@ -0,0 +1,115 @@ +import datetime +from _typeshed import Incomplete +from typing import ClassVar, Literal, Protocol, TypeVar + +from ..relativedelta import relativedelta +from ._common import _tzinfo as _tzinfo, enfold as enfold, tzname_in_python2 as tzname_in_python2, tzrangebase as tzrangebase + +_DT = TypeVar("_DT", bound=datetime.datetime) + +ZERO: datetime.timedelta +EPOCH: datetime.datetime +EPOCHORDINAL: int + +class tzutc(datetime.tzinfo): + def utcoffset(self, dt: datetime.datetime | None) -> datetime.timedelta | None: ... + def dst(self, dt: datetime.datetime | None) -> datetime.timedelta | None: ... + def tzname(self, dt: datetime.datetime | None) -> str: ... + def is_ambiguous(self, dt: datetime.datetime | None) -> bool: ... + def fromutc(self, dt: _DT) -> _DT: ... + def __eq__(self, other): ... + __hash__: ClassVar[None] # type: ignore[assignment] + def __ne__(self, other): ... + __reduce__ = object.__reduce__ + +class tzoffset(datetime.tzinfo): + def __init__(self, name, offset) -> None: ... + def utcoffset(self, dt: datetime.datetime | None) -> datetime.timedelta | None: ... + def dst(self, dt: datetime.datetime | None) -> datetime.timedelta | None: ... + def is_ambiguous(self, dt: datetime.datetime | None) -> bool: ... + def tzname(self, dt: datetime.datetime | None) -> str: ... + def fromutc(self, dt: _DT) -> _DT: ... + def __eq__(self, other): ... + __hash__: ClassVar[None] # type: ignore[assignment] + def __ne__(self, other): ... + __reduce__ = object.__reduce__ + @classmethod + def instance(cls, name, offset) -> tzoffset: ... + +class tzlocal(_tzinfo): + def __init__(self) -> None: ... + def utcoffset(self, dt: datetime.datetime | None) -> datetime.timedelta | None: ... + def dst(self, dt: datetime.datetime | None) -> datetime.timedelta | None: ... + def tzname(self, dt: datetime.datetime | None) -> str: ... + def is_ambiguous(self, dt: datetime.datetime | None) -> bool: ... + def __eq__(self, other): ... + __hash__: ClassVar[None] # type: ignore[assignment] + def __ne__(self, other): ... + __reduce__ = object.__reduce__ + +class _ttinfo: + def __init__(self) -> None: ... + def __eq__(self, other): ... + __hash__: ClassVar[None] # type: ignore[assignment] + def __ne__(self, other): ... + +class _TZFileReader(Protocol): + # optional attribute: + # name: str + def read(self, size: int, /) -> bytes: ... + def seek(self, target: int, whence: Literal[1], /) -> object: ... + +class tzfile(_tzinfo): + def __init__(self, fileobj: str | _TZFileReader, filename: str | None = None) -> None: ... + def is_ambiguous(self, dt: datetime.datetime | None, idx: int | None = None) -> bool: ... + def utcoffset(self, dt: datetime.datetime | None) -> datetime.timedelta | None: ... + def dst(self, dt: datetime.datetime | None) -> datetime.timedelta | None: ... + def tzname(self, dt: datetime.datetime | None) -> str: ... + def __eq__(self, other): ... + __hash__: ClassVar[None] # type: ignore[assignment] + def __ne__(self, other): ... + def __reduce__(self): ... + def __reduce_ex__(self, protocol): ... + +class tzrange(tzrangebase): + hasdst: bool + def __init__( + self, + stdabbr: str, + stdoffset: int | datetime.timedelta | None = None, + dstabbr: str | None = None, + dstoffset: int | datetime.timedelta | None = None, + start: relativedelta | None = None, + end: relativedelta | None = None, + ) -> None: ... + def transitions(self, year: int) -> tuple[datetime.datetime, datetime.datetime]: ... + def __eq__(self, other): ... + +class tzstr(tzrange): + hasdst: bool + def __init__(self, s: str, posix_offset: bool = False) -> None: ... + @classmethod + def instance(cls, name, offset) -> tzoffset: ... + +class _ICalReader(Protocol): + # optional attribute: + # name: str + def read(self) -> str: ... + +class tzical: + def __init__(self, fileobj: str | _ICalReader) -> None: ... + def keys(self): ... + def get(self, tzid: Incomplete | None = None): ... + +TZFILES: list[str] +TZPATHS: list[str] + +def datetime_exists(dt: datetime.datetime, tz: datetime.tzinfo | None = None) -> bool: ... +def datetime_ambiguous(dt: datetime.datetime, tz: datetime.tzinfo | None = None) -> bool: ... +def resolve_imaginary(dt: datetime.datetime) -> datetime.datetime: ... + +class _GetTZ: + def __call__(self, name: str | None = ...) -> datetime.tzinfo | None: ... + def nocache(self, name: str | None) -> datetime.tzinfo | None: ... + +gettz: _GetTZ diff --git a/lib/dateutil-stubs/utils.pyi b/lib/dateutil-stubs/utils.pyi new file mode 100644 index 00000000..8c9f5e44 --- /dev/null +++ b/lib/dateutil-stubs/utils.pyi @@ -0,0 +1,5 @@ +from datetime import datetime, timedelta, tzinfo + +def default_tzinfo(dt: datetime, tzinfo: tzinfo) -> datetime: ... +def today(tzinfo: tzinfo | None = None) -> datetime: ... +def within_delta(dt1: datetime, dt2: datetime, delta: timedelta) -> bool: ... diff --git a/lib/dateutil-stubs/zoneinfo/__init__.pyi b/lib/dateutil-stubs/zoneinfo/__init__.pyi new file mode 100644 index 00000000..7bd2845a --- /dev/null +++ b/lib/dateutil-stubs/zoneinfo/__init__.pyi @@ -0,0 +1,17 @@ +from _typeshed import Incomplete +from typing import IO +from typing_extensions import TypeAlias + +__all__ = ["get_zonefile_instance", "gettz", "gettz_db_metadata"] + +_MetadataType: TypeAlias = dict[str, Incomplete] + +class ZoneInfoFile: + zones: dict[Incomplete, Incomplete] + metadata: _MetadataType | None + def __init__(self, zonefile_stream: IO[bytes] | None = None) -> None: ... + def get(self, name, default: Incomplete | None = None): ... + +def get_zonefile_instance(new_instance: bool = False) -> ZoneInfoFile: ... +def gettz(name): ... +def gettz_db_metadata() -> _MetadataType: ... diff --git a/lib/dateutil-stubs/zoneinfo/rebuild.pyi b/lib/dateutil-stubs/zoneinfo/rebuild.pyi new file mode 100644 index 00000000..e3845926 --- /dev/null +++ b/lib/dateutil-stubs/zoneinfo/rebuild.pyi @@ -0,0 +1,11 @@ +from _typeshed import Incomplete, StrOrBytesPath +from collections.abc import Sequence +from tarfile import TarInfo + +def rebuild( + filename: StrOrBytesPath, + tag: Incomplete | None = None, + format: str = "gz", + zonegroups: Sequence[str | TarInfo] = [], + metadata: Incomplete | None = None, +) -> None: ... diff --git a/lib/dateutil/__init__.py b/lib/dateutil/__init__.py index 0defb82e..a2c19c06 100644 --- a/lib/dateutil/__init__.py +++ b/lib/dateutil/__init__.py @@ -1,4 +1,6 @@ # -*- coding: utf-8 -*- +import sys + try: from ._version import version as __version__ except ImportError: @@ -6,3 +8,17 @@ except ImportError: __all__ = ['easter', 'parser', 'relativedelta', 'rrule', 'tz', 'utils', 'zoneinfo'] + +def __getattr__(name): + import importlib + + if name in __all__: + return importlib.import_module("." + name, __name__) + raise AttributeError( + "module {!r} has not attribute {!r}".format(__name__, name) + ) + + +def __dir__(): + # __dir__ should include all the lazy-importable modules as well. + return [x for x in globals() if x not in sys.modules] + __all__ diff --git a/lib/dateutil/_version.py b/lib/dateutil/_version.py index b723056a..ddda9809 100644 --- a/lib/dateutil/_version.py +++ b/lib/dateutil/_version.py @@ -1,5 +1,4 @@ -# coding: utf-8 # file generated by setuptools_scm # don't change, don't track in version control -version = '2.8.2' -version_tuple = (2, 8, 2) +__version__ = version = '2.9.0.post0' +__version_tuple__ = version_tuple = (2, 9, 0) diff --git a/lib/dateutil/parser/isoparser.py b/lib/dateutil/parser/isoparser.py index 5d7bee38..7060087d 100644 --- a/lib/dateutil/parser/isoparser.py +++ b/lib/dateutil/parser/isoparser.py @@ -72,7 +72,7 @@ class isoparser(object): Common: - ``YYYY`` - - ``YYYY-MM`` or ``YYYYMM`` + - ``YYYY-MM`` - ``YYYY-MM-DD`` or ``YYYYMMDD`` Uncommon: diff --git a/lib/dateutil/relativedelta.py b/lib/dateutil/relativedelta.py index a9e85f7e..cd323a54 100644 --- a/lib/dateutil/relativedelta.py +++ b/lib/dateutil/relativedelta.py @@ -48,7 +48,7 @@ class relativedelta(object): the corresponding arithmetic operation on the original datetime value with the information in the relativedelta. - weekday: + weekday: One of the weekday instances (MO, TU, etc) available in the relativedelta module. These instances may receive a parameter N, specifying the Nth weekday, which could be positive or negative diff --git a/lib/dateutil/rrule.py b/lib/dateutil/rrule.py index b3203393..571a0d2b 100644 --- a/lib/dateutil/rrule.py +++ b/lib/dateutil/rrule.py @@ -182,7 +182,7 @@ class rrulebase(object): # __len__() introduces a large performance penalty. def count(self): """ Returns the number of recurrences in this set. It will have go - trough the whole recurrence, if this hasn't been done before. """ + through the whole recurrence, if this hasn't been done before. """ if self._len is None: for x in self: pass diff --git a/lib/dateutil/tz/tz.py b/lib/dateutil/tz/tz.py index c67f56d4..61759144 100644 --- a/lib/dateutil/tz/tz.py +++ b/lib/dateutil/tz/tz.py @@ -34,7 +34,7 @@ except ImportError: from warnings import warn ZERO = datetime.timedelta(0) -EPOCH = datetime.datetime.utcfromtimestamp(0) +EPOCH = datetime.datetime(1970, 1, 1, 0, 0) EPOCHORDINAL = EPOCH.toordinal() diff --git a/lib/dateutil/zoneinfo/dateutil-zoneinfo.tar.gz b/lib/dateutil/zoneinfo/dateutil-zoneinfo.tar.gz index 524c48e12db7dfe159f282e4664f71ce249e1970..1461f8c862df8c3eae75e0ea376788b5b2602269 100644 GIT binary patch literal 156400 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

oF5%wc?0lVIdiCvTMwKQ}m1M4pzSU2C#ISwFq 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
oHJaZa%&cRgbKqQScY`o5It4F}rqGD>-kDeG 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 diff --git a/requirements.txt b/requirements.txt index 73b6e088..84451150 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ apscheduler==3.10.1 -arrow==1.2.3 +arrow==1.3.0 backports.csv==1.0.7 backports.functools-lru-cache==1.6.6 backports.zoneinfo==0.2.1;python_version<"3.9" From e30779647593bc07ffa0ba5d74e09e29ebb8a822 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Mar 2024 15:21:17 -0700 Subject: [PATCH 05/13] Bump simplejson from 3.19.1 to 3.19.2 (#2176) * Bump simplejson from 3.19.1 to 3.19.2 Bumps [simplejson](https://github.com/simplejson/simplejson) from 3.19.1 to 3.19.2. - [Release notes](https://github.com/simplejson/simplejson/releases) - [Changelog](https://github.com/simplejson/simplejson/blob/master/CHANGES.txt) - [Commits](https://github.com/simplejson/simplejson/compare/v3.19.1...v3.19.2) --- updated-dependencies: - dependency-name: simplejson dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update simplejson==3.19.2 --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> [skip ci] --- lib/simplejson/__init__.py | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/simplejson/__init__.py b/lib/simplejson/__init__.py index 7e533a24..2d1900d8 100644 --- a/lib/simplejson/__init__.py +++ b/lib/simplejson/__init__.py @@ -118,7 +118,7 @@ Serializing multiple objects to JSON lines (newline-delimited JSON):: """ from __future__ import absolute_import -__version__ = '3.19.1' +__version__ = '3.19.2' __all__ = [ 'dump', 'dumps', 'load', 'loads', 'JSONDecoder', 'JSONDecodeError', 'JSONEncoder', diff --git a/requirements.txt b/requirements.txt index 84451150..7b0b98a8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -39,7 +39,7 @@ pytz==2023.3 requests==2.31.0 requests-oauthlib==1.3.1 rumps==0.4.0; platform_system == "Darwin" -simplejson==3.19.1 +simplejson==3.19.2 six==1.16.0 tempora==5.5.0 tokenize-rt==5.2.0 From dbffb519f53fbd5565a55566a54e29a280608669 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Mar 2024 15:21:33 -0700 Subject: [PATCH 06/13] Bump bleach from 6.0.0 to 6.1.0 (#2177) * Bump bleach from 6.0.0 to 6.1.0 Bumps [bleach](https://github.com/mozilla/bleach) from 6.0.0 to 6.1.0. - [Changelog](https://github.com/mozilla/bleach/blob/main/CHANGES) - [Commits](https://github.com/mozilla/bleach/compare/v6.0.0...v6.1.0) --- updated-dependencies: - dependency-name: bleach dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Update bleach==6.1.0 --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> [skip ci] --- lib/bleach/__init__.py | 4 ++-- lib/bleach/html5lib_shim.py | 15 +++++++++++---- lib/bleach/linkifier.py | 6 +++--- requirements.txt | 2 +- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/lib/bleach/__init__.py b/lib/bleach/__init__.py index 4e87eb80..12e93b4d 100644 --- a/lib/bleach/__init__.py +++ b/lib/bleach/__init__.py @@ -11,9 +11,9 @@ from bleach.sanitizer import ( # yyyymmdd -__releasedate__ = "20230123" +__releasedate__ = "20231006" # x.y.z or x.y.z.dev0 -- semver -__version__ = "6.0.0" +__version__ = "6.1.0" __all__ = ["clean", "linkify"] diff --git a/lib/bleach/html5lib_shim.py b/lib/bleach/html5lib_shim.py index aa5189b1..ca1cc8c8 100644 --- a/lib/bleach/html5lib_shim.py +++ b/lib/bleach/html5lib_shim.py @@ -395,10 +395,17 @@ class BleachHTMLTokenizer(HTMLTokenizer): # followed by a series of characters. It's treated as a tag # name that abruptly ends, but we should treat that like # character data - yield { - "type": TAG_TOKEN_TYPE_CHARACTERS, - "data": "<" + self.currentToken["name"], - } + yield {"type": TAG_TOKEN_TYPE_CHARACTERS, "data": self.stream.get_tag()} + elif last_error_token["data"] in ( + "eof-in-attribute-name", + "eof-in-attribute-value-no-quotes", + ): + # Handle the case where the text being parsed ends with < + # followed by a series of characters and then space and then + # more characters. It's treated as a tag name followed by an + # attribute that abruptly ends, but we should treat that like + # character data. + yield {"type": TAG_TOKEN_TYPE_CHARACTERS, "data": self.stream.get_tag()} else: yield last_error_token diff --git a/lib/bleach/linkifier.py b/lib/bleach/linkifier.py index 679d7ead..8fcefb2c 100644 --- a/lib/bleach/linkifier.py +++ b/lib/bleach/linkifier.py @@ -45,8 +45,8 @@ def build_url_re(tlds=TLDS, protocols=html5lib_shim.allowed_protocols): r"""\(* # Match any opening parentheses. \b(?"]*)? - # /path/zz (excluding "unsafe" chars from RFC 1738, + (?:[/?][^\s\{{\}}\|\\\^`<>"]*)? + # /path/zz (excluding "unsafe" chars from RFC 3986, # except for # and ~, which happen in practice) """.format( "|".join(sorted(protocols)), "|".join(sorted(tlds)) @@ -591,7 +591,7 @@ class LinkifyFilter(html5lib_shim.Filter): in_a = False token_buffer = [] else: - token_buffer.append(token) + token_buffer.extend(list(self.extract_entities(token))) continue if token["type"] in ["StartTag", "EmptyTag"]: diff --git a/requirements.txt b/requirements.txt index 7b0b98a8..8c8e91f3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ backports.csv==1.0.7 backports.functools-lru-cache==1.6.6 backports.zoneinfo==0.2.1;python_version<"3.9" beautifulsoup4==4.12.2 -bleach==6.0.0 +bleach==6.1.0 certifi==2023.7.22 cheroot==10.0.0 cherrypy==18.8.0 From 24b6d37bbe02c37416c838b4d3e529fefe444811 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Mar 2024 15:21:51 -0700 Subject: [PATCH 07/13] Bump websocket-client from 1.6.2 to 1.7.0 (#2207) * Bump websocket-client from 1.6.2 to 1.7.0 Bumps [websocket-client](https://github.com/websocket-client/websocket-client) from 1.6.2 to 1.7.0. - [Release notes](https://github.com/websocket-client/websocket-client/releases) - [Changelog](https://github.com/websocket-client/websocket-client/blob/master/ChangeLog) - [Commits](https://github.com/websocket-client/websocket-client/compare/v1.6.2...v1.7.0) --- updated-dependencies: - dependency-name: websocket-client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Update websocket-client==1.7.0 --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> [skip ci] --- lib/websocket/__init__.py | 2 +- lib/websocket/_abnf.py | 183 +++++++----- lib/websocket/_app.py | 283 ++++++++++++------ lib/websocket/_cookiejar.py | 37 ++- lib/websocket/_core.py | 182 +++++++----- lib/websocket/_exceptions.py | 16 +- lib/websocket/_handshake.py | 109 +++---- lib/websocket/_http.py | 203 +++++++------ lib/websocket/_logging.py | 27 +- lib/websocket/_socket.py | 34 ++- lib/websocket/_ssl_compat.py | 5 +- lib/websocket/_url.py | 49 +++- lib/websocket/_utils.py | 405 ++++++++++++++++++++++++-- lib/websocket/_wsdump.py | 87 +++--- lib/websocket/py.typed | 0 lib/websocket/tests/echo-server.py | 6 +- lib/websocket/tests/test_abnf.py | 98 +++++-- lib/websocket/tests/test_app.py | 180 +++++++----- lib/websocket/tests/test_cookiejar.py | 13 +- lib/websocket/tests/test_http.py | 281 +++++++++++++++--- lib/websocket/tests/test_url.py | 278 +++++++++++++----- lib/websocket/tests/test_websocket.py | 230 +++++++++------ requirements.txt | 2 +- 23 files changed, 1909 insertions(+), 801 deletions(-) create mode 100644 lib/websocket/py.typed diff --git a/lib/websocket/__init__.py b/lib/websocket/__init__.py index bfa71981..2ff75879 100644 --- a/lib/websocket/__init__.py +++ b/lib/websocket/__init__.py @@ -23,4 +23,4 @@ from ._exceptions import * from ._logging import * from ._socket import * -__version__ = "1.6.2" +__version__ = "1.7.0" diff --git a/lib/websocket/_abnf.py b/lib/websocket/_abnf.py index 6c2466ad..416ebc8f 100644 --- a/lib/websocket/_abnf.py +++ b/lib/websocket/_abnf.py @@ -2,10 +2,11 @@ import array import os import struct import sys +from threading import Lock +from typing import Callable, Optional, Union from ._exceptions import * from ._utils import validate_utf8 -from threading import Lock """ _abnf.py @@ -33,8 +34,9 @@ try: # Note that wsaccel is unmaintained. from wsaccel.xormask import XorMaskerSimple - def _mask(_m, _d) -> bytes: - return XorMaskerSimple(_m).process(_d) + def _mask(mask_value: array.array, data_value: array.array) -> bytes: + mask_result: bytes = XorMaskerSimple(mask_value).process(data_value) + return mask_result except ImportError: # wsaccel is not available, use websocket-client _mask() @@ -42,26 +44,30 @@ except ImportError: def _mask(mask_value: array.array, data_value: array.array) -> bytes: datalen = len(data_value) - data_value = int.from_bytes(data_value, native_byteorder) - mask_value = int.from_bytes(mask_value * (datalen // 4) + mask_value[: datalen % 4], native_byteorder) - return (data_value ^ mask_value).to_bytes(datalen, native_byteorder) + int_data_value = int.from_bytes(data_value, native_byteorder) + int_mask_value = int.from_bytes( + mask_value * (datalen // 4) + mask_value[: datalen % 4], native_byteorder + ) + return (int_data_value ^ int_mask_value).to_bytes(datalen, native_byteorder) __all__ = [ - 'ABNF', 'continuous_frame', 'frame_buffer', - 'STATUS_NORMAL', - 'STATUS_GOING_AWAY', - 'STATUS_PROTOCOL_ERROR', - 'STATUS_UNSUPPORTED_DATA_TYPE', - 'STATUS_STATUS_NOT_AVAILABLE', - 'STATUS_ABNORMAL_CLOSED', - 'STATUS_INVALID_PAYLOAD', - 'STATUS_POLICY_VIOLATION', - 'STATUS_MESSAGE_TOO_BIG', - 'STATUS_INVALID_EXTENSION', - 'STATUS_UNEXPECTED_CONDITION', - 'STATUS_BAD_GATEWAY', - 'STATUS_TLS_HANDSHAKE_ERROR', + "ABNF", + "continuous_frame", + "frame_buffer", + "STATUS_NORMAL", + "STATUS_GOING_AWAY", + "STATUS_PROTOCOL_ERROR", + "STATUS_UNSUPPORTED_DATA_TYPE", + "STATUS_STATUS_NOT_AVAILABLE", + "STATUS_ABNORMAL_CLOSED", + "STATUS_INVALID_PAYLOAD", + "STATUS_POLICY_VIOLATION", + "STATUS_MESSAGE_TOO_BIG", + "STATUS_INVALID_EXTENSION", + "STATUS_UNEXPECTED_CONDITION", + "STATUS_BAD_GATEWAY", + "STATUS_TLS_HANDSHAKE_ERROR", ] # closing frame status codes. @@ -110,11 +116,17 @@ class ABNF: OPCODE_BINARY = 0x2 OPCODE_CLOSE = 0x8 OPCODE_PING = 0x9 - OPCODE_PONG = 0xa + OPCODE_PONG = 0xA # available operation code value tuple - OPCODES = (OPCODE_CONT, OPCODE_TEXT, OPCODE_BINARY, OPCODE_CLOSE, - OPCODE_PING, OPCODE_PONG) + OPCODES = ( + OPCODE_CONT, + OPCODE_TEXT, + OPCODE_BINARY, + OPCODE_CLOSE, + OPCODE_PING, + OPCODE_PONG, + ) # opcode human readable string OPCODE_MAP = { @@ -123,16 +135,24 @@ class ABNF: OPCODE_BINARY: "binary", OPCODE_CLOSE: "close", OPCODE_PING: "ping", - OPCODE_PONG: "pong" + OPCODE_PONG: "pong", } # data length threshold. - LENGTH_7 = 0x7e + LENGTH_7 = 0x7E LENGTH_16 = 1 << 16 LENGTH_63 = 1 << 63 - def __init__(self, fin: int = 0, rsv1: int = 0, rsv2: int = 0, rsv3: int = 0, - opcode: int = OPCODE_TEXT, mask: int = 1, data: str or bytes = "") -> None: + def __init__( + self, + fin: int = 0, + rsv1: int = 0, + rsv2: int = 0, + rsv3: int = 0, + opcode: int = OPCODE_TEXT, + mask_value: int = 1, + data: Union[str, bytes, None] = "", + ) -> None: """ Constructor for ABNF. Please check RFC for arguments. """ @@ -141,7 +161,7 @@ class ABNF: self.rsv2 = rsv2 self.rsv3 = rsv3 self.opcode = opcode - self.mask = mask + self.mask_value = mask_value if data is None: data = "" self.data = data @@ -173,7 +193,7 @@ class ABNF: if l > 2 and not skip_utf8_validation and not validate_utf8(self.data[2:]): raise WebSocketProtocolException("Invalid close frame.") - code = 256 * self.data[0] + self.data[1] + code = 256 * int(self.data[0]) + int(self.data[1]) if not self._is_valid_close_status(code): raise WebSocketProtocolException("Invalid close opcode %r", code) @@ -182,12 +202,10 @@ class ABNF: return code in VALID_CLOSE_STATUS or (3000 <= code < 5000) def __str__(self) -> str: - return "fin=" + str(self.fin) \ - + " opcode=" + str(self.opcode) \ - + " data=" + str(self.data) + return f"fin={self.fin} opcode={self.opcode} data={self.data}" @staticmethod - def create_frame(data: str, opcode: int, fin: int = 1) -> 'ABNF': + def create_frame(data: Union[bytes, str], opcode: int, fin: int = 1) -> "ABNF": """ Create frame to send text, binary and other data. @@ -219,34 +237,39 @@ class ABNF: if length >= ABNF.LENGTH_63: raise ValueError("data is too long") - frame_header = chr(self.fin << 7 | - self.rsv1 << 6 | self.rsv2 << 5 | self.rsv3 << 4 | - self.opcode).encode('latin-1') + frame_header = chr( + self.fin << 7 + | self.rsv1 << 6 + | self.rsv2 << 5 + | self.rsv3 << 4 + | self.opcode + ).encode("latin-1") if length < ABNF.LENGTH_7: - frame_header += chr(self.mask << 7 | length).encode('latin-1') + frame_header += chr(self.mask_value << 7 | length).encode("latin-1") elif length < ABNF.LENGTH_16: - frame_header += chr(self.mask << 7 | 0x7e).encode('latin-1') + frame_header += chr(self.mask_value << 7 | 0x7E).encode("latin-1") frame_header += struct.pack("!H", length) else: - frame_header += chr(self.mask << 7 | 0x7f).encode('latin-1') + frame_header += chr(self.mask_value << 7 | 0x7F).encode("latin-1") frame_header += struct.pack("!Q", length) - if not self.mask: + if not self.mask_value: + if isinstance(self.data, str): + self.data = self.data.encode("utf-8") return frame_header + self.data - else: - mask_key = self.get_mask_key(4) - return frame_header + self._get_masked(mask_key) + mask_key = self.get_mask_key(4) + return frame_header + self._get_masked(mask_key) - def _get_masked(self, mask_key: str or bytes) -> bytes: + def _get_masked(self, mask_key: Union[str, bytes]) -> bytes: s = ABNF.mask(mask_key, self.data) if isinstance(mask_key, str): - mask_key = mask_key.encode('utf-8') + mask_key = mask_key.encode("utf-8") return mask_key + s @staticmethod - def mask(mask_key: str or bytes, data: str or bytes) -> bytes: + def mask(mask_key: Union[str, bytes], data: Union[str, bytes]) -> bytes: """ Mask or unmask data. Just do xor for each byte @@ -261,10 +284,10 @@ class ABNF: data = "" if isinstance(mask_key, str): - mask_key = mask_key.encode('latin-1') + mask_key = mask_key.encode("latin-1") if isinstance(data, str): - data = data.encode('latin-1') + data = data.encode("latin-1") return _mask(array.array("B", mask_key), array.array("B", data)) @@ -273,19 +296,21 @@ class frame_buffer: _HEADER_MASK_INDEX = 5 _HEADER_LENGTH_INDEX = 6 - def __init__(self, recv_fn: int, skip_utf8_validation: bool) -> None: + def __init__( + self, recv_fn: Callable[[int], int], skip_utf8_validation: bool + ) -> None: self.recv = recv_fn self.skip_utf8_validation = skip_utf8_validation # Buffers over the packets from the layer beneath until desired amount # bytes of bytes are received. - self.recv_buffer = [] + self.recv_buffer: list = [] self.clear() self.lock = Lock() def clear(self) -> None: - self.header = None - self.length = None - self.mask = None + self.header: Optional[tuple] = None + self.length: Optional[int] = None + self.mask_value: Union[bytes, str, None] = None def has_received_header(self) -> bool: return self.header is None @@ -297,41 +322,41 @@ class frame_buffer: rsv1 = b1 >> 6 & 1 rsv2 = b1 >> 5 & 1 rsv3 = b1 >> 4 & 1 - opcode = b1 & 0xf + opcode = b1 & 0xF b2 = header[1] has_mask = b2 >> 7 & 1 - length_bits = b2 & 0x7f + length_bits = b2 & 0x7F self.header = (fin, rsv1, rsv2, rsv3, opcode, has_mask, length_bits) - def has_mask(self) -> bool or int: + def has_mask(self) -> Union[bool, int]: if not self.header: return False - return self.header[frame_buffer._HEADER_MASK_INDEX] + header_val: int = self.header[frame_buffer._HEADER_MASK_INDEX] + return header_val def has_received_length(self) -> bool: return self.length is None def recv_length(self) -> None: bits = self.header[frame_buffer._HEADER_LENGTH_INDEX] - length_bits = bits & 0x7f - if length_bits == 0x7e: + length_bits = bits & 0x7F + if length_bits == 0x7E: v = self.recv_strict(2) self.length = struct.unpack("!H", v)[0] - elif length_bits == 0x7f: + elif length_bits == 0x7F: v = self.recv_strict(8) self.length = struct.unpack("!Q", v)[0] else: self.length = length_bits def has_received_mask(self) -> bool: - return self.mask is None + return self.mask_value is None def recv_mask(self) -> None: - self.mask = self.recv_strict(4) if self.has_mask() else "" + self.mask_value = self.recv_strict(4) if self.has_mask() else "" def recv_frame(self) -> ABNF: - with self.lock: # Header if self.has_received_header(): @@ -346,12 +371,12 @@ class frame_buffer: # Mask if self.has_received_mask(): self.recv_mask() - mask = self.mask + mask_value = self.mask_value # Payload payload = self.recv_strict(length) if has_mask: - payload = ABNF.mask(mask, payload) + payload = ABNF.mask(mask_value, payload) # Reset for next frame self.clear() @@ -385,18 +410,19 @@ class frame_buffer: class continuous_frame: - def __init__(self, fire_cont_frame: bool, skip_utf8_validation: bool) -> None: self.fire_cont_frame = fire_cont_frame self.skip_utf8_validation = skip_utf8_validation - self.cont_data = None - self.recving_frames = None + self.cont_data: Optional[list] = None + self.recving_frames: Optional[int] = None def validate(self, frame: ABNF) -> None: if not self.recving_frames and frame.opcode == ABNF.OPCODE_CONT: raise WebSocketProtocolException("Illegal frame") - if self.recving_frames and \ - frame.opcode in (ABNF.OPCODE_TEXT, ABNF.OPCODE_BINARY): + if self.recving_frames and frame.opcode in ( + ABNF.OPCODE_TEXT, + ABNF.OPCODE_BINARY, + ): raise WebSocketProtocolException("Illegal frame") def add(self, frame: ABNF) -> None: @@ -410,15 +436,18 @@ class continuous_frame: if frame.fin: self.recving_frames = None - def is_fire(self, frame: ABNF) -> bool or int: + def is_fire(self, frame: ABNF) -> Union[bool, int]: return frame.fin or self.fire_cont_frame - def extract(self, frame: ABNF) -> list: + def extract(self, frame: ABNF) -> tuple: data = self.cont_data self.cont_data = None frame.data = data[1] - if not self.fire_cont_frame and data[0] == ABNF.OPCODE_TEXT and not self.skip_utf8_validation and not validate_utf8(frame.data): - raise WebSocketPayloadException( - "cannot decode: " + repr(frame.data)) - - return [data[0], frame] + if ( + not self.fire_cont_frame + and data[0] == ABNF.OPCODE_TEXT + and not self.skip_utf8_validation + and not validate_utf8(frame.data) + ): + raise WebSocketPayloadException(f"cannot decode: {repr(frame.data)}") + return data[0], frame diff --git a/lib/websocket/_app.py b/lib/websocket/_app.py index 2577f1ba..4d8af3b5 100644 --- a/lib/websocket/_app.py +++ b/lib/websocket/_app.py @@ -1,18 +1,19 @@ import inspect import selectors -import sys +import socket import threading import time -import traceback -import socket - -from typing import Callable, Any +from typing import Any, Callable, Optional, Union from . import _logging from ._abnf import ABNF -from ._url import parse_url from ._core import WebSocket, getdefaulttimeout -from ._exceptions import * +from ._exceptions import ( + WebSocketConnectionClosedException, + WebSocketException, + WebSocketTimeoutException, +) +from ._url import parse_url """ _app.py @@ -47,22 +48,24 @@ class DispatcherBase: """ DispatcherBase """ - def __init__(self, app: Any, ping_timeout: float) -> None: + + def __init__(self, app: Any, ping_timeout: Union[float, int, None]) -> None: self.app = app self.ping_timeout = ping_timeout - def timeout(self, seconds: int, callback: Callable) -> None: + def timeout(self, seconds: Union[float, int, None], callback: Callable) -> None: time.sleep(seconds) callback() def reconnect(self, seconds: int, reconnector: Callable) -> None: try: - _logging.info("reconnect() - retrying in {seconds_count} seconds [{frame_count} frames in stack]".format( - seconds_count=seconds, frame_count=len(inspect.stack()))) + _logging.info( + f"reconnect() - retrying in {seconds} seconds [{len(inspect.stack())} frames in stack]" + ) time.sleep(seconds) reconnector(reconnecting=True) except KeyboardInterrupt as e: - _logging.info("User exited {err}".format(err=e)) + _logging.info(f"User exited {e}") raise e @@ -70,13 +73,18 @@ class Dispatcher(DispatcherBase): """ Dispatcher """ - def read(self, sock: socket.socket, read_callback: Callable, check_callback: Callable) -> None: + + def read( + self, + sock: socket.socket, + read_callback: Callable, + check_callback: Callable, + ) -> None: sel = selectors.DefaultSelector() sel.register(self.app.sock.sock, selectors.EVENT_READ) try: while self.app.keep_running: - r = sel.select(self.ping_timeout) - if r: + if sel.select(self.ping_timeout): if not read_callback(): break check_callback() @@ -88,24 +96,31 @@ class SSLDispatcher(DispatcherBase): """ SSLDispatcher """ - def read(self, sock: socket.socket, read_callback: Callable, check_callback: Callable) -> None: + + def read( + self, + sock: socket.socket, + read_callback: Callable, + check_callback: Callable, + ) -> None: sock = self.app.sock.sock sel = selectors.DefaultSelector() sel.register(sock, selectors.EVENT_READ) try: while self.app.keep_running: - r = self.select(sock, sel) - if r: + if self.select(sock, sel): if not read_callback(): break check_callback() finally: sel.close() - def select(self, sock, sel:selectors.DefaultSelector): + def select(self, sock, sel: selectors.DefaultSelector): sock = self.app.sock.sock if sock.pending(): - return [sock,] + return [ + sock, + ] r = sel.select(self.ping_timeout) @@ -117,17 +132,23 @@ class WrappedDispatcher: """ WrappedDispatcher """ - def __init__(self, app, ping_timeout: float, dispatcher: Dispatcher) -> None: + + def __init__(self, app, ping_timeout: Union[float, int, None], dispatcher) -> None: self.app = app self.ping_timeout = ping_timeout self.dispatcher = dispatcher dispatcher.signal(2, dispatcher.abort) # keyboard interrupt - def read(self, sock: socket.socket, read_callback: Callable, check_callback: Callable) -> None: + def read( + self, + sock: socket.socket, + read_callback: Callable, + check_callback: Callable, + ) -> None: self.dispatcher.read(sock, read_callback) self.ping_timeout and self.timeout(self.ping_timeout, check_callback) - def timeout(self, seconds: int, callback: Callable) -> None: + def timeout(self, seconds: float, callback: Callable) -> None: self.dispatcher.timeout(seconds, callback) def reconnect(self, seconds: int, reconnector: Callable) -> None: @@ -139,14 +160,24 @@ class WebSocketApp: Higher level of APIs are provided. The interface is like JavaScript WebSocket object. """ - def __init__(self, url: str, header: list or dict or Callable = None, - on_open: Callable = None, on_message: Callable = None, on_error: Callable = None, - on_close: Callable = None, on_ping: Callable = None, on_pong: Callable = None, - on_cont_message: Callable = None, - keep_running: bool = True, get_mask_key: Callable = None, cookie: str = None, - subprotocols: list = None, - on_data: Callable = None, - socket: socket.socket = None) -> None: + def __init__( + self, + url: str, + header: Union[list, dict, Callable, None] = None, + on_open: Optional[Callable[[WebSocket], None]] = None, + on_message: Optional[Callable[[WebSocket, Any], None]] = None, + on_error: Optional[Callable[[WebSocket, Any], None]] = None, + on_close: Optional[Callable[[WebSocket, Any, Any], None]] = None, + on_ping: Optional[Callable] = None, + on_pong: Optional[Callable] = None, + on_cont_message: Optional[Callable] = None, + keep_running: bool = True, + get_mask_key: Optional[Callable] = None, + cookie: Optional[str] = None, + subprotocols: Optional[list] = None, + on_data: Optional[Callable] = None, + socket: Optional[socket.socket] = None, + ) -> None: """ WebSocketApp initialization @@ -222,13 +253,13 @@ class WebSocketApp: self.on_cont_message = on_cont_message self.keep_running = False self.get_mask_key = get_mask_key - self.sock = None - self.last_ping_tm = 0 - self.last_pong_tm = 0 - self.ping_thread = None - self.stop_ping = None - self.ping_interval = 0 - self.ping_timeout = None + self.sock: Optional[WebSocket] = None + self.last_ping_tm = float(0) + self.last_pong_tm = float(0) + self.ping_thread: Optional[threading.Thread] = None + self.stop_ping: Optional[threading.Event] = None + self.ping_interval = float(0) + self.ping_timeout: Union[float, int, None] = None self.ping_payload = "" self.subprotocols = subprotocols self.prepared_socket = socket @@ -236,7 +267,7 @@ class WebSocketApp: self.has_done_teardown = False self.has_done_teardown_lock = threading.Lock() - def send(self, data: str, opcode: int = ABNF.OPCODE_TEXT) -> None: + def send(self, data: Union[bytes, str], opcode: int = ABNF.OPCODE_TEXT) -> None: """ send message @@ -250,8 +281,21 @@ class WebSocketApp: """ if not self.sock or self.sock.send(data, opcode) == 0: - raise WebSocketConnectionClosedException( - "Connection is already closed.") + raise WebSocketConnectionClosedException("Connection is already closed.") + + def send_text(self, text_data: str) -> None: + """ + Sends UTF-8 encoded text. + """ + if not self.sock or self.sock.send(text_data, ABNF.OPCODE_TEXT) == 0: + raise WebSocketConnectionClosedException("Connection is already closed.") + + def send_bytes(self, data: Union[bytes, bytearray]) -> None: + """ + Sends a sequence of bytes. + """ + if not self.sock or self.sock.send(data, ABNF.OPCODE_BINARY) == 0: + raise WebSocketConnectionClosedException("Connection is already closed.") def close(self, **kwargs) -> None: """ @@ -263,7 +307,7 @@ class WebSocketApp: self.sock = None def _start_ping_thread(self) -> None: - self.last_ping_tm = self.last_pong_tm = 0 + self.last_ping_tm = self.last_pong_tm = float(0) self.stop_ping = threading.Event() self.ping_thread = threading.Thread(target=self._send_ping) self.ping_thread.daemon = True @@ -274,7 +318,7 @@ class WebSocketApp: self.stop_ping.set() if self.ping_thread and self.ping_thread.is_alive(): self.ping_thread.join(3) - self.last_ping_tm = self.last_pong_tm = 0 + self.last_ping_tm = self.last_pong_tm = float(0) def _send_ping(self) -> None: if self.stop_ping.wait(self.ping_interval) or self.keep_running is False: @@ -286,17 +330,28 @@ class WebSocketApp: _logging.debug("Sending ping") self.sock.ping(self.ping_payload) except Exception as e: - _logging.debug("Failed to send ping: {err}".format(err=e)) + _logging.debug(f"Failed to send ping: {e}") - def run_forever(self, sockopt: tuple = None, sslopt: dict = None, - ping_interval: float = 0, ping_timeout: float or None = None, - ping_payload: str = "", - http_proxy_host: str = None, http_proxy_port: int or str = None, - http_no_proxy: list = None, http_proxy_auth: tuple = None, - http_proxy_timeout: float = None, - skip_utf8_validation: bool = False, - host: str = None, origin: str = None, dispatcher: Dispatcher = None, - suppress_origin: bool = False, proxy_type: str = None, reconnect: int = None) -> bool: + def run_forever( + self, + sockopt: tuple = None, + sslopt: dict = None, + ping_interval: Union[float, int] = 0, + ping_timeout: Union[float, int, None] = None, + ping_payload: str = "", + http_proxy_host: str = None, + http_proxy_port: Union[int, str] = None, + http_no_proxy: list = None, + http_proxy_auth: tuple = None, + http_proxy_timeout: Optional[float] = None, + skip_utf8_validation: bool = False, + host: str = None, + origin: str = None, + dispatcher=None, + suppress_origin: bool = False, + proxy_type: str = None, + reconnect: int = None, + ) -> bool: """ Run event loop for WebSocket framework. @@ -360,7 +415,7 @@ class WebSocketApp: if ping_timeout and ping_interval and ping_interval <= ping_timeout: raise WebSocketException("Ensure ping_interval > ping_timeout") if not sockopt: - sockopt = [] + sockopt = () if not sslopt: sslopt = {} if self.sock: @@ -394,7 +449,8 @@ class WebSocketApp: if self.sock: self.sock.close() close_status_code, close_reason = self._get_close_args( - close_frame if close_frame else None) + close_frame if close_frame else None + ) self.sock = None # Finally call the callback AFTER all teardown is complete @@ -405,24 +461,34 @@ class WebSocketApp: self.sock.shutdown() self.sock = WebSocket( - self.get_mask_key, sockopt=sockopt, sslopt=sslopt, + self.get_mask_key, + sockopt=sockopt, + sslopt=sslopt, fire_cont_frame=self.on_cont_message is not None, skip_utf8_validation=skip_utf8_validation, - enable_multithread=True) + enable_multithread=True, + ) self.sock.settimeout(getdefaulttimeout()) try: - header = self.header() if callable(self.header) else self.header self.sock.connect( - self.url, header=header, cookie=self.cookie, + self.url, + header=header, + cookie=self.cookie, http_proxy_host=http_proxy_host, - http_proxy_port=http_proxy_port, http_no_proxy=http_no_proxy, - http_proxy_auth=http_proxy_auth, http_proxy_timeout=http_proxy_timeout, + http_proxy_port=http_proxy_port, + http_no_proxy=http_no_proxy, + http_proxy_auth=http_proxy_auth, + http_proxy_timeout=http_proxy_timeout, subprotocols=self.subprotocols, - host=host, origin=origin, suppress_origin=suppress_origin, - proxy_type=proxy_type, socket=self.prepared_socket) + host=host, + origin=origin, + suppress_origin=suppress_origin, + proxy_type=proxy_type, + socket=self.prepared_socket, + ) _logging.info("Websocket connected") @@ -432,7 +498,13 @@ class WebSocketApp: self._callback(self.on_open) dispatcher.read(self.sock.sock, read, check) - except (WebSocketConnectionClosedException, ConnectionRefusedError, KeyboardInterrupt, SystemExit, Exception) as e: + except ( + WebSocketConnectionClosedException, + ConnectionRefusedError, + KeyboardInterrupt, + SystemExit, + Exception, + ) as e: handleDisconnect(e, reconnecting) def read() -> bool: @@ -441,7 +513,10 @@ class WebSocketApp: try: op_code, frame = self.sock.recv_data_frame(True) - except (WebSocketConnectionClosedException, KeyboardInterrupt) as e: + except ( + WebSocketConnectionClosedException, + KeyboardInterrupt, + ) as e: if custom_dispatcher: return handleDisconnect(e) else: @@ -455,10 +530,8 @@ class WebSocketApp: self.last_pong_tm = time.time() self._callback(self.on_pong, frame.data) elif op_code == ABNF.OPCODE_CONT and self.on_cont_message: - self._callback(self.on_data, frame.data, - frame.opcode, frame.fin) - self._callback(self.on_cont_message, - frame.data, frame.fin) + self._callback(self.on_data, frame.data, frame.opcode, frame.fin) + self._callback(self.on_cont_message, frame.data, frame.fin) else: data = frame.data if op_code == ABNF.OPCODE_TEXT and not skip_utf8_validation: @@ -469,18 +542,38 @@ class WebSocketApp: return True def check() -> bool: - if (self.ping_timeout): - has_timeout_expired = time.time() - self.last_ping_tm > self.ping_timeout - has_pong_not_arrived_after_last_ping = self.last_pong_tm - self.last_ping_tm < 0 - has_pong_arrived_too_late = self.last_pong_tm - self.last_ping_tm > self.ping_timeout + if self.ping_timeout: + has_timeout_expired = ( + time.time() - self.last_ping_tm > self.ping_timeout + ) + has_pong_not_arrived_after_last_ping = ( + self.last_pong_tm - self.last_ping_tm < 0 + ) + has_pong_arrived_too_late = ( + self.last_pong_tm - self.last_ping_tm > self.ping_timeout + ) - if (self.last_ping_tm and - has_timeout_expired and - (has_pong_not_arrived_after_last_ping or has_pong_arrived_too_late)): + if ( + self.last_ping_tm + and has_timeout_expired + and ( + has_pong_not_arrived_after_last_ping + or has_pong_arrived_too_late + ) + ): raise WebSocketTimeoutException("ping/pong timed out") return True - def handleDisconnect(e: Exception, reconnecting: bool = False) -> bool: + def handleDisconnect( + e: Union[ + WebSocketConnectionClosedException, + ConnectionRefusedError, + KeyboardInterrupt, + SystemExit, + Exception, + ], + reconnecting: bool = False, + ) -> bool: self.has_errored = True self._stop_ping_thread() if not reconnecting: @@ -492,25 +585,31 @@ class WebSocketApp: raise if reconnect: - _logging.info("{err} - reconnect".format(err=e)) + _logging.info(f"{e} - reconnect") if custom_dispatcher: - _logging.debug("Calling custom dispatcher reconnect [{frame_count} frames in stack]".format(frame_count=len(inspect.stack()))) + _logging.debug( + f"Calling custom dispatcher reconnect [{len(inspect.stack())} frames in stack]" + ) dispatcher.reconnect(reconnect, setSock) else: - _logging.error("{err} - goodbye".format(err=e)) + _logging.error(f"{e} - goodbye") teardown() custom_dispatcher = bool(dispatcher) - dispatcher = self.create_dispatcher(ping_timeout, dispatcher, parse_url(self.url)[3]) + dispatcher = self.create_dispatcher( + ping_timeout, dispatcher, parse_url(self.url)[3] + ) try: setSock() if not custom_dispatcher and reconnect: while self.keep_running: - _logging.debug("Calling dispatcher reconnect [{frame_count} frames in stack]".format(frame_count=len(inspect.stack()))) + _logging.debug( + f"Calling dispatcher reconnect [{len(inspect.stack())} frames in stack]" + ) dispatcher.reconnect(reconnect, setSock) except (KeyboardInterrupt, Exception) as e: - _logging.info("tearing down on exception {err}".format(err=e)) + _logging.info(f"tearing down on exception {e}") teardown() finally: if not custom_dispatcher: @@ -519,13 +618,17 @@ class WebSocketApp: return self.has_errored - def create_dispatcher(self, ping_timeout: int, dispatcher: Dispatcher = None, is_ssl: bool = False) -> DispatcherBase: + def create_dispatcher( + self, + ping_timeout: Union[float, int, None], + dispatcher: Optional[DispatcherBase] = None, + is_ssl: bool = False, + ) -> Union[Dispatcher, SSLDispatcher, WrappedDispatcher]: if dispatcher: # If custom dispatcher is set, use WrappedDispatcher return WrappedDispatcher(self, ping_timeout, dispatcher) timeout = ping_timeout or 10 if is_ssl: return SSLDispatcher(self, timeout) - return Dispatcher(self, timeout) def _get_close_args(self, close_frame: ABNF) -> list: @@ -540,8 +643,12 @@ class WebSocketApp: # Extract close frame status code if close_frame.data and len(close_frame.data) >= 2: - close_status_code = 256 * close_frame.data[0] + close_frame.data[1] - reason = close_frame.data[2:].decode('utf-8') + close_status_code = 256 * int(close_frame.data[0]) + int( + close_frame.data[1] + ) + reason = close_frame.data[2:] + if isinstance(reason, bytes): + reason = reason.decode("utf-8") return [close_status_code, reason] else: # Most likely reached this because len(close_frame_data.data) < 2 @@ -553,6 +660,6 @@ class WebSocketApp: callback(self, *args) except Exception as e: - _logging.error("error from callback {callback}: {err}".format(callback=callback, err=e)) + _logging.error(f"error from callback {callback}: {e}") if self.on_error: self.on_error(self, e) diff --git a/lib/websocket/_cookiejar.py b/lib/websocket/_cookiejar.py index 2047eddd..61079402 100644 --- a/lib/websocket/_cookiejar.py +++ b/lib/websocket/_cookiejar.py @@ -1,4 +1,5 @@ import http.cookies +from typing import Optional """ _cookiejar.py @@ -22,18 +23,21 @@ limitations under the License. class SimpleCookieJar: def __init__(self) -> None: - self.jar = dict() + self.jar: dict = dict() - def add(self, set_cookie: str) -> None: + def add(self, set_cookie: Optional[str]) -> None: if set_cookie: simpleCookie = http.cookies.SimpleCookie(set_cookie) for k, v in simpleCookie.items(): - domain = v.get("domain") - if domain: + if domain := v.get("domain"): if not domain.startswith("."): - domain = "." + domain - cookie = self.jar.get(domain) if self.jar.get(domain) else http.cookies.SimpleCookie() + domain = f".{domain}" + cookie = ( + self.jar.get(domain) + if self.jar.get(domain) + else http.cookies.SimpleCookie() + ) cookie.update(simpleCookie) self.jar[domain.lower()] = cookie @@ -42,10 +46,9 @@ class SimpleCookieJar: simpleCookie = http.cookies.SimpleCookie(set_cookie) for k, v in simpleCookie.items(): - domain = v.get("domain") - if domain: + if domain := v.get("domain"): if not domain.startswith("."): - domain = "." + domain + domain = f".{domain}" self.jar[domain.lower()] = simpleCookie def get(self, host: str) -> str: @@ -58,7 +61,15 @@ class SimpleCookieJar: if host.endswith(domain) or host == domain[1:]: cookies.append(self.jar.get(domain)) - return "; ".join(filter( - None, sorted( - ["%s=%s" % (k, v.value) for cookie in filter(None, cookies) for k, v in cookie.items()] - ))) + return "; ".join( + filter( + None, + sorted( + [ + "%s=%s" % (k, v.value) + for cookie in filter(None, cookies) + for k, v in cookie.items() + ] + ), + ) + ) diff --git a/lib/websocket/_core.py b/lib/websocket/_core.py index e81066ad..f28ca4b9 100644 --- a/lib/websocket/_core.py +++ b/lib/websocket/_core.py @@ -2,6 +2,7 @@ import socket import struct import threading import time +from typing import Optional, Union # websocket modules from ._abnf import * @@ -32,7 +33,7 @@ See the License for the specific language governing permissions and limitations under the License. """ -__all__ = ['WebSocket', 'create_connection'] +__all__ = ["WebSocket", "create_connection"] class WebSocket: @@ -73,9 +74,16 @@ class WebSocket: Skip utf8 validation. """ - def __init__(self, get_mask_key=None, sockopt=None, sslopt=None, - fire_cont_frame: bool = False, enable_multithread: bool = True, - skip_utf8_validation: bool = False, **_): + def __init__( + self, + get_mask_key=None, + sockopt=None, + sslopt=None, + fire_cont_frame: bool = False, + enable_multithread: bool = True, + skip_utf8_validation: bool = False, + **_, + ): """ Initialize WebSocket object. @@ -86,14 +94,13 @@ class WebSocket: """ self.sock_opt = sock_opt(sockopt, sslopt) self.handshake_response = None - self.sock = None + self.sock: Optional[socket.socket] = None self.connected = False self.get_mask_key = get_mask_key # These buffer over the build-up of a single frame. self.frame_buffer = frame_buffer(self._recv, skip_utf8_validation) - self.cont_frame = continuous_frame( - fire_cont_frame, skip_utf8_validation) + self.cont_frame = continuous_frame(fire_cont_frame, skip_utf8_validation) if enable_multithread: self.lock = threading.Lock() @@ -133,7 +140,7 @@ class WebSocket: """ self.get_mask_key = func - def gettimeout(self) -> float: + def gettimeout(self) -> Union[float, int, None]: """ Get the websocket timeout (in seconds) as an int or float @@ -144,7 +151,7 @@ class WebSocket: """ return self.sock_opt.timeout - def settimeout(self, timeout: float): + def settimeout(self, timeout: Union[float, int, None]): """ Set the timeout to the websocket. @@ -245,19 +252,26 @@ class WebSocket: socket: socket Pre-initialized stream socket. """ - self.sock_opt.timeout = options.get('timeout', self.sock_opt.timeout) - self.sock, addrs = connect(url, self.sock_opt, proxy_info(**options), - options.pop('socket', None)) + self.sock_opt.timeout = options.get("timeout", self.sock_opt.timeout) + self.sock, addrs = connect( + url, self.sock_opt, proxy_info(**options), options.pop("socket", None) + ) try: self.handshake_response = handshake(self.sock, url, *addrs, **options) - for attempt in range(options.pop('redirect_limit', 3)): + for attempt in range(options.pop("redirect_limit", 3)): if self.handshake_response.status in SUPPORTED_REDIRECT_STATUSES: - url = self.handshake_response.headers['location'] + url = self.handshake_response.headers["location"] self.sock.close() - self.sock, addrs = connect(url, self.sock_opt, proxy_info(**options), - options.pop('socket', None)) - self.handshake_response = handshake(self.sock, url, *addrs, **options) + self.sock, addrs = connect( + url, + self.sock_opt, + proxy_info(**options), + options.pop("socket", None), + ) + self.handshake_response = handshake( + self.sock, url, *addrs, **options + ) self.connected = True except: if self.sock: @@ -265,7 +279,7 @@ class WebSocket: self.sock = None raise - def send(self, payload: bytes or str, opcode: int = ABNF.OPCODE_TEXT) -> int: + def send(self, payload: Union[bytes, str], opcode: int = ABNF.OPCODE_TEXT) -> int: """ Send the data as string. @@ -282,6 +296,18 @@ class WebSocket: frame = ABNF.create_frame(payload, opcode) return self.send_frame(frame) + def send_text(self, text_data: str) -> int: + """ + Sends UTF-8 encoded text. + """ + return self.send(text_data, ABNF.OPCODE_TEXT) + + def send_bytes(self, data: Union[bytes, bytearray]) -> int: + """ + Sends a sequence of bytes. + """ + return self.send(data, ABNF.OPCODE_BINARY) + def send_frame(self, frame) -> int: """ Send the data frame. @@ -303,9 +329,9 @@ class WebSocket: frame.get_mask_key = self.get_mask_key data = frame.format() length = len(data) - if (isEnabledForTrace()): - trace("++Sent raw: " + repr(data)) - trace("++Sent decoded: " + frame.__str__()) + if isEnabledForTrace(): + trace(f"++Sent raw: {repr(data)}") + trace(f"++Sent decoded: {frame.__str__()}") with self.lock: while data: l = self._send(data) @@ -324,7 +350,7 @@ class WebSocket: """ return self.send(payload, ABNF.OPCODE_BINARY) - def ping(self, payload: str or bytes = ""): + def ping(self, payload: Union[str, bytes] = ""): """ Send ping data. @@ -337,7 +363,7 @@ class WebSocket: payload = payload.encode("utf-8") self.send(payload, ABNF.OPCODE_PING) - def pong(self, payload: str or bytes = ""): + def pong(self, payload: Union[str, bytes] = ""): """ Send pong data. @@ -350,7 +376,7 @@ class WebSocket: payload = payload.encode("utf-8") self.send(payload, ABNF.OPCODE_PONG) - def recv(self) -> str or bytes: + def recv(self) -> Union[str, bytes]: """ Receive string data(byte array) from the server. @@ -361,11 +387,16 @@ class WebSocket: with self.readlock: opcode, data = self.recv_data() if opcode == ABNF.OPCODE_TEXT: - return data.decode("utf-8") - elif opcode == ABNF.OPCODE_TEXT or opcode == ABNF.OPCODE_BINARY: - return data + data_received: Union[bytes, str] = data + if isinstance(data_received, bytes): + return data_received.decode("utf-8") + elif isinstance(data_received, str): + return data_received + elif opcode == ABNF.OPCODE_BINARY: + data_binary: bytes = data + return data_binary else: - return '' + return "" def recv_data(self, control_frame: bool = False) -> tuple: """ @@ -385,7 +416,7 @@ class WebSocket: opcode, frame = self.recv_data_frame(control_frame) return opcode, frame.data - def recv_data_frame(self, control_frame: bool = False): + def recv_data_frame(self, control_frame: bool = False) -> tuple: """ Receive data with operation code. @@ -404,15 +435,18 @@ class WebSocket: """ while True: frame = self.recv_frame() - if (isEnabledForTrace()): - trace("++Rcv raw: " + repr(frame.format())) - trace("++Rcv decoded: " + frame.__str__()) + if isEnabledForTrace(): + trace(f"++Rcv raw: {repr(frame.format())}") + trace(f"++Rcv decoded: {frame.__str__()}") if not frame: # handle error: # 'NoneType' object has no attribute 'opcode' - raise WebSocketProtocolException( - "Not a valid frame {frame}".format(frame=frame)) - elif frame.opcode in (ABNF.OPCODE_TEXT, ABNF.OPCODE_BINARY, ABNF.OPCODE_CONT): + raise WebSocketProtocolException(f"Not a valid frame {frame}") + elif frame.opcode in ( + ABNF.OPCODE_TEXT, + ABNF.OPCODE_BINARY, + ABNF.OPCODE_CONT, + ): self.cont_frame.validate(frame) self.cont_frame.add(frame) @@ -426,8 +460,7 @@ class WebSocket: if len(frame.data) < 126: self.pong(frame.data) else: - raise WebSocketProtocolException( - "Ping message is too long") + raise WebSocketProtocolException("Ping message is too long") if control_frame: return frame.opcode, frame elif frame.opcode == ABNF.OPCODE_PONG: @@ -458,9 +491,9 @@ class WebSocket: if status < 0 or status >= ABNF.LENGTH_16: raise ValueError("code is invalid range") self.connected = False - self.send(struct.pack('!H', status) + reason, ABNF.OPCODE_CLOSE) + self.send(struct.pack("!H", status) + reason, ABNF.OPCODE_CLOSE) - def close(self, status: int = STATUS_NORMAL, reason: bytes = b"", timeout: float = 3): + def close(self, status: int = STATUS_NORMAL, reason: bytes = b"", timeout: int = 3): """ Close Websocket object @@ -474,36 +507,37 @@ class WebSocket: Timeout until receive a close frame. If None, it will wait forever until receive a close frame. """ - if self.connected: - if status < 0 or status >= ABNF.LENGTH_16: - raise ValueError("code is invalid range") + if not self.connected: + return + if status < 0 or status >= ABNF.LENGTH_16: + raise ValueError("code is invalid range") - try: - self.connected = False - self.send(struct.pack('!H', status) + reason, ABNF.OPCODE_CLOSE) - sock_timeout = self.sock.gettimeout() - self.sock.settimeout(timeout) - start_time = time.time() - while timeout is None or time.time() - start_time < timeout: - try: - frame = self.recv_frame() - if frame.opcode != ABNF.OPCODE_CLOSE: - continue - if isEnabledForError(): - recv_status = struct.unpack("!H", frame.data[0:2])[0] - if recv_status >= 3000 and recv_status <= 4999: - debug("close status: " + repr(recv_status)) - elif recv_status != STATUS_NORMAL: - error("close status: " + repr(recv_status)) - break - except: - break - self.sock.settimeout(sock_timeout) - self.sock.shutdown(socket.SHUT_RDWR) - except: - pass + try: + self.connected = False + self.send(struct.pack("!H", status) + reason, ABNF.OPCODE_CLOSE) + sock_timeout = self.sock.gettimeout() + self.sock.settimeout(timeout) + start_time = time.time() + while timeout is None or time.time() - start_time < timeout: + try: + frame = self.recv_frame() + if frame.opcode != ABNF.OPCODE_CLOSE: + continue + if isEnabledForError(): + recv_status = struct.unpack("!H", frame.data[0:2])[0] + if recv_status >= 3000 and recv_status <= 4999: + debug(f"close status: {repr(recv_status)}") + elif recv_status != STATUS_NORMAL: + error(f"close status: {repr(recv_status)}") + break + except: + break + self.sock.settimeout(sock_timeout) + self.sock.shutdown(socket.SHUT_RDWR) + except: + pass - self.shutdown() + self.shutdown() def abort(self): """ @@ -521,7 +555,7 @@ class WebSocket: self.sock = None self.connected = False - def _send(self, data: str or bytes): + def _send(self, data: Union[str, bytes]): return send(self.sock, data) def _recv(self, bufsize): @@ -600,10 +634,14 @@ def create_connection(url: str, timeout=None, class_=WebSocket, **options): fire_cont_frame = options.pop("fire_cont_frame", False) enable_multithread = options.pop("enable_multithread", True) skip_utf8_validation = options.pop("skip_utf8_validation", False) - websock = class_(sockopt=sockopt, sslopt=sslopt, - fire_cont_frame=fire_cont_frame, - enable_multithread=enable_multithread, - skip_utf8_validation=skip_utf8_validation, **options) + websock = class_( + sockopt=sockopt, + sslopt=sslopt, + fire_cont_frame=fire_cont_frame, + enable_multithread=enable_multithread, + skip_utf8_validation=skip_utf8_validation, + **options, + ) websock.settimeout(timeout if timeout is not None else getdefaulttimeout()) websock.connect(url, **options) return websock diff --git a/lib/websocket/_exceptions.py b/lib/websocket/_exceptions.py index 48f40a07..c146fa5d 100644 --- a/lib/websocket/_exceptions.py +++ b/lib/websocket/_exceptions.py @@ -22,6 +22,7 @@ class WebSocketException(Exception): """ WebSocket exception class. """ + pass @@ -29,6 +30,7 @@ class WebSocketProtocolException(WebSocketException): """ If the WebSocket protocol is invalid, this exception will be raised. """ + pass @@ -36,6 +38,7 @@ class WebSocketPayloadException(WebSocketException): """ If the WebSocket payload is invalid, this exception will be raised. """ + pass @@ -44,6 +47,7 @@ class WebSocketConnectionClosedException(WebSocketException): If remote host closed the connection or some network error happened, this exception will be raised. """ + pass @@ -51,6 +55,7 @@ class WebSocketTimeoutException(WebSocketException): """ WebSocketTimeoutException will be raised at socket timeout during read/write data. """ + pass @@ -58,6 +63,7 @@ class WebSocketProxyException(WebSocketException): """ WebSocketProxyException will be raised when proxy error occurred. """ + pass @@ -66,7 +72,14 @@ class WebSocketBadStatusException(WebSocketException): WebSocketBadStatusException will be raised when we get bad handshake status code. """ - def __init__(self, message: str, status_code: int, status_message=None, resp_headers=None, resp_body=None): + def __init__( + self, + message: str, + status_code: int, + status_message=None, + resp_headers=None, + resp_body=None, + ): super().__init__(message) self.status_code = status_code self.resp_headers = resp_headers @@ -77,4 +90,5 @@ class WebSocketAddressException(WebSocketException): """ If the websocket address info cannot be found, this exception will be raised. """ + pass diff --git a/lib/websocket/_handshake.py b/lib/websocket/_handshake.py index d28aefd7..e63dc979 100644 --- a/lib/websocket/_handshake.py +++ b/lib/websocket/_handshake.py @@ -20,7 +20,8 @@ import hashlib import hmac import os from base64 import encodebytes as base64encode -from http import client as HTTPStatus +from http import HTTPStatus + from ._cookiejar import SimpleCookieJar from ._exceptions import * from ._http import * @@ -32,14 +33,19 @@ __all__ = ["handshake_response", "handshake", "SUPPORTED_REDIRECT_STATUSES"] # websocket supported version. VERSION = 13 -SUPPORTED_REDIRECT_STATUSES = (HTTPStatus.MOVED_PERMANENTLY, HTTPStatus.FOUND, HTTPStatus.SEE_OTHER,) +SUPPORTED_REDIRECT_STATUSES = ( + HTTPStatus.MOVED_PERMANENTLY, + HTTPStatus.FOUND, + HTTPStatus.SEE_OTHER, + HTTPStatus.TEMPORARY_REDIRECT, + HTTPStatus.PERMANENT_REDIRECT, +) SUCCESS_STATUSES = SUPPORTED_REDIRECT_STATUSES + (HTTPStatus.SWITCHING_PROTOCOLS,) CookieJar = SimpleCookieJar() class handshake_response: - def __init__(self, status: int, headers: dict, subprotocol): self.status = status self.headers = headers @@ -47,7 +53,9 @@ class handshake_response: CookieJar.add(headers.get("set-cookie")) -def handshake(sock, url: str, hostname: str, port: int, resource: str, **options): +def handshake( + sock, url: str, hostname: str, port: int, resource: str, **options +) -> handshake_response: headers, key = _get_handshake_headers(resource, url, hostname, port, options) header_str = "\r\n".join(headers) @@ -66,74 +74,64 @@ def handshake(sock, url: str, hostname: str, port: int, resource: str, **options def _pack_hostname(hostname: str) -> str: # IPv6 address - if ':' in hostname: - return '[' + hostname + ']' - + if ":" in hostname: + return f"[{hostname}]" return hostname -def _get_handshake_headers(resource: str, url: str, host: str, port: int, options: dict): - headers = [ - "GET {resource} HTTP/1.1".format(resource=resource), - "Upgrade: websocket" - ] - if port == 80 or port == 443: +def _get_handshake_headers( + resource: str, url: str, host: str, port: int, options: dict +) -> tuple: + headers = [f"GET {resource} HTTP/1.1", "Upgrade: websocket"] + if port in [80, 443]: hostport = _pack_hostname(host) else: - hostport = "{h}:{p}".format(h=_pack_hostname(host), p=port) + hostport = f"{_pack_hostname(host)}:{port}" if options.get("host"): - headers.append("Host: {h}".format(h=options["host"])) + headers.append(f'Host: {options["host"]}') else: - headers.append("Host: {hp}".format(hp=hostport)) + headers.append(f"Host: {hostport}") # scheme indicates whether http or https is used in Origin # The same approach is used in parse_url of _url.py to set default port scheme, url = url.split(":", 1) if not options.get("suppress_origin"): if "origin" in options and options["origin"] is not None: - headers.append("Origin: {origin}".format(origin=options["origin"])) + headers.append(f'Origin: {options["origin"]}') elif scheme == "wss": - headers.append("Origin: https://{hp}".format(hp=hostport)) + headers.append(f"Origin: https://{hostport}") else: - headers.append("Origin: http://{hp}".format(hp=hostport)) + headers.append(f"Origin: http://{hostport}") key = _create_sec_websocket_key() # Append Sec-WebSocket-Key & Sec-WebSocket-Version if not manually specified - if not options.get('header') or 'Sec-WebSocket-Key' not in options['header']: - headers.append("Sec-WebSocket-Key: {key}".format(key=key)) + if not options.get("header") or "Sec-WebSocket-Key" not in options["header"]: + headers.append(f"Sec-WebSocket-Key: {key}") else: - key = options['header']['Sec-WebSocket-Key'] + key = options["header"]["Sec-WebSocket-Key"] - if not options.get('header') or 'Sec-WebSocket-Version' not in options['header']: - headers.append("Sec-WebSocket-Version: {version}".format(version=VERSION)) + if not options.get("header") or "Sec-WebSocket-Version" not in options["header"]: + headers.append(f"Sec-WebSocket-Version: {VERSION}") - if not options.get('connection'): - headers.append('Connection: Upgrade') + if not options.get("connection"): + headers.append("Connection: Upgrade") else: - headers.append(options['connection']) + headers.append(options["connection"]) - subprotocols = options.get("subprotocols") - if subprotocols: - headers.append("Sec-WebSocket-Protocol: {protocols}".format(protocols=",".join(subprotocols))) + if subprotocols := options.get("subprotocols"): + headers.append(f'Sec-WebSocket-Protocol: {",".join(subprotocols)}') - header = options.get("header") - if header: + if header := options.get("header"): if isinstance(header, dict): - header = [ - ": ".join([k, v]) - for k, v in header.items() - if v is not None - ] + header = [": ".join([k, v]) for k, v in header.items() if v is not None] headers.extend(header) server_cookie = CookieJar.get(host) client_cookie = options.get("cookie", None) - cookie = "; ".join(filter(None, [server_cookie, client_cookie])) - - if cookie: - headers.append("Cookie: {cookie}".format(cookie=cookie)) + if cookie := "; ".join(filter(None, [server_cookie, client_cookie])): + headers.append(f"Cookie: {cookie}") headers.extend(("", "")) return headers, key @@ -142,12 +140,20 @@ def _get_handshake_headers(resource: str, url: str, host: str, port: int, option def _get_resp_headers(sock, success_statuses: tuple = SUCCESS_STATUSES) -> tuple: status, resp_headers, status_message = read_headers(sock) if status not in success_statuses: - content_len = resp_headers.get('content-length') + content_len = resp_headers.get("content-length") if content_len: - response_body = sock.recv(int(content_len)) # read the body of the HTTP error message response and include it in the exception + response_body = sock.recv( + int(content_len) + ) # read the body of the HTTP error message response and include it in the exception else: response_body = None - raise WebSocketBadStatusException("Handshake status {status} {message} -+-+- {headers} -+-+- {body}".format(status=status, message=status_message, headers=resp_headers, body=response_body), status, status_message, resp_headers, response_body) + raise WebSocketBadStatusException( + f"Handshake status {status} {status_message} -+-+- {resp_headers} -+-+- {response_body}", + status, + status_message, + resp_headers, + response_body, + ) return status, resp_headers @@ -157,20 +163,20 @@ _HEADERS_TO_CHECK = { } -def _validate(headers, key: str, subprotocols): +def _validate(headers, key: str, subprotocols) -> tuple: subproto = None for k, v in _HEADERS_TO_CHECK.items(): r = headers.get(k, None) if not r: return False, None - r = [x.strip().lower() for x in r.split(',')] + r = [x.strip().lower() for x in r.split(",")] if v not in r: return False, None if subprotocols: subproto = headers.get("sec-websocket-protocol", None) if not subproto or subproto.lower() not in [s.lower() for s in subprotocols]: - error("Invalid subprotocol: " + str(subprotocols)) + error(f"Invalid subprotocol: {subprotocols}") return False, None subproto = subproto.lower() @@ -180,13 +186,12 @@ def _validate(headers, key: str, subprotocols): result = result.lower() if isinstance(result, str): - result = result.encode('utf-8') + result = result.encode("utf-8") - value = (key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").encode('utf-8') + value = f"{key}258EAFA5-E914-47DA-95CA-C5AB0DC85B11".encode("utf-8") hashed = base64encode(hashlib.sha1(value).digest()).strip().lower() - success = hmac.compare_digest(hashed, result) - if success: + if hmac.compare_digest(hashed, result): return True, subproto else: return False, None @@ -194,4 +199,4 @@ def _validate(headers, key: str, subprotocols): def _create_sec_websocket_key() -> str: randomness = os.urandom(16) - return base64encode(randomness).decode('utf-8').strip() + return base64encode(randomness).decode("utf-8").strip() diff --git a/lib/websocket/_http.py b/lib/websocket/_http.py index 13183b20..977a30f1 100644 --- a/lib/websocket/_http.py +++ b/lib/websocket/_http.py @@ -19,6 +19,7 @@ limitations under the License. import errno import os import socket +from base64 import encodebytes as base64encode from ._exceptions import * from ._logging import * @@ -26,14 +27,13 @@ from ._socket import * from ._ssl_compat import * from ._url import * -from base64 import encodebytes as base64encode - __all__ = ["proxy_info", "connect", "read_headers"] try: - from python_socks.sync import Proxy from python_socks._errors import * from python_socks._types import ProxyType + from python_socks.sync import Proxy + HAVE_PYTHON_SOCKS = True except: HAVE_PYTHON_SOCKS = False @@ -49,7 +49,6 @@ except: class proxy_info: - def __init__(self, **options): self.proxy_host = options.get("http_proxy_host", None) if self.proxy_host: @@ -59,8 +58,16 @@ class proxy_info: self.proxy_protocol = options.get("proxy_type", "http") # Note: If timeout not specified, default python-socks timeout is 60 seconds self.proxy_timeout = options.get("http_proxy_timeout", None) - if self.proxy_protocol not in ['http', 'socks4', 'socks4a', 'socks5', 'socks5h']: - raise ProxyError("Only http, socks4, socks5 proxy protocols are supported") + if self.proxy_protocol not in [ + "http", + "socks4", + "socks4a", + "socks5", + "socks5h", + ]: + raise ProxyError( + "Only http, socks4, socks5 proxy protocols are supported" + ) else: self.proxy_port = 0 self.auth = None @@ -68,25 +75,28 @@ class proxy_info: self.proxy_protocol = "http" -def _start_proxied_socket(url: str, options, proxy): +def _start_proxied_socket(url: str, options, proxy) -> tuple: if not HAVE_PYTHON_SOCKS: - raise WebSocketException("Python Socks is needed for SOCKS proxying but is not available") + raise WebSocketException( + "Python Socks is needed for SOCKS proxying but is not available" + ) hostname, port, resource, is_secure = parse_url(url) - if proxy.proxy_protocol == "socks5": - rdns = False - proxy_type = ProxyType.SOCKS5 if proxy.proxy_protocol == "socks4": rdns = False proxy_type = ProxyType.SOCKS4 - # socks5h and socks4a send DNS through proxy - if proxy.proxy_protocol == "socks5h": - rdns = True - proxy_type = ProxyType.SOCKS5 - if proxy.proxy_protocol == "socks4a": + # socks4a sends DNS through proxy + elif proxy.proxy_protocol == "socks4a": rdns = True proxy_type = ProxyType.SOCKS4 + elif proxy.proxy_protocol == "socks5": + rdns = False + proxy_type = ProxyType.SOCKS5 + # socks5h sends DNS through proxy + elif proxy.proxy_protocol == "socks5h": + rdns = True + proxy_type = ProxyType.SOCKS5 ws_proxy = Proxy.create( proxy_type=proxy_type, @@ -94,14 +104,16 @@ def _start_proxied_socket(url: str, options, proxy): port=int(proxy.proxy_port), username=proxy.auth[0] if proxy.auth else None, password=proxy.auth[1] if proxy.auth else None, - rdns=rdns) + rdns=rdns, + ) sock = ws_proxy.connect(hostname, port, timeout=proxy.proxy_timeout) - if is_secure and HAVE_SSL: - sock = _ssl_socket(sock, options.sslopt, hostname) - elif is_secure: - raise WebSocketException("SSL not available.") + if is_secure: + if HAVE_SSL: + sock = _ssl_socket(sock, options.sslopt, hostname) + else: + raise WebSocketException("SSL not available.") return sock, (hostname, port, resource) @@ -110,7 +122,7 @@ def connect(url: str, options, proxy, socket): # Use _start_proxied_socket() only for socks4 or socks5 proxy # Use _tunnel() for http proxy # TODO: Use python-socks for http protocol also, to standardize flow - if proxy.proxy_host and not socket and not (proxy.proxy_protocol == "http"): + if proxy.proxy_host and not socket and proxy.proxy_protocol != "http": return _start_proxied_socket(url, options, proxy) hostname, port_from_url, resource, is_secure = parse_url(url) @@ -119,10 +131,10 @@ def connect(url: str, options, proxy, socket): return socket, (hostname, port_from_url, resource) addrinfo_list, need_tunnel, auth = _get_addrinfo_list( - hostname, port_from_url, is_secure, proxy) + hostname, port_from_url, is_secure, proxy + ) if not addrinfo_list: - raise WebSocketException( - "Host not found.: " + hostname + ":" + str(port_from_url)) + raise WebSocketException(f"Host not found.: {hostname}:{port_from_url}") sock = None try: @@ -143,16 +155,23 @@ def connect(url: str, options, proxy, socket): raise -def _get_addrinfo_list(hostname, port, is_secure, proxy): +def _get_addrinfo_list(hostname, port: int, is_secure: bool, proxy) -> tuple: phost, pport, pauth = get_proxy_info( - hostname, is_secure, proxy.proxy_host, proxy.proxy_port, proxy.auth, proxy.no_proxy) + hostname, + is_secure, + proxy.proxy_host, + proxy.proxy_port, + proxy.auth, + proxy.no_proxy, + ) try: # when running on windows 10, getaddrinfo without socktype returns a socktype 0. # This generates an error exception: `_on_error: exception Socket type must be stream or datagram, not 0` # or `OSError: [Errno 22] Invalid argument` when creating socket. Force the socket type to SOCK_STREAM. if not phost: addrinfo_list = socket.getaddrinfo( - hostname, port, 0, socket.SOCK_STREAM, socket.SOL_TCP) + hostname, port, 0, socket.SOCK_STREAM, socket.SOL_TCP + ) return addrinfo_list, False, None else: pport = pport and pport or 80 @@ -160,7 +179,9 @@ def _get_addrinfo_list(hostname, port, is_secure, proxy): # returns a socktype 0. This generates an error exception: # _on_error: exception Socket type must be stream or datagram, not 0 # Force the socket type to SOCK_STREAM - addrinfo_list = socket.getaddrinfo(phost, pport, 0, socket.SOCK_STREAM, socket.SOL_TCP) + addrinfo_list = socket.getaddrinfo( + phost, pport, 0, socket.SOCK_STREAM, socket.SOL_TCP + ) return addrinfo_list, True, pauth except socket.gaierror as e: raise WebSocketAddressException(e) @@ -186,14 +207,17 @@ def _open_socket(addrinfo_list, sockopt, timeout): sock.close() error.remote_ip = str(address[0]) try: - eConnRefused = (errno.ECONNREFUSED, errno.WSAECONNREFUSED, errno.ENETUNREACH) + eConnRefused = ( + errno.ECONNREFUSED, + errno.WSAECONNREFUSED, + errno.ENETUNREACH, + ) except AttributeError: eConnRefused = (errno.ECONNREFUSED, errno.ENETUNREACH) - if error.errno in eConnRefused: - err = error - continue - else: + if error.errno not in eConnRefused: raise error + err = error + continue else: break else: @@ -206,89 +230,97 @@ def _open_socket(addrinfo_list, sockopt, timeout): return sock -def _wrap_sni_socket(sock, sslopt, hostname, check_hostname): - context = sslopt.get('context', None) +def _wrap_sni_socket(sock: socket.socket, sslopt: dict, hostname, check_hostname): + context = sslopt.get("context", None) if not context: - context = ssl.SSLContext(sslopt.get('ssl_version', ssl.PROTOCOL_TLS_CLIENT)) + context = ssl.SSLContext(sslopt.get("ssl_version", ssl.PROTOCOL_TLS_CLIENT)) # Non default context need to manually enable SSLKEYLOGFILE support by setting the keylog_filename attribute. # For more details see also: # * https://docs.python.org/3.8/library/ssl.html?highlight=sslkeylogfile#context-creation # * https://docs.python.org/3.8/library/ssl.html?highlight=sslkeylogfile#ssl.SSLContext.keylog_filename context.keylog_filename = os.environ.get("SSLKEYLOGFILE", None) - if sslopt.get('cert_reqs', ssl.CERT_NONE) != ssl.CERT_NONE: - cafile = sslopt.get('ca_certs', None) - capath = sslopt.get('ca_cert_path', None) + if sslopt.get("cert_reqs", ssl.CERT_NONE) != ssl.CERT_NONE: + cafile = sslopt.get("ca_certs", None) + capath = sslopt.get("ca_cert_path", None) if cafile or capath: context.load_verify_locations(cafile=cafile, capath=capath) - elif hasattr(context, 'load_default_certs'): + elif hasattr(context, "load_default_certs"): context.load_default_certs(ssl.Purpose.SERVER_AUTH) - if sslopt.get('certfile', None): + if sslopt.get("certfile", None): context.load_cert_chain( - sslopt['certfile'], - sslopt.get('keyfile', None), - sslopt.get('password', None), + sslopt["certfile"], + sslopt.get("keyfile", None), + sslopt.get("password", None), ) # Python 3.10 switch to PROTOCOL_TLS_CLIENT defaults to "cert_reqs = ssl.CERT_REQUIRED" and "check_hostname = True" # If both disabled, set check_hostname before verify_mode # see https://github.com/liris/websocket-client/commit/b96a2e8fa765753e82eea531adb19716b52ca3ca#commitcomment-10803153 - if sslopt.get('cert_reqs', ssl.CERT_NONE) == ssl.CERT_NONE and not sslopt.get('check_hostname', False): + if sslopt.get("cert_reqs", ssl.CERT_NONE) == ssl.CERT_NONE and not sslopt.get( + "check_hostname", False + ): context.check_hostname = False context.verify_mode = ssl.CERT_NONE else: - context.check_hostname = sslopt.get('check_hostname', True) - context.verify_mode = sslopt.get('cert_reqs', ssl.CERT_REQUIRED) + context.check_hostname = sslopt.get("check_hostname", True) + context.verify_mode = sslopt.get("cert_reqs", ssl.CERT_REQUIRED) - if 'ciphers' in sslopt: - context.set_ciphers(sslopt['ciphers']) - if 'cert_chain' in sslopt: - certfile, keyfile, password = sslopt['cert_chain'] + if "ciphers" in sslopt: + context.set_ciphers(sslopt["ciphers"]) + if "cert_chain" in sslopt: + certfile, keyfile, password = sslopt["cert_chain"] context.load_cert_chain(certfile, keyfile, password) - if 'ecdh_curve' in sslopt: - context.set_ecdh_curve(sslopt['ecdh_curve']) + if "ecdh_curve" in sslopt: + context.set_ecdh_curve(sslopt["ecdh_curve"]) return context.wrap_socket( sock, - do_handshake_on_connect=sslopt.get('do_handshake_on_connect', True), - suppress_ragged_eofs=sslopt.get('suppress_ragged_eofs', True), + do_handshake_on_connect=sslopt.get("do_handshake_on_connect", True), + suppress_ragged_eofs=sslopt.get("suppress_ragged_eofs", True), server_hostname=hostname, ) -def _ssl_socket(sock, user_sslopt, hostname): - sslopt = dict(cert_reqs=ssl.CERT_REQUIRED) +def _ssl_socket(sock: socket.socket, user_sslopt: dict, hostname): + sslopt: dict = dict(cert_reqs=ssl.CERT_REQUIRED) sslopt.update(user_sslopt) - certPath = os.environ.get('WEBSOCKET_CLIENT_CA_BUNDLE') - if certPath and os.path.isfile(certPath) \ - and user_sslopt.get('ca_certs', None) is None: - sslopt['ca_certs'] = certPath - elif certPath and os.path.isdir(certPath) \ - and user_sslopt.get('ca_cert_path', None) is None: - sslopt['ca_cert_path'] = certPath + certPath = os.environ.get("WEBSOCKET_CLIENT_CA_BUNDLE") + if ( + certPath + and os.path.isfile(certPath) + and user_sslopt.get("ca_certs", None) is None + ): + sslopt["ca_certs"] = certPath + elif ( + certPath + and os.path.isdir(certPath) + and user_sslopt.get("ca_cert_path", None) is None + ): + sslopt["ca_cert_path"] = certPath - if sslopt.get('server_hostname', None): - hostname = sslopt['server_hostname'] + if sslopt.get("server_hostname", None): + hostname = sslopt["server_hostname"] - check_hostname = sslopt.get('check_hostname', True) + check_hostname = sslopt.get("check_hostname", True) sock = _wrap_sni_socket(sock, sslopt, hostname, check_hostname) return sock -def _tunnel(sock, host, port, auth): +def _tunnel(sock: socket.socket, host, port: int, auth) -> socket.socket: debug("Connecting proxy...") - connect_header = "CONNECT {h}:{p} HTTP/1.1\r\n".format(h=host, p=port) - connect_header += "Host: {h}:{p}\r\n".format(h=host, p=port) + connect_header = f"CONNECT {host}:{port} HTTP/1.1\r\n" + connect_header += f"Host: {host}:{port}\r\n" # TODO: support digest auth. if auth and auth[0]: auth_str = auth[0] if auth[1]: - auth_str += ":" + auth[1] - encoded_str = base64encode(auth_str.encode()).strip().decode().replace('\n', '') - connect_header += "Proxy-Authorization: Basic {str}\r\n".format(str=encoded_str) + auth_str += f":{auth[1]}" + encoded_str = base64encode(auth_str.encode()).strip().decode().replace("\n", "") + connect_header += f"Proxy-Authorization: Basic {encoded_str}\r\n" connect_header += "\r\n" dump("request header", connect_header) @@ -300,40 +332,37 @@ def _tunnel(sock, host, port, auth): raise WebSocketProxyException(str(e)) if status != 200: - raise WebSocketProxyException( - "failed CONNECT via proxy status: {status}".format(status=status)) + raise WebSocketProxyException(f"failed CONNECT via proxy status: {status}") return sock -def read_headers(sock): +def read_headers(sock: socket.socket) -> tuple: status = None status_message = None - headers = {} + headers: dict = {} trace("--- response header ---") while True: line = recv_line(sock) - line = line.decode('utf-8').strip() + line = line.decode("utf-8").strip() if not line: break trace(line) if not status: - status_info = line.split(" ", 2) status = int(status_info[1]) if len(status_info) > 2: status_message = status_info[2] else: kv = line.split(":", 1) - if len(kv) == 2: - key, value = kv - if key.lower() == "set-cookie" and headers.get("set-cookie"): - headers["set-cookie"] = headers.get("set-cookie") + "; " + value.strip() - else: - headers[key.lower()] = value.strip() - else: + if len(kv) != 2: raise WebSocketException("Invalid header") + key, value = kv + if key.lower() == "set-cookie" and headers.get("set-cookie"): + headers["set-cookie"] = headers.get("set-cookie") + "; " + value.strip() + else: + headers[key.lower()] = value.strip() trace("-----------------------") diff --git a/lib/websocket/_logging.py b/lib/websocket/_logging.py index 806de4d4..b88cda37 100644 --- a/lib/websocket/_logging.py +++ b/lib/websocket/_logging.py @@ -19,25 +19,38 @@ See the License for the specific language governing permissions and limitations under the License. """ -_logger = logging.getLogger('websocket') +_logger = logging.getLogger("websocket") try: from logging import NullHandler except ImportError: + class NullHandler(logging.Handler): def emit(self, record) -> None: pass + _logger.addHandler(NullHandler()) _traceEnabled = False -__all__ = ["enableTrace", "dump", "error", "warning", "debug", "trace", - "isEnabledForError", "isEnabledForDebug", "isEnabledForTrace"] +__all__ = [ + "enableTrace", + "dump", + "error", + "warning", + "debug", + "trace", + "isEnabledForError", + "isEnabledForDebug", + "isEnabledForTrace", +] -def enableTrace(traceable: bool, - handler: logging.StreamHandler = logging.StreamHandler(), - level: str = "DEBUG") -> None: +def enableTrace( + traceable: bool, + handler: logging.StreamHandler = logging.StreamHandler(), + level: str = "DEBUG", +) -> None: """ Turn on/off the traceability. @@ -55,7 +68,7 @@ def enableTrace(traceable: bool, def dump(title: str, message: str) -> None: if _traceEnabled: - _logger.debug("--- " + title + " ---") + _logger.debug(f"--- {title} ---") _logger.debug(message) _logger.debug("-----------------------") diff --git a/lib/websocket/_socket.py b/lib/websocket/_socket.py index e8858fc8..f0ad27a5 100644 --- a/lib/websocket/_socket.py +++ b/lib/websocket/_socket.py @@ -1,6 +1,7 @@ import errno import selectors import socket +from typing import Union from ._exceptions import * from ._ssl_compat import * @@ -37,12 +38,18 @@ if hasattr(socket, "TCP_KEEPCNT"): _default_timeout = None -__all__ = ["DEFAULT_SOCKET_OPTION", "sock_opt", "setdefaulttimeout", "getdefaulttimeout", - "recv", "recv_line", "send"] +__all__ = [ + "DEFAULT_SOCKET_OPTION", + "sock_opt", + "setdefaulttimeout", + "getdefaulttimeout", + "recv", + "recv_line", + "send", +] class sock_opt: - def __init__(self, sockopt: list, sslopt: dict) -> None: if sockopt is None: sockopt = [] @@ -53,7 +60,7 @@ class sock_opt: self.timeout = None -def setdefaulttimeout(timeout: int or float) -> None: +def setdefaulttimeout(timeout: Union[int, float, None]) -> None: """ Set the global timeout setting to connect. @@ -66,7 +73,7 @@ def setdefaulttimeout(timeout: int or float) -> None: _default_timeout = timeout -def getdefaulttimeout() -> int or float: +def getdefaulttimeout() -> Union[int, float, None]: """ Get default timeout @@ -89,7 +96,7 @@ def recv(sock: socket.socket, bufsize: int) -> bytes: pass except socket.error as exc: error_code = extract_error_code(exc) - if error_code != errno.EAGAIN and error_code != errno.EWOULDBLOCK: + if error_code not in [errno.EAGAIN, errno.EWOULDBLOCK]: raise sel = selectors.DefaultSelector() @@ -113,14 +120,13 @@ def recv(sock: socket.socket, bufsize: int) -> bytes: raise WebSocketTimeoutException(message) except SSLError as e: message = extract_err_message(e) - if isinstance(message, str) and 'timed out' in message: + if isinstance(message, str) and "timed out" in message: raise WebSocketTimeoutException(message) else: raise if not bytes_: - raise WebSocketConnectionClosedException( - "Connection to remote host was lost.") + raise WebSocketConnectionClosedException("Connection to remote host was lost.") return bytes_ @@ -130,14 +136,14 @@ def recv_line(sock: socket.socket) -> bytes: while True: c = recv(sock, 1) line.append(c) - if c == b'\n': + if c == b"\n": break - return b''.join(line) + return b"".join(line) -def send(sock: socket.socket, data: bytes) -> int: +def send(sock: socket.socket, data: Union[bytes, str]) -> int: if isinstance(data, str): - data = data.encode('utf-8') + data = data.encode("utf-8") if not sock: raise WebSocketConnectionClosedException("socket is already closed.") @@ -151,7 +157,7 @@ def send(sock: socket.socket, data: bytes) -> int: error_code = extract_error_code(exc) if error_code is None: raise - if error_code != errno.EAGAIN and error_code != errno.EWOULDBLOCK: + if error_code not in [errno.EAGAIN, errno.EWOULDBLOCK]: raise sel = selectors.DefaultSelector() diff --git a/lib/websocket/_ssl_compat.py b/lib/websocket/_ssl_compat.py index b2eba387..029a5c6e 100644 --- a/lib/websocket/_ssl_compat.py +++ b/lib/websocket/_ssl_compat.py @@ -20,9 +20,8 @@ __all__ = ["HAVE_SSL", "ssl", "SSLError", "SSLWantReadError", "SSLWantWriteError try: import ssl - from ssl import SSLError - from ssl import SSLWantReadError - from ssl import SSLWantWriteError + from ssl import SSLError, SSLWantReadError, SSLWantWriteError + HAVE_SSL = True except ImportError: # dummy class of SSLError for environment without ssl support diff --git a/lib/websocket/_url.py b/lib/websocket/_url.py index 2141b021..7d53830e 100644 --- a/lib/websocket/_url.py +++ b/lib/websocket/_url.py @@ -1,7 +1,7 @@ import os import socket import struct - +from typing import Optional from urllib.parse import unquote, urlparse """ @@ -67,7 +67,7 @@ def parse_url(url: str) -> tuple: resource = "/" if parsed.query: - resource += "?" + parsed.query + resource += f"?{parsed.query}" return hostname, port, resource, is_secure @@ -93,37 +93,50 @@ def _is_subnet_address(hostname: str) -> bool: def _is_address_in_network(ip: str, net: str) -> bool: - ipaddr = struct.unpack('!I', socket.inet_aton(ip))[0] - netaddr, netmask = net.split('/') - netaddr = struct.unpack('!I', socket.inet_aton(netaddr))[0] + ipaddr: int = struct.unpack("!I", socket.inet_aton(ip))[0] + netaddr, netmask = net.split("/") + netaddr: int = struct.unpack("!I", socket.inet_aton(netaddr))[0] netmask = (0xFFFFFFFF << (32 - int(netmask))) & 0xFFFFFFFF return ipaddr & netmask == netaddr -def _is_no_proxy_host(hostname: str, no_proxy: list) -> bool: +def _is_no_proxy_host(hostname: str, no_proxy: Optional[list]) -> bool: if not no_proxy: - v = os.environ.get("no_proxy", os.environ.get("NO_PROXY", "")).replace(" ", "") - if v: + if v := os.environ.get("no_proxy", os.environ.get("NO_PROXY", "")).replace( + " ", "" + ): no_proxy = v.split(",") if not no_proxy: no_proxy = DEFAULT_NO_PROXY_HOST - if '*' in no_proxy: + if "*" in no_proxy: return True if hostname in no_proxy: return True if _is_ip_address(hostname): - return any([_is_address_in_network(hostname, subnet) for subnet in no_proxy if _is_subnet_address(subnet)]) - for domain in [domain for domain in no_proxy if domain.startswith('.')]: + return any( + [ + _is_address_in_network(hostname, subnet) + for subnet in no_proxy + if _is_subnet_address(subnet) + ] + ) + for domain in [domain for domain in no_proxy if domain.startswith(".")]: if hostname.endswith(domain): return True return False def get_proxy_info( - hostname: str, is_secure: bool, proxy_host: str = None, proxy_port: int = 0, proxy_auth: tuple = None, - no_proxy: list = None, proxy_type: str = 'http') -> tuple: + hostname: str, + is_secure: bool, + proxy_host: Optional[str] = None, + proxy_port: int = 0, + proxy_auth: Optional[tuple] = None, + no_proxy: Optional[list] = None, + proxy_type: str = "http", +) -> tuple: """ Try to retrieve proxy host and port from environment if not provided in options. @@ -159,10 +172,16 @@ def get_proxy_info( return proxy_host, port, auth env_key = "https_proxy" if is_secure else "http_proxy" - value = os.environ.get(env_key, os.environ.get(env_key.upper(), "")).replace(" ", "") + value = os.environ.get(env_key, os.environ.get(env_key.upper(), "")).replace( + " ", "" + ) if value: proxy = urlparse(value) - auth = (unquote(proxy.username), unquote(proxy.password)) if proxy.username else None + auth = ( + (unquote(proxy.username), unquote(proxy.password)) + if proxy.username + else None + ) return proxy.hostname, proxy.port, auth return None, 0, None diff --git a/lib/websocket/_utils.py b/lib/websocket/_utils.py index 3db2d83b..c63adfa5 100644 --- a/lib/websocket/_utils.py +++ b/lib/websocket/_utils.py @@ -1,3 +1,5 @@ +from typing import Union + """ _url.py websocket - WebSocket client library for Python @@ -20,7 +22,6 @@ __all__ = ["NoLock", "validate_utf8", "extract_err_message", "extract_error_code class NoLock: - def __enter__(self) -> None: pass @@ -33,8 +34,9 @@ try: # strings. from wsaccel.utf8validator import Utf8Validator - def _validate_utf8(utfbytes: bytes) -> bool: - return Utf8Validator().validate(utfbytes)[0] + def _validate_utf8(utfbytes: Union[str, bytes]) -> bool: + result: bool = Utf8Validator().validate(utfbytes)[0] + return result except ImportError: # UTF-8 validator @@ -46,44 +48,396 @@ except ImportError: _UTF8D = [ # The first part of the table maps bytes to character classes that # to reduce the size of the transition table and create bitmasks. - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, - + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 8, + 8, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 10, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 4, + 3, + 3, + 11, + 6, + 6, + 6, + 5, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, # The second part is a transition table that maps a combination # of a state of the automaton and a character class to a state. - 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12, - 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12, - 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12, - 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12, - 12,36,12,12,12,12,12,12,12,12,12,12, ] + 0, + 12, + 24, + 36, + 60, + 96, + 84, + 12, + 12, + 12, + 48, + 72, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 0, + 12, + 12, + 12, + 12, + 12, + 0, + 12, + 0, + 12, + 12, + 12, + 24, + 12, + 12, + 12, + 12, + 12, + 24, + 12, + 24, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 24, + 12, + 12, + 12, + 12, + 12, + 24, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 24, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 36, + 12, + 36, + 12, + 12, + 12, + 36, + 12, + 12, + 12, + 12, + 12, + 36, + 12, + 36, + 12, + 12, + 12, + 36, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + ] def _decode(state: int, codep: int, ch: int) -> tuple: tp = _UTF8D[ch] - codep = (ch & 0x3f) | (codep << 6) if ( - state != _UTF8_ACCEPT) else (0xff >> tp) & ch + codep = ( + (ch & 0x3F) | (codep << 6) if (state != _UTF8_ACCEPT) else (0xFF >> tp) & ch + ) state = _UTF8D[256 + state + tp] return state, codep - def _validate_utf8(utfbytes: str or bytes) -> bool: + def _validate_utf8(utfbytes: Union[str, bytes]) -> bool: state = _UTF8_ACCEPT codep = 0 for i in utfbytes: - state, codep = _decode(state, codep, i) + state, codep = _decode(state, codep, int(i)) if state == _UTF8_REJECT: return False return True -def validate_utf8(utfbytes: str or bytes) -> bool: +def validate_utf8(utfbytes: Union[str, bytes]) -> bool: """ validate utf8 byte string. utfbytes: utf byte string to check. @@ -92,13 +446,14 @@ def validate_utf8(utfbytes: str or bytes) -> bool: return _validate_utf8(utfbytes) -def extract_err_message(exception: Exception) -> str or None: +def extract_err_message(exception: Exception) -> Union[str, None]: if exception.args: - return exception.args[0] + exception_message: str = exception.args[0] + return exception_message else: return None -def extract_error_code(exception: Exception) -> int or None: +def extract_error_code(exception: Exception) -> Union[int, None]: if exception.args and len(exception.args) > 1: return exception.args[0] if isinstance(exception.args[0], int) else None diff --git a/lib/websocket/_wsdump.py b/lib/websocket/_wsdump.py index d637ce2b..34c3d127 100644 --- a/lib/websocket/_wsdump.py +++ b/lib/websocket/_wsdump.py @@ -21,11 +21,11 @@ limitations under the License. import argparse import code +import gzip +import ssl import sys import threading import time -import ssl -import gzip import zlib from urllib.parse import urlparse @@ -50,8 +50,13 @@ ENCODING = get_encoding() class VAction(argparse.Action): - - def __call__(self, parser: argparse.Namespace, args: tuple, values: str, option_string: str = None) -> None: + def __call__( + self, + parser: argparse.Namespace, + args: tuple, + values: str, + option_string: str = None, + ) -> None: if values is None: values = "1" try: @@ -63,36 +68,42 @@ class VAction(argparse.Action): def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="WebSocket Simple Dump Tool") - parser.add_argument("url", metavar="ws_url", - help="websocket url. ex. ws://echo.websocket.events/") - parser.add_argument("-p", "--proxy", - help="proxy url. ex. http://127.0.0.1:8080") - parser.add_argument("-v", "--verbose", default=0, nargs='?', action=VAction, - dest="verbose", - help="set verbose mode. If set to 1, show opcode. " - "If set to 2, enable to trace websocket module") - parser.add_argument("-n", "--nocert", action='store_true', - help="Ignore invalid SSL cert") - parser.add_argument("-r", "--raw", action="store_true", - help="raw output") - parser.add_argument("-s", "--subprotocols", nargs='*', - help="Set subprotocols") - parser.add_argument("-o", "--origin", - help="Set origin") - parser.add_argument("--eof-wait", default=0, type=int, - help="wait time(second) after 'EOF' received.") - parser.add_argument("-t", "--text", - help="Send initial text") - parser.add_argument("--timings", action="store_true", - help="Print timings in seconds") - parser.add_argument("--headers", - help="Set custom headers. Use ',' as separator") + parser.add_argument( + "url", metavar="ws_url", help="websocket url. ex. ws://echo.websocket.events/" + ) + parser.add_argument("-p", "--proxy", help="proxy url. ex. http://127.0.0.1:8080") + parser.add_argument( + "-v", + "--verbose", + default=0, + nargs="?", + action=VAction, + dest="verbose", + help="set verbose mode. If set to 1, show opcode. " + "If set to 2, enable to trace websocket module", + ) + parser.add_argument( + "-n", "--nocert", action="store_true", help="Ignore invalid SSL cert" + ) + parser.add_argument("-r", "--raw", action="store_true", help="raw output") + parser.add_argument("-s", "--subprotocols", nargs="*", help="Set subprotocols") + parser.add_argument("-o", "--origin", help="Set origin") + parser.add_argument( + "--eof-wait", + default=0, + type=int, + help="wait time(second) after 'EOF' received.", + ) + parser.add_argument("-t", "--text", help="Send initial text") + parser.add_argument( + "--timings", action="store_true", help="Print timings in seconds" + ) + parser.add_argument("--headers", help="Set custom headers. Use ',' as separator") return parser.parse_args() class RawInput: - def raw_input(self, prompt: str = "") -> str: line = input(prompt) @@ -105,7 +116,6 @@ class RawInput: class InteractiveConsole(RawInput, code.InteractiveConsole): - def write(self, data: str) -> None: sys.stdout.write("\033[2K\033[E") # sys.stdout.write("\n") @@ -118,7 +128,6 @@ class InteractiveConsole(RawInput, code.InteractiveConsole): class NonInteractive(RawInput): - def write(self, data: str) -> None: sys.stdout.write(data) sys.stdout.write("\n") @@ -146,7 +155,7 @@ def main() -> None: if args.nocert: opts = {"cert_reqs": ssl.CERT_NONE, "check_hostname": False} if args.headers: - options['header'] = list(map(str.strip, args.headers.split(','))) + options["header"] = list(map(str.strip, args.headers.split(","))) ws = websocket.create_connection(args.url, sslopt=opts, **options) if args.raw: console = NonInteractive() @@ -160,7 +169,7 @@ def main() -> None: except websocket.WebSocketException: return websocket.ABNF.OPCODE_CLOSE, "" if not frame: - raise websocket.WebSocketException("Not a valid frame {frame}".format(frame=frame)) + raise websocket.WebSocketException(f"Not a valid frame {frame}") elif frame.opcode in OPCODE_DATA: return frame.opcode, frame.data elif frame.opcode == websocket.ABNF.OPCODE_CLOSE: @@ -178,14 +187,18 @@ def main() -> None: msg = None if opcode == websocket.ABNF.OPCODE_TEXT and isinstance(data, bytes): data = str(data, "utf-8") - if isinstance(data, bytes) and len(data) > 2 and data[:2] == b'\037\213': # gzip magick + if ( + isinstance(data, bytes) and len(data) > 2 and data[:2] == b"\037\213" + ): # gzip magick try: data = "[gzip] " + str(gzip.decompress(data), "utf-8") except: pass elif isinstance(data, bytes): try: - data = "[zlib] " + str(zlib.decompress(data, -zlib.MAX_WBITS), "utf-8") + data = "[zlib] " + str( + zlib.decompress(data, -zlib.MAX_WBITS), "utf-8" + ) except: pass @@ -193,13 +206,13 @@ def main() -> None: data = repr(data) if args.verbose: - msg = "{opcode}: {data}".format(opcode=websocket.ABNF.OPCODE_MAP.get(opcode), data=data) + msg = f"{websocket.ABNF.OPCODE_MAP.get(opcode)}: {data}" else: msg = data if msg is not None: if args.timings: - console.write(str(time.time() - start_time) + ": " + msg) + console.write(f"{time.time() - start_time}: {msg}") else: console.write(msg) diff --git a/lib/websocket/py.typed b/lib/websocket/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/lib/websocket/tests/echo-server.py b/lib/websocket/tests/echo-server.py index 42dd9e43..a32c6503 100644 --- a/lib/websocket/tests/echo-server.py +++ b/lib/websocket/tests/echo-server.py @@ -3,10 +3,11 @@ # From https://github.com/aaugustin/websockets/blob/main/example/echo.py import asyncio -import websockets import os -LOCAL_WS_SERVER_PORT = int(os.environ.get('LOCAL_WS_SERVER_PORT', '8765')) +import websockets + +LOCAL_WS_SERVER_PORT = int(os.environ.get("LOCAL_WS_SERVER_PORT", "8765")) async def echo(websocket, path): @@ -18,4 +19,5 @@ async def main(): async with websockets.serve(echo, "localhost", LOCAL_WS_SERVER_PORT): await asyncio.Future() # run forever + asyncio.run(main()) diff --git a/lib/websocket/tests/test_abnf.py b/lib/websocket/tests/test_abnf.py index dbf9b636..df5bc6bd 100644 --- a/lib/websocket/tests/test_abnf.py +++ b/lib/websocket/tests/test_abnf.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- # +import unittest + import websocket as ws from websocket._abnf import * -import unittest """ test_abnf.py @@ -25,54 +26,89 @@ limitations under the License. class ABNFTest(unittest.TestCase): - def testInit(self): - a = ABNF(0,0,0,0, opcode=ABNF.OPCODE_PING) + a = ABNF(0, 0, 0, 0, opcode=ABNF.OPCODE_PING) self.assertEqual(a.fin, 0) self.assertEqual(a.rsv1, 0) self.assertEqual(a.rsv2, 0) self.assertEqual(a.rsv3, 0) self.assertEqual(a.opcode, 9) - self.assertEqual(a.data, '') - a_bad = ABNF(0,1,0,0, opcode=77) + self.assertEqual(a.data, "") + a_bad = ABNF(0, 1, 0, 0, opcode=77) self.assertEqual(a_bad.rsv1, 1) self.assertEqual(a_bad.opcode, 77) def testValidate(self): - a_invalid_ping = ABNF(0,0,0,0, opcode=ABNF.OPCODE_PING) - self.assertRaises(ws._exceptions.WebSocketProtocolException, a_invalid_ping.validate, skip_utf8_validation=False) - a_bad_rsv_value = ABNF(0,1,0,0, opcode=ABNF.OPCODE_TEXT) - self.assertRaises(ws._exceptions.WebSocketProtocolException, a_bad_rsv_value.validate, skip_utf8_validation=False) - a_bad_opcode = ABNF(0,0,0,0, opcode=77) - self.assertRaises(ws._exceptions.WebSocketProtocolException, a_bad_opcode.validate, skip_utf8_validation=False) - a_bad_close_frame = ABNF(0,0,0,0, opcode=ABNF.OPCODE_CLOSE, data=b'\x01') - self.assertRaises(ws._exceptions.WebSocketProtocolException, a_bad_close_frame.validate, skip_utf8_validation=False) - a_bad_close_frame_2 = ABNF(0,0,0,0, opcode=ABNF.OPCODE_CLOSE, data=b'\x01\x8a\xaa\xff\xdd') - self.assertRaises(ws._exceptions.WebSocketProtocolException, a_bad_close_frame_2.validate, skip_utf8_validation=False) - a_bad_close_frame_3 = ABNF(0,0,0,0, opcode=ABNF.OPCODE_CLOSE, data=b'\x03\xe7') - self.assertRaises(ws._exceptions.WebSocketProtocolException, a_bad_close_frame_3.validate, skip_utf8_validation=True) + a_invalid_ping = ABNF(0, 0, 0, 0, opcode=ABNF.OPCODE_PING) + self.assertRaises( + ws._exceptions.WebSocketProtocolException, + a_invalid_ping.validate, + skip_utf8_validation=False, + ) + a_bad_rsv_value = ABNF(0, 1, 0, 0, opcode=ABNF.OPCODE_TEXT) + self.assertRaises( + ws._exceptions.WebSocketProtocolException, + a_bad_rsv_value.validate, + skip_utf8_validation=False, + ) + a_bad_opcode = ABNF(0, 0, 0, 0, opcode=77) + self.assertRaises( + ws._exceptions.WebSocketProtocolException, + a_bad_opcode.validate, + skip_utf8_validation=False, + ) + a_bad_close_frame = ABNF(0, 0, 0, 0, opcode=ABNF.OPCODE_CLOSE, data=b"\x01") + self.assertRaises( + ws._exceptions.WebSocketProtocolException, + a_bad_close_frame.validate, + skip_utf8_validation=False, + ) + a_bad_close_frame_2 = ABNF( + 0, 0, 0, 0, opcode=ABNF.OPCODE_CLOSE, data=b"\x01\x8a\xaa\xff\xdd" + ) + self.assertRaises( + ws._exceptions.WebSocketProtocolException, + a_bad_close_frame_2.validate, + skip_utf8_validation=False, + ) + a_bad_close_frame_3 = ABNF( + 0, 0, 0, 0, opcode=ABNF.OPCODE_CLOSE, data=b"\x03\xe7" + ) + self.assertRaises( + ws._exceptions.WebSocketProtocolException, + a_bad_close_frame_3.validate, + skip_utf8_validation=True, + ) def testMask(self): - abnf_none_data = ABNF(0,0,0,0, opcode=ABNF.OPCODE_PING, mask=1, data=None) + abnf_none_data = ABNF( + 0, 0, 0, 0, opcode=ABNF.OPCODE_PING, mask_value=1, data=None + ) bytes_val = b"aaaa" self.assertEqual(abnf_none_data._get_masked(bytes_val), bytes_val) - abnf_str_data = ABNF(0,0,0,0, opcode=ABNF.OPCODE_PING, mask=1, data="a") - self.assertEqual(abnf_str_data._get_masked(bytes_val), b'aaaa\x00') + abnf_str_data = ABNF( + 0, 0, 0, 0, opcode=ABNF.OPCODE_PING, mask_value=1, data="a" + ) + self.assertEqual(abnf_str_data._get_masked(bytes_val), b"aaaa\x00") def testFormat(self): - abnf_bad_rsv_bits = ABNF(2,0,0,0, opcode=ABNF.OPCODE_TEXT) + abnf_bad_rsv_bits = ABNF(2, 0, 0, 0, opcode=ABNF.OPCODE_TEXT) self.assertRaises(ValueError, abnf_bad_rsv_bits.format) - abnf_bad_opcode = ABNF(0,0,0,0, opcode=5) + abnf_bad_opcode = ABNF(0, 0, 0, 0, opcode=5) self.assertRaises(ValueError, abnf_bad_opcode.format) - abnf_length_10 = ABNF(0,0,0,0, opcode=ABNF.OPCODE_TEXT, data="abcdefghij") - self.assertEqual(b'\x01', abnf_length_10.format()[0].to_bytes(1, 'big')) - self.assertEqual(b'\x8a', abnf_length_10.format()[1].to_bytes(1, 'big')) + abnf_length_10 = ABNF(0, 0, 0, 0, opcode=ABNF.OPCODE_TEXT, data="abcdefghij") + self.assertEqual(b"\x01", abnf_length_10.format()[0].to_bytes(1, "big")) + self.assertEqual(b"\x8a", abnf_length_10.format()[1].to_bytes(1, "big")) self.assertEqual("fin=0 opcode=1 data=abcdefghij", abnf_length_10.__str__()) - abnf_length_20 = ABNF(0,0,0,0, opcode=ABNF.OPCODE_BINARY, data="abcdefghijabcdefghij") - self.assertEqual(b'\x02', abnf_length_20.format()[0].to_bytes(1, 'big')) - self.assertEqual(b'\x94', abnf_length_20.format()[1].to_bytes(1, 'big')) - abnf_no_mask = ABNF(0,0,0,0, opcode=ABNF.OPCODE_TEXT, mask=0, data=b'\x01\x8a\xcc') - self.assertEqual(b'\x01\x03\x01\x8a\xcc', abnf_no_mask.format()) + abnf_length_20 = ABNF( + 0, 0, 0, 0, opcode=ABNF.OPCODE_BINARY, data="abcdefghijabcdefghij" + ) + self.assertEqual(b"\x02", abnf_length_20.format()[0].to_bytes(1, "big")) + self.assertEqual(b"\x94", abnf_length_20.format()[1].to_bytes(1, "big")) + abnf_no_mask = ABNF( + 0, 0, 0, 0, opcode=ABNF.OPCODE_TEXT, mask_value=0, data=b"\x01\x8a\xcc" + ) + self.assertEqual(b"\x01\x03\x01\x8a\xcc", abnf_no_mask.format()) def testFrameBuffer(self): fb = frame_buffer(0, True) @@ -81,7 +117,7 @@ class ABNFTest(unittest.TestCase): fb.clear self.assertEqual(fb.header, None) self.assertEqual(fb.length, None) - self.assertEqual(fb.mask, None) + self.assertEqual(fb.mask_value, None) self.assertEqual(fb.has_mask(), False) diff --git a/lib/websocket/tests/test_app.py b/lib/websocket/tests/test_app.py index ff90a0aa..5ed9a22e 100644 --- a/lib/websocket/tests/test_app.py +++ b/lib/websocket/tests/test_app.py @@ -2,11 +2,12 @@ # import os import os.path -import threading -import websocket as ws import ssl +import threading import unittest +import websocket as ws + """ test_app.py websocket - WebSocket client library for Python @@ -27,18 +28,16 @@ limitations under the License. """ # Skip test to access the internet unless TEST_WITH_INTERNET == 1 -TEST_WITH_INTERNET = os.environ.get('TEST_WITH_INTERNET', '0') == '1' +TEST_WITH_INTERNET = os.environ.get("TEST_WITH_INTERNET", "0") == "1" # Skip tests relying on local websockets server unless LOCAL_WS_SERVER_PORT != -1 -LOCAL_WS_SERVER_PORT = os.environ.get('LOCAL_WS_SERVER_PORT', '-1') -TEST_WITH_LOCAL_SERVER = LOCAL_WS_SERVER_PORT != '-1' +LOCAL_WS_SERVER_PORT = os.environ.get("LOCAL_WS_SERVER_PORT", "-1") +TEST_WITH_LOCAL_SERVER = LOCAL_WS_SERVER_PORT != "-1" TRACEABLE = True class WebSocketAppTest(unittest.TestCase): - class NotSetYet: - """ A marker class for signalling that a value hasn't been set yet. - """ + """A marker class for signalling that a value hasn't been set yet.""" def setUp(self): ws.enableTrace(TRACEABLE) @@ -54,14 +53,16 @@ class WebSocketAppTest(unittest.TestCase): WebSocketAppTest.get_mask_key_id = WebSocketAppTest.NotSetYet() WebSocketAppTest.on_error_data = WebSocketAppTest.NotSetYet() - @unittest.skipUnless(TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled") + @unittest.skipUnless( + TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled" + ) def testKeepRunning(self): - """ A WebSocketApp should keep running as long as its self.keep_running + """A WebSocketApp should keep running as long as its self.keep_running is not False (in the boolean context). """ def on_open(self, *args, **kwargs): - """ Set the keep_running flag for later inspection and immediately + """Set the keep_running flag for later inspection and immediately close the connection. """ self.send("hello!") @@ -73,23 +74,26 @@ class WebSocketAppTest(unittest.TestCase): self.close() def on_close(self, *args, **kwargs): - """ Set the keep_running flag for the test to use. - """ + """Set the keep_running flag for the test to use.""" WebSocketAppTest.keep_running_close = self.keep_running - app = ws.WebSocketApp('ws://127.0.0.1:' + LOCAL_WS_SERVER_PORT, on_open=on_open, on_close=on_close, on_message=on_message) + app = ws.WebSocketApp( + f"ws://127.0.0.1:{LOCAL_WS_SERVER_PORT}", + on_open=on_open, + on_close=on_close, + on_message=on_message, + ) app.run_forever() -# @unittest.skipUnless(TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled") + # @unittest.skipUnless(TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled") @unittest.skipUnless(False, "Test disabled for now (requires rel)") def testRunForeverDispatcher(self): - """ A WebSocketApp should keep running as long as its self.keep_running + """A WebSocketApp should keep running as long as its self.keep_running is not False (in the boolean context). """ def on_open(self, *args, **kwargs): - """ Send a message, receive, and send one more - """ + """Send a message, receive, and send one more""" self.send("hello!") self.recv() self.send("goodbye!") @@ -98,30 +102,38 @@ class WebSocketAppTest(unittest.TestCase): print(message) self.close() - app = ws.WebSocketApp('ws://127.0.0.1:' + LOCAL_WS_SERVER_PORT, on_open=on_open, on_message=on_message) + app = ws.WebSocketApp( + f"ws://127.0.0.1:{LOCAL_WS_SERVER_PORT}", + on_open=on_open, + on_message=on_message, + ) app.run_forever(dispatcher="Dispatcher") # doesn't work -# app.run_forever(dispatcher=rel) # would work -# rel.dispatch() - @unittest.skipUnless(TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled") + # app.run_forever(dispatcher=rel) # would work + # rel.dispatch() + + @unittest.skipUnless( + TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled" + ) def testRunForeverTeardownCleanExit(self): - """ The WebSocketApp.run_forever() method should return `False` when the application ends gracefully. - """ - app = ws.WebSocketApp('ws://127.0.0.1:' + LOCAL_WS_SERVER_PORT) + """The WebSocketApp.run_forever() method should return `False` when the application ends gracefully.""" + app = ws.WebSocketApp(f"ws://127.0.0.1:{LOCAL_WS_SERVER_PORT}") threading.Timer(interval=0.2, function=app.close).start() teardown = app.run_forever() self.assertEqual(teardown, False) @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") def testSockMaskKey(self): - """ A WebSocketApp should forward the received mask_key function down + """A WebSocketApp should forward the received mask_key function down to the actual socket. """ def my_mask_key_func(): return "\x00\x00\x00\x00" - app = ws.WebSocketApp('wss://api-pub.bitfinex.com/ws/1', get_mask_key=my_mask_key_func) + app = ws.WebSocketApp( + "wss://api-pub.bitfinex.com/ws/1", get_mask_key=my_mask_key_func + ) # if numpy is installed, this assertion fail # Note: We can't use 'is' for comparing the functions directly, need to use 'id'. @@ -129,8 +141,7 @@ class WebSocketAppTest(unittest.TestCase): @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") def testInvalidPingIntervalPingTimeout(self): - """ Test exception handling if ping_interval < ping_timeout - """ + """Test exception handling if ping_interval < ping_timeout""" def on_ping(app, msg): print("Got a ping!") @@ -140,13 +151,20 @@ class WebSocketAppTest(unittest.TestCase): print("Got a pong! No need to respond") app.close() - app = ws.WebSocketApp('wss://api-pub.bitfinex.com/ws/1', on_ping=on_ping, on_pong=on_pong) - self.assertRaises(ws.WebSocketException, app.run_forever, ping_interval=1, ping_timeout=2, sslopt={"cert_reqs": ssl.CERT_NONE}) + app = ws.WebSocketApp( + "wss://api-pub.bitfinex.com/ws/1", on_ping=on_ping, on_pong=on_pong + ) + self.assertRaises( + ws.WebSocketException, + app.run_forever, + ping_interval=1, + ping_timeout=2, + sslopt={"cert_reqs": ssl.CERT_NONE}, + ) @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") def testPingInterval(self): - """ Test WebSocketApp proper ping functionality - """ + """Test WebSocketApp proper ping functionality""" def on_ping(app, msg): print("Got a ping!") @@ -156,15 +174,18 @@ class WebSocketAppTest(unittest.TestCase): print("Got a pong! No need to respond") app.close() - app = ws.WebSocketApp('wss://api-pub.bitfinex.com/ws/1', on_ping=on_ping, on_pong=on_pong) - app.run_forever(ping_interval=2, ping_timeout=1, sslopt={"cert_reqs": ssl.CERT_NONE}) + app = ws.WebSocketApp( + "wss://api-pub.bitfinex.com/ws/1", on_ping=on_ping, on_pong=on_pong + ) + app.run_forever( + ping_interval=2, ping_timeout=1, sslopt={"cert_reqs": ssl.CERT_NONE} + ) @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") def testOpcodeClose(self): - """ Test WebSocketApp close opcode - """ + """Test WebSocketApp close opcode""" - app = ws.WebSocketApp('wss://tsock.us1.twilio.com/v3/wsconnect') + app = ws.WebSocketApp("wss://tsock.us1.twilio.com/v3/wsconnect") app.run_forever(ping_interval=2, ping_timeout=1, ping_payload="Ping payload") # This is commented out because the URL no longer responds in the expected way @@ -177,41 +198,59 @@ class WebSocketAppTest(unittest.TestCase): @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") def testBadPingInterval(self): - """ A WebSocketApp handling of negative ping_interval - """ - app = ws.WebSocketApp('wss://api-pub.bitfinex.com/ws/1') - self.assertRaises(ws.WebSocketException, app.run_forever, ping_interval=-5, sslopt={"cert_reqs": ssl.CERT_NONE}) + """A WebSocketApp handling of negative ping_interval""" + app = ws.WebSocketApp("wss://api-pub.bitfinex.com/ws/1") + self.assertRaises( + ws.WebSocketException, + app.run_forever, + ping_interval=-5, + sslopt={"cert_reqs": ssl.CERT_NONE}, + ) @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") def testBadPingTimeout(self): - """ A WebSocketApp handling of negative ping_timeout - """ - app = ws.WebSocketApp('wss://api-pub.bitfinex.com/ws/1') - self.assertRaises(ws.WebSocketException, app.run_forever, ping_timeout=-3, sslopt={"cert_reqs": ssl.CERT_NONE}) + """A WebSocketApp handling of negative ping_timeout""" + app = ws.WebSocketApp("wss://api-pub.bitfinex.com/ws/1") + self.assertRaises( + ws.WebSocketException, + app.run_forever, + ping_timeout=-3, + sslopt={"cert_reqs": ssl.CERT_NONE}, + ) @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") def testCloseStatusCode(self): - """ Test extraction of close frame status code and close reason in WebSocketApp - """ + """Test extraction of close frame status code and close reason in WebSocketApp""" + def on_close(wsapp, close_status_code, close_msg): print("on_close reached") - app = ws.WebSocketApp('wss://tsock.us1.twilio.com/v3/wsconnect', on_close=on_close) - closeframe = ws.ABNF(opcode=ws.ABNF.OPCODE_CLOSE, data=b'\x03\xe8no-init-from-client') - self.assertEqual([1000, 'no-init-from-client'], app._get_close_args(closeframe)) + app = ws.WebSocketApp( + "wss://tsock.us1.twilio.com/v3/wsconnect", on_close=on_close + ) + closeframe = ws.ABNF( + opcode=ws.ABNF.OPCODE_CLOSE, data=b"\x03\xe8no-init-from-client" + ) + self.assertEqual([1000, "no-init-from-client"], app._get_close_args(closeframe)) - closeframe = ws.ABNF(opcode=ws.ABNF.OPCODE_CLOSE, data=b'') + closeframe = ws.ABNF(opcode=ws.ABNF.OPCODE_CLOSE, data=b"") self.assertEqual([None, None], app._get_close_args(closeframe)) - app2 = ws.WebSocketApp('wss://tsock.us1.twilio.com/v3/wsconnect') - closeframe = ws.ABNF(opcode=ws.ABNF.OPCODE_CLOSE, data=b'') + app2 = ws.WebSocketApp("wss://tsock.us1.twilio.com/v3/wsconnect") + closeframe = ws.ABNF(opcode=ws.ABNF.OPCODE_CLOSE, data=b"") self.assertEqual([None, None], app2._get_close_args(closeframe)) - self.assertRaises(ws.WebSocketConnectionClosedException, app.send, data="test if connection is closed") + self.assertRaises( + ws.WebSocketConnectionClosedException, + app.send, + data="test if connection is closed", + ) - @unittest.skipUnless(TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled") + @unittest.skipUnless( + TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled" + ) def testCallbackFunctionException(self): - """ Test callback function exception handling """ + """Test callback function exception handling""" exc = None passed_app = None @@ -228,26 +267,33 @@ class WebSocketAppTest(unittest.TestCase): def on_pong(app, msg): app.close() - app = ws.WebSocketApp('ws://127.0.0.1:' + LOCAL_WS_SERVER_PORT, on_open=on_open, on_error=on_error, on_pong=on_pong) + app = ws.WebSocketApp( + f"ws://127.0.0.1:{LOCAL_WS_SERVER_PORT}", + on_open=on_open, + on_error=on_error, + on_pong=on_pong, + ) app.run_forever(ping_interval=2, ping_timeout=1) self.assertEqual(passed_app, app) self.assertIsInstance(exc, RuntimeError) self.assertEqual(str(exc), "Callback failed") - @unittest.skipUnless(TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled") + @unittest.skipUnless( + TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled" + ) def testCallbackMethodException(self): - """ Test callback method exception handling """ + """Test callback method exception handling""" class Callbacks: def __init__(self): self.exc = None self.passed_app = None self.app = ws.WebSocketApp( - 'ws://127.0.0.1:' + LOCAL_WS_SERVER_PORT, + f"ws://127.0.0.1:{LOCAL_WS_SERVER_PORT}", on_open=self.on_open, on_error=self.on_error, - on_pong=self.on_pong + on_pong=self.on_pong, ) self.app.run_forever(ping_interval=2, ping_timeout=1) @@ -267,9 +313,11 @@ class WebSocketAppTest(unittest.TestCase): self.assertIsInstance(callbacks.exc, RuntimeError) self.assertEqual(str(callbacks.exc), "Callback failed") - @unittest.skipUnless(TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled") + @unittest.skipUnless( + TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled" + ) def testReconnect(self): - """ Test reconnect """ + """Test reconnect""" pong_count = 0 exc = None @@ -287,7 +335,9 @@ class WebSocketAppTest(unittest.TestCase): # Got second pong after reconnect app.close() - app = ws.WebSocketApp('ws://127.0.0.1:' + LOCAL_WS_SERVER_PORT, on_pong=on_pong, on_error=on_error) + app = ws.WebSocketApp( + f"ws://127.0.0.1:{LOCAL_WS_SERVER_PORT}", on_pong=on_pong, on_error=on_error + ) app.run_forever(ping_interval=2, ping_timeout=1, reconnect=3) self.assertEqual(pong_count, 2) diff --git a/lib/websocket/tests/test_cookiejar.py b/lib/websocket/tests/test_cookiejar.py index 8f835e9e..0de87517 100644 --- a/lib/websocket/tests/test_cookiejar.py +++ b/lib/websocket/tests/test_cookiejar.py @@ -1,4 +1,5 @@ import unittest + from websocket._cookiejar import SimpleCookieJar """ @@ -25,11 +26,15 @@ class CookieJarTest(unittest.TestCase): def testAdd(self): cookie_jar = SimpleCookieJar() cookie_jar.add("") - self.assertFalse(cookie_jar.jar, "Cookie with no domain should not be added to the jar") + self.assertFalse( + cookie_jar.jar, "Cookie with no domain should not be added to the jar" + ) cookie_jar = SimpleCookieJar() cookie_jar.add("a=b") - self.assertFalse(cookie_jar.jar, "Cookie with no domain should not be added to the jar") + self.assertFalse( + cookie_jar.jar, "Cookie with no domain should not be added to the jar" + ) cookie_jar = SimpleCookieJar() cookie_jar.add("a=b; domain=.abc") @@ -65,7 +70,9 @@ class CookieJarTest(unittest.TestCase): def testSet(self): cookie_jar = SimpleCookieJar() cookie_jar.set("a=b") - self.assertFalse(cookie_jar.jar, "Cookie with no domain should not be added to the jar") + self.assertFalse( + cookie_jar.jar, "Cookie with no domain should not be added to the jar" + ) cookie_jar = SimpleCookieJar() cookie_jar.set("a=b; domain=.abc") diff --git a/lib/websocket/tests/test_http.py b/lib/websocket/tests/test_http.py index d7de29d3..0d6031a3 100644 --- a/lib/websocket/tests/test_http.py +++ b/lib/websocket/tests/test_http.py @@ -2,12 +2,20 @@ # import os import os.path -import websocket as ws -from websocket._http import proxy_info, read_headers, _start_proxied_socket, _tunnel, _get_addrinfo_list, connect -import unittest -import ssl -import websocket import socket +import ssl +import unittest + +import websocket +import websocket as ws +from websocket._http import ( + _get_addrinfo_list, + _start_proxied_socket, + _tunnel, + connect, + proxy_info, + read_headers, +) """ test_http.py @@ -29,16 +37,16 @@ limitations under the License. """ try: - from python_socks._errors import ProxyError, ProxyTimeoutError, ProxyConnectionError + from python_socks._errors import ProxyConnectionError, ProxyError, ProxyTimeoutError except: - from websocket._http import ProxyError, ProxyTimeoutError, ProxyConnectionError + from websocket._http import ProxyConnectionError, ProxyError, ProxyTimeoutError # Skip test to access the internet unless TEST_WITH_INTERNET == 1 -TEST_WITH_INTERNET = os.environ.get('TEST_WITH_INTERNET', '0') == '1' -TEST_WITH_PROXY = os.environ.get('TEST_WITH_PROXY', '0') == '1' +TEST_WITH_INTERNET = os.environ.get("TEST_WITH_INTERNET", "0") == "1" +TEST_WITH_PROXY = os.environ.get("TEST_WITH_PROXY", "0") == "1" # Skip tests relying on local websockets server unless LOCAL_WS_SERVER_PORT != -1 -LOCAL_WS_SERVER_PORT = os.environ.get('LOCAL_WS_SERVER_PORT', '-1') -TEST_WITH_LOCAL_SERVER = LOCAL_WS_SERVER_PORT != '-1' +LOCAL_WS_SERVER_PORT = os.environ.get("LOCAL_WS_SERVER_PORT", "-1") +TEST_WITH_LOCAL_SERVER = LOCAL_WS_SERVER_PORT != "-1" class SockMock: @@ -70,7 +78,6 @@ class SockMock: class HeaderSockMock(SockMock): - def __init__(self, fname): SockMock.__init__(self) path = os.path.join(os.path.dirname(__file__), fname) @@ -78,8 +85,7 @@ class HeaderSockMock(SockMock): self.add_packet(f.read()) -class OptsList(): - +class OptsList: def __init__(self): self.timeout = 1 self.sockopt = [] @@ -87,17 +93,34 @@ class OptsList(): class HttpTest(unittest.TestCase): - def testReadHeader(self): - status, header, status_message = read_headers(HeaderSockMock("data/header01.txt")) + status, header, status_message = read_headers( + HeaderSockMock("data/header01.txt") + ) self.assertEqual(status, 101) self.assertEqual(header["connection"], "Upgrade") # header02.txt is intentionally malformed - self.assertRaises(ws.WebSocketException, read_headers, HeaderSockMock("data/header02.txt")) + self.assertRaises( + ws.WebSocketException, read_headers, HeaderSockMock("data/header02.txt") + ) def testTunnel(self): - self.assertRaises(ws.WebSocketProxyException, _tunnel, HeaderSockMock("data/header01.txt"), "example.com", 80, ("username", "password")) - self.assertRaises(ws.WebSocketProxyException, _tunnel, HeaderSockMock("data/header02.txt"), "example.com", 80, ("username", "password")) + self.assertRaises( + ws.WebSocketProxyException, + _tunnel, + HeaderSockMock("data/header01.txt"), + "example.com", + 80, + ("username", "password"), + ) + self.assertRaises( + ws.WebSocketProxyException, + _tunnel, + HeaderSockMock("data/header02.txt"), + "example.com", + 80, + ("username", "password"), + ) @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") def testConnect(self): @@ -105,34 +128,164 @@ class HttpTest(unittest.TestCase): if ws._http.HAVE_PYTHON_SOCKS: # Need this check, otherwise case where python_socks is not installed triggers # websocket._exceptions.WebSocketException: Python Socks is needed for SOCKS proxying but is not available - self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks4", http_proxy_timeout=1)) - self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks4a", http_proxy_timeout=1)) - self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks5", http_proxy_timeout=1)) - self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks5h", http_proxy_timeout=1)) - self.assertRaises(ProxyConnectionError, connect, "wss://example.com", OptsList(), proxy_info(http_proxy_host="127.0.0.1", http_proxy_port=9999, proxy_type="socks4", http_proxy_timeout=1), None) + self.assertRaises( + (ProxyTimeoutError, OSError), + _start_proxied_socket, + "wss://example.com", + OptsList(), + proxy_info( + http_proxy_host="example.com", + http_proxy_port="8080", + proxy_type="socks4", + http_proxy_timeout=1, + ), + ) + self.assertRaises( + (ProxyTimeoutError, OSError), + _start_proxied_socket, + "wss://example.com", + OptsList(), + proxy_info( + http_proxy_host="example.com", + http_proxy_port="8080", + proxy_type="socks4a", + http_proxy_timeout=1, + ), + ) + self.assertRaises( + (ProxyTimeoutError, OSError), + _start_proxied_socket, + "wss://example.com", + OptsList(), + proxy_info( + http_proxy_host="example.com", + http_proxy_port="8080", + proxy_type="socks5", + http_proxy_timeout=1, + ), + ) + self.assertRaises( + (ProxyTimeoutError, OSError), + _start_proxied_socket, + "wss://example.com", + OptsList(), + proxy_info( + http_proxy_host="example.com", + http_proxy_port="8080", + proxy_type="socks5h", + http_proxy_timeout=1, + ), + ) + self.assertRaises( + ProxyConnectionError, + connect, + "wss://example.com", + OptsList(), + proxy_info( + http_proxy_host="127.0.0.1", + http_proxy_port=9999, + proxy_type="socks4", + http_proxy_timeout=1, + ), + None, + ) - self.assertRaises(TypeError, _get_addrinfo_list, None, 80, True, proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="9999", proxy_type="http")) - self.assertRaises(TypeError, _get_addrinfo_list, None, 80, True, proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="9999", proxy_type="http")) - self.assertRaises(socket.timeout, connect, "wss://google.com", OptsList(), proxy_info(http_proxy_host="8.8.8.8", http_proxy_port=9999, proxy_type="http", http_proxy_timeout=1), None) + self.assertRaises( + TypeError, + _get_addrinfo_list, + None, + 80, + True, + proxy_info( + http_proxy_host="127.0.0.1", http_proxy_port="9999", proxy_type="http" + ), + ) + self.assertRaises( + TypeError, + _get_addrinfo_list, + None, + 80, + True, + proxy_info( + http_proxy_host="127.0.0.1", http_proxy_port="9999", proxy_type="http" + ), + ) + self.assertRaises( + socket.timeout, + connect, + "wss://google.com", + OptsList(), + proxy_info( + http_proxy_host="8.8.8.8", + http_proxy_port=9999, + proxy_type="http", + http_proxy_timeout=1, + ), + None, + ) self.assertEqual( - connect("wss://google.com", OptsList(), proxy_info(http_proxy_host="8.8.8.8", http_proxy_port=8080, proxy_type="http"), True), - (True, ("google.com", 443, "/"))) + connect( + "wss://google.com", + OptsList(), + proxy_info( + http_proxy_host="8.8.8.8", http_proxy_port=8080, proxy_type="http" + ), + True, + ), + (True, ("google.com", 443, "/")), + ) # The following test fails on Mac OS with a gaierror, not an OverflowError # self.assertRaises(OverflowError, connect, "wss://example.com", OptsList(), proxy_info(http_proxy_host="127.0.0.1", http_proxy_port=99999, proxy_type="socks4", timeout=2), False) @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") - @unittest.skipUnless(TEST_WITH_PROXY, "This test requires a HTTP proxy to be running on port 8899") - @unittest.skipUnless(TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled") + @unittest.skipUnless( + TEST_WITH_PROXY, "This test requires a HTTP proxy to be running on port 8899" + ) + @unittest.skipUnless( + TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled" + ) def testProxyConnect(self): ws = websocket.WebSocket() - ws.connect("ws://127.0.0.1:" + LOCAL_WS_SERVER_PORT, http_proxy_host="127.0.0.1", http_proxy_port="8899", proxy_type="http") + ws.connect( + f"ws://127.0.0.1:{LOCAL_WS_SERVER_PORT}", + http_proxy_host="127.0.0.1", + http_proxy_port="8899", + proxy_type="http", + ) ws.send("Hello, Server") server_response = ws.recv() self.assertEqual(server_response, "Hello, Server") # self.assertEqual(_start_proxied_socket("wss://api.bitfinex.com/ws/2", OptsList(), proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="8899", proxy_type="http"))[1], ("api.bitfinex.com", 443, '/ws/2')) - self.assertEqual(_get_addrinfo_list("api.bitfinex.com", 443, True, proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="8899", proxy_type="http")), - (socket.getaddrinfo("127.0.0.1", 8899, 0, socket.SOCK_STREAM, socket.SOL_TCP), True, None)) - self.assertEqual(connect("wss://api.bitfinex.com/ws/2", OptsList(), proxy_info(http_proxy_host="127.0.0.1", http_proxy_port=8899, proxy_type="http"), None)[1], ("api.bitfinex.com", 443, '/ws/2')) + self.assertEqual( + _get_addrinfo_list( + "api.bitfinex.com", + 443, + True, + proxy_info( + http_proxy_host="127.0.0.1", + http_proxy_port="8899", + proxy_type="http", + ), + ), + ( + socket.getaddrinfo( + "127.0.0.1", 8899, 0, socket.SOCK_STREAM, socket.SOL_TCP + ), + True, + None, + ), + ) + self.assertEqual( + connect( + "wss://api.bitfinex.com/ws/2", + OptsList(), + proxy_info( + http_proxy_host="127.0.0.1", http_proxy_port=8899, proxy_type="http" + ), + None, + )[1], + ("api.bitfinex.com", 443, "/ws/2"), + ) # TODO: Test SOCKS4 and SOCK5 proxies with unit tests @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") @@ -151,7 +304,7 @@ class HttpTest(unittest.TestCase): DHE-RSA-AES256-SHA256:ECDHE-ECDSA-AES128-SHA256:\ ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:\ ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA", - "ecdh_curve": "prime256v1" + "ecdh_curve": "prime256v1", } ws_ssl1 = websocket.WebSocket(sslopt=ssloptions) ws_ssl1.connect("wss://api.bitfinex.com/ws/2") @@ -163,13 +316,55 @@ class HttpTest(unittest.TestCase): ws_ssl2.close def testProxyInfo(self): - self.assertEqual(proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="8080", proxy_type="http").proxy_protocol, "http") - self.assertRaises(ProxyError, proxy_info, http_proxy_host="127.0.0.1", http_proxy_port="8080", proxy_type="badval") - self.assertEqual(proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="http").proxy_host, "example.com") - self.assertEqual(proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="8080", proxy_type="http").proxy_port, "8080") - self.assertEqual(proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="8080", proxy_type="http").auth, None) - self.assertEqual(proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="8080", proxy_type="http", http_proxy_auth=("my_username123", "my_pass321")).auth[0], "my_username123") - self.assertEqual(proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="8080", proxy_type="http", http_proxy_auth=("my_username123", "my_pass321")).auth[1], "my_pass321") + self.assertEqual( + proxy_info( + http_proxy_host="127.0.0.1", http_proxy_port="8080", proxy_type="http" + ).proxy_protocol, + "http", + ) + self.assertRaises( + ProxyError, + proxy_info, + http_proxy_host="127.0.0.1", + http_proxy_port="8080", + proxy_type="badval", + ) + self.assertEqual( + proxy_info( + http_proxy_host="example.com", http_proxy_port="8080", proxy_type="http" + ).proxy_host, + "example.com", + ) + self.assertEqual( + proxy_info( + http_proxy_host="127.0.0.1", http_proxy_port="8080", proxy_type="http" + ).proxy_port, + "8080", + ) + self.assertEqual( + proxy_info( + http_proxy_host="127.0.0.1", http_proxy_port="8080", proxy_type="http" + ).auth, + None, + ) + self.assertEqual( + proxy_info( + http_proxy_host="127.0.0.1", + http_proxy_port="8080", + proxy_type="http", + http_proxy_auth=("my_username123", "my_pass321"), + ).auth[0], + "my_username123", + ) + self.assertEqual( + proxy_info( + http_proxy_host="127.0.0.1", + http_proxy_port="8080", + proxy_type="http", + http_proxy_auth=("my_username123", "my_pass321"), + ).auth[1], + "my_pass321", + ) if __name__ == "__main__": diff --git a/lib/websocket/tests/test_url.py b/lib/websocket/tests/test_url.py index a74dd766..792399eb 100644 --- a/lib/websocket/tests/test_url.py +++ b/lib/websocket/tests/test_url.py @@ -2,7 +2,13 @@ # import os import unittest -from websocket._url import get_proxy_info, parse_url, _is_address_in_network, _is_no_proxy_host + +from websocket._url import ( + _is_address_in_network, + _is_no_proxy_host, + get_proxy_info, + parse_url, +) """ test_url.py @@ -25,11 +31,10 @@ limitations under the License. class UrlTest(unittest.TestCase): - def test_address_in_network(self): - self.assertTrue(_is_address_in_network('127.0.0.1', '127.0.0.0/8')) - self.assertTrue(_is_address_in_network('127.1.0.1', '127.0.0.0/8')) - self.assertFalse(_is_address_in_network('127.1.0.1', '127.0.0.0/24')) + self.assertTrue(_is_address_in_network("127.0.0.1", "127.0.0.0/8")) + self.assertTrue(_is_address_in_network("127.1.0.1", "127.0.0.0/8")) + self.assertFalse(_is_address_in_network("127.1.0.1", "127.0.0.0/24")) def testParseUrl(self): p = parse_url("ws://www.example.com/r") @@ -126,57 +131,71 @@ class IsNoProxyHostTest(unittest.TestCase): del os.environ["no_proxy"] def testMatchAll(self): - self.assertTrue(_is_no_proxy_host("any.websocket.org", ['*'])) - self.assertTrue(_is_no_proxy_host("192.168.0.1", ['*'])) - self.assertTrue(_is_no_proxy_host("any.websocket.org", ['other.websocket.org', '*'])) - os.environ['no_proxy'] = '*' + self.assertTrue(_is_no_proxy_host("any.websocket.org", ["*"])) + self.assertTrue(_is_no_proxy_host("192.168.0.1", ["*"])) + self.assertTrue( + _is_no_proxy_host("any.websocket.org", ["other.websocket.org", "*"]) + ) + os.environ["no_proxy"] = "*" self.assertTrue(_is_no_proxy_host("any.websocket.org", None)) self.assertTrue(_is_no_proxy_host("192.168.0.1", None)) - os.environ['no_proxy'] = 'other.websocket.org, *' + os.environ["no_proxy"] = "other.websocket.org, *" self.assertTrue(_is_no_proxy_host("any.websocket.org", None)) def testIpAddress(self): - self.assertTrue(_is_no_proxy_host("127.0.0.1", ['127.0.0.1'])) - self.assertFalse(_is_no_proxy_host("127.0.0.2", ['127.0.0.1'])) - self.assertTrue(_is_no_proxy_host("127.0.0.1", ['other.websocket.org', '127.0.0.1'])) - self.assertFalse(_is_no_proxy_host("127.0.0.2", ['other.websocket.org', '127.0.0.1'])) - os.environ['no_proxy'] = '127.0.0.1' + self.assertTrue(_is_no_proxy_host("127.0.0.1", ["127.0.0.1"])) + self.assertFalse(_is_no_proxy_host("127.0.0.2", ["127.0.0.1"])) + self.assertTrue( + _is_no_proxy_host("127.0.0.1", ["other.websocket.org", "127.0.0.1"]) + ) + self.assertFalse( + _is_no_proxy_host("127.0.0.2", ["other.websocket.org", "127.0.0.1"]) + ) + os.environ["no_proxy"] = "127.0.0.1" self.assertTrue(_is_no_proxy_host("127.0.0.1", None)) self.assertFalse(_is_no_proxy_host("127.0.0.2", None)) - os.environ['no_proxy'] = 'other.websocket.org, 127.0.0.1' + os.environ["no_proxy"] = "other.websocket.org, 127.0.0.1" self.assertTrue(_is_no_proxy_host("127.0.0.1", None)) self.assertFalse(_is_no_proxy_host("127.0.0.2", None)) def testIpAddressInRange(self): - self.assertTrue(_is_no_proxy_host("127.0.0.1", ['127.0.0.0/8'])) - self.assertTrue(_is_no_proxy_host("127.0.0.2", ['127.0.0.0/8'])) - self.assertFalse(_is_no_proxy_host("127.1.0.1", ['127.0.0.0/24'])) - os.environ['no_proxy'] = '127.0.0.0/8' + self.assertTrue(_is_no_proxy_host("127.0.0.1", ["127.0.0.0/8"])) + self.assertTrue(_is_no_proxy_host("127.0.0.2", ["127.0.0.0/8"])) + self.assertFalse(_is_no_proxy_host("127.1.0.1", ["127.0.0.0/24"])) + os.environ["no_proxy"] = "127.0.0.0/8" self.assertTrue(_is_no_proxy_host("127.0.0.1", None)) self.assertTrue(_is_no_proxy_host("127.0.0.2", None)) - os.environ['no_proxy'] = '127.0.0.0/24' + os.environ["no_proxy"] = "127.0.0.0/24" self.assertFalse(_is_no_proxy_host("127.1.0.1", None)) def testHostnameMatch(self): - self.assertTrue(_is_no_proxy_host("my.websocket.org", ['my.websocket.org'])) - self.assertTrue(_is_no_proxy_host("my.websocket.org", ['other.websocket.org', 'my.websocket.org'])) - self.assertFalse(_is_no_proxy_host("my.websocket.org", ['other.websocket.org'])) - os.environ['no_proxy'] = 'my.websocket.org' + self.assertTrue(_is_no_proxy_host("my.websocket.org", ["my.websocket.org"])) + self.assertTrue( + _is_no_proxy_host( + "my.websocket.org", ["other.websocket.org", "my.websocket.org"] + ) + ) + self.assertFalse(_is_no_proxy_host("my.websocket.org", ["other.websocket.org"])) + os.environ["no_proxy"] = "my.websocket.org" self.assertTrue(_is_no_proxy_host("my.websocket.org", None)) self.assertFalse(_is_no_proxy_host("other.websocket.org", None)) - os.environ['no_proxy'] = 'other.websocket.org, my.websocket.org' + os.environ["no_proxy"] = "other.websocket.org, my.websocket.org" self.assertTrue(_is_no_proxy_host("my.websocket.org", None)) def testHostnameMatchDomain(self): - self.assertTrue(_is_no_proxy_host("any.websocket.org", ['.websocket.org'])) - self.assertTrue(_is_no_proxy_host("my.other.websocket.org", ['.websocket.org'])) - self.assertTrue(_is_no_proxy_host("any.websocket.org", ['my.websocket.org', '.websocket.org'])) - self.assertFalse(_is_no_proxy_host("any.websocket.com", ['.websocket.org'])) - os.environ['no_proxy'] = '.websocket.org' + self.assertTrue(_is_no_proxy_host("any.websocket.org", [".websocket.org"])) + self.assertTrue(_is_no_proxy_host("my.other.websocket.org", [".websocket.org"])) + self.assertTrue( + _is_no_proxy_host( + "any.websocket.org", ["my.websocket.org", ".websocket.org"] + ) + ) + self.assertFalse(_is_no_proxy_host("any.websocket.com", [".websocket.org"])) + os.environ["no_proxy"] = ".websocket.org" self.assertTrue(_is_no_proxy_host("any.websocket.org", None)) self.assertTrue(_is_no_proxy_host("my.other.websocket.org", None)) self.assertFalse(_is_no_proxy_host("any.websocket.com", None)) - os.environ['no_proxy'] = 'my.websocket.org, .websocket.org' + os.environ["no_proxy"] = "my.websocket.org, .websocket.org" self.assertTrue(_is_no_proxy_host("any.websocket.org", None)) @@ -209,96 +228,205 @@ class ProxyInfoTest(unittest.TestCase): del os.environ["no_proxy"] def testProxyFromArgs(self): - self.assertEqual(get_proxy_info("echo.websocket.events", False, proxy_host="localhost"), ("localhost", 0, None)) - self.assertEqual(get_proxy_info("echo.websocket.events", False, proxy_host="localhost", proxy_port=3128), - ("localhost", 3128, None)) - self.assertEqual(get_proxy_info("echo.websocket.events", True, proxy_host="localhost"), ("localhost", 0, None)) - self.assertEqual(get_proxy_info("echo.websocket.events", True, proxy_host="localhost", proxy_port=3128), - ("localhost", 3128, None)) - - self.assertEqual(get_proxy_info("echo.websocket.events", False, proxy_host="localhost", proxy_auth=("a", "b")), - ("localhost", 0, ("a", "b"))) self.assertEqual( - get_proxy_info("echo.websocket.events", False, proxy_host="localhost", proxy_port=3128, proxy_auth=("a", "b")), - ("localhost", 3128, ("a", "b"))) - self.assertEqual(get_proxy_info("echo.websocket.events", True, proxy_host="localhost", proxy_auth=("a", "b")), - ("localhost", 0, ("a", "b"))) + get_proxy_info("echo.websocket.events", False, proxy_host="localhost"), + ("localhost", 0, None), + ) self.assertEqual( - get_proxy_info("echo.websocket.events", True, proxy_host="localhost", proxy_port=3128, proxy_auth=("a", "b")), - ("localhost", 3128, ("a", "b"))) + get_proxy_info( + "echo.websocket.events", False, proxy_host="localhost", proxy_port=3128 + ), + ("localhost", 3128, None), + ) + self.assertEqual( + get_proxy_info("echo.websocket.events", True, proxy_host="localhost"), + ("localhost", 0, None), + ) + self.assertEqual( + get_proxy_info( + "echo.websocket.events", True, proxy_host="localhost", proxy_port=3128 + ), + ("localhost", 3128, None), + ) - self.assertEqual(get_proxy_info("echo.websocket.events", True, proxy_host="localhost", proxy_port=3128, - no_proxy=["example.com"], proxy_auth=("a", "b")), - ("localhost", 3128, ("a", "b"))) - self.assertEqual(get_proxy_info("echo.websocket.events", True, proxy_host="localhost", proxy_port=3128, - no_proxy=["echo.websocket.events"], proxy_auth=("a", "b")), - (None, 0, None)) + self.assertEqual( + get_proxy_info( + "echo.websocket.events", + False, + proxy_host="localhost", + proxy_auth=("a", "b"), + ), + ("localhost", 0, ("a", "b")), + ) + self.assertEqual( + get_proxy_info( + "echo.websocket.events", + False, + proxy_host="localhost", + proxy_port=3128, + proxy_auth=("a", "b"), + ), + ("localhost", 3128, ("a", "b")), + ) + self.assertEqual( + get_proxy_info( + "echo.websocket.events", + True, + proxy_host="localhost", + proxy_auth=("a", "b"), + ), + ("localhost", 0, ("a", "b")), + ) + self.assertEqual( + get_proxy_info( + "echo.websocket.events", + True, + proxy_host="localhost", + proxy_port=3128, + proxy_auth=("a", "b"), + ), + ("localhost", 3128, ("a", "b")), + ) + + self.assertEqual( + get_proxy_info( + "echo.websocket.events", + True, + proxy_host="localhost", + proxy_port=3128, + no_proxy=["example.com"], + proxy_auth=("a", "b"), + ), + ("localhost", 3128, ("a", "b")), + ) + self.assertEqual( + get_proxy_info( + "echo.websocket.events", + True, + proxy_host="localhost", + proxy_port=3128, + no_proxy=["echo.websocket.events"], + proxy_auth=("a", "b"), + ), + (None, 0, None), + ) def testProxyFromEnv(self): os.environ["http_proxy"] = "http://localhost/" - self.assertEqual(get_proxy_info("echo.websocket.events", False), ("localhost", None, None)) + self.assertEqual( + get_proxy_info("echo.websocket.events", False), ("localhost", None, None) + ) os.environ["http_proxy"] = "http://localhost:3128/" - self.assertEqual(get_proxy_info("echo.websocket.events", False), ("localhost", 3128, None)) + self.assertEqual( + get_proxy_info("echo.websocket.events", False), ("localhost", 3128, None) + ) os.environ["http_proxy"] = "http://localhost/" os.environ["https_proxy"] = "http://localhost2/" - self.assertEqual(get_proxy_info("echo.websocket.events", False), ("localhost", None, None)) + self.assertEqual( + get_proxy_info("echo.websocket.events", False), ("localhost", None, None) + ) os.environ["http_proxy"] = "http://localhost:3128/" os.environ["https_proxy"] = "http://localhost2:3128/" - self.assertEqual(get_proxy_info("echo.websocket.events", False), ("localhost", 3128, None)) + self.assertEqual( + get_proxy_info("echo.websocket.events", False), ("localhost", 3128, None) + ) os.environ["http_proxy"] = "http://localhost/" os.environ["https_proxy"] = "http://localhost2/" - self.assertEqual(get_proxy_info("echo.websocket.events", True), ("localhost2", None, None)) + self.assertEqual( + get_proxy_info("echo.websocket.events", True), ("localhost2", None, None) + ) os.environ["http_proxy"] = "http://localhost:3128/" os.environ["https_proxy"] = "http://localhost2:3128/" - self.assertEqual(get_proxy_info("echo.websocket.events", True), ("localhost2", 3128, None)) + self.assertEqual( + get_proxy_info("echo.websocket.events", True), ("localhost2", 3128, None) + ) os.environ["http_proxy"] = "" os.environ["https_proxy"] = "http://localhost2/" - self.assertEqual(get_proxy_info("echo.websocket.events", True), ("localhost2", None, None)) - self.assertEqual(get_proxy_info("echo.websocket.events", False), (None, 0, None)) + self.assertEqual( + get_proxy_info("echo.websocket.events", True), ("localhost2", None, None) + ) + self.assertEqual( + get_proxy_info("echo.websocket.events", False), (None, 0, None) + ) os.environ["http_proxy"] = "" os.environ["https_proxy"] = "http://localhost2:3128/" - self.assertEqual(get_proxy_info("echo.websocket.events", True), ("localhost2", 3128, None)) - self.assertEqual(get_proxy_info("echo.websocket.events", False), (None, 0, None)) + self.assertEqual( + get_proxy_info("echo.websocket.events", True), ("localhost2", 3128, None) + ) + self.assertEqual( + get_proxy_info("echo.websocket.events", False), (None, 0, None) + ) os.environ["http_proxy"] = "http://localhost/" os.environ["https_proxy"] = "" self.assertEqual(get_proxy_info("echo.websocket.events", True), (None, 0, None)) - self.assertEqual(get_proxy_info("echo.websocket.events", False), ("localhost", None, None)) + self.assertEqual( + get_proxy_info("echo.websocket.events", False), ("localhost", None, None) + ) os.environ["http_proxy"] = "http://localhost:3128/" os.environ["https_proxy"] = "" self.assertEqual(get_proxy_info("echo.websocket.events", True), (None, 0, None)) - self.assertEqual(get_proxy_info("echo.websocket.events", False), ("localhost", 3128, None)) + self.assertEqual( + get_proxy_info("echo.websocket.events", False), ("localhost", 3128, None) + ) os.environ["http_proxy"] = "http://a:b@localhost/" - self.assertEqual(get_proxy_info("echo.websocket.events", False), ("localhost", None, ("a", "b"))) + self.assertEqual( + get_proxy_info("echo.websocket.events", False), + ("localhost", None, ("a", "b")), + ) os.environ["http_proxy"] = "http://a:b@localhost:3128/" - self.assertEqual(get_proxy_info("echo.websocket.events", False), ("localhost", 3128, ("a", "b"))) + self.assertEqual( + get_proxy_info("echo.websocket.events", False), + ("localhost", 3128, ("a", "b")), + ) os.environ["http_proxy"] = "http://a:b@localhost/" os.environ["https_proxy"] = "http://a:b@localhost2/" - self.assertEqual(get_proxy_info("echo.websocket.events", False), ("localhost", None, ("a", "b"))) + self.assertEqual( + get_proxy_info("echo.websocket.events", False), + ("localhost", None, ("a", "b")), + ) os.environ["http_proxy"] = "http://a:b@localhost:3128/" os.environ["https_proxy"] = "http://a:b@localhost2:3128/" - self.assertEqual(get_proxy_info("echo.websocket.events", False), ("localhost", 3128, ("a", "b"))) + self.assertEqual( + get_proxy_info("echo.websocket.events", False), + ("localhost", 3128, ("a", "b")), + ) os.environ["http_proxy"] = "http://a:b@localhost/" os.environ["https_proxy"] = "http://a:b@localhost2/" - self.assertEqual(get_proxy_info("echo.websocket.events", True), ("localhost2", None, ("a", "b"))) + self.assertEqual( + get_proxy_info("echo.websocket.events", True), + ("localhost2", None, ("a", "b")), + ) os.environ["http_proxy"] = "http://a:b@localhost:3128/" os.environ["https_proxy"] = "http://a:b@localhost2:3128/" - self.assertEqual(get_proxy_info("echo.websocket.events", True), ("localhost2", 3128, ("a", "b"))) + self.assertEqual( + get_proxy_info("echo.websocket.events", True), + ("localhost2", 3128, ("a", "b")), + ) - os.environ["http_proxy"] = "http://john%40example.com:P%40SSWORD@localhost:3128/" - os.environ["https_proxy"] = "http://john%40example.com:P%40SSWORD@localhost2:3128/" - self.assertEqual(get_proxy_info("echo.websocket.events", True), ("localhost2", 3128, ("john@example.com", "P@SSWORD"))) + os.environ[ + "http_proxy" + ] = "http://john%40example.com:P%40SSWORD@localhost:3128/" + os.environ[ + "https_proxy" + ] = "http://john%40example.com:P%40SSWORD@localhost2:3128/" + self.assertEqual( + get_proxy_info("echo.websocket.events", True), + ("localhost2", 3128, ("john@example.com", "P@SSWORD")), + ) os.environ["http_proxy"] = "http://a:b@localhost/" os.environ["https_proxy"] = "http://a:b@localhost2/" os.environ["no_proxy"] = "example1.com,example2.com" - self.assertEqual(get_proxy_info("example.1.com", True), ("localhost2", None, ("a", "b"))) + self.assertEqual( + get_proxy_info("example.1.com", True), ("localhost2", None, ("a", "b")) + ) os.environ["http_proxy"] = "http://a:b@localhost:3128/" os.environ["https_proxy"] = "http://a:b@localhost2:3128/" os.environ["no_proxy"] = "example1.com,example2.com, echo.websocket.events" diff --git a/lib/websocket/tests/test_websocket.py b/lib/websocket/tests/test_websocket.py index a140066e..498def57 100644 --- a/lib/websocket/tests/test_websocket.py +++ b/lib/websocket/tests/test_websocket.py @@ -3,13 +3,14 @@ import os import os.path import socket -import websocket as ws import unittest -from websocket._handshake import _create_sec_websocket_key, \ - _validate as _validate_header +from base64 import decodebytes as base64decode + +import websocket as ws +from websocket._handshake import _create_sec_websocket_key +from websocket._handshake import _validate as _validate_header from websocket._http import read_headers from websocket._utils import validate_utf8 -from base64 import decodebytes as base64decode """ test_websocket.py @@ -38,11 +39,12 @@ except ImportError: class SSLError(Exception): pass + # Skip test to access the internet unless TEST_WITH_INTERNET == 1 -TEST_WITH_INTERNET = os.environ.get('TEST_WITH_INTERNET', '0') == '1' +TEST_WITH_INTERNET = os.environ.get("TEST_WITH_INTERNET", "0") == "1" # Skip tests relying on local websockets server unless LOCAL_WS_SERVER_PORT != -1 -LOCAL_WS_SERVER_PORT = os.environ.get('LOCAL_WS_SERVER_PORT', '-1') -TEST_WITH_LOCAL_SERVER = LOCAL_WS_SERVER_PORT != '-1' +LOCAL_WS_SERVER_PORT = os.environ.get("LOCAL_WS_SERVER_PORT", "-1") +TEST_WITH_LOCAL_SERVER = LOCAL_WS_SERVER_PORT != "-1" TRACEABLE = True @@ -79,7 +81,6 @@ class SockMock: class HeaderSockMock(SockMock): - def __init__(self, fname): SockMock.__init__(self) path = os.path.join(os.path.dirname(__file__), fname) @@ -103,11 +104,10 @@ class WebSocketTest(unittest.TestCase): def testWSKey(self): key = _create_sec_websocket_key() self.assertTrue(key != 24) - self.assertTrue(str("¥n") not in key) + self.assertTrue("¥n" not in key) def testNonce(self): - """ WebSocket key should be a random 16-byte nonce. - """ + """WebSocket key should be a random 16-byte nonce.""" key = _create_sec_websocket_key() nonce = base64decode(key.encode("utf-8")) self.assertEqual(16, len(nonce)) @@ -117,7 +117,8 @@ class WebSocketTest(unittest.TestCase): required_header = { "upgrade": "websocket", "connection": "upgrade", - "sec-websocket-accept": "Kxep+hNu9n51529fGidYu7a3wO0="} + "sec-websocket-accept": "Kxep+hNu9n51529fGidYu7a3wO0=", + } self.assertEqual(_validate_header(required_header, key, None), (True, None)) header = required_header.copy() @@ -140,29 +141,39 @@ class WebSocketTest(unittest.TestCase): header = required_header.copy() header["sec-websocket-protocol"] = "sub1" - self.assertEqual(_validate_header(header, key, ["sub1", "sub2"]), (True, "sub1")) + self.assertEqual( + _validate_header(header, key, ["sub1", "sub2"]), (True, "sub1") + ) # This case will print out a logging error using the error() function, but that is expected self.assertEqual(_validate_header(header, key, ["sub2", "sub3"]), (False, None)) header = required_header.copy() header["sec-websocket-protocol"] = "sUb1" - self.assertEqual(_validate_header(header, key, ["Sub1", "suB2"]), (True, "sub1")) + self.assertEqual( + _validate_header(header, key, ["Sub1", "suB2"]), (True, "sub1") + ) header = required_header.copy() # This case will print out a logging error using the error() function, but that is expected self.assertEqual(_validate_header(header, key, ["Sub1", "suB2"]), (False, None)) def testReadHeader(self): - status, header, status_message = read_headers(HeaderSockMock("data/header01.txt")) + status, header, status_message = read_headers( + HeaderSockMock("data/header01.txt") + ) self.assertEqual(status, 101) self.assertEqual(header["connection"], "Upgrade") - status, header, status_message = read_headers(HeaderSockMock("data/header03.txt")) + status, header, status_message = read_headers( + HeaderSockMock("data/header03.txt") + ) self.assertEqual(status, 101) self.assertEqual(header["connection"], "Upgrade, Keep-Alive") HeaderSockMock("data/header02.txt") - self.assertRaises(ws.WebSocketException, read_headers, HeaderSockMock("data/header02.txt")) + self.assertRaises( + ws.WebSocketException, read_headers, HeaderSockMock("data/header02.txt") + ) def testSend(self): # TODO: add longer frame data @@ -170,33 +181,38 @@ class WebSocketTest(unittest.TestCase): sock.set_mask_key(create_mask_key) s = sock.sock = HeaderSockMock("data/header01.txt") sock.send("Hello") - self.assertEqual(s.sent[0], b'\x81\x85abcd)\x07\x0f\x08\x0e') + self.assertEqual(s.sent[0], b"\x81\x85abcd)\x07\x0f\x08\x0e") sock.send("こんにちは") - self.assertEqual(s.sent[1], b'\x81\x8fabcd\x82\xe3\xf0\x87\xe3\xf1\x80\xe5\xca\x81\xe2\xc5\x82\xe3\xcc') + self.assertEqual( + s.sent[1], + b"\x81\x8fabcd\x82\xe3\xf0\x87\xe3\xf1\x80\xe5\xca\x81\xe2\xc5\x82\xe3\xcc", + ) -# sock.send("x" * 5000) -# self.assertEqual(s.sent[1], b'\x81\x8fabcd\x82\xe3\xf0\x87\xe3\xf1\x80\xe5\xca\x81\xe2\xc5\x82\xe3\xcc") + # sock.send("x" * 5000) + # self.assertEqual(s.sent[1], b'\x81\x8fabcd\x82\xe3\xf0\x87\xe3\xf1\x80\xe5\xca\x81\xe2\xc5\x82\xe3\xcc") - self.assertEqual(sock.send_binary(b'1111111111101'), 19) + self.assertEqual(sock.send_binary(b"1111111111101"), 19) def testRecv(self): # TODO: add longer frame data sock = ws.WebSocket() s = sock.sock = SockMock() - something = b'\x81\x8fabcd\x82\xe3\xf0\x87\xe3\xf1\x80\xe5\xca\x81\xe2\xc5\x82\xe3\xcc' + something = ( + b"\x81\x8fabcd\x82\xe3\xf0\x87\xe3\xf1\x80\xe5\xca\x81\xe2\xc5\x82\xe3\xcc" + ) s.add_packet(something) data = sock.recv() self.assertEqual(data, "こんにちは") - s.add_packet(b'\x81\x85abcd)\x07\x0f\x08\x0e') + s.add_packet(b"\x81\x85abcd)\x07\x0f\x08\x0e") data = sock.recv() self.assertEqual(data, "Hello") @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") def testIter(self): count = 2 - s = ws.create_connection('wss://api.bitfinex.com/ws/2') + s = ws.create_connection("wss://api.bitfinex.com/ws/2") s.send('{"event": "subscribe", "channel": "ticker"}') for _ in s: count -= 1 @@ -205,34 +221,34 @@ class WebSocketTest(unittest.TestCase): @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") def testNext(self): - sock = ws.create_connection('wss://api.bitfinex.com/ws/2') + sock = ws.create_connection("wss://api.bitfinex.com/ws/2") self.assertEqual(str, type(next(sock))) def testInternalRecvStrict(self): sock = ws.WebSocket() s = sock.sock = SockMock() - s.add_packet(b'foo') + s.add_packet(b"foo") s.add_packet(socket.timeout()) - s.add_packet(b'bar') + s.add_packet(b"bar") # s.add_packet(SSLError("The read operation timed out")) - s.add_packet(b'baz') + s.add_packet(b"baz") with self.assertRaises(ws.WebSocketTimeoutException): sock.frame_buffer.recv_strict(9) # with self.assertRaises(SSLError): # data = sock._recv_strict(9) data = sock.frame_buffer.recv_strict(9) - self.assertEqual(data, b'foobarbaz') + self.assertEqual(data, b"foobarbaz") with self.assertRaises(ws.WebSocketConnectionClosedException): sock.frame_buffer.recv_strict(1) def testRecvTimeout(self): sock = ws.WebSocket() s = sock.sock = SockMock() - s.add_packet(b'\x81') + s.add_packet(b"\x81") s.add_packet(socket.timeout()) - s.add_packet(b'\x8dabcd\x29\x07\x0f\x08\x0e') + s.add_packet(b"\x8dabcd\x29\x07\x0f\x08\x0e") s.add_packet(socket.timeout()) - s.add_packet(b'\x4e\x43\x33\x0e\x10\x0f\x00\x40') + s.add_packet(b"\x4e\x43\x33\x0e\x10\x0f\x00\x40") with self.assertRaises(ws.WebSocketTimeoutException): sock.recv() with self.assertRaises(ws.WebSocketTimeoutException): @@ -246,9 +262,9 @@ class WebSocketTest(unittest.TestCase): sock = ws.WebSocket() s = sock.sock = SockMock() # OPCODE=TEXT, FIN=0, MSG="Brevity is " - s.add_packet(b'\x01\x8babcd#\x10\x06\x12\x08\x16\x1aD\x08\x11C') + s.add_packet(b"\x01\x8babcd#\x10\x06\x12\x08\x16\x1aD\x08\x11C") # OPCODE=CONT, FIN=1, MSG="the soul of wit" - s.add_packet(b'\x80\x8fabcd\x15\n\x06D\x12\r\x16\x08A\r\x05D\x16\x0b\x17') + s.add_packet(b"\x80\x8fabcd\x15\n\x06D\x12\r\x16\x08A\r\x05D\x16\x0b\x17") data = sock.recv() self.assertEqual(data, "Brevity is the soul of wit") with self.assertRaises(ws.WebSocketConnectionClosedException): @@ -258,21 +274,21 @@ class WebSocketTest(unittest.TestCase): sock = ws.WebSocket(fire_cont_frame=True) s = sock.sock = SockMock() # OPCODE=TEXT, FIN=0, MSG="Brevity is " - s.add_packet(b'\x01\x8babcd#\x10\x06\x12\x08\x16\x1aD\x08\x11C') + s.add_packet(b"\x01\x8babcd#\x10\x06\x12\x08\x16\x1aD\x08\x11C") # OPCODE=CONT, FIN=0, MSG="Brevity is " - s.add_packet(b'\x00\x8babcd#\x10\x06\x12\x08\x16\x1aD\x08\x11C') + s.add_packet(b"\x00\x8babcd#\x10\x06\x12\x08\x16\x1aD\x08\x11C") # OPCODE=CONT, FIN=1, MSG="the soul of wit" - s.add_packet(b'\x80\x8fabcd\x15\n\x06D\x12\r\x16\x08A\r\x05D\x16\x0b\x17') + s.add_packet(b"\x80\x8fabcd\x15\n\x06D\x12\r\x16\x08A\r\x05D\x16\x0b\x17") _, data = sock.recv_data() - self.assertEqual(data, b'Brevity is ') + self.assertEqual(data, b"Brevity is ") _, data = sock.recv_data() - self.assertEqual(data, b'Brevity is ') + self.assertEqual(data, b"Brevity is ") _, data = sock.recv_data() - self.assertEqual(data, b'the soul of wit') + self.assertEqual(data, b"the soul of wit") # OPCODE=CONT, FIN=0, MSG="Brevity is " - s.add_packet(b'\x80\x8babcd#\x10\x06\x12\x08\x16\x1aD\x08\x11C') + s.add_packet(b"\x80\x8babcd#\x10\x06\x12\x08\x16\x1aD\x08\x11C") with self.assertRaises(ws.WebSocketException): sock.recv_data() @@ -288,7 +304,7 @@ class WebSocketTest(unittest.TestCase): sock = ws.WebSocket() s = sock.sock = SockMock() sock.connected = True - s.add_packet(b'\x88\x80\x17\x98p\x84') + s.add_packet(b"\x88\x80\x17\x98p\x84") sock.recv() self.assertEqual(sock.connected, False) @@ -296,22 +312,22 @@ class WebSocketTest(unittest.TestCase): sock = ws.WebSocket() s = sock.sock = SockMock() # OPCODE=CONT, FIN=1, MSG="the soul of wit" - s.add_packet(b'\x80\x8fabcd\x15\n\x06D\x12\r\x16\x08A\r\x05D\x16\x0b\x17') + s.add_packet(b"\x80\x8fabcd\x15\n\x06D\x12\r\x16\x08A\r\x05D\x16\x0b\x17") self.assertRaises(ws.WebSocketException, sock.recv) def testRecvWithProlongedFragmentation(self): sock = ws.WebSocket() s = sock.sock = SockMock() # OPCODE=TEXT, FIN=0, MSG="Once more unto the breach, " - s.add_packet(b'\x01\x9babcd.\x0c\x00\x01A\x0f\x0c\x16\x04B\x16\n\x15\rC\x10\t\x07C\x06\x13\x07\x02\x07\tNC') + s.add_packet( + b"\x01\x9babcd.\x0c\x00\x01A\x0f\x0c\x16\x04B\x16\n\x15\rC\x10\t\x07C\x06\x13\x07\x02\x07\tNC" + ) # OPCODE=CONT, FIN=0, MSG="dear friends, " - s.add_packet(b'\x00\x8eabcd\x05\x07\x02\x16A\x04\x11\r\x04\x0c\x07\x17MB') + s.add_packet(b"\x00\x8eabcd\x05\x07\x02\x16A\x04\x11\r\x04\x0c\x07\x17MB") # OPCODE=CONT, FIN=1, MSG="once more" - s.add_packet(b'\x80\x89abcd\x0e\x0c\x00\x01A\x0f\x0c\x16\x04') + s.add_packet(b"\x80\x89abcd\x0e\x0c\x00\x01A\x0f\x0c\x16\x04") data = sock.recv() - self.assertEqual( - data, - "Once more unto the breach, dear friends, once more") + self.assertEqual(data, "Once more unto the breach, dear friends, once more") with self.assertRaises(ws.WebSocketConnectionClosedException): sock.recv() @@ -320,22 +336,24 @@ class WebSocketTest(unittest.TestCase): sock.set_mask_key(create_mask_key) s = sock.sock = SockMock() # OPCODE=TEXT, FIN=0, MSG="Too much " - s.add_packet(b'\x01\x89abcd5\r\x0cD\x0c\x17\x00\x0cA') + s.add_packet(b"\x01\x89abcd5\r\x0cD\x0c\x17\x00\x0cA") # OPCODE=PING, FIN=1, MSG="Please PONG this" - s.add_packet(b'\x89\x90abcd1\x0e\x06\x05\x12\x07C4.,$D\x15\n\n\x17') + s.add_packet(b"\x89\x90abcd1\x0e\x06\x05\x12\x07C4.,$D\x15\n\n\x17") # OPCODE=CONT, FIN=1, MSG="of a good thing" - s.add_packet(b'\x80\x8fabcd\x0e\x04C\x05A\x05\x0c\x0b\x05B\x17\x0c\x08\x0c\x04') + s.add_packet(b"\x80\x8fabcd\x0e\x04C\x05A\x05\x0c\x0b\x05B\x17\x0c\x08\x0c\x04") data = sock.recv() self.assertEqual(data, "Too much of a good thing") with self.assertRaises(ws.WebSocketConnectionClosedException): sock.recv() self.assertEqual( - s.sent[0], - b'\x8a\x90abcd1\x0e\x06\x05\x12\x07C4.,$D\x15\n\n\x17') + s.sent[0], b"\x8a\x90abcd1\x0e\x06\x05\x12\x07C4.,$D\x15\n\n\x17" + ) - @unittest.skipUnless(TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled") + @unittest.skipUnless( + TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled" + ) def testWebSocket(self): - s = ws.create_connection("ws://127.0.0.1:" + LOCAL_WS_SERVER_PORT) + s = ws.create_connection(f"ws://127.0.0.1:{LOCAL_WS_SERVER_PORT}") self.assertNotEqual(s, None) s.send("Hello, World") result = s.next() @@ -348,9 +366,11 @@ class WebSocketTest(unittest.TestCase): self.assertRaises(ValueError, s.send_close, -1, "") s.close() - @unittest.skipUnless(TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled") + @unittest.skipUnless( + TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled" + ) def testPingPong(self): - s = ws.create_connection("ws://127.0.0.1:" + LOCAL_WS_SERVER_PORT) + s = ws.create_connection(f"ws://127.0.0.1:{LOCAL_WS_SERVER_PORT}") self.assertNotEqual(s, None) s.ping("Hello") s.pong("Hi") @@ -359,12 +379,15 @@ class WebSocketTest(unittest.TestCase): @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") def testSupportRedirect(self): s = ws.WebSocket() - self.assertRaises(ws._exceptions.WebSocketBadStatusException, s.connect, "ws://google.com/") + self.assertRaises( + ws._exceptions.WebSocketBadStatusException, s.connect, "ws://google.com/" + ) # Need to find a URL that has a redirect code leading to a websocket @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") def testSecureWebSocket(self): import ssl + s = ws.create_connection("wss://api.bitfinex.com/ws/2") self.assertNotEqual(s, None) self.assertTrue(isinstance(s.sock, ssl.SSLSocket)) @@ -375,10 +398,14 @@ class WebSocketTest(unittest.TestCase): self.assertEqual(s.getsubprotocol(), None) s.abort() - @unittest.skipUnless(TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled") + @unittest.skipUnless( + TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled" + ) def testWebSocketWithCustomHeader(self): - s = ws.create_connection("ws://127.0.0.1:" + LOCAL_WS_SERVER_PORT, - headers={"User-Agent": "PythonWebsocketClient"}) + s = ws.create_connection( + f"ws://127.0.0.1:{LOCAL_WS_SERVER_PORT}", + headers={"User-Agent": "PythonWebsocketClient"}, + ) self.assertNotEqual(s, None) self.assertEqual(s.getsubprotocol(), None) s.send("Hello, World") @@ -387,9 +414,11 @@ class WebSocketTest(unittest.TestCase): self.assertRaises(ValueError, s.close, -1, "") s.close() - @unittest.skipUnless(TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled") + @unittest.skipUnless( + TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled" + ) def testAfterClose(self): - s = ws.create_connection("ws://127.0.0.1:" + LOCAL_WS_SERVER_PORT) + s = ws.create_connection(f"ws://127.0.0.1:{LOCAL_WS_SERVER_PORT}") self.assertNotEqual(s, None) s.close() self.assertRaises(ws.WebSocketConnectionClosedException, s.send, "Hello") @@ -397,48 +426,69 @@ class WebSocketTest(unittest.TestCase): class SockOptTest(unittest.TestCase): - @unittest.skipUnless(TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled") + @unittest.skipUnless( + TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled" + ) def testSockOpt(self): sockopt = ((socket.IPPROTO_TCP, socket.TCP_NODELAY, 1),) - s = ws.create_connection("ws://127.0.0.1:" + LOCAL_WS_SERVER_PORT, sockopt=sockopt) - self.assertNotEqual(s.sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY), 0) + s = ws.create_connection( + f"ws://127.0.0.1:{LOCAL_WS_SERVER_PORT}", sockopt=sockopt + ) + self.assertNotEqual( + s.sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY), 0 + ) s.close() class UtilsTest(unittest.TestCase): def testUtf8Validator(self): - state = validate_utf8(b'\xf0\x90\x80\x80') + state = validate_utf8(b"\xf0\x90\x80\x80") self.assertEqual(state, True) - state = validate_utf8(b'\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5\xed\xa0\x80edited') + state = validate_utf8( + b"\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5\xed\xa0\x80edited" + ) self.assertEqual(state, False) - state = validate_utf8(b'') + state = validate_utf8(b"") self.assertEqual(state, True) class HandshakeTest(unittest.TestCase): @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") def test_http_SSL(self): - websock1 = ws.WebSocket(sslopt={"cert_chain": ssl.get_default_verify_paths().capath}, enable_multithread=False) - self.assertRaises(ValueError, - websock1.connect, "wss://api.bitfinex.com/ws/2") + websock1 = ws.WebSocket( + sslopt={"cert_chain": ssl.get_default_verify_paths().capath}, + enable_multithread=False, + ) + self.assertRaises(ValueError, websock1.connect, "wss://api.bitfinex.com/ws/2") websock2 = ws.WebSocket(sslopt={"certfile": "myNonexistentCertFile"}) - self.assertRaises(FileNotFoundError, - websock2.connect, "wss://api.bitfinex.com/ws/2") + self.assertRaises( + FileNotFoundError, websock2.connect, "wss://api.bitfinex.com/ws/2" + ) @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") def testManualHeaders(self): - websock3 = ws.WebSocket(sslopt={"ca_certs": ssl.get_default_verify_paths().cafile, - "ca_cert_path": ssl.get_default_verify_paths().capath}) - self.assertRaises(ws._exceptions.WebSocketBadStatusException, - websock3.connect, "wss://api.bitfinex.com/ws/2", cookie="chocolate", - origin="testing_websockets.com", - host="echo.websocket.events/websocket-client-test", - subprotocols=["testproto"], - connection="Upgrade", - header={"CustomHeader1":"123", - "Cookie":"TestValue", - "Sec-WebSocket-Key":"k9kFAUWNAMmf5OEMfTlOEA==", - "Sec-WebSocket-Protocol":"newprotocol"}) + websock3 = ws.WebSocket( + sslopt={ + "ca_certs": ssl.get_default_verify_paths().cafile, + "ca_cert_path": ssl.get_default_verify_paths().capath, + } + ) + self.assertRaises( + ws._exceptions.WebSocketBadStatusException, + websock3.connect, + "wss://api.bitfinex.com/ws/2", + cookie="chocolate", + origin="testing_websockets.com", + host="echo.websocket.events/websocket-client-test", + subprotocols=["testproto"], + connection="Upgrade", + header={ + "CustomHeader1": "123", + "Cookie": "TestValue", + "Sec-WebSocket-Key": "k9kFAUWNAMmf5OEMfTlOEA==", + "Sec-WebSocket-Protocol": "newprotocol", + }, + ) def testIPv6(self): websock2 = ws.WebSocket() @@ -447,7 +497,9 @@ class HandshakeTest(unittest.TestCase): def testBadURLs(self): websock3 = ws.WebSocket() self.assertRaises(ValueError, websock3.connect, "ws//example.com") - self.assertRaises(ws.WebSocketAddressException, websock3.connect, "ws://example") + self.assertRaises( + ws.WebSocketAddressException, websock3.connect, "ws://example" + ) self.assertRaises(ValueError, websock3.connect, "example.com") diff --git a/requirements.txt b/requirements.txt index 8c8e91f3..bdf83410 100644 --- a/requirements.txt +++ b/requirements.txt @@ -47,7 +47,7 @@ tzdata==2023.3 tzlocal==5.0.1 urllib3<2 webencodings==0.5.1 -websocket-client==1.6.2 +websocket-client==1.7.0 xmltodict==0.13.0 zipp==3.16.2 From 52819f7da6ca8434ecc632f9b1a155bd690d9b81 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Mar 2024 15:22:05 -0700 Subject: [PATCH 08/13] Bump pytz from 2023.3 to 2024.1 (#2254) * Bump pytz from 2023.3 to 2024.1 Bumps [pytz](https://github.com/stub42/pytz) from 2023.3 to 2024.1. - [Release notes](https://github.com/stub42/pytz/releases) - [Commits](https://github.com/stub42/pytz/compare/release_2023.3...release_2024.1) --- updated-dependencies: - dependency-name: pytz dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Update pytz==2024.1 --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> [skip ci] --- lib/pytz/__init__.py | 4 +- lib/pytz/tzinfo.py | 11 +- lib/pytz/zoneinfo/America/Godthab | Bin 1903 -> 1889 bytes lib/pytz/zoneinfo/America/Miquelon | Bin 1652 -> 1652 bytes lib/pytz/zoneinfo/America/Montreal | Bin 3494 -> 3494 bytes lib/pytz/zoneinfo/America/Nassau | Bin 3494 -> 3494 bytes lib/pytz/zoneinfo/America/Nipigon | Bin 3494 -> 3494 bytes lib/pytz/zoneinfo/America/Nuuk | Bin 1903 -> 1889 bytes lib/pytz/zoneinfo/America/Scoresbysund | Bin 1902 -> 1935 bytes lib/pytz/zoneinfo/America/Thunder_Bay | Bin 3494 -> 3494 bytes lib/pytz/zoneinfo/America/Toronto | Bin 3494 -> 3494 bytes lib/pytz/zoneinfo/Antarctica/Casey | Bin 370 -> 423 bytes lib/pytz/zoneinfo/Antarctica/Vostok | Bin 151 -> 213 bytes lib/pytz/zoneinfo/Asia/Almaty | Bin 983 -> 983 bytes lib/pytz/zoneinfo/Asia/Gaza | Bin 3808 -> 3844 bytes lib/pytz/zoneinfo/Asia/Hebron | Bin 3836 -> 3872 bytes lib/pytz/zoneinfo/Asia/Ho_Chi_Minh | Bin 337 -> 337 bytes lib/pytz/zoneinfo/Asia/Qostanay | Bin 997 -> 1025 bytes lib/pytz/zoneinfo/Asia/Saigon | Bin 337 -> 337 bytes lib/pytz/zoneinfo/Canada/Eastern | Bin 3494 -> 3494 bytes lib/pytz/zoneinfo/iso3166.tab | 17 +- lib/pytz/zoneinfo/leapseconds | 19 +- lib/pytz/zoneinfo/tzdata.zi | 3961 ++++++++++++------------ lib/pytz/zoneinfo/zone.tab | 24 +- lib/pytz/zoneinfo/zone1970.tab | 29 +- lib/pytz/zoneinfo/zonenow.tab | 303 ++ requirements.txt | 2 +- 27 files changed, 2344 insertions(+), 2026 deletions(-) create mode 100644 lib/pytz/zoneinfo/zonenow.tab diff --git a/lib/pytz/__init__.py b/lib/pytz/__init__.py index 98b66553..2355f8b4 100644 --- a/lib/pytz/__init__.py +++ b/lib/pytz/__init__.py @@ -22,8 +22,8 @@ from pytz.tzfile import build_tzinfo # The IANA (nee Olson) database is updated several times a year. -OLSON_VERSION = '2023c' -VERSION = '2023.3' # pip compatible version number. +OLSON_VERSION = '2024a' +VERSION = '2024.1' # pip compatible version number. __version__ = VERSION OLSEN_VERSION = OLSON_VERSION # Old releases had this misspelling diff --git a/lib/pytz/tzinfo.py b/lib/pytz/tzinfo.py index 725978d5..49b5c3fe 100644 --- a/lib/pytz/tzinfo.py +++ b/lib/pytz/tzinfo.py @@ -24,7 +24,8 @@ def memorized_timedelta(seconds): _timedelta_cache[seconds] = delta return delta -_epoch = datetime.utcfromtimestamp(0) + +_epoch = datetime(1970, 1, 1, 0, 0) # datetime.utcfromtimestamp(0) _datetime_cache = {0: _epoch} @@ -33,12 +34,13 @@ def memorized_datetime(seconds): try: return _datetime_cache[seconds] except KeyError: - # NB. We can't just do datetime.utcfromtimestamp(seconds) as this - # fails with negative values under Windows (Bug #90096) + # NB. We can't just do datetime.fromtimestamp(seconds, tz=timezone.utc).replace(tzinfo=None) + # as this fails with negative values under Windows (Bug #90096) dt = _epoch + timedelta(seconds=seconds) _datetime_cache[seconds] = dt return dt + _ttinfo_cache = {} @@ -55,6 +57,7 @@ def memorized_ttinfo(*args): _ttinfo_cache[args] = ttinfo return ttinfo + _notime = memorized_timedelta(0) @@ -355,7 +358,7 @@ class DstTzInfo(BaseTzInfo): is_dst=False) + timedelta(hours=6) # If we get this far, we have multiple possible timezones - this - # is an ambiguous case occuring during the end-of-DST transition. + # is an ambiguous case occurring during the end-of-DST transition. # If told to be strict, raise an exception since we have an # ambiguous case diff --git a/lib/pytz/zoneinfo/America/Godthab b/lib/pytz/zoneinfo/America/Godthab index adb7934aadf5f45928ce67e82efa92ca92391703..29958cf12a9df7cf775e3337b4894e4cf4b82f58 100644 GIT binary patch delta 54 zcmaFQ_mFRbGGoa`l?=wo6Bv(A{>UaeiJfgS3%l3ky-Yxf%@3K*Fm2w-YRrg`$_4-+ CSrVE6 delta 70 zcmaFJ_nvQpGGpmRl?+CfRNHkECigHNXJnrIkWGB@2R63J1x(qDrJL_ConZpYZeGG_ N&WIxIG1-A#5de#87;FFl diff --git a/lib/pytz/zoneinfo/America/Miquelon b/lib/pytz/zoneinfo/America/Miquelon index 5eccd861071d4eccb76fe0d8f5195bd1a7f646b7..f780ea990ff22675b5cc4e4dbe2c8690ae4e41b4 100644 GIT binary patch delta 23 ccmeyu^Mz-EF7thHjg1DeOdxvm1g0m<0BZ>dYybcN delta 23 ccmeyu^Mz-EF7q~v6&np=nLzaB2~1Cz0dxlmTmS$7 diff --git a/lib/pytz/zoneinfo/America/Montreal b/lib/pytz/zoneinfo/America/Montreal index 6752c5b05285678b86aea170f0921fc5f5e57738..170137333f9f6dba10ac3ad7f32876aaf518c4fd 100644 GIT binary patch delta 82 zcmZ1`y-a$-FR^1Et|{z)aNTsphZ_tFAKVn}`f$s5Qo?2d#`UaP$3FZA0+2k22B`tj SAax)bq!vVj)xTuh%LV{v;5Kvs delta 82 zcmZ1`y-a$-FR@h@t|=@&aNV@$!VQMj12;wUF5EIMbJ#4vxSmyO)rJ2+0FnpMAT=Nw Rqz*)b)PiWR`j>2b*#PJ9Go%0j diff --git a/lib/pytz/zoneinfo/America/Nassau b/lib/pytz/zoneinfo/America/Nassau index 6752c5b05285678b86aea170f0921fc5f5e57738..170137333f9f6dba10ac3ad7f32876aaf518c4fd 100644 GIT binary patch delta 82 zcmZ1`y-a$-FR^1Et|{z)aNTsphZ_tFAKVn}`f$s5Qo?2d#`UaP$3FZA0+2k22B`tj SAax)bq!vVj)xTuh%LV{v;5Kvs delta 82 zcmZ1`y-a$-FR@h@t|=@&aNV@$!VQMj12;wUF5EIMbJ#4vxSmyO)rJ2+0FnpMAT=Nw Rqz*)b)PiWR`j>2b*#PJ9Go%0j diff --git a/lib/pytz/zoneinfo/America/Nipigon b/lib/pytz/zoneinfo/America/Nipigon index 6752c5b05285678b86aea170f0921fc5f5e57738..170137333f9f6dba10ac3ad7f32876aaf518c4fd 100644 GIT binary patch delta 82 zcmZ1`y-a$-FR^1Et|{z)aNTsphZ_tFAKVn}`f$s5Qo?2d#`UaP$3FZA0+2k22B`tj SAax)bq!vVj)xTuh%LV{v;5Kvs delta 82 zcmZ1`y-a$-FR@h@t|=@&aNV@$!VQMj12;wUF5EIMbJ#4vxSmyO)rJ2+0FnpMAT=Nw Rqz*)b)PiWR`j>2b*#PJ9Go%0j diff --git a/lib/pytz/zoneinfo/America/Nuuk b/lib/pytz/zoneinfo/America/Nuuk index adb7934aadf5f45928ce67e82efa92ca92391703..29958cf12a9df7cf775e3337b4894e4cf4b82f58 100644 GIT binary patch delta 54 zcmaFQ_mFRbGGoa`l?=wo6Bv(A{>UaeiJfgS3%l3ky-Yxf%@3K*Fm2w-YRrg`$_4-+ CSrVE6 delta 70 zcmaFJ_nvQpGGpmRl?+CfRNHkECigHNXJnrIkWGB@2R63J1x(qDrJL_ConZpYZeGG_ N&WIxIG1-A#5de#87;FFl diff --git a/lib/pytz/zoneinfo/America/Scoresbysund b/lib/pytz/zoneinfo/America/Scoresbysund index 286d13216eb3b14bf9fec1fceebf2fe731472d39..9bf411ef5ad5f81f3863223ea75117404d5d1421 100644 GIT binary patch delta 251 zcmaFI*UzsJ5|x=|%zyznfg&Ib0;NFAxlzNANrs&RH=NAIuEq2J|HluE9RL46e!##o z*??W#n2`}=0+3{6B-W~RKBOqyLr{im^XR2qQuWP8|YiIyw H8gKys5jrGH delta 204 zcmeC@f5)d05|x=|#DD?Vfg&Ib0;NFAzEQ)FY4QO!naN`8T5dkRAq=_(MnG)Hplx6P zlxGA2kXj&vfmkCqe`R82fthKC-%KtWpj~!`HbC3#bbO8VO!W-(4Rm}B4ZtizE&#Rx B8D#(f diff --git a/lib/pytz/zoneinfo/America/Thunder_Bay b/lib/pytz/zoneinfo/America/Thunder_Bay index 6752c5b05285678b86aea170f0921fc5f5e57738..170137333f9f6dba10ac3ad7f32876aaf518c4fd 100644 GIT binary patch delta 82 zcmZ1`y-a$-FR^1Et|{z)aNTsphZ_tFAKVn}`f$s5Qo?2d#`UaP$3FZA0+2k22B`tj SAax)bq!vVj)xTuh%LV{v;5Kvs delta 82 zcmZ1`y-a$-FR@h@t|=@&aNV@$!VQMj12;wUF5EIMbJ#4vxSmyO)rJ2+0FnpMAT=Nw Rqz*)b)PiWR`j>2b*#PJ9Go%0j diff --git a/lib/pytz/zoneinfo/America/Toronto b/lib/pytz/zoneinfo/America/Toronto index 6752c5b05285678b86aea170f0921fc5f5e57738..170137333f9f6dba10ac3ad7f32876aaf518c4fd 100644 GIT binary patch delta 82 zcmZ1`y-a$-FR^1Et|{z)aNTsphZ_tFAKVn}`f$s5Qo?2d#`UaP$3FZA0+2k22B`tj SAax)bq!vVj)xTuh%LV{v;5Kvs delta 82 zcmZ1`y-a$-FR@h@t|=@&aNV@$!VQMj12;wUF5EIMbJ#4vxSmyO)rJ2+0FnpMAT=Nw Rqz*)b)PiWR`j>2b*#PJ9Go%0j diff --git a/lib/pytz/zoneinfo/Antarctica/Casey b/lib/pytz/zoneinfo/Antarctica/Casey index 4b98133d7af497a840e2630bc72a02439c4d774f..586a7653ef20d04440bfcb6645454ef215a1bba4 100644 GIT binary patch literal 423 zcmWHE%1kq2zyK^j5fBCeK_CXPdH%_rY4Ezmrr_Ow>Vx0PIST&HXD38(SvN#2;TMSB zDdG^*E87q|&D9_-`6xqt#R8iIpX~vO5luEpIx_>3EmCY!I5sjcGBGkS12G(eYyg3R z29PDQHZX8N*t!M=4B7@34BCcAOP|lhz5BOM1wpDqCp-7(IC%)Xo@||WdjTXJ6#Jd E02EY6j{pDw delta 150 zcmZ3^{E2CTxF9P70|N+y01ptePSh~rVPs-tVg_OmoY*KK!@w|W0|SSyfdPZIfdzxM ep&>{$BZRFb;1VjD<0ZxOsY=Fku I>6&o?0LBIr)c^nh diff --git a/lib/pytz/zoneinfo/Asia/Almaty b/lib/pytz/zoneinfo/Asia/Almaty index 91c916a3a5d7949cc304532fe3fb2eac117ab2ef..855abbd6e3ee338c3d46bee7b592f3d645d2c273 100644 GIT binary patch delta 134 zcmcc4ew}@SG%qIu1egFR&WRcqSW+JxQ<(U}n2~X^Hlvw{k8cQrwt*=Sn**^KSncE* hMg>%Tn^!WXS+eYkYoCHe1rxa`{yT%PTM%U>4LIxC+xl2z4acv+hSfMCtBc*n zeqCM;Z1g&Z-Z*d=HnD8R#cS-voh1rpx!mnOLWh zlm!cIp1-+Z@%g37x{G;tt_}~`qVK`By(YLP!H?6RC$#|X^}U3?cf=3w^Y4WFqB14_ z$>TJzTdZ#6d^iQ`_fA0H?@Z@phcXPk%JJ4A4OWk0VW9IQJb2Lo50)a>;AA{54AmY) zKOCA54`(il&oMUK5d@DEY@r`nTYyJn)bOZI`sv1Q9T2w}8?&huVyM{I_9mynxN;sB zCK5M^Y{C>RdE5j~Uil191y8|K*+$7PQ#cKrr<-8s?mP6;Nhu0COczRj{+VN4@XSIT z`dOcL(H9t-P0N%9J7z4*bv=aVR<63~@I8E&BV8Q5t5pxXKI}@~$mP~Z|Fbe-*<+t@ HL$3J`1v@2F delta 1028 zcmXBST}V@57zgloT8UO>r1^mk$)N8nNet2`yO2VNB#gqOZuCOJEpHN`bINU++Wa_f zZfZw!8W9NLEDJPhrkkHjH=Rx+g|I|}lTefxcAoz^H}CU%{{Q#v;!LMrhiJxwDngQ~v8U{OJ7%Pp-)GlQ~u)W+;m( z3ksF3op4p!14%Bhs)BCC@4Df~d^KzgKZL$9J%?({D4LO1-_jzlUNj@Gi4KHo?%zXR zd(lXBR{JJRHYX2D8WiesZ=fJ3?`4Aih2p*_T&O>r3Y&tnU{g+(h6YoG9yTAi4x5)x z!3{}&(QmkYl&6Iy=nQhp&|c(LmM78gGi!=hS$vB_p|LB8r$wVL6mHsj9(mK?Cfr;X zj=Z_OMDg5r_{p>Zmecv1hcNvg4rV>{r1Eyc(OZFbxnoLGXL!70d{-b~n~ zjYsZ!u6zpDay0Ux?&HXZGhFa6m#la)8GUY~J`9Udbs-j`nQe-@BH^*3HF#`g9v)A) z#ON8XRX&CL<}TRn&}nFJOFi%>?Hu|OsXyTf>k-AyT%Hz_SNg~t^Tc|{%#&w9!6R;i zy(e2>@5U>5D(#$xhN*%gcsiyRo}O=jeIcE&FFl5*g>PMiXL^f~&n#Y*Xqb(1z_Wf{ e&gK7&zr)1S#^1An3;v}YPRfpZ~FO(`0+7)t%#?JXbQIq=Tq>+q!gmK)8kUJ)E|wu0>p(?*S|!7#05 zl!h{hIm4&#B(bMVUwud&{?MJNb$di-++Ajr?dQtR6r(Cwc@@+J)BBA009T?-Mqbc& zA}9blXBox7<_)7Wu)HcL3(}*YDi{tj>Voq&LEOX@+nyjV`0ip9F!6n5=R(KwKl$-3>G|J;^n%AC z^g&^9M|#n`EceA1i}aH9UV3TF|L@;np%2O_ttI*9Ko2ul?w-&CJdB`+g)9CldVp>f tJ;3&-pcq&=MGr7NhxdWe40?b*KYDv&(U3;hAsr%m2t@>eLpB7VwAqqDlY>N3Q$u(`Z77Q1jFFlj z&>}=Hhz5tWbO?u{EutkP$OmtXNb06$LvX|kLBLBHyQkpjbwN*ZeCI&UoxlKZkf}bLweZ9nei>KNj7qTI+0$ym$yQw85m|8pmdS%OV3XXK5~!1NFMx`Tv+e~zm3;ja7_#xj zs}s3DyI+(0bBT`3=UeZFdC7;1!nCk*Cv(v|By-7Ekh%18OZ#m4%<819SO2o|pPKq? zj=_D?A@f7muI$$fnw+aYwFGwToLw9PatCLLS%H2sm=_o!J({b f;2Rm+0ql^0QGs0H%vlBWlPw=;5oO+jrvvGK>WF^6 diff --git a/lib/pytz/zoneinfo/Asia/Ho_Chi_Minh b/lib/pytz/zoneinfo/Asia/Ho_Chi_Minh index a213d290e1a920271e924506a57191f1f4bfc4c0..9c45ed991a230919d129c63c660aa8d1ad74d0ea 100644 GIT binary patch delta 25 hcmcb}bdhO-8|$YDZ}n$PW@L1qI4Ozg(}aoNq5+R=3x5Cr delta 25 hcmcb}bdhO-8|#yXxB4?CGcvkQoRq}$q+#N>XaJ1b3qt?^ diff --git a/lib/pytz/zoneinfo/Asia/Qostanay b/lib/pytz/zoneinfo/Asia/Qostanay index f8baf676496adea298f078d6d5931ba7aa64e902..2ee9ef7e9859bc95da2450e3b282fd4275cbbb39 100644 GIT binary patch delta 113 zcmaFL-pDaQnwN(G0!)Au&qR$2EU6EUDNOcZHfCg+T+i&p#=zhfz`!y2AhR?h1G@6f Z8yM#>a)9*X)WpTWWut9iYNu<;1pxiI75@ML delta 78 zcmZqVc*;IOnwOga0*rwa_e6~glM|SYCmS$2O}@h{jV`@;591t0WCfgDHrfVecDiO< E0Bdg$5dZ)H diff --git a/lib/pytz/zoneinfo/Asia/Saigon b/lib/pytz/zoneinfo/Asia/Saigon index a213d290e1a920271e924506a57191f1f4bfc4c0..9c45ed991a230919d129c63c660aa8d1ad74d0ea 100644 GIT binary patch delta 25 hcmcb}bdhO-8|$YDZ}n$PW@L1qI4Ozg(}aoNq5+R=3x5Cr delta 25 hcmcb}bdhO-8|#yXxB4?CGcvkQoRq}$q+#N>XaJ1b3qt?^ diff --git a/lib/pytz/zoneinfo/Canada/Eastern b/lib/pytz/zoneinfo/Canada/Eastern index 6752c5b05285678b86aea170f0921fc5f5e57738..170137333f9f6dba10ac3ad7f32876aaf518c4fd 100644 GIT binary patch delta 82 zcmZ1`y-a$-FR^1Et|{z)aNTsphZ_tFAKVn}`f$s5Qo?2d#`UaP$3FZA0+2k22B`tj SAax)bq!vVj)xTuh%LV{v;5Kvs delta 82 zcmZ1`y-a$-FR@h@t|=@&aNV@$!VQMj12;wUF5EIMbJ#4vxSmyO)rJ2+0FnpMAT=Nw Rqz*)b)PiWR`j>2b*#PJ9Go%0j diff --git a/lib/pytz/zoneinfo/iso3166.tab b/lib/pytz/zoneinfo/iso3166.tab index be3348d1..402c015e 100644 --- a/lib/pytz/zoneinfo/iso3166.tab +++ b/lib/pytz/zoneinfo/iso3166.tab @@ -3,17 +3,22 @@ # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. # -# From Paul Eggert (2022-11-18): +# From Paul Eggert (2023-09-06): # This file contains a table of two-letter country codes. Columns are # separated by a single tab. Lines beginning with '#' are comments. # All text uses UTF-8 encoding. The columns of the table are as follows: # # 1. ISO 3166-1 alpha-2 country code, current as of -# ISO 3166-1 N1087 (2022-09-02). See: Updates on ISO 3166-1 -# https://isotc.iso.org/livelink/livelink/Open/16944257 -# 2. The usual English name for the coded region, -# chosen so that alphabetic sorting of subsets produces helpful lists. -# This is not the same as the English name in the ISO 3166 tables. +# ISO/TC 46 N1108 (2023-04-05). See: ISO/TC 46 Documents +# https://www.iso.org/committee/48750.html?view=documents +# 2. The usual English name for the coded region. This sometimes +# departs from ISO-listed names, sometimes so that sorted subsets +# of names are useful (e.g., "Samoa (American)" and "Samoa +# (western)" rather than "American Samoa" and "Samoa"), +# sometimes to avoid confusion among non-experts (e.g., +# "Czech Republic" and "Turkey" rather than "Czechia" and "Türkiye"), +# and sometimes to omit needless detail or churn (e.g., "Netherlands" +# rather than "Netherlands (the)" or "Netherlands (Kingdom of the)"). # # The table is sorted by country code. # diff --git a/lib/pytz/zoneinfo/leapseconds b/lib/pytz/zoneinfo/leapseconds index a6a170aa..ce150bfe 100644 --- a/lib/pytz/zoneinfo/leapseconds +++ b/lib/pytz/zoneinfo/leapseconds @@ -3,13 +3,10 @@ # This file is in the public domain. # This file is generated automatically from the data in the public-domain -# NIST format leap-seconds.list file, which can be copied from -# -# or . -# The NIST file is used instead of its IERS upstream counterpart +# NIST/IERS format leap-seconds.list file, which can be copied from # -# because under US law the NIST file is public domain -# whereas the IERS file's copyright and license status is unclear. +# or, in a variant with different comments, from +# . # For more about leap-seconds.list, please see # The NTP Timescale and Leap Seconds # . @@ -72,11 +69,11 @@ Leap 2016 Dec 31 23:59:60 + S # Any additional leap seconds will come after this. # This Expires line is commented out for now, # so that pre-2020a zic implementations do not reject this file. -#Expires 2023 Dec 28 00:00:00 +#Expires 2024 Dec 28 00:00:00 # POSIX timestamps for the data in this file: -#updated 1467936000 (2016-07-08 00:00:00 UTC) -#expires 1703721600 (2023-12-28 00:00:00 UTC) +#updated 1704708379 (2024-01-08 10:06:19 UTC) +#expires 1735344000 (2024-12-28 00:00:00 UTC) -# Updated through IERS Bulletin C65 -# File expires on: 28 December 2023 +# Updated through IERS Bulletin C (https://hpiers.obspm.fr/iers/bul/bulc/bulletinc.dat) +# File expires on 28 December 2024 diff --git a/lib/pytz/zoneinfo/tzdata.zi b/lib/pytz/zoneinfo/tzdata.zi index 23d99be4..b5a03be7 100644 --- a/lib/pytz/zoneinfo/tzdata.zi +++ b/lib/pytz/zoneinfo/tzdata.zi @@ -1,4 +1,4 @@ -# version unknown-dirty +# version unknown # This zic input file is in the public domain. R d 1916 o - Jun 14 23s 1 S R d 1916 1919 - O Su>=1 23s 0 - @@ -22,27 +22,6 @@ R d 1978 o - Mar 24 1 1 S R d 1978 o - S 22 3 0 - R d 1980 o - Ap 25 0 1 S R d 1980 o - O 31 2 0 - -Z Africa/Algiers 0:12:12 - LMT 1891 Mar 16 -0:9:21 - PMT 1911 Mar 11 -0 d WE%sT 1940 F 25 2 -1 d CE%sT 1946 O 7 -0 - WET 1956 Ja 29 -1 - CET 1963 Ap 14 -0 d WE%sT 1977 O 21 -1 d CE%sT 1979 O 26 -0 d WE%sT 1981 May -1 - CET -Z Atlantic/Cape_Verde -1:34:4 - LMT 1912 Ja 1 2u --2 - -02 1942 S --2 1 -01 1945 O 15 --2 - -02 1975 N 25 2 --1 - -01 -Z Africa/Ndjamena 1:0:12 - LMT 1912 -1 - WAT 1979 O 14 -1 1 WAST 1980 Mar 8 -1 - WAT -Z Africa/Abidjan -0:16:8 - LMT 1912 -0 - GMT R K 1940 o - Jul 15 0 1 S R K 1940 o - O 1 0 0 - R K 1941 o - Ap 15 0 1 S @@ -77,21 +56,6 @@ R K 2014 o - Jul 31 24 1 S R K 2014 o - S lastTh 24 0 - R K 2023 ma - Ap lastF 0 1 S R K 2023 ma - O lastTh 24 0 - -Z Africa/Cairo 2:5:9 - LMT 1900 O -2 K EE%sT -Z Africa/Bissau -1:2:20 - LMT 1912 Ja 1 1u --1 - -01 1975 -0 - GMT -Z Africa/Nairobi 2:27:16 - LMT 1908 May -2:30 - +0230 1928 Jun 30 24 -3 - EAT 1930 Ja 4 24 -2:30 - +0230 1936 D 31 24 -2:45 - +0245 1942 Jul 31 24 -3 - EAT -Z Africa/Monrovia -0:43:8 - LMT 1882 --0:43:8 - MMT 1919 Mar --0:44:30 - MMT 1972 Ja 7 -0 - GMT R L 1951 o - O 14 2 1 S R L 1952 o - Ja 1 0 0 - R L 1953 o - O 9 2 1 S @@ -109,21 +73,10 @@ R L 1997 o - Ap 4 0 1 S R L 1997 o - O 4 0 0 - R L 2013 o - Mar lastF 1 1 S R L 2013 o - O lastF 2 0 - -Z Africa/Tripoli 0:52:44 - LMT 1920 -1 L CE%sT 1959 -2 - EET 1982 -1 L CE%sT 1990 May 4 -2 - EET 1996 S 30 -1 L CE%sT 1997 O 4 -2 - EET 2012 N 10 2 -1 L CE%sT 2013 O 25 2 -2 - EET R MU 1982 o - O 10 0 1 - R MU 1983 o - Mar 21 0 0 - R MU 2008 o - O lastSu 2 1 - R MU 2009 o - Mar lastSu 2 0 - -Z Indian/Mauritius 3:50 - LMT 1907 -4 MU +04/+05 R M 1939 o - S 12 0 1 - R M 1939 o - N 19 0 0 - R M 1940 o - F 25 0 1 - @@ -307,53 +260,15 @@ R M 2086 o - Ap 14 3 -1 - R M 2086 o - May 19 2 0 - R M 2087 o - Mar 30 3 -1 - R M 2087 o - May 11 2 0 - -Z Africa/Casablanca -0:30:20 - LMT 1913 O 26 -0 M +00/+01 1984 Mar 16 -1 - +01 1986 -0 M +00/+01 2018 O 28 3 -1 M +01/+00 -Z Africa/El_Aaiun -0:52:48 - LMT 1934 --1 - -01 1976 Ap 14 -0 M +00/+01 2018 O 28 3 -1 M +01/+00 -Z Africa/Maputo 2:10:20 - LMT 1903 Mar -2 - CAT R NA 1994 o - Mar 21 0 -1 WAT R NA 1994 2017 - S Su>=1 2 0 CAT R NA 1995 2017 - Ap Su>=1 2 -1 WAT -Z Africa/Windhoek 1:8:24 - LMT 1892 F 8 -1:30 - +0130 1903 Mar -2 - SAST 1942 S 20 2 -2 1 SAST 1943 Mar 21 2 -2 - SAST 1990 Mar 21 -2 NA %s -Z Africa/Lagos 0:13:35 - LMT 1905 Jul -0 - GMT 1908 Jul -0:13:35 - LMT 1914 -0:30 - +0030 1919 S -1 - WAT -Z Africa/Sao_Tome 0:26:56 - LMT 1884 --0:36:45 - LMT 1912 Ja 1 0u -0 - GMT 2018 Ja 1 1 -1 - WAT 2019 Ja 1 2 -0 - GMT R SA 1942 1943 - S Su>=15 2 1 - R SA 1943 1944 - Mar Su>=15 2 0 - -Z Africa/Johannesburg 1:52 - LMT 1892 F 8 -1:30 - SAST 1903 Mar -2 SA SAST R SD 1970 o - May 1 0 1 S R SD 1970 1985 - O 15 0 0 - R SD 1971 o - Ap 30 0 1 S R SD 1972 1985 - Ap lastSu 0 1 S -Z Africa/Khartoum 2:10:8 - LMT 1931 -2 SD CA%sT 2000 Ja 15 12 -3 - EAT 2017 N -2 - CAT -Z Africa/Juba 2:6:28 - LMT 1931 -2 SD CA%sT 2000 Ja 15 12 -3 - EAT 2021 F -2 - CAT R n 1939 o - Ap 15 23s 1 S R n 1939 o - N 18 23s 0 - R n 1940 o - F 25 23s 1 S @@ -379,80 +294,14 @@ R n 2005 o - May 1 0s 1 S R n 2005 o - S 30 1s 0 - R n 2006 2008 - Mar lastSu 2s 1 S R n 2006 2008 - O lastSu 2s 0 - -Z Africa/Tunis 0:40:44 - LMT 1881 May 12 -0:9:21 - PMT 1911 Mar 11 -1 n CE%sT -Z Antarctica/Casey 0 - -00 1969 -8 - +08 2009 O 18 2 -11 - +11 2010 Mar 5 2 -8 - +08 2011 O 28 2 -11 - +11 2012 F 21 17u -8 - +08 2016 O 22 -11 - +11 2018 Mar 11 4 -8 - +08 2018 O 7 4 -11 - +11 2019 Mar 17 3 -8 - +08 2019 O 4 3 -11 - +11 2020 Mar 8 3 -8 - +08 2020 O 4 0:1 -11 - +11 -Z Antarctica/Davis 0 - -00 1957 Ja 13 -7 - +07 1964 N -0 - -00 1969 F -7 - +07 2009 O 18 2 -5 - +05 2010 Mar 10 20u -7 - +07 2011 O 28 2 -5 - +05 2012 F 21 20u -7 - +07 -Z Antarctica/Mawson 0 - -00 1954 F 13 -6 - +06 2009 O 18 2 -5 - +05 R Tr 2005 ma - Mar lastSu 1u 2 +02 R Tr 2004 ma - O lastSu 1u 0 +00 -Z Antarctica/Troll 0 - -00 2005 F 12 -0 Tr %s -Z Antarctica/Rothera 0 - -00 1976 D --3 - -03 -Z Asia/Kabul 4:36:48 - LMT 1890 -4 - +04 1945 -4:30 - +0430 R AM 2011 o - Mar lastSu 2s 1 - R AM 2011 o - O lastSu 2s 0 - -Z Asia/Yerevan 2:58 - LMT 1924 May 2 -3 - +03 1957 Mar -4 R +04/+05 1991 Mar 31 2s -3 R +03/+04 1995 S 24 2s -4 - +04 1997 -4 R +04/+05 2011 -4 AM +04/+05 R AZ 1997 2015 - Mar lastSu 4 1 - R AZ 1997 2015 - O lastSu 5 0 - -Z Asia/Baku 3:19:24 - LMT 1924 May 2 -3 - +03 1957 Mar -4 R +04/+05 1991 Mar 31 2s -3 R +03/+04 1992 S lastSu 2s -4 - +04 1996 -4 E +04/+05 1997 -4 AZ +04/+05 R BD 2009 o - Jun 19 23 1 - R BD 2009 o - D 31 24 0 - -Z Asia/Dhaka 6:1:40 - LMT 1890 -5:53:20 - HMT 1941 O -6:30 - +0630 1942 May 15 -5:30 - +0530 1942 S -6:30 - +0630 1951 S 30 -6 - +06 2009 -6 BD +06/+07 -Z Asia/Thimphu 5:58:36 - LMT 1947 Au 15 -5:30 - +0530 1987 O -6 - +06 -Z Indian/Chagos 4:49:40 - LMT 1907 -5 - +05 1996 -6 - +06 -Z Asia/Yangon 6:24:47 - LMT 1880 -6:24:47 - RMT 1920 -6:30 - +0630 1942 May -9 - +09 1945 May 3 -6:30 - +0630 R Sh 1919 o - Ap 12 24 1 D R Sh 1919 o - S 30 24 0 S R Sh 1940 o - Jun 1 0 1 D @@ -470,11 +319,6 @@ R Sh 1948 1949 - S 30 24 0 S R CN 1986 o - May 4 2 1 D R CN 1986 1991 - S Su>=11 2 0 S R CN 1987 1991 - Ap Su>=11 2 1 D -Z Asia/Shanghai 8:5:43 - LMT 1901 -8 Sh C%sT 1949 May 28 -8 CN C%sT -Z Asia/Urumqi 5:50:20 - LMT 1928 -6 - +06 R HK 1946 o - Ap 21 0 1 S R HK 1946 o - D 1 3:30s 0 - R HK 1947 o - Ap 13 3:30s 1 S @@ -489,12 +333,6 @@ R HK 1965 1976 - O Su>=16 3:30 0 - R HK 1973 o - D 30 3:30 1 S R HK 1979 o - May 13 3:30 1 S R HK 1979 o - O 21 3:30 0 - -Z Asia/Hong_Kong 7:36:42 - LMT 1904 O 29 17u -8 - HKT 1941 Jun 15 3 -8 1 HKST 1941 O 1 4 -8 0:30 HKWT 1941 D 25 -9 - JST 1945 N 18 2 -8 HK HK%sT R f 1946 o - May 15 0 1 D R f 1946 o - O 1 0 0 S R f 1947 o - Ap 15 0 1 D @@ -510,10 +348,6 @@ R f 1974 1975 - Ap 1 0 1 D R f 1974 1975 - O 1 0 0 S R f 1979 o - Jul 1 0 1 D R f 1979 o - O 1 0 0 S -Z Asia/Taipei 8:6 - LMT 1896 -8 - CST 1937 O -9 - JST 1945 S 21 1 -8 f C%sT R _ 1942 1943 - Ap 30 23 1 - R _ 1942 o - N 17 23 0 - R _ 1943 o - S 30 23 0 S @@ -541,10 +375,6 @@ R _ 1973 o - D 30 3:30 1 D R _ 1975 1976 - Ap Su>=16 3:30 1 D R _ 1979 o - May 13 3:30 1 D R _ 1979 o - O Su>=16 3:30 0 S -Z Asia/Macau 7:34:10 - LMT 1904 O 30 -8 - CST 1941 D 21 23 -9 _ +09/+10 1945 S 30 24 -8 _ C%sT R CY 1975 o - Ap 13 0 1 S R CY 1975 o - O 12 0 0 - R CY 1976 o - May 15 0 1 S @@ -554,65 +384,6 @@ R CY 1977 o - S 25 0 0 - R CY 1978 o - O 2 0 0 - R CY 1979 1997 - S lastSu 0 0 - R CY 1981 1998 - Mar lastSu 0 1 S -Z Asia/Nicosia 2:13:28 - LMT 1921 N 14 -2 CY EE%sT 1998 S -2 E EE%sT -Z Asia/Famagusta 2:15:48 - LMT 1921 N 14 -2 CY EE%sT 1998 S -2 E EE%sT 2016 S 8 -3 - +03 2017 O 29 1u -2 E EE%sT -Z Asia/Tbilisi 2:59:11 - LMT 1880 -2:59:11 - TBMT 1924 May 2 -3 - +03 1957 Mar -4 R +04/+05 1991 Mar 31 2s -3 R +03/+04 1992 -3 e +03/+04 1994 S lastSu -4 e +04/+05 1996 O lastSu -4 1 +05 1997 Mar lastSu -4 e +04/+05 2004 Jun 27 -3 R +03/+04 2005 Mar lastSu 2 -4 - +04 -Z Asia/Dili 8:22:20 - LMT 1912 -8 - +08 1942 F 21 23 -9 - +09 1976 May 3 -8 - +08 2000 S 17 -9 - +09 -Z Asia/Kolkata 5:53:28 - LMT 1854 Jun 28 -5:53:20 - HMT 1870 -5:21:10 - MMT 1906 -5:30 - IST 1941 O -5:30 1 +0630 1942 May 15 -5:30 - IST 1942 S -5:30 1 +0630 1945 O 15 -5:30 - IST -Z Asia/Jakarta 7:7:12 - LMT 1867 Au 10 -7:7:12 - BMT 1923 D 31 16:40u -7:20 - +0720 1932 N -7:30 - +0730 1942 Mar 23 -9 - +09 1945 S 23 -7:30 - +0730 1948 May -8 - +08 1950 May -7:30 - +0730 1964 -7 - WIB -Z Asia/Pontianak 7:17:20 - LMT 1908 May -7:17:20 - PMT 1932 N -7:30 - +0730 1942 Ja 29 -9 - +09 1945 S 23 -7:30 - +0730 1948 May -8 - +08 1950 May -7:30 - +0730 1964 -8 - WITA 1988 -7 - WIB -Z Asia/Makassar 7:57:36 - LMT 1920 -7:57:36 - MMT 1932 N -8 - +08 1942 F 9 -9 - +09 1945 S 23 -8 - WITA -Z Asia/Jayapura 9:22:48 - LMT 1932 N -9 - +09 1944 S -9:30 - +0930 1964 -9 - WIT R i 1910 o - Ja 1 0 0 - R i 1977 o - Mar 21 23 1 - R i 1977 o - O 20 24 0 - @@ -653,11 +424,6 @@ R i 2020 o - Mar 20 24 1 - R i 2020 o - S 20 24 0 - R i 2021 2022 - Mar 21 24 1 - R i 2021 2022 - S 21 24 0 - -Z Asia/Tehran 3:25:44 - LMT 1916 -3:25:44 - TMT 1935 Jun 13 -3:30 i +0330/+0430 1977 O 20 24 -4 i +04/+05 1979 -3:30 i +0330/+0430 R IQ 1982 o - May 1 0 1 - R IQ 1982 1984 - O 1 0 0 - R IQ 1983 o - Mar 31 0 1 - @@ -666,10 +432,6 @@ R IQ 1985 1990 - S lastSu 1s 0 - R IQ 1986 1990 - Mar lastSu 1s 1 - R IQ 1991 2007 - Ap 1 3s 1 - R IQ 1991 2007 - O 1 3s 0 - -Z Asia/Baghdad 2:57:40 - LMT 1890 -2:57:36 - BMT 1918 -3 - +03 1982 May -3 IQ +03/+04 R Z 1940 o - May 31 24u 1 D R Z 1940 o - S 30 24u 0 S R Z 1940 o - N 16 24u 1 D @@ -755,15 +517,10 @@ R Z 2011 o - O 2 2 0 S R Z 2012 o - S 23 2 0 S R Z 2013 ma - Mar F>=23 2 1 D R Z 2013 ma - O lastSu 2 0 S -Z Asia/Jerusalem 2:20:54 - LMT 1880 -2:20:40 - JMT 1918 -2 Z I%sT R JP 1948 o - May Sa>=1 24 1 D R JP 1948 1951 - S Sa>=8 25 0 S R JP 1949 o - Ap Sa>=1 24 1 D R JP 1950 1951 - May Sa>=1 24 1 D -Z Asia/Tokyo 9:18:59 - LMT 1887 D 31 15u -9 JP J%sT R J 1973 o - Jun 6 0 1 S R J 1973 1975 - O 1 0 0 - R J 1974 1977 - May 1 0 1 S @@ -796,83 +553,10 @@ R J 2013 o - D 20 0 0 - R J 2014 2021 - Mar lastTh 24 1 S R J 2014 2022 - O lastF 0s 0 - R J 2022 o - F lastTh 24 1 S -Z Asia/Amman 2:23:44 - LMT 1931 -2 J EE%sT 2022 O 28 0s -3 - +03 -Z Asia/Almaty 5:7:48 - LMT 1924 May 2 -5 - +05 1930 Jun 21 -6 R +06/+07 1991 Mar 31 2s -5 R +05/+06 1992 Ja 19 2s -6 R +06/+07 2004 O 31 2s -6 - +06 -Z Asia/Qyzylorda 4:21:52 - LMT 1924 May 2 -4 - +04 1930 Jun 21 -5 - +05 1981 Ap -5 1 +06 1981 O -6 - +06 1982 Ap -5 R +05/+06 1991 Mar 31 2s -4 R +04/+05 1991 S 29 2s -5 R +05/+06 1992 Ja 19 2s -6 R +06/+07 1992 Mar 29 2s -5 R +05/+06 2004 O 31 2s -6 - +06 2018 D 21 -5 - +05 -Z Asia/Qostanay 4:14:28 - LMT 1924 May 2 -4 - +04 1930 Jun 21 -5 - +05 1981 Ap -5 1 +06 1981 O -6 - +06 1982 Ap -5 R +05/+06 1991 Mar 31 2s -4 R +04/+05 1992 Ja 19 2s -5 R +05/+06 2004 O 31 2s -6 - +06 -Z Asia/Aqtobe 3:48:40 - LMT 1924 May 2 -4 - +04 1930 Jun 21 -5 - +05 1981 Ap -5 1 +06 1981 O -6 - +06 1982 Ap -5 R +05/+06 1991 Mar 31 2s -4 R +04/+05 1992 Ja 19 2s -5 R +05/+06 2004 O 31 2s -5 - +05 -Z Asia/Aqtau 3:21:4 - LMT 1924 May 2 -4 - +04 1930 Jun 21 -5 - +05 1981 O -6 - +06 1982 Ap -5 R +05/+06 1991 Mar 31 2s -4 R +04/+05 1992 Ja 19 2s -5 R +05/+06 1994 S 25 2s -4 R +04/+05 2004 O 31 2s -5 - +05 -Z Asia/Atyrau 3:27:44 - LMT 1924 May 2 -3 - +03 1930 Jun 21 -5 - +05 1981 O -6 - +06 1982 Ap -5 R +05/+06 1991 Mar 31 2s -4 R +04/+05 1992 Ja 19 2s -5 R +05/+06 1999 Mar 28 2s -4 R +04/+05 2004 O 31 2s -5 - +05 -Z Asia/Oral 3:25:24 - LMT 1924 May 2 -3 - +03 1930 Jun 21 -5 - +05 1981 Ap -5 1 +06 1981 O -6 - +06 1982 Ap -5 R +05/+06 1989 Mar 26 2s -4 R +04/+05 1992 Ja 19 2s -5 R +05/+06 1992 Mar 29 2s -4 R +04/+05 2004 O 31 2s -5 - +05 R KG 1992 1996 - Ap Su>=7 0s 1 - R KG 1992 1996 - S lastSu 0 0 - R KG 1997 2005 - Mar lastSu 2:30 1 - R KG 1997 2004 - O lastSu 2:30 0 - -Z Asia/Bishkek 4:58:24 - LMT 1924 May 2 -5 - +05 1930 Jun 21 -6 R +06/+07 1991 Mar 31 2s -5 R +05/+06 1991 Au 31 2 -5 KG +05/+06 2005 Au 12 -6 - +06 R KR 1948 o - Jun 1 0 1 D R KR 1948 o - S 12 24 0 S R KR 1949 o - Ap 3 0 1 D @@ -887,18 +571,6 @@ R KR 1957 1960 - May Su>=1 0 1 D R KR 1957 1960 - S Sa>=17 24 0 S R KR 1987 1988 - May Su>=8 2 1 D R KR 1987 1988 - O Su>=8 3 0 S -Z Asia/Seoul 8:27:52 - LMT 1908 Ap -8:30 - KST 1912 -9 - JST 1945 S 8 -9 KR K%sT 1954 Mar 21 -8:30 KR K%sT 1961 Au 10 -9 KR K%sT -Z Asia/Pyongyang 8:23 - LMT 1908 Ap -8:30 - KST 1912 -9 - JST 1945 Au 24 -9 - KST 2015 Au 15 -8:30 - KST 2018 May 4 23:30 -9 - KST R l 1920 o - Mar 28 0 1 S R l 1920 o - O 25 0 0 - R l 1921 o - Ap 3 0 1 S @@ -923,18 +595,8 @@ R l 1992 o - O 4 0 0 - R l 1993 ma - Mar lastSu 0 1 S R l 1993 1998 - S lastSu 0 0 - R l 1999 ma - O lastSu 0 0 - -Z Asia/Beirut 2:22 - LMT 1880 -2 l EE%sT R NB 1935 1941 - S 14 0 0:20 - R NB 1935 1941 - D 14 0 0 - -Z Asia/Kuching 7:21:20 - LMT 1926 Mar -7:30 - +0730 1933 -8 NB +08/+0820 1942 F 16 -9 - +09 1945 S 12 -8 - +08 -Z Indian/Maldives 4:54 - LMT 1880 -4:54 - MMT 1960 -5 - +05 R X 1983 1984 - Ap 1 0 1 - R X 1983 o - O 1 0 0 - R X 1985 1998 - Mar lastSu 0 1 - @@ -944,31 +606,11 @@ R X 2001 2006 - S lastSa 2 0 - R X 2002 2006 - Mar lastSa 2 1 - R X 2015 2016 - Mar lastSa 2 1 - R X 2015 2016 - S lastSa 0 0 - -Z Asia/Hovd 6:6:36 - LMT 1905 Au -6 - +06 1978 -7 X +07/+08 -Z Asia/Ulaanbaatar 7:7:32 - LMT 1905 Au -7 - +07 1978 -8 X +08/+09 -Z Asia/Choibalsan 7:38 - LMT 1905 Au -7 - +07 1978 -8 - +08 1983 Ap -9 X +09/+10 2008 Mar 31 -8 X +08/+09 -Z Asia/Kathmandu 5:41:16 - LMT 1920 -5:30 - +0530 1986 -5:45 - +0545 R PK 2002 o - Ap Su>=2 0 1 S R PK 2002 o - O Su>=2 0 0 - R PK 2008 o - Jun 1 0 1 S R PK 2008 2009 - N 1 0 0 - R PK 2009 o - Ap 15 0 1 S -Z Asia/Karachi 4:28:12 - LMT 1907 -5:30 - +0530 1942 S -5:30 1 +0630 1945 O 15 -5:30 - +0530 1951 S 30 -5 - +05 1971 Mar 26 -5 PK PK%sT R P 1999 2005 - Ap F>=15 0 1 S R P 1999 2003 - O F>=15 0 0 - R P 2004 o - O 1 1 0 - @@ -1001,136 +643,90 @@ R P 2021 o - O 29 1 0 - R P 2022 o - Mar 27 0 1 S R P 2022 2035 - O Sa<=30 2 0 - R P 2023 o - Ap 29 2 1 S -R P 2024 o - Ap 13 2 1 S -R P 2025 o - Ap 5 2 1 S +R P 2024 o - Ap 20 2 1 S +R P 2025 o - Ap 12 2 1 S R P 2026 2054 - Mar Sa<=30 2 1 S R P 2036 o - O 18 2 0 - R P 2037 o - O 10 2 0 - R P 2038 o - S 25 2 0 - R P 2039 o - S 17 2 0 - -R P 2039 o - O 22 2 1 S -R P 2039 2067 - O Sa<=30 2 0 - R P 2040 o - S 1 2 0 - -R P 2040 o - O 13 2 1 S +R P 2040 o - O 20 2 1 S +R P 2040 2067 - O Sa<=30 2 0 - R P 2041 o - Au 24 2 0 - -R P 2041 o - S 28 2 1 S +R P 2041 o - O 5 2 1 S R P 2042 o - Au 16 2 0 - -R P 2042 o - S 20 2 1 S +R P 2042 o - S 27 2 1 S R P 2043 o - Au 1 2 0 - -R P 2043 o - S 12 2 1 S +R P 2043 o - S 19 2 1 S R P 2044 o - Jul 23 2 0 - -R P 2044 o - Au 27 2 1 S +R P 2044 o - S 3 2 1 S R P 2045 o - Jul 15 2 0 - -R P 2045 o - Au 19 2 1 S +R P 2045 o - Au 26 2 1 S R P 2046 o - Jun 30 2 0 - -R P 2046 o - Au 11 2 1 S +R P 2046 o - Au 18 2 1 S R P 2047 o - Jun 22 2 0 - -R P 2047 o - Jul 27 2 1 S +R P 2047 o - Au 3 2 1 S R P 2048 o - Jun 6 2 0 - -R P 2048 o - Jul 18 2 1 S +R P 2048 o - Jul 25 2 1 S R P 2049 o - May 29 2 0 - -R P 2049 o - Jul 3 2 1 S +R P 2049 o - Jul 10 2 1 S R P 2050 o - May 21 2 0 - -R P 2050 o - Jun 25 2 1 S +R P 2050 o - Jul 2 2 1 S R P 2051 o - May 6 2 0 - -R P 2051 o - Jun 17 2 1 S +R P 2051 o - Jun 24 2 1 S R P 2052 o - Ap 27 2 0 - -R P 2052 o - Jun 1 2 1 S +R P 2052 o - Jun 8 2 1 S R P 2053 o - Ap 12 2 0 - -R P 2053 o - May 24 2 1 S +R P 2053 o - May 31 2 1 S R P 2054 o - Ap 4 2 0 - -R P 2054 o - May 16 2 1 S -R P 2055 o - May 1 2 1 S -R P 2056 o - Ap 22 2 1 S -R P 2057 o - Ap 7 2 1 S -R P 2058 ma - Mar Sa<=30 2 1 S +R P 2054 o - May 23 2 1 S +R P 2055 o - May 8 2 1 S +R P 2056 o - Ap 29 2 1 S +R P 2057 o - Ap 14 2 1 S +R P 2058 o - Ap 6 2 1 S +R P 2059 ma - Mar Sa<=30 2 1 S R P 2068 o - O 20 2 0 - R P 2069 o - O 12 2 0 - R P 2070 o - O 4 2 0 - R P 2071 o - S 19 2 0 - R P 2072 o - S 10 2 0 - -R P 2072 o - O 15 2 1 S +R P 2072 o - O 22 2 1 S +R P 2072 ma - O Sa<=30 2 0 - R P 2073 o - S 2 2 0 - -R P 2073 o - O 7 2 1 S +R P 2073 o - O 14 2 1 S R P 2074 o - Au 18 2 0 - -R P 2074 o - S 29 2 1 S +R P 2074 o - O 6 2 1 S R P 2075 o - Au 10 2 0 - -R P 2075 o - S 14 2 1 S -R P 2075 ma - O Sa<=30 2 0 - +R P 2075 o - S 21 2 1 S R P 2076 o - Jul 25 2 0 - -R P 2076 o - S 5 2 1 S +R P 2076 o - S 12 2 1 S R P 2077 o - Jul 17 2 0 - -R P 2077 o - Au 28 2 1 S +R P 2077 o - S 4 2 1 S R P 2078 o - Jul 9 2 0 - -R P 2078 o - Au 13 2 1 S +R P 2078 o - Au 20 2 1 S R P 2079 o - Jun 24 2 0 - -R P 2079 o - Au 5 2 1 S +R P 2079 o - Au 12 2 1 S R P 2080 o - Jun 15 2 0 - -R P 2080 o - Jul 20 2 1 S +R P 2080 o - Jul 27 2 1 S R P 2081 o - Jun 7 2 0 - -R P 2081 o - Jul 12 2 1 S +R P 2081 o - Jul 19 2 1 S R P 2082 o - May 23 2 0 - -R P 2082 o - Jul 4 2 1 S +R P 2082 o - Jul 11 2 1 S R P 2083 o - May 15 2 0 - -R P 2083 o - Jun 19 2 1 S +R P 2083 o - Jun 26 2 1 S R P 2084 o - Ap 29 2 0 - -R P 2084 o - Jun 10 2 1 S +R P 2084 o - Jun 17 2 1 S R P 2085 o - Ap 21 2 0 - -R P 2085 o - Jun 2 2 1 S +R P 2085 o - Jun 9 2 1 S R P 2086 o - Ap 13 2 0 - -R P 2086 o - May 18 2 1 S -Z Asia/Gaza 2:17:52 - LMT 1900 O -2 Z EET/EEST 1948 May 15 -2 K EE%sT 1967 Jun 5 -2 Z I%sT 1996 -2 J EE%sT 1999 -2 P EE%sT 2008 Au 29 -2 - EET 2008 S -2 P EE%sT 2010 -2 - EET 2010 Mar 27 0:1 -2 P EE%sT 2011 Au -2 - EET 2012 -2 P EE%sT -Z Asia/Hebron 2:20:23 - LMT 1900 O -2 Z EET/EEST 1948 May 15 -2 K EE%sT 1967 Jun 5 -2 Z I%sT 1996 -2 J EE%sT 1999 -2 P EE%sT +R P 2086 o - May 25 2 1 S R PH 1936 o - N 1 0 1 D R PH 1937 o - F 1 0 0 S R PH 1954 o - Ap 12 0 1 D R PH 1954 o - Jul 1 0 0 S R PH 1978 o - Mar 22 0 1 D R PH 1978 o - S 21 0 0 S -Z Asia/Manila -15:56 - LMT 1844 D 31 -8:4 - LMT 1899 May 11 -8 PH P%sT 1942 May -9 - JST 1944 N -8 PH P%sT -Z Asia/Qatar 3:26:8 - LMT 1920 -4 - +04 1972 Jun -3 - +03 -Z Asia/Riyadh 3:6:52 - LMT 1947 Mar 14 -3 - +03 -Z Asia/Singapore 6:55:25 - LMT 1901 -6:55:25 - SMT 1905 Jun -7 - +07 1933 -7 0:20 +0720 1936 -7:20 - +0720 1941 S -7:30 - +0730 1942 F 16 -9 - +09 1945 S 12 -7:30 - +0730 1981 D 31 16u -8 - +08 -Z Asia/Colombo 5:19:24 - LMT 1880 -5:19:32 - MMT 1906 -5:30 - +0530 1942 Ja 5 -5:30 0:30 +06 1942 S -5:30 1 +0630 1945 O 16 2 -5:30 - +0530 1996 May 25 -6:30 - +0630 1996 O 26 0:30 -6 - +06 2006 Ap 15 0:30 -5:30 - +0530 R S 1920 1923 - Ap Su>=15 2 1 S R S 1920 1923 - O Su>=1 2 0 - R S 1962 o - Ap 29 2 1 S @@ -1172,46 +768,6 @@ R S 2009 o - Mar lastF 0 1 S R S 2010 2011 - Ap F>=1 0 1 S R S 2012 2022 - Mar lastF 0 1 S R S 2009 2022 - O lastF 0 0 - -Z Asia/Damascus 2:25:12 - LMT 1920 -2 S EE%sT 2022 O 28 -3 - +03 -Z Asia/Dushanbe 4:35:12 - LMT 1924 May 2 -5 - +05 1930 Jun 21 -6 R +06/+07 1991 Mar 31 2s -5 1 +06 1991 S 9 2s -5 - +05 -Z Asia/Bangkok 6:42:4 - LMT 1880 -6:42:4 - BMT 1920 Ap -7 - +07 -Z Asia/Ashgabat 3:53:32 - LMT 1924 May 2 -4 - +04 1930 Jun 21 -5 R +05/+06 1991 Mar 31 2 -4 R +04/+05 1992 Ja 19 2 -5 - +05 -Z Asia/Dubai 3:41:12 - LMT 1920 -4 - +04 -Z Asia/Samarkand 4:27:53 - LMT 1924 May 2 -4 - +04 1930 Jun 21 -5 - +05 1981 Ap -5 1 +06 1981 O -6 - +06 1982 Ap -5 R +05/+06 1992 -5 - +05 -Z Asia/Tashkent 4:37:11 - LMT 1924 May 2 -5 - +05 1930 Jun 21 -6 R +06/+07 1991 Mar 31 2 -5 R +05/+06 1992 -5 - +05 -Z Asia/Ho_Chi_Minh 7:6:30 - LMT 1906 Jul -7:6:30 - PLMT 1911 May -7 - +07 1942 D 31 23 -8 - +08 1945 Mar 14 23 -9 - +09 1945 S 2 -7 - +07 1947 Ap -8 - +08 1955 Jul -7 - +07 1959 D 31 23 -8 - +08 1975 Jun 13 -7 - +07 R AU 1917 o - Ja 1 2s 1 D R AU 1917 o - Mar lastSu 2s 0 S R AU 1942 o - Ja 1 2s 1 D @@ -1219,9 +775,6 @@ R AU 1942 o - Mar lastSu 2s 0 S R AU 1942 o - S 27 2s 1 D R AU 1943 1944 - Mar lastSu 2s 0 S R AU 1943 o - O 3 2s 1 D -Z Australia/Darwin 8:43:20 - LMT 1895 F -9 - ACST 1899 May -9:30 AU AC%sT R AW 1974 o - O lastSu 2s 1 D R AW 1975 o - Mar Su>=1 2s 0 S R AW 1983 o - O lastSu 2s 1 D @@ -1231,25 +784,12 @@ R AW 1992 o - Mar Su>=1 2s 0 S R AW 2006 o - D 3 2s 1 D R AW 2007 2009 - Mar lastSu 2s 0 S R AW 2007 2008 - O lastSu 2s 1 D -Z Australia/Perth 7:43:24 - LMT 1895 D -8 AU AW%sT 1943 Jul -8 AW AW%sT -Z Australia/Eucla 8:35:28 - LMT 1895 D -8:45 AU +0845/+0945 1943 Jul -8:45 AW +0845/+0945 R AQ 1971 o - O lastSu 2s 1 D R AQ 1972 o - F lastSu 2s 0 S R AQ 1989 1991 - O lastSu 2s 1 D R AQ 1990 1992 - Mar Su>=1 2s 0 S R Ho 1992 1993 - O lastSu 2s 1 D R Ho 1993 1994 - Mar Su>=1 2s 0 S -Z Australia/Brisbane 10:12:8 - LMT 1895 -10 AU AE%sT 1971 -10 AQ AE%sT -Z Australia/Lindeman 9:55:56 - LMT 1895 -10 AU AE%sT 1971 -10 AQ AE%sT 1992 Jul -10 Ho AE%sT R AS 1971 1985 - O lastSu 2s 1 D R AS 1986 o - O 19 2s 1 D R AS 1987 2007 - O lastSu 2s 1 D @@ -1265,10 +805,6 @@ R AS 2006 o - Ap 2 2s 0 S R AS 2007 o - Mar lastSu 2s 0 S R AS 2008 ma - Ap Su>=1 2s 0 S R AS 2008 ma - O Su>=1 2s 1 D -Z Australia/Adelaide 9:14:20 - LMT 1895 F -9 - ACST 1899 May -9:30 AU AC%sT 1971 -9:30 AS AC%sT R AT 1916 o - O Su>=1 2s 1 D R AT 1917 o - Mar lastSu 2s 0 S R AT 1917 1918 - O Su>=22 2s 1 D @@ -1292,10 +828,6 @@ R AT 2001 ma - O Su>=1 2s 1 D R AT 2006 o - Ap Su>=1 2s 0 S R AT 2007 o - Mar lastSu 2s 0 S R AT 2008 ma - Ap Su>=1 2s 0 S -Z Australia/Hobart 9:49:16 - LMT 1895 S -10 AT AE%sT 1919 O 24 -10 AU AE%sT 1967 -10 AT AE%sT R AV 1971 1985 - O lastSu 2s 1 D R AV 1972 o - F lastSu 2s 0 S R AV 1973 1985 - Mar Su>=1 2s 0 S @@ -1310,9 +842,6 @@ R AV 2006 o - Ap Su>=1 2s 0 S R AV 2007 o - Mar lastSu 2s 0 S R AV 2008 ma - Ap Su>=1 2s 0 S R AV 2008 ma - O Su>=1 2s 1 D -Z Australia/Melbourne 9:39:52 - LMT 1895 F -10 AU AE%sT 1971 -10 AV AE%sT R AN 1971 1985 - O lastSu 2s 1 D R AN 1972 o - F 27 2s 0 S R AN 1973 1981 - Mar Su>=1 2s 0 S @@ -1329,15 +858,6 @@ R AN 2006 o - Ap Su>=1 2s 0 S R AN 2007 o - Mar lastSu 2s 0 S R AN 2008 ma - Ap Su>=1 2s 0 S R AN 2008 ma - O Su>=1 2s 1 D -Z Australia/Sydney 10:4:52 - LMT 1895 F -10 AU AE%sT 1971 -10 AN AE%sT -Z Australia/Broken_Hill 9:25:48 - LMT 1895 F -10 - AEST 1896 Au 23 -9 - ACST 1899 May -9:30 AU AC%sT 1971 -9:30 AN AC%sT 2000 -9:30 AS AC%sT R LH 1981 1984 - O lastSu 2 1 - R LH 1982 1985 - Mar Su>=1 2 0 - R LH 1985 o - O lastSu 2 0:30 - @@ -1352,19 +872,6 @@ R LH 2006 o - Ap Su>=1 2 0 - R LH 2007 o - Mar lastSu 2 0 - R LH 2008 ma - Ap Su>=1 2 0 - R LH 2008 ma - O Su>=1 2 0:30 - -Z Australia/Lord_Howe 10:36:20 - LMT 1895 F -10 - AEST 1981 Mar -10:30 LH +1030/+1130 1985 Jul -10:30 LH +1030/+11 -Z Antarctica/Macquarie 0 - -00 1899 N -10 - AEST 1916 O 1 2 -10 1 AEDT 1917 F -10 AU AE%sT 1919 Ap 1 0s -0 - -00 1948 Mar 25 -10 AU AE%sT 1967 -10 AT AE%sT 2010 -10 1 AEDT 2011 -10 AT AE%sT R FJ 1998 1999 - N Su>=1 2 1 - R FJ 1999 2000 - F lastSu 3 0 - R FJ 2009 o - N 29 2 1 - @@ -1377,14 +884,6 @@ R FJ 2014 2018 - N Su>=1 2 1 - R FJ 2015 2021 - Ja Su>=12 3 0 - R FJ 2019 o - N Su>=8 2 1 - R FJ 2020 o - D 20 2 1 - -Z Pacific/Fiji 11:55:44 - LMT 1915 O 26 -12 FJ +12/+13 -Z Pacific/Gambier -8:59:48 - LMT 1912 O --9 - -09 -Z Pacific/Marquesas -9:18 - LMT 1912 O --9:30 - -0930 -Z Pacific/Tahiti -9:58:16 - LMT 1912 O --10 - -10 R Gu 1959 o - Jun 27 2 1 D R Gu 1961 o - Ja 29 2 0 S R Gu 1967 o - S 1 2 1 D @@ -1399,50 +898,10 @@ R Gu 1976 o - May 26 2 1 D R Gu 1976 o - Au 22 2:1 0 S R Gu 1977 o - Ap 24 2 1 D R Gu 1977 o - Au 28 2 0 S -Z Pacific/Guam -14:21 - LMT 1844 D 31 -9:39 - LMT 1901 -10 - GST 1941 D 10 -9 - +09 1944 Jul 31 -10 Gu G%sT 2000 D 23 -10 - ChST -Z Pacific/Tarawa 11:32:4 - LMT 1901 -12 - +12 -Z Pacific/Kanton 0 - -00 1937 Au 31 --12 - -12 1979 O --11 - -11 1994 D 31 -13 - +13 -Z Pacific/Kiritimati -10:29:20 - LMT 1901 --10:40 - -1040 1979 O --10 - -10 1994 D 31 -14 - +14 -Z Pacific/Kwajalein 11:9:20 - LMT 1901 -11 - +11 1937 -10 - +10 1941 Ap -9 - +09 1944 F 6 -11 - +11 1969 O --12 - -12 1993 Au 20 24 -12 - +12 -Z Pacific/Kosrae -13:8:4 - LMT 1844 D 31 -10:51:56 - LMT 1901 -11 - +11 1914 O -9 - +09 1919 F -11 - +11 1937 -10 - +10 1941 Ap -9 - +09 1945 Au -11 - +11 1969 O -12 - +12 1999 -11 - +11 -Z Pacific/Nauru 11:7:40 - LMT 1921 Ja 15 -11:30 - +1130 1942 Au 29 -9 - +09 1945 S 8 -11:30 - +1130 1979 F 10 2 -12 - +12 R NC 1977 1978 - D Su>=1 0 1 - R NC 1978 1979 - F 27 0 0 - R NC 1996 o - D 1 2s 1 - R NC 1997 o - Mar 2 2s 0 - -Z Pacific/Noumea 11:5:48 - LMT 1912 Ja 13 -11 NC +11/+12 R NZ 1927 o - N 6 2 1 S R NZ 1928 o - Mar 4 2 0 M R NZ 1928 1933 - O Su>=8 2 0:30 S @@ -1468,80 +927,26 @@ R NZ 2007 ma - S lastSu 2s 1 D R k 2007 ma - S lastSu 2:45s 1 - R NZ 2008 ma - Ap Su>=1 2s 0 S R k 2008 ma - Ap Su>=1 2:45s 0 - -Z Pacific/Auckland 11:39:4 - LMT 1868 N 2 -11:30 NZ NZ%sT 1946 -12 NZ NZ%sT -Z Pacific/Chatham 12:13:48 - LMT 1868 N 2 -12:15 - +1215 1946 -12:45 k +1245/+1345 R CK 1978 o - N 12 0 0:30 - R CK 1979 1991 - Mar Su>=1 0 0 - R CK 1979 1990 - O lastSu 0 0:30 - -Z Pacific/Rarotonga 13:20:56 - LMT 1899 D 26 --10:39:4 - LMT 1952 O 16 --10:30 - -1030 1978 N 12 --10 CK -10/-0930 -Z Pacific/Niue -11:19:40 - LMT 1952 O 16 --11:20 - -1120 1964 Jul --11 - -11 -Z Pacific/Norfolk 11:11:52 - LMT 1901 -11:12 - +1112 1951 -11:30 - +1130 1974 O 27 2s -11:30 1 +1230 1975 Mar 2 2s -11:30 - +1130 2015 O 4 2s -11 - +11 2019 Jul -11 AN +11/+12 -Z Pacific/Palau -15:2:4 - LMT 1844 D 31 -8:57:56 - LMT 1901 -9 - +09 -Z Pacific/Port_Moresby 9:48:40 - LMT 1880 -9:48:32 - PMMT 1895 -10 - +10 -Z Pacific/Bougainville 10:22:16 - LMT 1880 -9:48:32 - PMMT 1895 -10 - +10 1942 Jul -9 - +09 1945 Au 21 -10 - +10 2014 D 28 2 -11 - +11 -Z Pacific/Pitcairn -8:40:20 - LMT 1901 --8:30 - -0830 1998 Ap 27 --8 - -08 -Z Pacific/Pago_Pago 12:37:12 - LMT 1892 Jul 5 --11:22:48 - LMT 1911 --11 - SST R WS 2010 o - S lastSu 0 1 - R WS 2011 o - Ap Sa>=1 4 0 - R WS 2011 o - S lastSa 3 1 - R WS 2012 2021 - Ap Su>=1 4 0 - R WS 2012 2020 - S lastSu 3 1 - -Z Pacific/Apia 12:33:4 - LMT 1892 Jul 5 --11:26:56 - LMT 1911 --11:30 - -1130 1950 --11 WS -11/-10 2011 D 29 24 -13 WS +13/+14 -Z Pacific/Guadalcanal 10:39:48 - LMT 1912 O -11 - +11 -Z Pacific/Fakaofo -11:24:56 - LMT 1901 --11 - -11 2011 D 30 -13 - +13 R TO 1999 o - O 7 2s 1 - R TO 2000 o - Mar 19 2s 0 - R TO 2000 2001 - N Su>=1 2 1 - R TO 2001 2002 - Ja lastSu 2 0 - R TO 2016 o - N Su>=1 2 1 - R TO 2017 o - Ja Su>=15 3 0 - -Z Pacific/Tongatapu 12:19:12 - LMT 1945 S 10 -12:20 - +1220 1961 -13 - +13 1999 -13 TO +13/+14 R VU 1973 o - D 22 12u 1 - R VU 1974 o - Mar 30 12u 0 - R VU 1983 1991 - S Sa>=22 24 1 - R VU 1984 1991 - Mar Sa>=22 24 0 - R VU 1992 1993 - Ja Sa>=22 24 0 - R VU 1992 o - O Sa>=22 24 1 - -Z Pacific/Efate 11:13:16 - LMT 1912 Ja 13 -11 VU +11/+12 R G 1916 o - May 21 2s 1 BST R G 1916 o - O 1 2s 0 GMT R G 1917 o - Ap 8 2s 1 BST @@ -1607,11 +1012,6 @@ R G 1972 1980 - O Su>=23 2s 0 GMT R G 1981 1995 - Mar lastSu 1u 1 BST R G 1981 1989 - O Su>=23 1u 0 GMT R G 1990 1995 - O Su>=22 1u 0 GMT -Z Europe/London -0:1:15 - LMT 1847 D -0 G %s 1968 O 27 -1 - BST 1971 O 31 2u -0 G %s 1996 -0 E GMT/BST R IE 1971 o - O 31 2u -1 - R IE 1972 1980 - Mar Su>=16 2u 0 - R IE 1972 1980 - O Su>=23 2u -1 - @@ -1619,17 +1019,6 @@ R IE 1981 ma - Mar lastSu 1u 0 - R IE 1981 1989 - O Su>=23 1u -1 - R IE 1990 1995 - O Su>=22 1u -1 - R IE 1996 ma - O lastSu 1u -1 - -Z Europe/Dublin -0:25:21 - LMT 1880 Au 2 --0:25:21 - DMT 1916 May 21 2s --0:25:21 1 IST 1916 O 1 2s -0 G %s 1921 D 6 -0 G GMT/IST 1940 F 25 2s -0 1 IST 1946 O 6 2s -0 - GMT 1947 Mar 16 2s -0 1 IST 1947 N 2 2s -0 - GMT 1948 Ap 18 2s -0 G GMT/IST 1968 O 27 -1 IE IST/GMT R E 1977 1980 - Ap Su>=1 1u 1 S R E 1977 o - S lastSu 1u 0 - R E 1978 o - O 1 1u 0 - @@ -1681,10 +1070,6 @@ R R 1981 1983 - O 1 0 0 - R R 1984 1995 - S lastSu 2s 0 - R R 1985 2010 - Mar lastSu 2s 1 S R R 1996 2010 - O lastSu 2s 0 - -Z WET 0 E WE%sT -Z CET 1 c CE%sT -Z MET 1 c ME%sT -Z EET 2 E EE%sT R q 1940 o - Jun 16 0 1 S R q 1942 o - N 2 3 0 - R q 1943 o - Mar 29 2 1 S @@ -1710,14 +1095,6 @@ R q 1982 o - O 3 0 0 - R q 1983 o - Ap 18 0 1 S R q 1983 o - O 1 0 0 - R q 1984 o - Ap 1 0 1 S -Z Europe/Tirane 1:19:20 - LMT 1914 -1 - CET 1940 Jun 16 -1 q CE%sT 1984 Jul -1 E CE%sT -Z Europe/Andorra 0:6:4 - LMT 1901 -0 - WET 1946 S 30 -1 - CET 1985 Mar 31 2 -1 E CE%sT R a 1920 o - Ap 5 2s 1 S R a 1920 o - S 13 2s 0 - R a 1946 o - Ap 14 2s 1 S @@ -1727,23 +1104,6 @@ R a 1947 o - Ap 6 2s 1 S R a 1948 o - Ap 18 2s 1 S R a 1980 o - Ap 6 0 1 S R a 1980 o - S 28 0 0 - -Z Europe/Vienna 1:5:21 - LMT 1893 Ap -1 c CE%sT 1920 -1 a CE%sT 1940 Ap 1 2s -1 c CE%sT 1945 Ap 2 2s -1 1 CEST 1945 Ap 12 2s -1 - CET 1946 -1 a CE%sT 1981 -1 E CE%sT -Z Europe/Minsk 1:50:16 - LMT 1880 -1:50 - MMT 1924 May 2 -2 - EET 1930 Jun 21 -3 - MSK 1941 Jun 28 -1 c CE%sT 1944 Jul 3 -3 R MSK/MSD 1990 -3 - MSK 1991 Mar 31 2s -2 R EE%sT 2011 Mar 27 2s -3 - +03 R b 1918 o - Mar 9 0s 1 S R b 1918 1919 - O Sa>=1 23s 0 - R b 1919 o - Mar 1 23s 1 S @@ -1778,87 +1138,27 @@ R b 1945 o - Ap 2 2s 1 S R b 1945 o - S 16 2s 0 - R b 1946 o - May 19 2s 1 S R b 1946 o - O 7 2s 0 - -Z Europe/Brussels 0:17:30 - LMT 1880 -0:17:30 - BMT 1892 May 1 0:17:30 -0 - WET 1914 N 8 -1 - CET 1916 May -1 c CE%sT 1918 N 11 11u -0 b WE%sT 1940 May 20 2s -1 c CE%sT 1944 S 3 -1 b CE%sT 1977 -1 E CE%sT R BG 1979 o - Mar 31 23 1 S R BG 1979 o - O 1 1 0 - R BG 1980 1982 - Ap Sa>=1 23 1 S R BG 1980 o - S 29 1 0 - R BG 1981 o - S 27 2 0 - -Z Europe/Sofia 1:33:16 - LMT 1880 -1:56:56 - IMT 1894 N 30 -2 - EET 1942 N 2 3 -1 c CE%sT 1945 -1 - CET 1945 Ap 2 3 -2 - EET 1979 Mar 31 23 -2 BG EE%sT 1982 S 26 3 -2 c EE%sT 1991 -2 e EE%sT 1997 -2 E EE%sT R CZ 1945 o - Ap M>=1 2s 1 S R CZ 1945 o - O 1 2s 0 - R CZ 1946 o - May 6 2s 1 S R CZ 1946 1949 - O Su>=1 2s 0 - R CZ 1947 1948 - Ap Su>=15 2s 1 S R CZ 1949 o - Ap 9 2s 1 S -Z Europe/Prague 0:57:44 - LMT 1850 -0:57:44 - PMT 1891 O -1 c CE%sT 1945 May 9 -1 CZ CE%sT 1946 D 1 3 -1 -1 GMT 1947 F 23 2 -1 CZ CE%sT 1979 -1 E CE%sT -Z Atlantic/Faroe -0:27:4 - LMT 1908 Ja 11 -0 - WET 1981 -0 E WE%sT R Th 1991 1992 - Mar lastSu 2 1 D R Th 1991 1992 - S lastSu 2 0 S R Th 1993 2006 - Ap Su>=1 2 1 D R Th 1993 2006 - O lastSu 2 0 S R Th 2007 ma - Mar Su>=8 2 1 D R Th 2007 ma - N Su>=1 2 0 S -Z America/Danmarkshavn -1:14:40 - LMT 1916 Jul 28 --3 - -03 1980 Ap 6 2 --3 E -03/-02 1996 -0 - GMT -Z America/Scoresbysund -1:27:52 - LMT 1916 Jul 28 --2 - -02 1980 Ap 6 2 --2 c -02/-01 1981 Mar 29 --1 E -01/+00 -Z America/Nuuk -3:26:56 - LMT 1916 Jul 28 --3 - -03 1980 Ap 6 2 --3 E -03/-02 2023 O 29 1u --2 E -02/-01 -Z America/Thule -4:35:8 - LMT 1916 Jul 28 --4 Th A%sT -Z Europe/Tallinn 1:39 - LMT 1880 -1:39 - TMT 1918 F -1 c CE%sT 1919 Jul -1:39 - TMT 1921 May -2 - EET 1940 Au 6 -3 - MSK 1941 S 15 -1 c CE%sT 1944 S 22 -3 R MSK/MSD 1989 Mar 26 2s -2 1 EEST 1989 S 24 2s -2 c EE%sT 1998 S 22 -2 E EE%sT 1999 O 31 4 -2 - EET 2002 F 21 -2 E EE%sT R FI 1942 o - Ap 2 24 1 S R FI 1942 o - O 4 1 0 - R FI 1981 1982 - Mar lastSu 2 1 S R FI 1981 1982 - S lastSu 3 0 - -Z Europe/Helsinki 1:39:49 - LMT 1878 May 31 -1:39:49 - HMT 1921 May -2 FI EE%sT 1983 -2 E EE%sT R F 1916 o - Jun 14 23s 1 S R F 1916 1919 - O Su>=1 23s 0 - R F 1917 o - Mar 24 23s 1 S @@ -1901,13 +1201,6 @@ R F 1945 o - Ap 2 2 2 M R F 1945 o - S 16 3 0 - R F 1976 o - Mar 28 1 1 S R F 1976 o - S 26 1 0 - -Z Europe/Paris 0:9:21 - LMT 1891 Mar 16 -0:9:21 - PMT 1911 Mar 11 -0 F WE%sT 1940 Jun 14 23 -1 c CE%sT 1944 Au 25 -0 F WE%sT 1945 S 16 3 -1 F CE%sT 1977 -1 E CE%sT R DE 1946 o - Ap 14 2s 1 S R DE 1946 o - O 7 2s 0 - R DE 1947 1949 - O Su>=1 2s 0 - @@ -1919,15 +1212,6 @@ R DE 1949 o - Ap 10 2s 1 S R So 1945 o - May 24 2 2 M R So 1945 o - S 24 3 1 S R So 1945 o - N 18 2s 0 - -Z Europe/Berlin 0:53:28 - LMT 1893 Ap -1 c CE%sT 1945 May 24 2 -1 So CE%sT 1946 -1 DE CE%sT 1980 -1 E CE%sT -Z Europe/Gibraltar -0:21:24 - LMT 1880 Au 2 -0 G %s 1957 Ap 14 2 -1 - CET 1982 -1 E CE%sT R g 1932 o - Jul 7 0 1 S R g 1932 o - S 1 0 0 - R g 1941 o - Ap 7 0 1 S @@ -1947,12 +1231,6 @@ R g 1979 o - Ap 1 9 1 S R g 1979 o - S 29 2 0 - R g 1980 o - Ap 1 0 1 S R g 1980 o - S 28 0 0 - -Z Europe/Athens 1:34:52 - LMT 1895 S 14 -1:34:52 - AMT 1916 Jul 28 0:1 -2 g EE%sT 1941 Ap 30 -1 g CE%sT 1944 Ap 4 -2 g EE%sT 1981 -2 E EE%sT R h 1918 1919 - Ap 15 2 1 S R h 1918 1920 - S M>=15 3 0 - R h 1920 o - Ap 5 2 1 S @@ -1972,12 +1250,6 @@ R h 1980 o - Ap 6 0 1 S R h 1980 o - S 28 1 0 - R h 1981 1983 - Mar lastSu 0 1 S R h 1981 1983 - S lastSu 1 0 - -Z Europe/Budapest 1:16:20 - LMT 1890 N -1 c CE%sT 1918 -1 h CE%sT 1941 Ap 7 23 -1 c CE%sT 1945 -1 h CE%sT 1984 -1 E CE%sT R I 1916 o - Jun 3 24 1 S R I 1916 1917 - S 30 24 0 - R I 1917 o - Mar 31 24 1 S @@ -2019,44 +1291,8 @@ R I 1976 o - May 30 0s 1 S R I 1977 1979 - May Su>=22 0s 1 S R I 1978 o - O 1 0s 0 - R I 1979 o - S 30 0s 0 - -Z Europe/Rome 0:49:56 - LMT 1866 D 12 -0:49:56 - RMT 1893 O 31 23u -1 I CE%sT 1943 S 10 -1 c CE%sT 1944 Jun 4 -1 I CE%sT 1980 -1 E CE%sT R LV 1989 1996 - Mar lastSu 2s 1 S R LV 1989 1996 - S lastSu 2s 0 - -Z Europe/Riga 1:36:34 - LMT 1880 -1:36:34 - RMT 1918 Ap 15 2 -1:36:34 1 LST 1918 S 16 3 -1:36:34 - RMT 1919 Ap 1 2 -1:36:34 1 LST 1919 May 22 3 -1:36:34 - RMT 1926 May 11 -2 - EET 1940 Au 5 -3 - MSK 1941 Jul -1 c CE%sT 1944 O 13 -3 R MSK/MSD 1989 Mar lastSu 2s -2 1 EEST 1989 S lastSu 2s -2 LV EE%sT 1997 Ja 21 -2 E EE%sT 2000 F 29 -2 - EET 2001 Ja 2 -2 E EE%sT -Z Europe/Vilnius 1:41:16 - LMT 1880 -1:24 - WMT 1917 -1:35:36 - KMT 1919 O 10 -1 - CET 1920 Jul 12 -2 - EET 1920 O 9 -1 - CET 1940 Au 3 -3 - MSK 1941 Jun 24 -1 c CE%sT 1944 Au -3 R MSK/MSD 1989 Mar 26 2s -2 R EE%sT 1991 S 29 2s -2 c EE%sT 1998 -2 - EET 1998 Mar 29 1u -1 E CE%sT 1999 O 31 1u -2 - EET 2003 -2 E EE%sT R MT 1973 o - Mar 31 0s 1 S R MT 1973 o - S 29 0s 0 - R MT 1974 o - Ap 21 0s 1 S @@ -2064,22 +1300,8 @@ R MT 1974 o - S 16 0s 0 - R MT 1975 1979 - Ap Su>=15 2 1 S R MT 1975 1980 - S Su>=15 2 0 - R MT 1980 o - Mar 31 2 1 S -Z Europe/Malta 0:58:4 - LMT 1893 N 2 -1 I CE%sT 1973 Mar 31 -1 MT CE%sT 1981 -1 E CE%sT R MD 1997 ma - Mar lastSu 2 1 S R MD 1997 ma - O lastSu 3 0 - -Z Europe/Chisinau 1:55:20 - LMT 1880 -1:55 - CMT 1918 F 15 -1:44:24 - BMT 1931 Jul 24 -2 z EE%sT 1940 Au 15 -2 1 EEST 1941 Jul 17 -1 c CE%sT 1944 Au 24 -3 R MSK/MSD 1990 May 6 2 -2 R EE%sT 1992 -2 e EE%sT 1997 -2 MD EE%sT R O 1918 1919 - S 16 2s 0 - R O 1919 o - Ap 15 2s 1 S R O 1944 o - Ap 3 2s 1 S @@ -2100,15 +1322,6 @@ R O 1959 1961 - O Su>=1 1s 0 - R O 1960 o - Ap 3 1s 1 S R O 1961 1964 - May lastSu 1s 1 S R O 1962 1964 - S lastSu 1s 0 - -Z Europe/Warsaw 1:24 - LMT 1880 -1:24 - WMT 1915 Au 5 -1 c CE%sT 1918 S 16 3 -2 O EE%sT 1922 Jun -1 O CE%sT 1940 Jun 23 2 -1 c CE%sT 1944 O -1 O CE%sT 1977 -1 W- CE%sT 1988 -1 E CE%sT R p 1916 o - Jun 17 23 1 S R p 1916 o - N 1 1 0 - R p 1917 o - F 28 23s 1 S @@ -2157,42 +1370,6 @@ R p 1979 1982 - S lastSu 1s 0 - R p 1980 o - Mar lastSu 0s 1 S R p 1981 1982 - Mar lastSu 1s 1 S R p 1983 o - Mar lastSu 2s 1 S -Z Europe/Lisbon -0:36:45 - LMT 1884 --0:36:45 - LMT 1912 Ja 1 0u -0 p WE%sT 1966 Ap 3 2 -1 - CET 1976 S 26 1 -0 p WE%sT 1983 S 25 1s -0 W- WE%sT 1992 S 27 1s -1 E CE%sT 1996 Mar 31 1u -0 E WE%sT -Z Atlantic/Azores -1:42:40 - LMT 1884 --1:54:32 - HMT 1912 Ja 1 2u --2 p -02/-01 1942 Ap 25 22s --2 p +00 1942 Au 15 22s --2 p -02/-01 1943 Ap 17 22s --2 p +00 1943 Au 28 22s --2 p -02/-01 1944 Ap 22 22s --2 p +00 1944 Au 26 22s --2 p -02/-01 1945 Ap 21 22s --2 p +00 1945 Au 25 22s --2 p -02/-01 1966 Ap 3 2 --1 p -01/+00 1983 S 25 1s --1 W- -01/+00 1992 S 27 1s -0 E WE%sT 1993 Mar 28 1u --1 E -01/+00 -Z Atlantic/Madeira -1:7:36 - LMT 1884 --1:7:36 - FMT 1912 Ja 1 1u --1 p -01/+00 1942 Ap 25 22s --1 p +01 1942 Au 15 22s --1 p -01/+00 1943 Ap 17 22s --1 p +01 1943 Au 28 22s --1 p -01/+00 1944 Ap 22 22s --1 p +01 1944 Au 26 22s --1 p -01/+00 1945 Ap 21 22s --1 p +01 1945 Au 25 22s --1 p -01/+00 1966 Ap 3 2 -0 p WE%sT 1983 S 25 1s -0 E WE%sT R z 1932 o - May 21 0s 1 S R z 1932 1939 - O Su>=1 0s 0 - R z 1933 1939 - Ap Su>=2 0s 1 S @@ -2202,252 +1379,6 @@ R z 1980 o - Ap 5 23 1 S R z 1980 o - S lastSu 1 0 - R z 1991 1993 - Mar lastSu 0s 1 S R z 1991 1993 - S lastSu 0s 0 - -Z Europe/Bucharest 1:44:24 - LMT 1891 O -1:44:24 - BMT 1931 Jul 24 -2 z EE%sT 1981 Mar 29 2s -2 c EE%sT 1991 -2 z EE%sT 1994 -2 e EE%sT 1997 -2 E EE%sT -Z Europe/Kaliningrad 1:22 - LMT 1893 Ap -1 c CE%sT 1945 Ap 10 -2 O EE%sT 1946 Ap 7 -3 R MSK/MSD 1989 Mar 26 2s -2 R EE%sT 2011 Mar 27 2s -3 - +03 2014 O 26 2s -2 - EET -Z Europe/Moscow 2:30:17 - LMT 1880 -2:30:17 - MMT 1916 Jul 3 -2:31:19 R %s 1919 Jul 1 0u -3 R %s 1921 O -3 R MSK/MSD 1922 O -2 - EET 1930 Jun 21 -3 R MSK/MSD 1991 Mar 31 2s -2 R EE%sT 1992 Ja 19 2s -3 R MSK/MSD 2011 Mar 27 2s -4 - MSK 2014 O 26 2s -3 - MSK -Z Europe/Simferopol 2:16:24 - LMT 1880 -2:16 - SMT 1924 May 2 -2 - EET 1930 Jun 21 -3 - MSK 1941 N -1 c CE%sT 1944 Ap 13 -3 R MSK/MSD 1990 -3 - MSK 1990 Jul 1 2 -2 - EET 1992 Mar 20 -2 c EE%sT 1994 May -3 c MSK/MSD 1996 Mar 31 0s -3 1 MSD 1996 O 27 3s -3 - MSK 1997 Mar lastSu 1u -2 E EE%sT 2014 Mar 30 2 -4 - MSK 2014 O 26 2s -3 - MSK -Z Europe/Astrakhan 3:12:12 - LMT 1924 May -3 - +03 1930 Jun 21 -4 R +04/+05 1989 Mar 26 2s -3 R +03/+04 1991 Mar 31 2s -4 - +04 1992 Mar 29 2s -3 R +03/+04 2011 Mar 27 2s -4 - +04 2014 O 26 2s -3 - +03 2016 Mar 27 2s -4 - +04 -Z Europe/Volgograd 2:57:40 - LMT 1920 Ja 3 -3 - +03 1930 Jun 21 -4 - +04 1961 N 11 -4 R +04/+05 1988 Mar 27 2s -3 R MSK/MSD 1991 Mar 31 2s -4 - +04 1992 Mar 29 2s -3 R MSK/MSD 2011 Mar 27 2s -4 - MSK 2014 O 26 2s -3 - MSK 2018 O 28 2s -4 - +04 2020 D 27 2s -3 - MSK -Z Europe/Saratov 3:4:18 - LMT 1919 Jul 1 0u -3 - +03 1930 Jun 21 -4 R +04/+05 1988 Mar 27 2s -3 R +03/+04 1991 Mar 31 2s -4 - +04 1992 Mar 29 2s -3 R +03/+04 2011 Mar 27 2s -4 - +04 2014 O 26 2s -3 - +03 2016 D 4 2s -4 - +04 -Z Europe/Kirov 3:18:48 - LMT 1919 Jul 1 0u -3 - +03 1930 Jun 21 -4 R +04/+05 1989 Mar 26 2s -3 R MSK/MSD 1991 Mar 31 2s -4 - +04 1992 Mar 29 2s -3 R MSK/MSD 2011 Mar 27 2s -4 - MSK 2014 O 26 2s -3 - MSK -Z Europe/Samara 3:20:20 - LMT 1919 Jul 1 0u -3 - +03 1930 Jun 21 -4 - +04 1935 Ja 27 -4 R +04/+05 1989 Mar 26 2s -3 R +03/+04 1991 Mar 31 2s -2 R +02/+03 1991 S 29 2s -3 - +03 1991 O 20 3 -4 R +04/+05 2010 Mar 28 2s -3 R +03/+04 2011 Mar 27 2s -4 - +04 -Z Europe/Ulyanovsk 3:13:36 - LMT 1919 Jul 1 0u -3 - +03 1930 Jun 21 -4 R +04/+05 1989 Mar 26 2s -3 R +03/+04 1991 Mar 31 2s -2 R +02/+03 1992 Ja 19 2s -3 R +03/+04 2011 Mar 27 2s -4 - +04 2014 O 26 2s -3 - +03 2016 Mar 27 2s -4 - +04 -Z Asia/Yekaterinburg 4:2:33 - LMT 1916 Jul 3 -3:45:5 - PMT 1919 Jul 15 4 -4 - +04 1930 Jun 21 -5 R +05/+06 1991 Mar 31 2s -4 R +04/+05 1992 Ja 19 2s -5 R +05/+06 2011 Mar 27 2s -6 - +06 2014 O 26 2s -5 - +05 -Z Asia/Omsk 4:53:30 - LMT 1919 N 14 -5 - +05 1930 Jun 21 -6 R +06/+07 1991 Mar 31 2s -5 R +05/+06 1992 Ja 19 2s -6 R +06/+07 2011 Mar 27 2s -7 - +07 2014 O 26 2s -6 - +06 -Z Asia/Barnaul 5:35 - LMT 1919 D 10 -6 - +06 1930 Jun 21 -7 R +07/+08 1991 Mar 31 2s -6 R +06/+07 1992 Ja 19 2s -7 R +07/+08 1995 May 28 -6 R +06/+07 2011 Mar 27 2s -7 - +07 2014 O 26 2s -6 - +06 2016 Mar 27 2s -7 - +07 -Z Asia/Novosibirsk 5:31:40 - LMT 1919 D 14 6 -6 - +06 1930 Jun 21 -7 R +07/+08 1991 Mar 31 2s -6 R +06/+07 1992 Ja 19 2s -7 R +07/+08 1993 May 23 -6 R +06/+07 2011 Mar 27 2s -7 - +07 2014 O 26 2s -6 - +06 2016 Jul 24 2s -7 - +07 -Z Asia/Tomsk 5:39:51 - LMT 1919 D 22 -6 - +06 1930 Jun 21 -7 R +07/+08 1991 Mar 31 2s -6 R +06/+07 1992 Ja 19 2s -7 R +07/+08 2002 May 1 3 -6 R +06/+07 2011 Mar 27 2s -7 - +07 2014 O 26 2s -6 - +06 2016 May 29 2s -7 - +07 -Z Asia/Novokuznetsk 5:48:48 - LMT 1924 May -6 - +06 1930 Jun 21 -7 R +07/+08 1991 Mar 31 2s -6 R +06/+07 1992 Ja 19 2s -7 R +07/+08 2010 Mar 28 2s -6 R +06/+07 2011 Mar 27 2s -7 - +07 -Z Asia/Krasnoyarsk 6:11:26 - LMT 1920 Ja 6 -6 - +06 1930 Jun 21 -7 R +07/+08 1991 Mar 31 2s -6 R +06/+07 1992 Ja 19 2s -7 R +07/+08 2011 Mar 27 2s -8 - +08 2014 O 26 2s -7 - +07 -Z Asia/Irkutsk 6:57:5 - LMT 1880 -6:57:5 - IMT 1920 Ja 25 -7 - +07 1930 Jun 21 -8 R +08/+09 1991 Mar 31 2s -7 R +07/+08 1992 Ja 19 2s -8 R +08/+09 2011 Mar 27 2s -9 - +09 2014 O 26 2s -8 - +08 -Z Asia/Chita 7:33:52 - LMT 1919 D 15 -8 - +08 1930 Jun 21 -9 R +09/+10 1991 Mar 31 2s -8 R +08/+09 1992 Ja 19 2s -9 R +09/+10 2011 Mar 27 2s -10 - +10 2014 O 26 2s -8 - +08 2016 Mar 27 2 -9 - +09 -Z Asia/Yakutsk 8:38:58 - LMT 1919 D 15 -8 - +08 1930 Jun 21 -9 R +09/+10 1991 Mar 31 2s -8 R +08/+09 1992 Ja 19 2s -9 R +09/+10 2011 Mar 27 2s -10 - +10 2014 O 26 2s -9 - +09 -Z Asia/Vladivostok 8:47:31 - LMT 1922 N 15 -9 - +09 1930 Jun 21 -10 R +10/+11 1991 Mar 31 2s -9 R +09/+10 1992 Ja 19 2s -10 R +10/+11 2011 Mar 27 2s -11 - +11 2014 O 26 2s -10 - +10 -Z Asia/Khandyga 9:2:13 - LMT 1919 D 15 -8 - +08 1930 Jun 21 -9 R +09/+10 1991 Mar 31 2s -8 R +08/+09 1992 Ja 19 2s -9 R +09/+10 2004 -10 R +10/+11 2011 Mar 27 2s -11 - +11 2011 S 13 0s -10 - +10 2014 O 26 2s -9 - +09 -Z Asia/Sakhalin 9:30:48 - LMT 1905 Au 23 -9 - +09 1945 Au 25 -11 R +11/+12 1991 Mar 31 2s -10 R +10/+11 1992 Ja 19 2s -11 R +11/+12 1997 Mar lastSu 2s -10 R +10/+11 2011 Mar 27 2s -11 - +11 2014 O 26 2s -10 - +10 2016 Mar 27 2s -11 - +11 -Z Asia/Magadan 10:3:12 - LMT 1924 May 2 -10 - +10 1930 Jun 21 -11 R +11/+12 1991 Mar 31 2s -10 R +10/+11 1992 Ja 19 2s -11 R +11/+12 2011 Mar 27 2s -12 - +12 2014 O 26 2s -10 - +10 2016 Ap 24 2s -11 - +11 -Z Asia/Srednekolymsk 10:14:52 - LMT 1924 May 2 -10 - +10 1930 Jun 21 -11 R +11/+12 1991 Mar 31 2s -10 R +10/+11 1992 Ja 19 2s -11 R +11/+12 2011 Mar 27 2s -12 - +12 2014 O 26 2s -11 - +11 -Z Asia/Ust-Nera 9:32:54 - LMT 1919 D 15 -8 - +08 1930 Jun 21 -9 R +09/+10 1981 Ap -11 R +11/+12 1991 Mar 31 2s -10 R +10/+11 1992 Ja 19 2s -11 R +11/+12 2011 Mar 27 2s -12 - +12 2011 S 13 0s -11 - +11 2014 O 26 2s -10 - +10 -Z Asia/Kamchatka 10:34:36 - LMT 1922 N 10 -11 - +11 1930 Jun 21 -12 R +12/+13 1991 Mar 31 2s -11 R +11/+12 1992 Ja 19 2s -12 R +12/+13 2010 Mar 28 2s -11 R +11/+12 2011 Mar 27 2s -12 - +12 -Z Asia/Anadyr 11:49:56 - LMT 1924 May 2 -12 - +12 1930 Jun 21 -13 R +13/+14 1982 Ap 1 0s -12 R +12/+13 1991 Mar 31 2s -11 R +11/+12 1992 Ja 19 2s -12 R +12/+13 2010 Mar 28 2s -11 R +11/+12 2011 Mar 27 2s -12 - +12 -Z Europe/Belgrade 1:22 - LMT 1884 -1 - CET 1941 Ap 18 23 -1 c CE%sT 1945 -1 - CET 1945 May 8 2s -1 1 CEST 1945 S 16 2s -1 - CET 1982 N 27 -1 E CE%sT R s 1918 o - Ap 15 23 1 S R s 1918 1919 - O 6 24s 0 - R s 1919 o - Ap 6 23 1 S @@ -2487,30 +1418,8 @@ R Sp 1976 o - Au 1 0 0 - R Sp 1977 o - S 28 0 0 - R Sp 1978 o - Jun 1 0 1 S R Sp 1978 o - Au 4 0 0 - -Z Europe/Madrid -0:14:44 - LMT 1901 Ja 1 0u -0 s WE%sT 1940 Mar 16 23 -1 s CE%sT 1979 -1 E CE%sT -Z Africa/Ceuta -0:21:16 - LMT 1901 Ja 1 0u -0 - WET 1918 May 6 23 -0 1 WEST 1918 O 7 23 -0 - WET 1924 -0 s WE%sT 1929 -0 - WET 1967 -0 Sp WE%sT 1984 Mar 16 -1 - CET 1986 -1 E CE%sT -Z Atlantic/Canary -1:1:36 - LMT 1922 Mar --1 - -01 1946 S 30 1 -0 - WET 1980 Ap 6 0s -0 1 WEST 1980 S 28 1u -0 E WE%sT R CH 1941 1942 - May M>=1 1 1 S R CH 1941 1942 - O M>=1 2 0 - -Z Europe/Zurich 0:34:8 - LMT 1853 Jul 16 -0:29:46 - BMT 1894 Jun -1 CH CE%sT 1981 -1 E CE%sT R T 1916 o - May 1 0 1 S R T 1916 o - O 1 0 0 - R T 1920 o - Mar 28 0 1 S @@ -2556,28 +1465,6 @@ R T 1986 1995 - S lastSu 1s 0 - R T 1994 o - Mar 20 1s 1 S R T 1995 2006 - Mar lastSu 1s 1 S R T 1996 2006 - O lastSu 1s 0 - -Z Europe/Istanbul 1:55:52 - LMT 1880 -1:56:56 - IMT 1910 O -2 T EE%sT 1978 Jun 29 -3 T +03/+04 1984 N 1 2 -2 T EE%sT 2007 -2 E EE%sT 2011 Mar 27 1u -2 - EET 2011 Mar 28 1u -2 E EE%sT 2014 Mar 30 1u -2 - EET 2014 Mar 31 1u -2 E EE%sT 2015 O 25 1u -2 1 EEST 2015 N 8 1u -2 E EE%sT 2016 S 7 -3 - +03 -Z Europe/Kyiv 2:2:4 - LMT 1880 -2:2:4 - KMT 1924 May 2 -2 - EET 1930 Jun 21 -3 - MSK 1941 S 20 -1 c CE%sT 1943 N 6 -3 R MSK/MSD 1990 Jul 1 2 -2 1 EEST 1991 S 29 3 -2 c EE%sT 1996 May 13 -2 E EE%sT R u 1918 1919 - Mar lastSu 2 1 D R u 1918 1919 - O lastSu 2 0 S R u 1942 o - F 9 2 1 W @@ -2591,172 +1478,34 @@ R u 1976 1986 - Ap lastSu 2 1 D R u 1987 2006 - Ap Su>=1 2 1 D R u 2007 ma - Mar Su>=8 2 1 D R u 2007 ma - N Su>=1 2 0 S -Z EST -5 - EST -Z MST -7 - MST -Z HST -10 - HST -Z EST5EDT -5 u E%sT -Z CST6CDT -6 u C%sT -Z MST7MDT -7 u M%sT -Z PST8PDT -8 u P%sT R NY 1920 o - Mar lastSu 2 1 D R NY 1920 o - O lastSu 2 0 S R NY 1921 1966 - Ap lastSu 2 1 D R NY 1921 1954 - S lastSu 2 0 S R NY 1955 1966 - O lastSu 2 0 S -Z America/New_York -4:56:2 - LMT 1883 N 18 17u --5 u E%sT 1920 --5 NY E%sT 1942 --5 u E%sT 1946 --5 NY E%sT 1967 --5 u E%sT R Ch 1920 o - Jun 13 2 1 D R Ch 1920 1921 - O lastSu 2 0 S R Ch 1921 o - Mar lastSu 2 1 D R Ch 1922 1966 - Ap lastSu 2 1 D R Ch 1922 1954 - S lastSu 2 0 S R Ch 1955 1966 - O lastSu 2 0 S -Z America/Chicago -5:50:36 - LMT 1883 N 18 18u --6 u C%sT 1920 --6 Ch C%sT 1936 Mar 1 2 --5 - EST 1936 N 15 2 --6 Ch C%sT 1942 --6 u C%sT 1946 --6 Ch C%sT 1967 --6 u C%sT -Z America/North_Dakota/Center -6:45:12 - LMT 1883 N 18 19u --7 u M%sT 1992 O 25 2 --6 u C%sT -Z America/North_Dakota/New_Salem -6:45:39 - LMT 1883 N 18 19u --7 u M%sT 2003 O 26 2 --6 u C%sT -Z America/North_Dakota/Beulah -6:47:7 - LMT 1883 N 18 19u --7 u M%sT 2010 N 7 2 --6 u C%sT R De 1920 1921 - Mar lastSu 2 1 D R De 1920 o - O lastSu 2 0 S R De 1921 o - May 22 2 0 S R De 1965 1966 - Ap lastSu 2 1 D R De 1965 1966 - O lastSu 2 0 S -Z America/Denver -6:59:56 - LMT 1883 N 18 19u --7 u M%sT 1920 --7 De M%sT 1942 --7 u M%sT 1946 --7 De M%sT 1967 --7 u M%sT R CA 1948 o - Mar 14 2:1 1 D R CA 1949 o - Ja 1 2 0 S R CA 1950 1966 - Ap lastSu 1 1 D R CA 1950 1961 - S lastSu 2 0 S R CA 1962 1966 - O lastSu 2 0 S -Z America/Los_Angeles -7:52:58 - LMT 1883 N 18 20u --8 u P%sT 1946 --8 CA P%sT 1967 --8 u P%sT -Z America/Juneau 15:2:19 - LMT 1867 O 19 15:33:32 --8:57:41 - LMT 1900 Au 20 12 --8 - PST 1942 --8 u P%sT 1946 --8 - PST 1969 --8 u P%sT 1980 Ap 27 2 --9 u Y%sT 1980 O 26 2 --8 u P%sT 1983 O 30 2 --9 u Y%sT 1983 N 30 --9 u AK%sT -Z America/Sitka 14:58:47 - LMT 1867 O 19 15:30 --9:1:13 - LMT 1900 Au 20 12 --8 - PST 1942 --8 u P%sT 1946 --8 - PST 1969 --8 u P%sT 1983 O 30 2 --9 u Y%sT 1983 N 30 --9 u AK%sT -Z America/Metlakatla 15:13:42 - LMT 1867 O 19 15:44:55 --8:46:18 - LMT 1900 Au 20 12 --8 - PST 1942 --8 u P%sT 1946 --8 - PST 1969 --8 u P%sT 1983 O 30 2 --8 - PST 2015 N 1 2 --9 u AK%sT 2018 N 4 2 --8 - PST 2019 Ja 20 2 --9 u AK%sT -Z America/Yakutat 14:41:5 - LMT 1867 O 19 15:12:18 --9:18:55 - LMT 1900 Au 20 12 --9 - YST 1942 --9 u Y%sT 1946 --9 - YST 1969 --9 u Y%sT 1983 N 30 --9 u AK%sT -Z America/Anchorage 14:0:24 - LMT 1867 O 19 14:31:37 --9:59:36 - LMT 1900 Au 20 12 --10 - AST 1942 --10 u A%sT 1967 Ap --10 - AHST 1969 --10 u AH%sT 1983 O 30 2 --9 u Y%sT 1983 N 30 --9 u AK%sT -Z America/Nome 12:58:22 - LMT 1867 O 19 13:29:35 --11:1:38 - LMT 1900 Au 20 12 --11 - NST 1942 --11 u N%sT 1946 --11 - NST 1967 Ap --11 - BST 1969 --11 u B%sT 1983 O 30 2 --9 u Y%sT 1983 N 30 --9 u AK%sT -Z America/Adak 12:13:22 - LMT 1867 O 19 12:44:35 --11:46:38 - LMT 1900 Au 20 12 --11 - NST 1942 --11 u N%sT 1946 --11 - NST 1967 Ap --11 - BST 1969 --11 u B%sT 1983 O 30 2 --10 u AH%sT 1983 N 30 --10 u H%sT -Z Pacific/Honolulu -10:31:26 - LMT 1896 Ja 13 12 --10:30 - HST 1933 Ap 30 2 --10:30 1 HDT 1933 May 21 12 --10:30 u H%sT 1947 Jun 8 2 --10 - HST -Z America/Phoenix -7:28:18 - LMT 1883 N 18 19u --7 u M%sT 1944 Ja 1 0:1 --7 - MST 1944 Ap 1 0:1 --7 u M%sT 1944 O 1 0:1 --7 - MST 1967 --7 u M%sT 1968 Mar 21 --7 - MST -Z America/Boise -7:44:49 - LMT 1883 N 18 20u --8 u P%sT 1923 May 13 2 --7 u M%sT 1974 --7 - MST 1974 F 3 2 --7 u M%sT R In 1941 o - Jun 22 2 1 D R In 1941 1954 - S lastSu 2 0 S R In 1946 1954 - Ap lastSu 2 1 D -Z America/Indiana/Indianapolis -5:44:38 - LMT 1883 N 18 18u --6 u C%sT 1920 --6 In C%sT 1942 --6 u C%sT 1946 --6 In C%sT 1955 Ap 24 2 --5 - EST 1957 S 29 2 --6 - CST 1958 Ap 27 2 --5 - EST 1969 --5 u E%sT 1971 --5 - EST 2006 --5 u E%sT R Ma 1951 o - Ap lastSu 2 1 D R Ma 1951 o - S lastSu 2 0 S R Ma 1954 1960 - Ap lastSu 2 1 D R Ma 1954 1960 - S lastSu 2 0 S -Z America/Indiana/Marengo -5:45:23 - LMT 1883 N 18 18u --6 u C%sT 1951 --6 Ma C%sT 1961 Ap 30 2 --5 - EST 1969 --5 u E%sT 1974 Ja 6 2 --6 1 CDT 1974 O 27 2 --5 u E%sT 1976 --5 - EST 2006 --5 u E%sT R V 1946 o - Ap lastSu 2 1 D R V 1946 o - S lastSu 2 0 S R V 1953 1954 - Ap lastSu 2 1 D @@ -2766,68 +1515,23 @@ R V 1956 1963 - Ap lastSu 2 1 D R V 1960 o - O lastSu 2 0 S R V 1961 o - S lastSu 2 0 S R V 1962 1963 - O lastSu 2 0 S -Z America/Indiana/Vincennes -5:50:7 - LMT 1883 N 18 18u --6 u C%sT 1946 --6 V C%sT 1964 Ap 26 2 --5 - EST 1969 --5 u E%sT 1971 --5 - EST 2006 Ap 2 2 --6 u C%sT 2007 N 4 2 --5 u E%sT R Pe 1955 o - May 1 0 1 D R Pe 1955 1960 - S lastSu 2 0 S R Pe 1956 1963 - Ap lastSu 2 1 D R Pe 1961 1963 - O lastSu 2 0 S -Z America/Indiana/Tell_City -5:47:3 - LMT 1883 N 18 18u --6 u C%sT 1946 --6 Pe C%sT 1964 Ap 26 2 --5 - EST 1967 O 29 2 --6 u C%sT 1969 Ap 27 2 --5 u E%sT 1971 --5 - EST 2006 Ap 2 2 --6 u C%sT R Pi 1955 o - May 1 0 1 D R Pi 1955 1960 - S lastSu 2 0 S R Pi 1956 1964 - Ap lastSu 2 1 D R Pi 1961 1964 - O lastSu 2 0 S -Z America/Indiana/Petersburg -5:49:7 - LMT 1883 N 18 18u --6 u C%sT 1955 --6 Pi C%sT 1965 Ap 25 2 --5 - EST 1966 O 30 2 --6 u C%sT 1977 O 30 2 --5 - EST 2006 Ap 2 2 --6 u C%sT 2007 N 4 2 --5 u E%sT R St 1947 1961 - Ap lastSu 2 1 D R St 1947 1954 - S lastSu 2 0 S R St 1955 1956 - O lastSu 2 0 S R St 1957 1958 - S lastSu 2 0 S R St 1959 1961 - O lastSu 2 0 S -Z America/Indiana/Knox -5:46:30 - LMT 1883 N 18 18u --6 u C%sT 1947 --6 St C%sT 1962 Ap 29 2 --5 - EST 1963 O 27 2 --6 u C%sT 1991 O 27 2 --5 - EST 2006 Ap 2 2 --6 u C%sT R Pu 1946 1960 - Ap lastSu 2 1 D R Pu 1946 1954 - S lastSu 2 0 S R Pu 1955 1956 - O lastSu 2 0 S R Pu 1957 1960 - S lastSu 2 0 S -Z America/Indiana/Winamac -5:46:25 - LMT 1883 N 18 18u --6 u C%sT 1946 --6 Pu C%sT 1961 Ap 30 2 --5 - EST 1969 --5 u E%sT 1971 --5 - EST 2006 Ap 2 2 --6 u C%sT 2007 Mar 11 2 --5 u E%sT -Z America/Indiana/Vevay -5:40:16 - LMT 1883 N 18 18u --6 u C%sT 1954 Ap 25 2 --5 - EST 1969 --5 u E%sT 1973 --5 - EST 2006 --5 u E%sT R v 1921 o - May 1 2 1 D R v 1921 o - S 1 2 0 S R v 1941 o - Ap lastSu 2 1 D @@ -2837,41 +1541,12 @@ R v 1946 o - Jun 2 2 0 S R v 1950 1961 - Ap lastSu 2 1 D R v 1950 1955 - S lastSu 2 0 S R v 1956 1961 - O lastSu 2 0 S -Z America/Kentucky/Louisville -5:43:2 - LMT 1883 N 18 18u --6 u C%sT 1921 --6 v C%sT 1942 --6 u C%sT 1946 --6 v C%sT 1961 Jul 23 2 --5 - EST 1968 --5 u E%sT 1974 Ja 6 2 --6 1 CDT 1974 O 27 2 --5 u E%sT -Z America/Kentucky/Monticello -5:39:24 - LMT 1883 N 18 18u --6 u C%sT 1946 --6 - CST 1968 --6 u C%sT 2000 O 29 2 --5 u E%sT R Dt 1948 o - Ap lastSu 2 1 D R Dt 1948 o - S lastSu 2 0 S -Z America/Detroit -5:32:11 - LMT 1905 --6 - CST 1915 May 15 2 --5 - EST 1942 --5 u E%sT 1946 --5 Dt E%sT 1967 Jun 14 0:1 --5 u E%sT 1969 --5 - EST 1973 --5 u E%sT 1975 --5 - EST 1975 Ap 27 2 --5 u E%sT R Me 1946 o - Ap lastSu 2 1 D R Me 1946 o - S lastSu 2 0 S R Me 1966 o - Ap lastSu 2 1 D R Me 1966 o - O lastSu 2 0 S -Z America/Menominee -5:50:27 - LMT 1885 S 18 12 --6 u C%sT 1946 --6 Me C%sT 1969 Ap 27 2 --5 - EST 1973 Ap 29 2 --6 u C%sT R C 1918 o - Ap 14 2 1 D R C 1918 o - O 27 2 0 S R C 1942 o - F 9 2 1 W @@ -2901,24 +1576,6 @@ R j 1988 o - Ap Su>=1 0:1 2 DD R j 1989 2006 - Ap Su>=1 0:1 1 D R j 2007 2011 - Mar Su>=8 0:1 1 D R j 2007 2010 - N Su>=1 0:1 0 S -Z America/St_Johns -3:30:52 - LMT 1884 --3:30:52 j N%sT 1918 --3:30:52 C N%sT 1919 --3:30:52 j N%sT 1935 Mar 30 --3:30 j N%sT 1942 May 11 --3:30 C N%sT 1946 --3:30 j N%sT 2011 N --3:30 C N%sT -Z America/Goose_Bay -4:1:40 - LMT 1884 --3:30:52 - NST 1918 --3:30:52 C N%sT 1919 --3:30:52 - NST 1935 Mar 30 --3:30 - NST 1936 --3:30 j N%sT 1942 May 11 --3:30 C N%sT 1946 --3:30 j N%sT 1966 Mar 15 2 --4 j A%sT 2011 N --4 C A%sT R H 1916 o - Ap 1 0 1 D R H 1916 o - O 1 0 0 S R H 1920 o - May 9 0 1 D @@ -2960,19 +1617,6 @@ R H 1956 1959 - Ap lastSu 2 1 D R H 1956 1959 - S lastSu 2 0 S R H 1962 1973 - Ap lastSu 2 1 D R H 1962 1973 - O lastSu 2 0 S -Z America/Halifax -4:14:24 - LMT 1902 Jun 15 --4 H A%sT 1918 --4 C A%sT 1919 --4 H A%sT 1942 F 9 2s --4 C A%sT 1946 --4 H A%sT 1974 --4 C A%sT -Z America/Glace_Bay -3:59:48 - LMT 1902 Jun 15 --4 C A%sT 1953 --4 H A%sT 1954 --4 - AST 1972 --4 H A%sT 1974 --4 C A%sT R o 1933 1935 - Jun Su>=8 1 1 D R o 1933 1935 - S Su>=8 1 0 S R o 1936 1938 - Jun Su>=1 1 1 D @@ -2986,15 +1630,6 @@ R o 1946 1956 - S lastSu 2 0 S R o 1957 1972 - O lastSu 2 0 S R o 1993 2006 - Ap Su>=1 0:1 1 D R o 1993 2006 - O lastSu 0:1 0 S -Z America/Moncton -4:19:8 - LMT 1883 D 9 --5 - EST 1902 Jun 15 --4 C A%sT 1933 --4 o A%sT 1942 --4 C A%sT 1946 --4 o A%sT 1973 --4 C A%sT 1993 --4 o A%sT 2007 --4 C A%sT R t 1919 o - Mar 30 23:30 1 D R t 1919 o - O 26 0 0 S R t 1920 o - May 2 2 1 D @@ -3008,21 +1643,11 @@ R t 1927 1937 - S Su>=25 2 0 S R t 1928 1937 - Ap Su>=25 2 1 D R t 1938 1940 - Ap lastSu 2 1 D R t 1938 1939 - S lastSu 2 0 S -R t 1945 1946 - S lastSu 2 0 S -R t 1946 o - Ap lastSu 2 1 D -R t 1947 1949 - Ap lastSu 0 1 D -R t 1947 1948 - S lastSu 0 0 S -R t 1949 o - N lastSu 0 0 S -R t 1950 1973 - Ap lastSu 2 1 D -R t 1950 o - N lastSu 2 0 S +R t 1945 1948 - S lastSu 2 0 S +R t 1946 1973 - Ap lastSu 2 1 D +R t 1949 1950 - N lastSu 2 0 S R t 1951 1956 - S lastSu 2 0 S R t 1957 1973 - O lastSu 2 0 S -Z America/Toronto -5:17:32 - LMT 1895 --5 C E%sT 1919 --5 t E%sT 1942 F 9 2s --5 C E%sT 1946 --5 t E%sT 1974 --5 C E%sT R W 1916 o - Ap 23 0 1 D R W 1916 o - S 17 0 0 S R W 1918 o - Ap 14 2 1 D @@ -3047,9 +1672,6 @@ R W 1963 o - S 22 2 0 S R W 1966 1986 - Ap lastSu 2s 1 D R W 1966 2005 - O lastSu 2s 0 S R W 1987 2005 - Ap Su>=1 2s 1 D -Z America/Winnipeg -6:28:36 - LMT 1887 Jul 16 --6 W C%sT 2006 --6 C C%sT R r 1918 o - Ap 14 2 1 D R r 1918 o - O 27 2 0 S R r 1930 1934 - May Su>=1 0 1 D @@ -3072,14 +1694,6 @@ R Sw 1957 o - O lastSu 2 0 S R Sw 1959 1961 - Ap lastSu 2 1 D R Sw 1959 o - O lastSu 2 0 S R Sw 1960 1961 - S lastSu 2 0 S -Z America/Regina -6:58:36 - LMT 1905 S --7 r M%sT 1960 Ap lastSu 2 --6 - CST -Z America/Swift_Current -7:11:20 - LMT 1905 S --7 C M%sT 1946 Ap lastSu 2 --7 r M%sT 1950 --7 Sw M%sT 1972 Ap lastSu 2 --6 - CST R Ed 1918 1919 - Ap Su>=8 2 1 D R Ed 1918 o - O 27 2 0 S R Ed 1919 o - May 27 2 0 S @@ -3093,9 +1707,6 @@ R Ed 1947 o - Ap lastSu 2 1 D R Ed 1947 o - S lastSu 2 0 S R Ed 1972 1986 - Ap lastSu 2 1 D R Ed 1972 2006 - O lastSu 2 0 S -Z America/Edmonton -7:33:52 - LMT 1906 S --7 Ed M%sT 1987 --7 C M%sT R Va 1918 o - Ap 14 2 1 D R Va 1918 o - O 27 2 0 S R Va 1942 o - F 9 2 1 W @@ -3105,19 +1716,6 @@ R Va 1946 1986 - Ap lastSu 2 1 D R Va 1946 o - S 29 2 0 S R Va 1947 1961 - S lastSu 2 0 S R Va 1962 2006 - O lastSu 2 0 S -Z America/Vancouver -8:12:28 - LMT 1884 --8 Va P%sT 1987 --8 C P%sT -Z America/Dawson_Creek -8:0:56 - LMT 1884 --8 C P%sT 1947 --8 Va P%sT 1972 Au 30 2 --7 - MST -Z America/Fort_Nelson -8:10:47 - LMT 1884 --8 Va P%sT 1946 --8 - PST 1947 --8 Va P%sT 1987 --8 C P%sT 2015 Mar 8 2 --7 - MST R Y 1918 o - Ap 14 2 1 D R Y 1918 o - O 27 2 0 S R Y 1919 o - May 25 2 1 D @@ -3130,42 +1728,6 @@ R Y 1972 2006 - O lastSu 2 0 S R Y 1987 2006 - Ap Su>=1 2 1 D R Yu 1965 o - Ap lastSu 0 2 DD R Yu 1965 o - O lastSu 2 0 S -Z America/Iqaluit 0 - -00 1942 Au --5 Y E%sT 1999 O 31 2 --6 C C%sT 2000 O 29 2 --5 C E%sT -Z America/Resolute 0 - -00 1947 Au 31 --6 Y C%sT 2000 O 29 2 --5 - EST 2001 Ap 1 3 --6 C C%sT 2006 O 29 2 --5 - EST 2007 Mar 11 3 --6 C C%sT -Z America/Rankin_Inlet 0 - -00 1957 --6 Y C%sT 2000 O 29 2 --5 - EST 2001 Ap 1 3 --6 C C%sT -Z America/Cambridge_Bay 0 - -00 1920 --7 Y M%sT 1999 O 31 2 --6 C C%sT 2000 O 29 2 --5 - EST 2000 N 5 --6 - CST 2001 Ap 1 3 --7 C M%sT -Z America/Inuvik 0 - -00 1953 --8 Y P%sT 1979 Ap lastSu 2 --7 Y M%sT 1980 --7 C M%sT -Z America/Whitehorse -9:0:12 - LMT 1900 Au 20 --9 Y Y%sT 1965 --9 Yu Y%sT 1966 F 27 --8 - PST 1980 --8 C P%sT 2020 N --7 - MST -Z America/Dawson -9:17:40 - LMT 1900 Au 20 --9 Y Y%sT 1965 --9 Yu Y%sT 1973 O 28 --8 - PST 1980 --8 C P%sT 2020 N --7 - MST R m 1931 o - May 1 23 1 D R m 1931 o - O 1 0 0 S R m 1939 o - F 5 0 1 D @@ -3182,107 +1744,6 @@ R m 2001 o - May Su>=1 2 1 D R m 2001 o - S lastSu 2 0 S R m 2002 2022 - Ap Su>=1 2 1 D R m 2002 2022 - O lastSu 2 0 S -Z America/Cancun -5:47:4 - LMT 1922 Ja 1 6u --6 - CST 1981 D 23 --5 m E%sT 1998 Au 2 2 --6 m C%sT 2015 F 1 2 --5 - EST -Z America/Merida -5:58:28 - LMT 1922 Ja 1 6u --6 - CST 1981 D 23 --5 - EST 1982 D 2 --6 m C%sT -Z America/Matamoros -6:30 - LMT 1922 Ja 1 6u --6 - CST 1988 --6 u C%sT 1989 --6 m C%sT 2010 --6 u C%sT -Z America/Monterrey -6:41:16 - LMT 1922 Ja 1 6u --6 - CST 1988 --6 u C%sT 1989 --6 m C%sT -Z America/Mexico_City -6:36:36 - LMT 1922 Ja 1 7u --7 - MST 1927 Jun 10 23 --6 - CST 1930 N 15 --7 m M%sT 1932 Ap --6 m C%sT 2001 S 30 2 --6 - CST 2002 F 20 --6 m C%sT -Z America/Ciudad_Juarez -7:5:56 - LMT 1922 Ja 1 7u --7 - MST 1927 Jun 10 23 --6 - CST 1930 N 15 --7 m M%sT 1932 Ap --6 - CST 1996 --6 m C%sT 1998 --6 - CST 1998 Ap Su>=1 3 --7 m M%sT 2010 --7 u M%sT 2022 O 30 2 --6 - CST 2022 N 30 --7 u M%sT -Z America/Ojinaga -6:57:40 - LMT 1922 Ja 1 7u --7 - MST 1927 Jun 10 23 --6 - CST 1930 N 15 --7 m M%sT 1932 Ap --6 - CST 1996 --6 m C%sT 1998 --6 - CST 1998 Ap Su>=1 3 --7 m M%sT 2010 --7 u M%sT 2022 O 30 2 --6 - CST 2022 N 30 --6 u C%sT -Z America/Chihuahua -7:4:20 - LMT 1922 Ja 1 7u --7 - MST 1927 Jun 10 23 --6 - CST 1930 N 15 --7 m M%sT 1932 Ap --6 - CST 1996 --6 m C%sT 1998 --6 - CST 1998 Ap Su>=1 3 --7 m M%sT 2022 O 30 2 --6 - CST -Z America/Hermosillo -7:23:52 - LMT 1922 Ja 1 7u --7 - MST 1927 Jun 10 23 --6 - CST 1930 N 15 --7 m M%sT 1932 Ap --6 - CST 1942 Ap 24 --7 - MST 1949 Ja 14 --8 - PST 1970 --7 m M%sT 1999 --7 - MST -Z America/Mazatlan -7:5:40 - LMT 1922 Ja 1 7u --7 - MST 1927 Jun 10 23 --6 - CST 1930 N 15 --7 m M%sT 1932 Ap --6 - CST 1942 Ap 24 --7 - MST 1949 Ja 14 --8 - PST 1970 --7 m M%sT -Z America/Bahia_Banderas -7:1 - LMT 1922 Ja 1 7u --7 - MST 1927 Jun 10 23 --6 - CST 1930 N 15 --7 m M%sT 1932 Ap --6 - CST 1942 Ap 24 --7 - MST 1949 Ja 14 --8 - PST 1970 --7 m M%sT 2010 Ap 4 2 --6 m C%sT -Z America/Tijuana -7:48:4 - LMT 1922 Ja 1 7u --7 - MST 1924 --8 - PST 1927 Jun 10 23 --7 - MST 1930 N 15 --8 - PST 1931 Ap --8 1 PDT 1931 S 30 --8 - PST 1942 Ap 24 --8 1 PWT 1945 Au 14 23u --8 1 PPT 1945 N 12 --8 - PST 1948 Ap 5 --8 1 PDT 1949 Ja 14 --8 - PST 1954 --8 CA P%sT 1961 --8 - PST 1976 --8 u P%sT 1996 --8 m P%sT 2001 --8 u P%sT 2002 F 20 --8 m P%sT 2010 --8 u P%sT R BB 1942 o - Ap 19 5u 1 D R BB 1942 o - Au 31 6u 0 S R BB 1943 o - May 2 5u 1 D @@ -3294,10 +1755,6 @@ R BB 1977 1978 - O Su>=1 2 0 S R BB 1978 1980 - Ap Su>=15 2 1 D R BB 1979 o - S 30 2 0 S R BB 1980 o - S 25 2 0 S -Z America/Barbados -3:58:29 - LMT 1911 Au 28 --4 BB A%sT 1944 --4 BB AST/-0330 1945 --4 BB A%sT R BZ 1918 1941 - O Sa>=1 24 0:30 -0530 R BZ 1919 1942 - F Sa>=8 24 0 CST R BZ 1942 o - Jun 27 24 1 CWT @@ -3309,8 +1766,6 @@ R BZ 1973 o - D 5 0 1 CDT R BZ 1974 o - F 9 0 0 CST R BZ 1982 o - D 18 0 1 CDT R BZ 1983 o - F 12 0 0 CST -Z America/Belize -5:52:48 - LMT 1912 Ap --6 BZ %s R Be 1917 o - Ap 5 24 1 - R Be 1917 o - S 30 24 0 - R Be 1918 o - Ap 13 24 1 - @@ -3327,19 +1782,11 @@ R Be 1948 1952 - May Su>=22 2 1 D R Be 1948 1952 - S Su>=1 2 0 S R Be 1956 o - May Su>=22 2 1 D R Be 1956 o - O lastSu 2 0 S -Z Atlantic/Bermuda -4:19:18 - LMT 1890 --4:19:18 Be BMT/BST 1930 Ja 1 2 --4 Be A%sT 1974 Ap 28 2 --4 C A%sT 1976 --4 u A%sT R CR 1979 1980 - F lastSu 0 1 D R CR 1979 1980 - Jun Su>=1 0 0 S R CR 1991 1992 - Ja Sa>=15 0 1 D R CR 1991 o - Jul 1 0 0 S R CR 1992 o - Mar 15 0 0 S -Z America/Costa_Rica -5:36:13 - LMT 1890 --5:36:13 - SJMT 1921 Ja 15 --6 CR C%sT R Q 1928 o - Jun 10 0 1 D R Q 1928 o - O 10 0 0 S R Q 1940 1942 - Jun Su>=1 0 1 D @@ -3379,25 +1826,14 @@ R Q 2011 o - N 13 0s 0 S R Q 2012 o - Ap 1 0s 1 D R Q 2012 ma - N Su>=1 0s 0 S R Q 2013 ma - Mar Su>=8 0s 1 D -Z America/Havana -5:29:28 - LMT 1890 --5:29:36 - HMT 1925 Jul 19 12 --5 Q C%sT R DO 1966 o - O 30 0 1 EDT R DO 1967 o - F 28 0 0 EST R DO 1969 1973 - O lastSu 0 0:30 -0430 R DO 1970 o - F 21 0 0 EST R DO 1971 o - Ja 20 0 0 EST R DO 1972 1974 - Ja 21 0 0 EST -Z America/Santo_Domingo -4:39:36 - LMT 1890 --4:40 - SDMT 1933 Ap 1 12 --5 DO %s 1974 O 27 --4 - AST 2000 O 29 2 --5 u E%sT 2000 D 3 1 --4 - AST R SV 1987 1988 - May Su>=1 0 1 D R SV 1987 1988 - S lastSu 0 0 S -Z America/El_Salvador -5:56:48 - LMT 1921 --6 SV C%sT R GT 1973 o - N 25 0 1 D R GT 1974 o - F 24 0 0 S R GT 1983 o - May 21 0 1 D @@ -3406,8 +1842,6 @@ R GT 1991 o - Mar 23 0 1 D R GT 1991 o - S 7 0 0 S R GT 2006 o - Ap 30 0 1 D R GT 2006 o - O 1 0 0 S -Z America/Guatemala -6:2:4 - LMT 1918 O 5 --6 GT C%sT R HT 1983 o - May 8 0 1 D R HT 1984 1987 - Ap lastSu 0 1 D R HT 1983 1987 - O lastSu 0 0 S @@ -3419,57 +1853,16 @@ R HT 2012 2015 - Mar Su>=8 2 1 D R HT 2012 2015 - N Su>=1 2 0 S R HT 2017 ma - Mar Su>=8 2 1 D R HT 2017 ma - N Su>=1 2 0 S -Z America/Port-au-Prince -4:49:20 - LMT 1890 --4:49 - PPMT 1917 Ja 24 12 --5 HT E%sT R HN 1987 1988 - May Su>=1 0 1 D R HN 1987 1988 - S lastSu 0 0 S R HN 2006 o - May Su>=1 0 1 D R HN 2006 o - Au M>=1 0 0 S -Z America/Tegucigalpa -5:48:52 - LMT 1921 Ap --6 HN C%sT -Z America/Jamaica -5:7:10 - LMT 1890 --5:7:10 - KMT 1912 F --5 - EST 1974 --5 u E%sT 1984 --5 - EST -Z America/Martinique -4:4:20 - LMT 1890 --4:4:20 - FFMT 1911 May --4 - AST 1980 Ap 6 --4 1 ADT 1980 S 28 --4 - AST R NI 1979 1980 - Mar Su>=16 0 1 D R NI 1979 1980 - Jun M>=23 0 0 S R NI 2005 o - Ap 10 0 1 D R NI 2005 o - O Su>=1 0 0 S R NI 2006 o - Ap 30 2 1 D R NI 2006 o - O Su>=1 1 0 S -Z America/Managua -5:45:8 - LMT 1890 --5:45:12 - MMT 1934 Jun 23 --6 - CST 1973 May --5 - EST 1975 F 16 --6 NI C%sT 1992 Ja 1 4 --5 - EST 1992 S 24 --6 - CST 1993 --5 - EST 1997 --6 NI C%sT -Z America/Panama -5:18:8 - LMT 1890 --5:19:36 - CMT 1908 Ap 22 --5 - EST -Z America/Puerto_Rico -4:24:25 - LMT 1899 Mar 28 12 --4 - AST 1942 May 3 --4 u A%sT 1946 --4 - AST -Z America/Miquelon -3:44:40 - LMT 1911 May 15 --4 - AST 1980 May --3 - -03 1987 --3 C -03/-02 -Z America/Grand_Turk -4:44:32 - LMT 1890 --5:7:10 - KMT 1912 F --5 - EST 1979 --5 u E%sT 2015 Mar 8 2 --4 - AST 2018 Mar 11 3 --5 u E%sT R A 1930 o - D 1 0 1 - R A 1931 o - Ap 1 0 0 - R A 1931 o - O 15 0 1 - @@ -3499,150 +1892,8 @@ R A 2000 o - Mar 3 0 0 - R A 2007 o - D 30 0 1 - R A 2008 2009 - Mar Su>=15 0 0 - R A 2008 o - O Su>=15 0 1 - -Z America/Argentina/Buenos_Aires -3:53:48 - LMT 1894 O 31 --4:16:48 - CMT 1920 May --4 - -04 1930 D --4 A -04/-03 1969 O 5 --3 A -03/-02 1999 O 3 --4 A -04/-03 2000 Mar 3 --3 A -03/-02 -Z America/Argentina/Cordoba -4:16:48 - LMT 1894 O 31 --4:16:48 - CMT 1920 May --4 - -04 1930 D --4 A -04/-03 1969 O 5 --3 A -03/-02 1991 Mar 3 --4 - -04 1991 O 20 --3 A -03/-02 1999 O 3 --4 A -04/-03 2000 Mar 3 --3 A -03/-02 -Z America/Argentina/Salta -4:21:40 - LMT 1894 O 31 --4:16:48 - CMT 1920 May --4 - -04 1930 D --4 A -04/-03 1969 O 5 --3 A -03/-02 1991 Mar 3 --4 - -04 1991 O 20 --3 A -03/-02 1999 O 3 --4 A -04/-03 2000 Mar 3 --3 A -03/-02 2008 O 18 --3 - -03 -Z America/Argentina/Tucuman -4:20:52 - LMT 1894 O 31 --4:16:48 - CMT 1920 May --4 - -04 1930 D --4 A -04/-03 1969 O 5 --3 A -03/-02 1991 Mar 3 --4 - -04 1991 O 20 --3 A -03/-02 1999 O 3 --4 A -04/-03 2000 Mar 3 --3 - -03 2004 Jun --4 - -04 2004 Jun 13 --3 A -03/-02 -Z America/Argentina/La_Rioja -4:27:24 - LMT 1894 O 31 --4:16:48 - CMT 1920 May --4 - -04 1930 D --4 A -04/-03 1969 O 5 --3 A -03/-02 1991 Mar --4 - -04 1991 May 7 --3 A -03/-02 1999 O 3 --4 A -04/-03 2000 Mar 3 --3 - -03 2004 Jun --4 - -04 2004 Jun 20 --3 A -03/-02 2008 O 18 --3 - -03 -Z America/Argentina/San_Juan -4:34:4 - LMT 1894 O 31 --4:16:48 - CMT 1920 May --4 - -04 1930 D --4 A -04/-03 1969 O 5 --3 A -03/-02 1991 Mar --4 - -04 1991 May 7 --3 A -03/-02 1999 O 3 --4 A -04/-03 2000 Mar 3 --3 - -03 2004 May 31 --4 - -04 2004 Jul 25 --3 A -03/-02 2008 O 18 --3 - -03 -Z America/Argentina/Jujuy -4:21:12 - LMT 1894 O 31 --4:16:48 - CMT 1920 May --4 - -04 1930 D --4 A -04/-03 1969 O 5 --3 A -03/-02 1990 Mar 4 --4 - -04 1990 O 28 --4 1 -03 1991 Mar 17 --4 - -04 1991 O 6 --3 1 -02 1992 --3 A -03/-02 1999 O 3 --4 A -04/-03 2000 Mar 3 --3 A -03/-02 2008 O 18 --3 - -03 -Z America/Argentina/Catamarca -4:23:8 - LMT 1894 O 31 --4:16:48 - CMT 1920 May --4 - -04 1930 D --4 A -04/-03 1969 O 5 --3 A -03/-02 1991 Mar 3 --4 - -04 1991 O 20 --3 A -03/-02 1999 O 3 --4 A -04/-03 2000 Mar 3 --3 - -03 2004 Jun --4 - -04 2004 Jun 20 --3 A -03/-02 2008 O 18 --3 - -03 -Z America/Argentina/Mendoza -4:35:16 - LMT 1894 O 31 --4:16:48 - CMT 1920 May --4 - -04 1930 D --4 A -04/-03 1969 O 5 --3 A -03/-02 1990 Mar 4 --4 - -04 1990 O 15 --4 1 -03 1991 Mar --4 - -04 1991 O 15 --4 1 -03 1992 Mar --4 - -04 1992 O 18 --3 A -03/-02 1999 O 3 --4 A -04/-03 2000 Mar 3 --3 - -03 2004 May 23 --4 - -04 2004 S 26 --3 A -03/-02 2008 O 18 --3 - -03 R Sa 2008 2009 - Mar Su>=8 0 0 - R Sa 2007 2008 - O Su>=8 0 1 - -Z America/Argentina/San_Luis -4:25:24 - LMT 1894 O 31 --4:16:48 - CMT 1920 May --4 - -04 1930 D --4 A -04/-03 1969 O 5 --3 A -03/-02 1990 --3 1 -02 1990 Mar 14 --4 - -04 1990 O 15 --4 1 -03 1991 Mar --4 - -04 1991 Jun --3 - -03 1999 O 3 --4 1 -03 2000 Mar 3 --3 - -03 2004 May 31 --4 - -04 2004 Jul 25 --3 A -03/-02 2008 Ja 21 --4 Sa -04/-03 2009 O 11 --3 - -03 -Z America/Argentina/Rio_Gallegos -4:36:52 - LMT 1894 O 31 --4:16:48 - CMT 1920 May --4 - -04 1930 D --4 A -04/-03 1969 O 5 --3 A -03/-02 1999 O 3 --4 A -04/-03 2000 Mar 3 --3 - -03 2004 Jun --4 - -04 2004 Jun 20 --3 A -03/-02 2008 O 18 --3 - -03 -Z America/Argentina/Ushuaia -4:33:12 - LMT 1894 O 31 --4:16:48 - CMT 1920 May --4 - -04 1930 D --4 A -04/-03 1969 O 5 --3 A -03/-02 1999 O 3 --4 A -04/-03 2000 Mar 3 --3 - -03 2004 May 30 --4 - -04 2004 Jun 20 --3 A -03/-02 2008 O 18 --3 - -03 -Z America/La_Paz -4:32:36 - LMT 1890 --4:32:36 - CMT 1931 O 15 --4:32:36 1 BST 1932 Mar 21 --4 - -04 R B 1931 o - O 3 11 1 - R B 1932 1933 - Ap 1 0 0 - R B 1932 o - O 3 0 1 - @@ -3700,90 +1951,6 @@ R B 2013 2014 - F Su>=15 0 0 - R B 2015 o - F Su>=22 0 0 - R B 2016 2019 - F Su>=15 0 0 - R B 2018 o - N Su>=1 0 1 - -Z America/Noronha -2:9:40 - LMT 1914 --2 B -02/-01 1990 S 17 --2 - -02 1999 S 30 --2 B -02/-01 2000 O 15 --2 - -02 2001 S 13 --2 B -02/-01 2002 O --2 - -02 -Z America/Belem -3:13:56 - LMT 1914 --3 B -03/-02 1988 S 12 --3 - -03 -Z America/Santarem -3:38:48 - LMT 1914 --4 B -04/-03 1988 S 12 --4 - -04 2008 Jun 24 --3 - -03 -Z America/Fortaleza -2:34 - LMT 1914 --3 B -03/-02 1990 S 17 --3 - -03 1999 S 30 --3 B -03/-02 2000 O 22 --3 - -03 2001 S 13 --3 B -03/-02 2002 O --3 - -03 -Z America/Recife -2:19:36 - LMT 1914 --3 B -03/-02 1990 S 17 --3 - -03 1999 S 30 --3 B -03/-02 2000 O 15 --3 - -03 2001 S 13 --3 B -03/-02 2002 O --3 - -03 -Z America/Araguaina -3:12:48 - LMT 1914 --3 B -03/-02 1990 S 17 --3 - -03 1995 S 14 --3 B -03/-02 2003 S 24 --3 - -03 2012 O 21 --3 B -03/-02 2013 S --3 - -03 -Z America/Maceio -2:22:52 - LMT 1914 --3 B -03/-02 1990 S 17 --3 - -03 1995 O 13 --3 B -03/-02 1996 S 4 --3 - -03 1999 S 30 --3 B -03/-02 2000 O 22 --3 - -03 2001 S 13 --3 B -03/-02 2002 O --3 - -03 -Z America/Bahia -2:34:4 - LMT 1914 --3 B -03/-02 2003 S 24 --3 - -03 2011 O 16 --3 B -03/-02 2012 O 21 --3 - -03 -Z America/Sao_Paulo -3:6:28 - LMT 1914 --3 B -03/-02 1963 O 23 --3 1 -02 1964 --3 B -03/-02 -Z America/Campo_Grande -3:38:28 - LMT 1914 --4 B -04/-03 -Z America/Cuiaba -3:44:20 - LMT 1914 --4 B -04/-03 2003 S 24 --4 - -04 2004 O --4 B -04/-03 -Z America/Porto_Velho -4:15:36 - LMT 1914 --4 B -04/-03 1988 S 12 --4 - -04 -Z America/Boa_Vista -4:2:40 - LMT 1914 --4 B -04/-03 1988 S 12 --4 - -04 1999 S 30 --4 B -04/-03 2000 O 15 --4 - -04 -Z America/Manaus -4:0:4 - LMT 1914 --4 B -04/-03 1988 S 12 --4 - -04 1993 S 28 --4 B -04/-03 1994 S 22 --4 - -04 -Z America/Eirunepe -4:39:28 - LMT 1914 --5 B -05/-04 1988 S 12 --5 - -05 1993 S 28 --5 B -05/-04 1994 S 22 --5 - -05 2008 Jun 24 --4 - -04 2013 N 10 --5 - -05 -Z America/Rio_Branco -4:31:12 - LMT 1914 --5 B -05/-04 1988 S 12 --5 - -05 2008 Jun 24 --4 - -04 2013 N 10 --5 - -05 R x 1927 1931 - S 1 0 1 - R x 1928 1932 - Ap 1 0 0 - R x 1968 o - N 3 4u 1 - @@ -3820,56 +1987,10 @@ R x 2019 ma - Ap Su>=2 3u 0 - R x 2019 2021 - S Su>=2 4u 1 - R x 2022 o - S Su>=9 4u 1 - R x 2023 ma - S Su>=2 4u 1 - -Z America/Santiago -4:42:45 - LMT 1890 --4:42:45 - SMT 1910 Ja 10 --5 - -05 1916 Jul --4:42:45 - SMT 1918 S 10 --4 - -04 1919 Jul --4:42:45 - SMT 1927 S --5 x -05/-04 1932 S --4 - -04 1942 Jun --5 - -05 1942 Au --4 - -04 1946 Jul 14 24 --4 1 -03 1946 Au 28 24 --5 1 -04 1947 Mar 31 24 --5 - -05 1947 May 21 23 --4 x -04/-03 -Z America/Punta_Arenas -4:43:40 - LMT 1890 --4:42:45 - SMT 1910 Ja 10 --5 - -05 1916 Jul --4:42:45 - SMT 1918 S 10 --4 - -04 1919 Jul --4:42:45 - SMT 1927 S --5 x -05/-04 1932 S --4 - -04 1942 Jun --5 - -05 1942 Au --4 - -04 1946 Au 28 24 --5 1 -04 1947 Mar 31 24 --5 - -05 1947 May 21 23 --4 x -04/-03 2016 D 4 --3 - -03 -Z Pacific/Easter -7:17:28 - LMT 1890 --7:17:28 - EMT 1932 S --7 x -07/-06 1982 Mar 14 3u --6 x -06/-05 -Z Antarctica/Palmer 0 - -00 1965 --4 A -04/-03 1969 O 5 --3 A -03/-02 1982 May --4 x -04/-03 2016 D 4 --3 - -03 R CO 1992 o - May 3 0 1 - R CO 1993 o - F 6 24 0 - -Z America/Bogota -4:56:16 - LMT 1884 Mar 13 --4:56:16 - BMT 1914 N 23 --5 CO -05/-04 R EC 1992 o - N 28 0 1 - R EC 1993 o - F 5 0 0 - -Z America/Guayaquil -5:19:20 - LMT 1890 --5:14 - QMT 1931 --5 EC -05/-04 -Z Pacific/Galapagos -5:58:24 - LMT 1931 --5 - -05 1986 --6 EC -06/-05 R FK 1937 1938 - S lastSu 0 1 - R FK 1938 1942 - Mar Su>=19 0 0 - R FK 1939 o - O 1 0 1 - @@ -3882,20 +2003,6 @@ R FK 1985 2000 - S Su>=9 0 1 - R FK 1986 2000 - Ap Su>=16 0 0 - R FK 2001 2010 - Ap Su>=15 2 0 - R FK 2001 2010 - S Su>=1 2 1 - -Z Atlantic/Stanley -3:51:24 - LMT 1890 --3:51:24 - SMT 1912 Mar 12 --4 FK -04/-03 1983 May --3 FK -03/-02 1985 S 15 --4 FK -04/-03 2010 S 5 2 --3 - -03 -Z America/Cayenne -3:29:20 - LMT 1911 Jul --4 - -04 1967 O --3 - -03 -Z America/Guyana -3:52:39 - LMT 1911 Au --4 - -04 1915 Mar --3:45 - -0345 1975 Au --3 - -03 1992 Mar 29 1 --4 - -04 R y 1975 1988 - O 1 0 1 - R y 1975 1978 - Mar 1 0 0 - R y 1979 1991 - Ap 1 0 0 - @@ -3918,11 +2025,6 @@ R y 2005 2009 - Mar Su>=8 0 0 - R y 2010 ma - O Su>=1 0 1 - R y 2010 2012 - Ap Su>=8 0 0 - R y 2013 ma - Mar Su>=22 0 0 - -Z America/Asuncion -3:50:40 - LMT 1890 --3:50:40 - AMT 1931 O 10 --4 - -04 1972 O --3 - -03 1974 Ap --4 y -04/-03 R PE 1938 o - Ja 1 0 1 - R PE 1938 o - Ap 1 0 0 - R PE 1938 1939 - S lastSu 0 1 - @@ -3933,16 +2035,6 @@ R PE 1990 o - Ja 1 0 1 - R PE 1990 o - Ap 1 0 0 - R PE 1994 o - Ja 1 0 1 - R PE 1994 o - Ap 1 0 0 - -Z America/Lima -5:8:12 - LMT 1890 --5:8:36 - LMT 1908 Jul 28 --5 PE -05/-04 -Z Atlantic/South_Georgia -2:26:8 - LMT 1890 --2 - -02 -Z America/Paramaribo -3:40:40 - LMT 1911 --3:40:52 - PMT 1935 --3:40:36 - PMT 1945 O --3:30 - -0330 1984 O --3 - -03 R U 1923 1925 - O 1 0 0:30 - R U 1924 1926 - Ap 1 0 0 - R U 1933 1938 - O lastSu 0 0:30 - @@ -3991,6 +2083,659 @@ R U 2005 o - Mar 27 2 0 - R U 2005 o - O 9 2 1 - R U 2006 2015 - Mar Su>=8 2 0 - R U 2006 2014 - O Su>=1 2 1 - +Z Africa/Abidjan -0:16:8 - LMT 1912 +0 - GMT +Z Africa/Algiers 0:12:12 - LMT 1891 Mar 16 +0:9:21 - PMT 1911 Mar 11 +0 d WE%sT 1940 F 25 2 +1 d CE%sT 1946 O 7 +0 - WET 1956 Ja 29 +1 - CET 1963 Ap 14 +0 d WE%sT 1977 O 21 +1 d CE%sT 1979 O 26 +0 d WE%sT 1981 May +1 - CET +Z Africa/Bissau -1:2:20 - LMT 1912 Ja 1 1u +-1 - -01 1975 +0 - GMT +Z Africa/Cairo 2:5:9 - LMT 1900 O +2 K EE%sT +Z Africa/Casablanca -0:30:20 - LMT 1913 O 26 +0 M +00/+01 1984 Mar 16 +1 - +01 1986 +0 M +00/+01 2018 O 28 3 +1 M +01/+00 +Z Africa/Ceuta -0:21:16 - LMT 1901 Ja 1 0u +0 - WET 1918 May 6 23 +0 1 WEST 1918 O 7 23 +0 - WET 1924 +0 s WE%sT 1929 +0 - WET 1967 +0 Sp WE%sT 1984 Mar 16 +1 - CET 1986 +1 E CE%sT +Z Africa/El_Aaiun -0:52:48 - LMT 1934 +-1 - -01 1976 Ap 14 +0 M +00/+01 2018 O 28 3 +1 M +01/+00 +Z Africa/Johannesburg 1:52 - LMT 1892 F 8 +1:30 - SAST 1903 Mar +2 SA SAST +Z Africa/Juba 2:6:28 - LMT 1931 +2 SD CA%sT 2000 Ja 15 12 +3 - EAT 2021 F +2 - CAT +Z Africa/Khartoum 2:10:8 - LMT 1931 +2 SD CA%sT 2000 Ja 15 12 +3 - EAT 2017 N +2 - CAT +Z Africa/Lagos 0:13:35 - LMT 1905 Jul +0 - GMT 1908 Jul +0:13:35 - LMT 1914 +0:30 - +0030 1919 S +1 - WAT +Z Africa/Maputo 2:10:20 - LMT 1903 Mar +2 - CAT +Z Africa/Monrovia -0:43:8 - LMT 1882 +-0:43:8 - MMT 1919 Mar +-0:44:30 - MMT 1972 Ja 7 +0 - GMT +Z Africa/Nairobi 2:27:16 - LMT 1908 May +2:30 - +0230 1928 Jun 30 24 +3 - EAT 1930 Ja 4 24 +2:30 - +0230 1936 D 31 24 +2:45 - +0245 1942 Jul 31 24 +3 - EAT +Z Africa/Ndjamena 1:0:12 - LMT 1912 +1 - WAT 1979 O 14 +1 1 WAST 1980 Mar 8 +1 - WAT +Z Africa/Sao_Tome 0:26:56 - LMT 1884 +-0:36:45 - LMT 1912 Ja 1 0u +0 - GMT 2018 Ja 1 1 +1 - WAT 2019 Ja 1 2 +0 - GMT +Z Africa/Tripoli 0:52:44 - LMT 1920 +1 L CE%sT 1959 +2 - EET 1982 +1 L CE%sT 1990 May 4 +2 - EET 1996 S 30 +1 L CE%sT 1997 O 4 +2 - EET 2012 N 10 2 +1 L CE%sT 2013 O 25 2 +2 - EET +Z Africa/Tunis 0:40:44 - LMT 1881 May 12 +0:9:21 - PMT 1911 Mar 11 +1 n CE%sT +Z Africa/Windhoek 1:8:24 - LMT 1892 F 8 +1:30 - +0130 1903 Mar +2 - SAST 1942 S 20 2 +2 1 SAST 1943 Mar 21 2 +2 - SAST 1990 Mar 21 +2 NA %s +Z America/Adak 12:13:22 - LMT 1867 O 19 12:44:35 +-11:46:38 - LMT 1900 Au 20 12 +-11 - NST 1942 +-11 u N%sT 1946 +-11 - NST 1967 Ap +-11 - BST 1969 +-11 u B%sT 1983 O 30 2 +-10 u AH%sT 1983 N 30 +-10 u H%sT +Z America/Anchorage 14:0:24 - LMT 1867 O 19 14:31:37 +-9:59:36 - LMT 1900 Au 20 12 +-10 - AST 1942 +-10 u A%sT 1967 Ap +-10 - AHST 1969 +-10 u AH%sT 1983 O 30 2 +-9 u Y%sT 1983 N 30 +-9 u AK%sT +Z America/Araguaina -3:12:48 - LMT 1914 +-3 B -03/-02 1990 S 17 +-3 - -03 1995 S 14 +-3 B -03/-02 2003 S 24 +-3 - -03 2012 O 21 +-3 B -03/-02 2013 S +-3 - -03 +Z America/Argentina/Buenos_Aires -3:53:48 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1999 O 3 +-4 A -04/-03 2000 Mar 3 +-3 A -03/-02 +Z America/Argentina/Catamarca -4:23:8 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1991 Mar 3 +-4 - -04 1991 O 20 +-3 A -03/-02 1999 O 3 +-4 A -04/-03 2000 Mar 3 +-3 - -03 2004 Jun +-4 - -04 2004 Jun 20 +-3 A -03/-02 2008 O 18 +-3 - -03 +Z America/Argentina/Cordoba -4:16:48 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1991 Mar 3 +-4 - -04 1991 O 20 +-3 A -03/-02 1999 O 3 +-4 A -04/-03 2000 Mar 3 +-3 A -03/-02 +Z America/Argentina/Jujuy -4:21:12 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1990 Mar 4 +-4 - -04 1990 O 28 +-4 1 -03 1991 Mar 17 +-4 - -04 1991 O 6 +-3 1 -02 1992 +-3 A -03/-02 1999 O 3 +-4 A -04/-03 2000 Mar 3 +-3 A -03/-02 2008 O 18 +-3 - -03 +Z America/Argentina/La_Rioja -4:27:24 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1991 Mar +-4 - -04 1991 May 7 +-3 A -03/-02 1999 O 3 +-4 A -04/-03 2000 Mar 3 +-3 - -03 2004 Jun +-4 - -04 2004 Jun 20 +-3 A -03/-02 2008 O 18 +-3 - -03 +Z America/Argentina/Mendoza -4:35:16 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1990 Mar 4 +-4 - -04 1990 O 15 +-4 1 -03 1991 Mar +-4 - -04 1991 O 15 +-4 1 -03 1992 Mar +-4 - -04 1992 O 18 +-3 A -03/-02 1999 O 3 +-4 A -04/-03 2000 Mar 3 +-3 - -03 2004 May 23 +-4 - -04 2004 S 26 +-3 A -03/-02 2008 O 18 +-3 - -03 +Z America/Argentina/Rio_Gallegos -4:36:52 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1999 O 3 +-4 A -04/-03 2000 Mar 3 +-3 - -03 2004 Jun +-4 - -04 2004 Jun 20 +-3 A -03/-02 2008 O 18 +-3 - -03 +Z America/Argentina/Salta -4:21:40 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1991 Mar 3 +-4 - -04 1991 O 20 +-3 A -03/-02 1999 O 3 +-4 A -04/-03 2000 Mar 3 +-3 A -03/-02 2008 O 18 +-3 - -03 +Z America/Argentina/San_Juan -4:34:4 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1991 Mar +-4 - -04 1991 May 7 +-3 A -03/-02 1999 O 3 +-4 A -04/-03 2000 Mar 3 +-3 - -03 2004 May 31 +-4 - -04 2004 Jul 25 +-3 A -03/-02 2008 O 18 +-3 - -03 +Z America/Argentina/San_Luis -4:25:24 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1990 +-3 1 -02 1990 Mar 14 +-4 - -04 1990 O 15 +-4 1 -03 1991 Mar +-4 - -04 1991 Jun +-3 - -03 1999 O 3 +-4 1 -03 2000 Mar 3 +-3 - -03 2004 May 31 +-4 - -04 2004 Jul 25 +-3 A -03/-02 2008 Ja 21 +-4 Sa -04/-03 2009 O 11 +-3 - -03 +Z America/Argentina/Tucuman -4:20:52 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1991 Mar 3 +-4 - -04 1991 O 20 +-3 A -03/-02 1999 O 3 +-4 A -04/-03 2000 Mar 3 +-3 - -03 2004 Jun +-4 - -04 2004 Jun 13 +-3 A -03/-02 +Z America/Argentina/Ushuaia -4:33:12 - LMT 1894 O 31 +-4:16:48 - CMT 1920 May +-4 - -04 1930 D +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1999 O 3 +-4 A -04/-03 2000 Mar 3 +-3 - -03 2004 May 30 +-4 - -04 2004 Jun 20 +-3 A -03/-02 2008 O 18 +-3 - -03 +Z America/Asuncion -3:50:40 - LMT 1890 +-3:50:40 - AMT 1931 O 10 +-4 - -04 1972 O +-3 - -03 1974 Ap +-4 y -04/-03 +Z America/Bahia -2:34:4 - LMT 1914 +-3 B -03/-02 2003 S 24 +-3 - -03 2011 O 16 +-3 B -03/-02 2012 O 21 +-3 - -03 +Z America/Bahia_Banderas -7:1 - LMT 1922 Ja 1 7u +-7 - MST 1927 Jun 10 23 +-6 - CST 1930 N 15 +-7 m M%sT 1932 Ap +-6 - CST 1942 Ap 24 +-7 - MST 1949 Ja 14 +-8 - PST 1970 +-7 m M%sT 2010 Ap 4 2 +-6 m C%sT +Z America/Barbados -3:58:29 - LMT 1911 Au 28 +-4 BB A%sT 1944 +-4 BB AST/-0330 1945 +-4 BB A%sT +Z America/Belem -3:13:56 - LMT 1914 +-3 B -03/-02 1988 S 12 +-3 - -03 +Z America/Belize -5:52:48 - LMT 1912 Ap +-6 BZ %s +Z America/Boa_Vista -4:2:40 - LMT 1914 +-4 B -04/-03 1988 S 12 +-4 - -04 1999 S 30 +-4 B -04/-03 2000 O 15 +-4 - -04 +Z America/Bogota -4:56:16 - LMT 1884 Mar 13 +-4:56:16 - BMT 1914 N 23 +-5 CO -05/-04 +Z America/Boise -7:44:49 - LMT 1883 N 18 20u +-8 u P%sT 1923 May 13 2 +-7 u M%sT 1974 +-7 - MST 1974 F 3 2 +-7 u M%sT +Z America/Cambridge_Bay 0 - -00 1920 +-7 Y M%sT 1999 O 31 2 +-6 C C%sT 2000 O 29 2 +-5 - EST 2000 N 5 +-6 - CST 2001 Ap 1 3 +-7 C M%sT +Z America/Campo_Grande -3:38:28 - LMT 1914 +-4 B -04/-03 +Z America/Cancun -5:47:4 - LMT 1922 Ja 1 6u +-6 - CST 1981 D 23 +-5 m E%sT 1998 Au 2 2 +-6 m C%sT 2015 F 1 2 +-5 - EST +Z America/Caracas -4:27:44 - LMT 1890 +-4:27:40 - CMT 1912 F 12 +-4:30 - -0430 1965 +-4 - -04 2007 D 9 3 +-4:30 - -0430 2016 May 1 2:30 +-4 - -04 +Z America/Cayenne -3:29:20 - LMT 1911 Jul +-4 - -04 1967 O +-3 - -03 +Z America/Chicago -5:50:36 - LMT 1883 N 18 18u +-6 u C%sT 1920 +-6 Ch C%sT 1936 Mar 1 2 +-5 - EST 1936 N 15 2 +-6 Ch C%sT 1942 +-6 u C%sT 1946 +-6 Ch C%sT 1967 +-6 u C%sT +Z America/Chihuahua -7:4:20 - LMT 1922 Ja 1 7u +-7 - MST 1927 Jun 10 23 +-6 - CST 1930 N 15 +-7 m M%sT 1932 Ap +-6 - CST 1996 +-6 m C%sT 1998 +-6 - CST 1998 Ap Su>=1 3 +-7 m M%sT 2022 O 30 2 +-6 - CST +Z America/Ciudad_Juarez -7:5:56 - LMT 1922 Ja 1 7u +-7 - MST 1927 Jun 10 23 +-6 - CST 1930 N 15 +-7 m M%sT 1932 Ap +-6 - CST 1996 +-6 m C%sT 1998 +-6 - CST 1998 Ap Su>=1 3 +-7 m M%sT 2010 +-7 u M%sT 2022 O 30 2 +-6 - CST 2022 N 30 +-7 u M%sT +Z America/Costa_Rica -5:36:13 - LMT 1890 +-5:36:13 - SJMT 1921 Ja 15 +-6 CR C%sT +Z America/Cuiaba -3:44:20 - LMT 1914 +-4 B -04/-03 2003 S 24 +-4 - -04 2004 O +-4 B -04/-03 +Z America/Danmarkshavn -1:14:40 - LMT 1916 Jul 28 +-3 - -03 1980 Ap 6 2 +-3 E -03/-02 1996 +0 - GMT +Z America/Dawson -9:17:40 - LMT 1900 Au 20 +-9 Y Y%sT 1965 +-9 Yu Y%sT 1973 O 28 +-8 - PST 1980 +-8 C P%sT 2020 N +-7 - MST +Z America/Dawson_Creek -8:0:56 - LMT 1884 +-8 C P%sT 1947 +-8 Va P%sT 1972 Au 30 2 +-7 - MST +Z America/Denver -6:59:56 - LMT 1883 N 18 19u +-7 u M%sT 1920 +-7 De M%sT 1942 +-7 u M%sT 1946 +-7 De M%sT 1967 +-7 u M%sT +Z America/Detroit -5:32:11 - LMT 1905 +-6 - CST 1915 May 15 2 +-5 - EST 1942 +-5 u E%sT 1946 +-5 Dt E%sT 1967 Jun 14 0:1 +-5 u E%sT 1969 +-5 - EST 1973 +-5 u E%sT 1975 +-5 - EST 1975 Ap 27 2 +-5 u E%sT +Z America/Edmonton -7:33:52 - LMT 1906 S +-7 Ed M%sT 1987 +-7 C M%sT +Z America/Eirunepe -4:39:28 - LMT 1914 +-5 B -05/-04 1988 S 12 +-5 - -05 1993 S 28 +-5 B -05/-04 1994 S 22 +-5 - -05 2008 Jun 24 +-4 - -04 2013 N 10 +-5 - -05 +Z America/El_Salvador -5:56:48 - LMT 1921 +-6 SV C%sT +Z America/Fort_Nelson -8:10:47 - LMT 1884 +-8 Va P%sT 1946 +-8 - PST 1947 +-8 Va P%sT 1987 +-8 C P%sT 2015 Mar 8 2 +-7 - MST +Z America/Fortaleza -2:34 - LMT 1914 +-3 B -03/-02 1990 S 17 +-3 - -03 1999 S 30 +-3 B -03/-02 2000 O 22 +-3 - -03 2001 S 13 +-3 B -03/-02 2002 O +-3 - -03 +Z America/Glace_Bay -3:59:48 - LMT 1902 Jun 15 +-4 C A%sT 1953 +-4 H A%sT 1954 +-4 - AST 1972 +-4 H A%sT 1974 +-4 C A%sT +Z America/Goose_Bay -4:1:40 - LMT 1884 +-3:30:52 - NST 1918 +-3:30:52 C N%sT 1919 +-3:30:52 - NST 1935 Mar 30 +-3:30 - NST 1936 +-3:30 j N%sT 1942 May 11 +-3:30 C N%sT 1946 +-3:30 j N%sT 1966 Mar 15 2 +-4 j A%sT 2011 N +-4 C A%sT +Z America/Grand_Turk -4:44:32 - LMT 1890 +-5:7:10 - KMT 1912 F +-5 - EST 1979 +-5 u E%sT 2015 Mar 8 2 +-4 - AST 2018 Mar 11 3 +-5 u E%sT +Z America/Guatemala -6:2:4 - LMT 1918 O 5 +-6 GT C%sT +Z America/Guayaquil -5:19:20 - LMT 1890 +-5:14 - QMT 1931 +-5 EC -05/-04 +Z America/Guyana -3:52:39 - LMT 1911 Au +-4 - -04 1915 Mar +-3:45 - -0345 1975 Au +-3 - -03 1992 Mar 29 1 +-4 - -04 +Z America/Halifax -4:14:24 - LMT 1902 Jun 15 +-4 H A%sT 1918 +-4 C A%sT 1919 +-4 H A%sT 1942 F 9 2s +-4 C A%sT 1946 +-4 H A%sT 1974 +-4 C A%sT +Z America/Havana -5:29:28 - LMT 1890 +-5:29:36 - HMT 1925 Jul 19 12 +-5 Q C%sT +Z America/Hermosillo -7:23:52 - LMT 1922 Ja 1 7u +-7 - MST 1927 Jun 10 23 +-6 - CST 1930 N 15 +-7 m M%sT 1932 Ap +-6 - CST 1942 Ap 24 +-7 - MST 1949 Ja 14 +-8 - PST 1970 +-7 m M%sT 1999 +-7 - MST +Z America/Indiana/Indianapolis -5:44:38 - LMT 1883 N 18 18u +-6 u C%sT 1920 +-6 In C%sT 1942 +-6 u C%sT 1946 +-6 In C%sT 1955 Ap 24 2 +-5 - EST 1957 S 29 2 +-6 - CST 1958 Ap 27 2 +-5 - EST 1969 +-5 u E%sT 1971 +-5 - EST 2006 +-5 u E%sT +Z America/Indiana/Knox -5:46:30 - LMT 1883 N 18 18u +-6 u C%sT 1947 +-6 St C%sT 1962 Ap 29 2 +-5 - EST 1963 O 27 2 +-6 u C%sT 1991 O 27 2 +-5 - EST 2006 Ap 2 2 +-6 u C%sT +Z America/Indiana/Marengo -5:45:23 - LMT 1883 N 18 18u +-6 u C%sT 1951 +-6 Ma C%sT 1961 Ap 30 2 +-5 - EST 1969 +-5 u E%sT 1974 Ja 6 2 +-6 1 CDT 1974 O 27 2 +-5 u E%sT 1976 +-5 - EST 2006 +-5 u E%sT +Z America/Indiana/Petersburg -5:49:7 - LMT 1883 N 18 18u +-6 u C%sT 1955 +-6 Pi C%sT 1965 Ap 25 2 +-5 - EST 1966 O 30 2 +-6 u C%sT 1977 O 30 2 +-5 - EST 2006 Ap 2 2 +-6 u C%sT 2007 N 4 2 +-5 u E%sT +Z America/Indiana/Tell_City -5:47:3 - LMT 1883 N 18 18u +-6 u C%sT 1946 +-6 Pe C%sT 1964 Ap 26 2 +-5 - EST 1967 O 29 2 +-6 u C%sT 1969 Ap 27 2 +-5 u E%sT 1971 +-5 - EST 2006 Ap 2 2 +-6 u C%sT +Z America/Indiana/Vevay -5:40:16 - LMT 1883 N 18 18u +-6 u C%sT 1954 Ap 25 2 +-5 - EST 1969 +-5 u E%sT 1973 +-5 - EST 2006 +-5 u E%sT +Z America/Indiana/Vincennes -5:50:7 - LMT 1883 N 18 18u +-6 u C%sT 1946 +-6 V C%sT 1964 Ap 26 2 +-5 - EST 1969 +-5 u E%sT 1971 +-5 - EST 2006 Ap 2 2 +-6 u C%sT 2007 N 4 2 +-5 u E%sT +Z America/Indiana/Winamac -5:46:25 - LMT 1883 N 18 18u +-6 u C%sT 1946 +-6 Pu C%sT 1961 Ap 30 2 +-5 - EST 1969 +-5 u E%sT 1971 +-5 - EST 2006 Ap 2 2 +-6 u C%sT 2007 Mar 11 2 +-5 u E%sT +Z America/Inuvik 0 - -00 1953 +-8 Y P%sT 1979 Ap lastSu 2 +-7 Y M%sT 1980 +-7 C M%sT +Z America/Iqaluit 0 - -00 1942 Au +-5 Y E%sT 1999 O 31 2 +-6 C C%sT 2000 O 29 2 +-5 C E%sT +Z America/Jamaica -5:7:10 - LMT 1890 +-5:7:10 - KMT 1912 F +-5 - EST 1974 +-5 u E%sT 1984 +-5 - EST +Z America/Juneau 15:2:19 - LMT 1867 O 19 15:33:32 +-8:57:41 - LMT 1900 Au 20 12 +-8 - PST 1942 +-8 u P%sT 1946 +-8 - PST 1969 +-8 u P%sT 1980 Ap 27 2 +-9 u Y%sT 1980 O 26 2 +-8 u P%sT 1983 O 30 2 +-9 u Y%sT 1983 N 30 +-9 u AK%sT +Z America/Kentucky/Louisville -5:43:2 - LMT 1883 N 18 18u +-6 u C%sT 1921 +-6 v C%sT 1942 +-6 u C%sT 1946 +-6 v C%sT 1961 Jul 23 2 +-5 - EST 1968 +-5 u E%sT 1974 Ja 6 2 +-6 1 CDT 1974 O 27 2 +-5 u E%sT +Z America/Kentucky/Monticello -5:39:24 - LMT 1883 N 18 18u +-6 u C%sT 1946 +-6 - CST 1968 +-6 u C%sT 2000 O 29 2 +-5 u E%sT +Z America/La_Paz -4:32:36 - LMT 1890 +-4:32:36 - CMT 1931 O 15 +-4:32:36 1 BST 1932 Mar 21 +-4 - -04 +Z America/Lima -5:8:12 - LMT 1890 +-5:8:36 - LMT 1908 Jul 28 +-5 PE -05/-04 +Z America/Los_Angeles -7:52:58 - LMT 1883 N 18 20u +-8 u P%sT 1946 +-8 CA P%sT 1967 +-8 u P%sT +Z America/Maceio -2:22:52 - LMT 1914 +-3 B -03/-02 1990 S 17 +-3 - -03 1995 O 13 +-3 B -03/-02 1996 S 4 +-3 - -03 1999 S 30 +-3 B -03/-02 2000 O 22 +-3 - -03 2001 S 13 +-3 B -03/-02 2002 O +-3 - -03 +Z America/Managua -5:45:8 - LMT 1890 +-5:45:12 - MMT 1934 Jun 23 +-6 - CST 1973 May +-5 - EST 1975 F 16 +-6 NI C%sT 1992 Ja 1 4 +-5 - EST 1992 S 24 +-6 - CST 1993 +-5 - EST 1997 +-6 NI C%sT +Z America/Manaus -4:0:4 - LMT 1914 +-4 B -04/-03 1988 S 12 +-4 - -04 1993 S 28 +-4 B -04/-03 1994 S 22 +-4 - -04 +Z America/Martinique -4:4:20 - LMT 1890 +-4:4:20 - FFMT 1911 May +-4 - AST 1980 Ap 6 +-4 1 ADT 1980 S 28 +-4 - AST +Z America/Matamoros -6:30 - LMT 1922 Ja 1 6u +-6 - CST 1988 +-6 u C%sT 1989 +-6 m C%sT 2010 +-6 u C%sT +Z America/Mazatlan -7:5:40 - LMT 1922 Ja 1 7u +-7 - MST 1927 Jun 10 23 +-6 - CST 1930 N 15 +-7 m M%sT 1932 Ap +-6 - CST 1942 Ap 24 +-7 - MST 1949 Ja 14 +-8 - PST 1970 +-7 m M%sT +Z America/Menominee -5:50:27 - LMT 1885 S 18 12 +-6 u C%sT 1946 +-6 Me C%sT 1969 Ap 27 2 +-5 - EST 1973 Ap 29 2 +-6 u C%sT +Z America/Merida -5:58:28 - LMT 1922 Ja 1 6u +-6 - CST 1981 D 23 +-5 - EST 1982 D 2 +-6 m C%sT +Z America/Metlakatla 15:13:42 - LMT 1867 O 19 15:44:55 +-8:46:18 - LMT 1900 Au 20 12 +-8 - PST 1942 +-8 u P%sT 1946 +-8 - PST 1969 +-8 u P%sT 1983 O 30 2 +-8 - PST 2015 N 1 2 +-9 u AK%sT 2018 N 4 2 +-8 - PST 2019 Ja 20 2 +-9 u AK%sT +Z America/Mexico_City -6:36:36 - LMT 1922 Ja 1 7u +-7 - MST 1927 Jun 10 23 +-6 - CST 1930 N 15 +-7 m M%sT 1932 Ap +-6 m C%sT 2001 S 30 2 +-6 - CST 2002 F 20 +-6 m C%sT +Z America/Miquelon -3:44:40 - LMT 1911 Jun 15 +-4 - AST 1980 May +-3 - -03 1987 +-3 C -03/-02 +Z America/Moncton -4:19:8 - LMT 1883 D 9 +-5 - EST 1902 Jun 15 +-4 C A%sT 1933 +-4 o A%sT 1942 +-4 C A%sT 1946 +-4 o A%sT 1973 +-4 C A%sT 1993 +-4 o A%sT 2007 +-4 C A%sT +Z America/Monterrey -6:41:16 - LMT 1922 Ja 1 6u +-6 - CST 1988 +-6 u C%sT 1989 +-6 m C%sT Z America/Montevideo -3:44:51 - LMT 1908 Jun 10 -3:44:51 - MMT 1920 May -4 - -04 1923 O @@ -4002,30 +2747,842 @@ Z America/Montevideo -3:44:51 - LMT 1908 Jun 10 -3 U -03/-0130 1974 Mar 10 -3 U -03/-0230 1974 D 22 -3 U -03/-02 -Z America/Caracas -4:27:44 - LMT 1890 --4:27:40 - CMT 1912 F 12 --4:30 - -0430 1965 --4 - -04 2007 D 9 3 --4:30 - -0430 2016 May 1 2:30 +Z America/New_York -4:56:2 - LMT 1883 N 18 17u +-5 u E%sT 1920 +-5 NY E%sT 1942 +-5 u E%sT 1946 +-5 NY E%sT 1967 +-5 u E%sT +Z America/Nome 12:58:22 - LMT 1867 O 19 13:29:35 +-11:1:38 - LMT 1900 Au 20 12 +-11 - NST 1942 +-11 u N%sT 1946 +-11 - NST 1967 Ap +-11 - BST 1969 +-11 u B%sT 1983 O 30 2 +-9 u Y%sT 1983 N 30 +-9 u AK%sT +Z America/Noronha -2:9:40 - LMT 1914 +-2 B -02/-01 1990 S 17 +-2 - -02 1999 S 30 +-2 B -02/-01 2000 O 15 +-2 - -02 2001 S 13 +-2 B -02/-01 2002 O +-2 - -02 +Z America/North_Dakota/Beulah -6:47:7 - LMT 1883 N 18 19u +-7 u M%sT 2010 N 7 2 +-6 u C%sT +Z America/North_Dakota/Center -6:45:12 - LMT 1883 N 18 19u +-7 u M%sT 1992 O 25 2 +-6 u C%sT +Z America/North_Dakota/New_Salem -6:45:39 - LMT 1883 N 18 19u +-7 u M%sT 2003 O 26 2 +-6 u C%sT +Z America/Nuuk -3:26:56 - LMT 1916 Jul 28 +-3 - -03 1980 Ap 6 2 +-3 E -03/-02 2023 Mar 26 1u +-2 - -02 2023 O 29 1u +-2 E -02/-01 +Z America/Ojinaga -6:57:40 - LMT 1922 Ja 1 7u +-7 - MST 1927 Jun 10 23 +-6 - CST 1930 N 15 +-7 m M%sT 1932 Ap +-6 - CST 1996 +-6 m C%sT 1998 +-6 - CST 1998 Ap Su>=1 3 +-7 m M%sT 2010 +-7 u M%sT 2022 O 30 2 +-6 - CST 2022 N 30 +-6 u C%sT +Z America/Panama -5:18:8 - LMT 1890 +-5:19:36 - CMT 1908 Ap 22 +-5 - EST +Z America/Paramaribo -3:40:40 - LMT 1911 +-3:40:52 - PMT 1935 +-3:40:36 - PMT 1945 O +-3:30 - -0330 1984 O +-3 - -03 +Z America/Phoenix -7:28:18 - LMT 1883 N 18 19u +-7 u M%sT 1944 Ja 1 0:1 +-7 - MST 1944 Ap 1 0:1 +-7 u M%sT 1944 O 1 0:1 +-7 - MST 1967 +-7 u M%sT 1968 Mar 21 +-7 - MST +Z America/Port-au-Prince -4:49:20 - LMT 1890 +-4:49 - PPMT 1917 Ja 24 12 +-5 HT E%sT +Z America/Porto_Velho -4:15:36 - LMT 1914 +-4 B -04/-03 1988 S 12 -4 - -04 -Z Etc/UTC 0 - UTC +Z America/Puerto_Rico -4:24:25 - LMT 1899 Mar 28 12 +-4 - AST 1942 May 3 +-4 u A%sT 1946 +-4 - AST +Z America/Punta_Arenas -4:43:40 - LMT 1890 +-4:42:45 - SMT 1910 Ja 10 +-5 - -05 1916 Jul +-4:42:45 - SMT 1918 S 10 +-4 - -04 1919 Jul +-4:42:45 - SMT 1927 S +-5 x -05/-04 1932 S +-4 - -04 1942 Jun +-5 - -05 1942 Au +-4 - -04 1946 Au 28 24 +-5 1 -04 1947 Mar 31 24 +-5 - -05 1947 May 21 23 +-4 x -04/-03 2016 D 4 +-3 - -03 +Z America/Rankin_Inlet 0 - -00 1957 +-6 Y C%sT 2000 O 29 2 +-5 - EST 2001 Ap 1 3 +-6 C C%sT +Z America/Recife -2:19:36 - LMT 1914 +-3 B -03/-02 1990 S 17 +-3 - -03 1999 S 30 +-3 B -03/-02 2000 O 15 +-3 - -03 2001 S 13 +-3 B -03/-02 2002 O +-3 - -03 +Z America/Regina -6:58:36 - LMT 1905 S +-7 r M%sT 1960 Ap lastSu 2 +-6 - CST +Z America/Resolute 0 - -00 1947 Au 31 +-6 Y C%sT 2000 O 29 2 +-5 - EST 2001 Ap 1 3 +-6 C C%sT 2006 O 29 2 +-5 - EST 2007 Mar 11 3 +-6 C C%sT +Z America/Rio_Branco -4:31:12 - LMT 1914 +-5 B -05/-04 1988 S 12 +-5 - -05 2008 Jun 24 +-4 - -04 2013 N 10 +-5 - -05 +Z America/Santarem -3:38:48 - LMT 1914 +-4 B -04/-03 1988 S 12 +-4 - -04 2008 Jun 24 +-3 - -03 +Z America/Santiago -4:42:45 - LMT 1890 +-4:42:45 - SMT 1910 Ja 10 +-5 - -05 1916 Jul +-4:42:45 - SMT 1918 S 10 +-4 - -04 1919 Jul +-4:42:45 - SMT 1927 S +-5 x -05/-04 1932 S +-4 - -04 1942 Jun +-5 - -05 1942 Au +-4 - -04 1946 Jul 14 24 +-4 1 -03 1946 Au 28 24 +-5 1 -04 1947 Mar 31 24 +-5 - -05 1947 May 21 23 +-4 x -04/-03 +Z America/Santo_Domingo -4:39:36 - LMT 1890 +-4:40 - SDMT 1933 Ap 1 12 +-5 DO %s 1974 O 27 +-4 - AST 2000 O 29 2 +-5 u E%sT 2000 D 3 1 +-4 - AST +Z America/Sao_Paulo -3:6:28 - LMT 1914 +-3 B -03/-02 1963 O 23 +-3 1 -02 1964 +-3 B -03/-02 +Z America/Scoresbysund -1:27:52 - LMT 1916 Jul 28 +-2 - -02 1980 Ap 6 2 +-2 c -02/-01 1981 Mar 29 +-1 E -01/+00 2024 Mar 31 +-2 E -02/-01 +Z America/Sitka 14:58:47 - LMT 1867 O 19 15:30 +-9:1:13 - LMT 1900 Au 20 12 +-8 - PST 1942 +-8 u P%sT 1946 +-8 - PST 1969 +-8 u P%sT 1983 O 30 2 +-9 u Y%sT 1983 N 30 +-9 u AK%sT +Z America/St_Johns -3:30:52 - LMT 1884 +-3:30:52 j N%sT 1918 +-3:30:52 C N%sT 1919 +-3:30:52 j N%sT 1935 Mar 30 +-3:30 j N%sT 1942 May 11 +-3:30 C N%sT 1946 +-3:30 j N%sT 2011 N +-3:30 C N%sT +Z America/Swift_Current -7:11:20 - LMT 1905 S +-7 C M%sT 1946 Ap lastSu 2 +-7 r M%sT 1950 +-7 Sw M%sT 1972 Ap lastSu 2 +-6 - CST +Z America/Tegucigalpa -5:48:52 - LMT 1921 Ap +-6 HN C%sT +Z America/Thule -4:35:8 - LMT 1916 Jul 28 +-4 Th A%sT +Z America/Tijuana -7:48:4 - LMT 1922 Ja 1 7u +-7 - MST 1924 +-8 - PST 1927 Jun 10 23 +-7 - MST 1930 N 15 +-8 - PST 1931 Ap +-8 1 PDT 1931 S 30 +-8 - PST 1942 Ap 24 +-8 1 PWT 1945 Au 14 23u +-8 1 PPT 1945 N 12 +-8 - PST 1948 Ap 5 +-8 1 PDT 1949 Ja 14 +-8 - PST 1954 +-8 CA P%sT 1961 +-8 - PST 1976 +-8 u P%sT 1996 +-8 m P%sT 2001 +-8 u P%sT 2002 F 20 +-8 m P%sT 2010 +-8 u P%sT +Z America/Toronto -5:17:32 - LMT 1895 +-5 C E%sT 1919 +-5 t E%sT 1942 F 9 2s +-5 C E%sT 1946 +-5 t E%sT 1974 +-5 C E%sT +Z America/Vancouver -8:12:28 - LMT 1884 +-8 Va P%sT 1987 +-8 C P%sT +Z America/Whitehorse -9:0:12 - LMT 1900 Au 20 +-9 Y Y%sT 1965 +-9 Yu Y%sT 1966 F 27 +-8 - PST 1980 +-8 C P%sT 2020 N +-7 - MST +Z America/Winnipeg -6:28:36 - LMT 1887 Jul 16 +-6 W C%sT 2006 +-6 C C%sT +Z America/Yakutat 14:41:5 - LMT 1867 O 19 15:12:18 +-9:18:55 - LMT 1900 Au 20 12 +-9 - YST 1942 +-9 u Y%sT 1946 +-9 - YST 1969 +-9 u Y%sT 1983 N 30 +-9 u AK%sT +Z Antarctica/Casey 0 - -00 1969 +8 - +08 2009 O 18 2 +11 - +11 2010 Mar 5 2 +8 - +08 2011 O 28 2 +11 - +11 2012 F 21 17u +8 - +08 2016 O 22 +11 - +11 2018 Mar 11 4 +8 - +08 2018 O 7 4 +11 - +11 2019 Mar 17 3 +8 - +08 2019 O 4 3 +11 - +11 2020 Mar 8 3 +8 - +08 2020 O 4 0:1 +11 - +11 2021 Mar 14 +8 - +08 2021 O 3 0:1 +11 - +11 2022 Mar 13 +8 - +08 2022 O 2 0:1 +11 - +11 2023 Mar 9 3 +8 - +08 +Z Antarctica/Davis 0 - -00 1957 Ja 13 +7 - +07 1964 N +0 - -00 1969 F +7 - +07 2009 O 18 2 +5 - +05 2010 Mar 10 20u +7 - +07 2011 O 28 2 +5 - +05 2012 F 21 20u +7 - +07 +Z Antarctica/Macquarie 0 - -00 1899 N +10 - AEST 1916 O 1 2 +10 1 AEDT 1917 F +10 AU AE%sT 1919 Ap 1 0s +0 - -00 1948 Mar 25 +10 AU AE%sT 1967 +10 AT AE%sT 2010 +10 1 AEDT 2011 +10 AT AE%sT +Z Antarctica/Mawson 0 - -00 1954 F 13 +6 - +06 2009 O 18 2 +5 - +05 +Z Antarctica/Palmer 0 - -00 1965 +-4 A -04/-03 1969 O 5 +-3 A -03/-02 1982 May +-4 x -04/-03 2016 D 4 +-3 - -03 +Z Antarctica/Rothera 0 - -00 1976 D +-3 - -03 +Z Antarctica/Troll 0 - -00 2005 F 12 +0 Tr %s +Z Antarctica/Vostok 0 - -00 1957 D 16 +7 - +07 1994 F +0 - -00 1994 N +7 - +07 2023 D 18 2 +5 - +05 +Z Asia/Almaty 5:7:48 - LMT 1924 May 2 +5 - +05 1930 Jun 21 +6 R +06/+07 1991 Mar 31 2s +5 R +05/+06 1992 Ja 19 2s +6 R +06/+07 2004 O 31 2s +6 - +06 2024 Mar +5 - +05 +Z Asia/Amman 2:23:44 - LMT 1931 +2 J EE%sT 2022 O 28 0s +3 - +03 +Z Asia/Anadyr 11:49:56 - LMT 1924 May 2 +12 - +12 1930 Jun 21 +13 R +13/+14 1982 Ap 1 0s +12 R +12/+13 1991 Mar 31 2s +11 R +11/+12 1992 Ja 19 2s +12 R +12/+13 2010 Mar 28 2s +11 R +11/+12 2011 Mar 27 2s +12 - +12 +Z Asia/Aqtau 3:21:4 - LMT 1924 May 2 +4 - +04 1930 Jun 21 +5 - +05 1981 O +6 - +06 1982 Ap +5 R +05/+06 1991 Mar 31 2s +4 R +04/+05 1992 Ja 19 2s +5 R +05/+06 1994 S 25 2s +4 R +04/+05 2004 O 31 2s +5 - +05 +Z Asia/Aqtobe 3:48:40 - LMT 1924 May 2 +4 - +04 1930 Jun 21 +5 - +05 1981 Ap +5 1 +06 1981 O +6 - +06 1982 Ap +5 R +05/+06 1991 Mar 31 2s +4 R +04/+05 1992 Ja 19 2s +5 R +05/+06 2004 O 31 2s +5 - +05 +Z Asia/Ashgabat 3:53:32 - LMT 1924 May 2 +4 - +04 1930 Jun 21 +5 R +05/+06 1991 Mar 31 2 +4 R +04/+05 1992 Ja 19 2 +5 - +05 +Z Asia/Atyrau 3:27:44 - LMT 1924 May 2 +3 - +03 1930 Jun 21 +5 - +05 1981 O +6 - +06 1982 Ap +5 R +05/+06 1991 Mar 31 2s +4 R +04/+05 1992 Ja 19 2s +5 R +05/+06 1999 Mar 28 2s +4 R +04/+05 2004 O 31 2s +5 - +05 +Z Asia/Baghdad 2:57:40 - LMT 1890 +2:57:36 - BMT 1918 +3 - +03 1982 May +3 IQ +03/+04 +Z Asia/Baku 3:19:24 - LMT 1924 May 2 +3 - +03 1957 Mar +4 R +04/+05 1991 Mar 31 2s +3 R +03/+04 1992 S lastSu 2s +4 - +04 1996 +4 E +04/+05 1997 +4 AZ +04/+05 +Z Asia/Bangkok 6:42:4 - LMT 1880 +6:42:4 - BMT 1920 Ap +7 - +07 +Z Asia/Barnaul 5:35 - LMT 1919 D 10 +6 - +06 1930 Jun 21 +7 R +07/+08 1991 Mar 31 2s +6 R +06/+07 1992 Ja 19 2s +7 R +07/+08 1995 May 28 +6 R +06/+07 2011 Mar 27 2s +7 - +07 2014 O 26 2s +6 - +06 2016 Mar 27 2s +7 - +07 +Z Asia/Beirut 2:22 - LMT 1880 +2 l EE%sT +Z Asia/Bishkek 4:58:24 - LMT 1924 May 2 +5 - +05 1930 Jun 21 +6 R +06/+07 1991 Mar 31 2s +5 R +05/+06 1991 Au 31 2 +5 KG +05/+06 2005 Au 12 +6 - +06 +Z Asia/Chita 7:33:52 - LMT 1919 D 15 +8 - +08 1930 Jun 21 +9 R +09/+10 1991 Mar 31 2s +8 R +08/+09 1992 Ja 19 2s +9 R +09/+10 2011 Mar 27 2s +10 - +10 2014 O 26 2s +8 - +08 2016 Mar 27 2 +9 - +09 +Z Asia/Choibalsan 7:38 - LMT 1905 Au +7 - +07 1978 +8 - +08 1983 Ap +9 X +09/+10 2008 Mar 31 +8 X +08/+09 +Z Asia/Colombo 5:19:24 - LMT 1880 +5:19:32 - MMT 1906 +5:30 - +0530 1942 Ja 5 +5:30 0:30 +06 1942 S +5:30 1 +0630 1945 O 16 2 +5:30 - +0530 1996 May 25 +6:30 - +0630 1996 O 26 0:30 +6 - +06 2006 Ap 15 0:30 +5:30 - +0530 +Z Asia/Damascus 2:25:12 - LMT 1920 +2 S EE%sT 2022 O 28 +3 - +03 +Z Asia/Dhaka 6:1:40 - LMT 1890 +5:53:20 - HMT 1941 O +6:30 - +0630 1942 May 15 +5:30 - +0530 1942 S +6:30 - +0630 1951 S 30 +6 - +06 2009 +6 BD +06/+07 +Z Asia/Dili 8:22:20 - LMT 1912 +8 - +08 1942 F 21 23 +9 - +09 1976 May 3 +8 - +08 2000 S 17 +9 - +09 +Z Asia/Dubai 3:41:12 - LMT 1920 +4 - +04 +Z Asia/Dushanbe 4:35:12 - LMT 1924 May 2 +5 - +05 1930 Jun 21 +6 R +06/+07 1991 Mar 31 2s +5 1 +06 1991 S 9 2s +5 - +05 +Z Asia/Famagusta 2:15:48 - LMT 1921 N 14 +2 CY EE%sT 1998 S +2 E EE%sT 2016 S 8 +3 - +03 2017 O 29 1u +2 E EE%sT +Z Asia/Gaza 2:17:52 - LMT 1900 O +2 Z EET/EEST 1948 May 15 +2 K EE%sT 1967 Jun 5 +2 Z I%sT 1996 +2 J EE%sT 1999 +2 P EE%sT 2008 Au 29 +2 - EET 2008 S +2 P EE%sT 2010 +2 - EET 2010 Mar 27 0:1 +2 P EE%sT 2011 Au +2 - EET 2012 +2 P EE%sT +Z Asia/Hebron 2:20:23 - LMT 1900 O +2 Z EET/EEST 1948 May 15 +2 K EE%sT 1967 Jun 5 +2 Z I%sT 1996 +2 J EE%sT 1999 +2 P EE%sT +Z Asia/Ho_Chi_Minh 7:6:30 - LMT 1906 Jul +7:6:30 - PLMT 1911 May +7 - +07 1942 D 31 23 +8 - +08 1945 Mar 14 23 +9 - +09 1945 S 1 24 +7 - +07 1947 Ap +8 - +08 1955 Jul 1 1 +7 - +07 1959 D 31 23 +8 - +08 1975 Jun 13 +7 - +07 +Z Asia/Hong_Kong 7:36:42 - LMT 1904 O 29 17u +8 - HKT 1941 Jun 15 3 +8 1 HKST 1941 O 1 4 +8 0:30 HKWT 1941 D 25 +9 - JST 1945 N 18 2 +8 HK HK%sT +Z Asia/Hovd 6:6:36 - LMT 1905 Au +6 - +06 1978 +7 X +07/+08 +Z Asia/Irkutsk 6:57:5 - LMT 1880 +6:57:5 - IMT 1920 Ja 25 +7 - +07 1930 Jun 21 +8 R +08/+09 1991 Mar 31 2s +7 R +07/+08 1992 Ja 19 2s +8 R +08/+09 2011 Mar 27 2s +9 - +09 2014 O 26 2s +8 - +08 +Z Asia/Jakarta 7:7:12 - LMT 1867 Au 10 +7:7:12 - BMT 1923 D 31 16:40u +7:20 - +0720 1932 N +7:30 - +0730 1942 Mar 23 +9 - +09 1945 S 23 +7:30 - +0730 1948 May +8 - +08 1950 May +7:30 - +0730 1964 +7 - WIB +Z Asia/Jayapura 9:22:48 - LMT 1932 N +9 - +09 1944 S +9:30 - +0930 1964 +9 - WIT +Z Asia/Jerusalem 2:20:54 - LMT 1880 +2:20:40 - JMT 1918 +2 Z I%sT +Z Asia/Kabul 4:36:48 - LMT 1890 +4 - +04 1945 +4:30 - +0430 +Z Asia/Kamchatka 10:34:36 - LMT 1922 N 10 +11 - +11 1930 Jun 21 +12 R +12/+13 1991 Mar 31 2s +11 R +11/+12 1992 Ja 19 2s +12 R +12/+13 2010 Mar 28 2s +11 R +11/+12 2011 Mar 27 2s +12 - +12 +Z Asia/Karachi 4:28:12 - LMT 1907 +5:30 - +0530 1942 S +5:30 1 +0630 1945 O 15 +5:30 - +0530 1951 S 30 +5 - +05 1971 Mar 26 +5 PK PK%sT +Z Asia/Kathmandu 5:41:16 - LMT 1920 +5:30 - +0530 1986 +5:45 - +0545 +Z Asia/Khandyga 9:2:13 - LMT 1919 D 15 +8 - +08 1930 Jun 21 +9 R +09/+10 1991 Mar 31 2s +8 R +08/+09 1992 Ja 19 2s +9 R +09/+10 2004 +10 R +10/+11 2011 Mar 27 2s +11 - +11 2011 S 13 0s +10 - +10 2014 O 26 2s +9 - +09 +Z Asia/Kolkata 5:53:28 - LMT 1854 Jun 28 +5:53:20 - HMT 1870 +5:21:10 - MMT 1906 +5:30 - IST 1941 O +5:30 1 +0630 1942 May 15 +5:30 - IST 1942 S +5:30 1 +0630 1945 O 15 +5:30 - IST +Z Asia/Krasnoyarsk 6:11:26 - LMT 1920 Ja 6 +6 - +06 1930 Jun 21 +7 R +07/+08 1991 Mar 31 2s +6 R +06/+07 1992 Ja 19 2s +7 R +07/+08 2011 Mar 27 2s +8 - +08 2014 O 26 2s +7 - +07 +Z Asia/Kuching 7:21:20 - LMT 1926 Mar +7:30 - +0730 1933 +8 NB +08/+0820 1942 F 16 +9 - +09 1945 S 12 +8 - +08 +Z Asia/Macau 7:34:10 - LMT 1904 O 30 +8 - CST 1941 D 21 23 +9 _ +09/+10 1945 S 30 24 +8 _ C%sT +Z Asia/Magadan 10:3:12 - LMT 1924 May 2 +10 - +10 1930 Jun 21 +11 R +11/+12 1991 Mar 31 2s +10 R +10/+11 1992 Ja 19 2s +11 R +11/+12 2011 Mar 27 2s +12 - +12 2014 O 26 2s +10 - +10 2016 Ap 24 2s +11 - +11 +Z Asia/Makassar 7:57:36 - LMT 1920 +7:57:36 - MMT 1932 N +8 - +08 1942 F 9 +9 - +09 1945 S 23 +8 - WITA +Z Asia/Manila -15:56 - LMT 1844 D 31 +8:4 - LMT 1899 May 11 +8 PH P%sT 1942 May +9 - JST 1944 N +8 PH P%sT +Z Asia/Nicosia 2:13:28 - LMT 1921 N 14 +2 CY EE%sT 1998 S +2 E EE%sT +Z Asia/Novokuznetsk 5:48:48 - LMT 1924 May +6 - +06 1930 Jun 21 +7 R +07/+08 1991 Mar 31 2s +6 R +06/+07 1992 Ja 19 2s +7 R +07/+08 2010 Mar 28 2s +6 R +06/+07 2011 Mar 27 2s +7 - +07 +Z Asia/Novosibirsk 5:31:40 - LMT 1919 D 14 6 +6 - +06 1930 Jun 21 +7 R +07/+08 1991 Mar 31 2s +6 R +06/+07 1992 Ja 19 2s +7 R +07/+08 1993 May 23 +6 R +06/+07 2011 Mar 27 2s +7 - +07 2014 O 26 2s +6 - +06 2016 Jul 24 2s +7 - +07 +Z Asia/Omsk 4:53:30 - LMT 1919 N 14 +5 - +05 1930 Jun 21 +6 R +06/+07 1991 Mar 31 2s +5 R +05/+06 1992 Ja 19 2s +6 R +06/+07 2011 Mar 27 2s +7 - +07 2014 O 26 2s +6 - +06 +Z Asia/Oral 3:25:24 - LMT 1924 May 2 +3 - +03 1930 Jun 21 +5 - +05 1981 Ap +5 1 +06 1981 O +6 - +06 1982 Ap +5 R +05/+06 1989 Mar 26 2s +4 R +04/+05 1992 Ja 19 2s +5 R +05/+06 1992 Mar 29 2s +4 R +04/+05 2004 O 31 2s +5 - +05 +Z Asia/Pontianak 7:17:20 - LMT 1908 May +7:17:20 - PMT 1932 N +7:30 - +0730 1942 Ja 29 +9 - +09 1945 S 23 +7:30 - +0730 1948 May +8 - +08 1950 May +7:30 - +0730 1964 +8 - WITA 1988 +7 - WIB +Z Asia/Pyongyang 8:23 - LMT 1908 Ap +8:30 - KST 1912 +9 - JST 1945 Au 24 +9 - KST 2015 Au 15 +8:30 - KST 2018 May 4 23:30 +9 - KST +Z Asia/Qatar 3:26:8 - LMT 1920 +4 - +04 1972 Jun +3 - +03 +Z Asia/Qostanay 4:14:28 - LMT 1924 May 2 +4 - +04 1930 Jun 21 +5 - +05 1981 Ap +5 1 +06 1981 O +6 - +06 1982 Ap +5 R +05/+06 1991 Mar 31 2s +4 R +04/+05 1992 Ja 19 2s +5 R +05/+06 2004 O 31 2s +6 - +06 2024 Mar +5 - +05 +Z Asia/Qyzylorda 4:21:52 - LMT 1924 May 2 +4 - +04 1930 Jun 21 +5 - +05 1981 Ap +5 1 +06 1981 O +6 - +06 1982 Ap +5 R +05/+06 1991 Mar 31 2s +4 R +04/+05 1991 S 29 2s +5 R +05/+06 1992 Ja 19 2s +6 R +06/+07 1992 Mar 29 2s +5 R +05/+06 2004 O 31 2s +6 - +06 2018 D 21 +5 - +05 +Z Asia/Riyadh 3:6:52 - LMT 1947 Mar 14 +3 - +03 +Z Asia/Sakhalin 9:30:48 - LMT 1905 Au 23 +9 - +09 1945 Au 25 +11 R +11/+12 1991 Mar 31 2s +10 R +10/+11 1992 Ja 19 2s +11 R +11/+12 1997 Mar lastSu 2s +10 R +10/+11 2011 Mar 27 2s +11 - +11 2014 O 26 2s +10 - +10 2016 Mar 27 2s +11 - +11 +Z Asia/Samarkand 4:27:53 - LMT 1924 May 2 +4 - +04 1930 Jun 21 +5 - +05 1981 Ap +5 1 +06 1981 O +6 - +06 1982 Ap +5 R +05/+06 1992 +5 - +05 +Z Asia/Seoul 8:27:52 - LMT 1908 Ap +8:30 - KST 1912 +9 - JST 1945 S 8 +9 KR K%sT 1954 Mar 21 +8:30 KR K%sT 1961 Au 10 +9 KR K%sT +Z Asia/Shanghai 8:5:43 - LMT 1901 +8 Sh C%sT 1949 May 28 +8 CN C%sT +Z Asia/Singapore 6:55:25 - LMT 1901 +6:55:25 - SMT 1905 Jun +7 - +07 1933 +7 0:20 +0720 1936 +7:20 - +0720 1941 S +7:30 - +0730 1942 F 16 +9 - +09 1945 S 12 +7:30 - +0730 1981 D 31 16u +8 - +08 +Z Asia/Srednekolymsk 10:14:52 - LMT 1924 May 2 +10 - +10 1930 Jun 21 +11 R +11/+12 1991 Mar 31 2s +10 R +10/+11 1992 Ja 19 2s +11 R +11/+12 2011 Mar 27 2s +12 - +12 2014 O 26 2s +11 - +11 +Z Asia/Taipei 8:6 - LMT 1896 +8 - CST 1937 O +9 - JST 1945 S 21 1 +8 f C%sT +Z Asia/Tashkent 4:37:11 - LMT 1924 May 2 +5 - +05 1930 Jun 21 +6 R +06/+07 1991 Mar 31 2 +5 R +05/+06 1992 +5 - +05 +Z Asia/Tbilisi 2:59:11 - LMT 1880 +2:59:11 - TBMT 1924 May 2 +3 - +03 1957 Mar +4 R +04/+05 1991 Mar 31 2s +3 R +03/+04 1992 +3 e +03/+04 1994 S lastSu +4 e +04/+05 1996 O lastSu +4 1 +05 1997 Mar lastSu +4 e +04/+05 2004 Jun 27 +3 R +03/+04 2005 Mar lastSu 2 +4 - +04 +Z Asia/Tehran 3:25:44 - LMT 1916 +3:25:44 - TMT 1935 Jun 13 +3:30 i +0330/+0430 1977 O 20 24 +4 i +04/+05 1979 +3:30 i +0330/+0430 +Z Asia/Thimphu 5:58:36 - LMT 1947 Au 15 +5:30 - +0530 1987 O +6 - +06 +Z Asia/Tokyo 9:18:59 - LMT 1887 D 31 15u +9 JP J%sT +Z Asia/Tomsk 5:39:51 - LMT 1919 D 22 +6 - +06 1930 Jun 21 +7 R +07/+08 1991 Mar 31 2s +6 R +06/+07 1992 Ja 19 2s +7 R +07/+08 2002 May 1 3 +6 R +06/+07 2011 Mar 27 2s +7 - +07 2014 O 26 2s +6 - +06 2016 May 29 2s +7 - +07 +Z Asia/Ulaanbaatar 7:7:32 - LMT 1905 Au +7 - +07 1978 +8 X +08/+09 +Z Asia/Urumqi 5:50:20 - LMT 1928 +6 - +06 +Z Asia/Ust-Nera 9:32:54 - LMT 1919 D 15 +8 - +08 1930 Jun 21 +9 R +09/+10 1981 Ap +11 R +11/+12 1991 Mar 31 2s +10 R +10/+11 1992 Ja 19 2s +11 R +11/+12 2011 Mar 27 2s +12 - +12 2011 S 13 0s +11 - +11 2014 O 26 2s +10 - +10 +Z Asia/Vladivostok 8:47:31 - LMT 1922 N 15 +9 - +09 1930 Jun 21 +10 R +10/+11 1991 Mar 31 2s +9 R +09/+10 1992 Ja 19 2s +10 R +10/+11 2011 Mar 27 2s +11 - +11 2014 O 26 2s +10 - +10 +Z Asia/Yakutsk 8:38:58 - LMT 1919 D 15 +8 - +08 1930 Jun 21 +9 R +09/+10 1991 Mar 31 2s +8 R +08/+09 1992 Ja 19 2s +9 R +09/+10 2011 Mar 27 2s +10 - +10 2014 O 26 2s +9 - +09 +Z Asia/Yangon 6:24:47 - LMT 1880 +6:24:47 - RMT 1920 +6:30 - +0630 1942 May +9 - +09 1945 May 3 +6:30 - +0630 +Z Asia/Yekaterinburg 4:2:33 - LMT 1916 Jul 3 +3:45:5 - PMT 1919 Jul 15 4 +4 - +04 1930 Jun 21 +5 R +05/+06 1991 Mar 31 2s +4 R +04/+05 1992 Ja 19 2s +5 R +05/+06 2011 Mar 27 2s +6 - +06 2014 O 26 2s +5 - +05 +Z Asia/Yerevan 2:58 - LMT 1924 May 2 +3 - +03 1957 Mar +4 R +04/+05 1991 Mar 31 2s +3 R +03/+04 1995 S 24 2s +4 - +04 1997 +4 R +04/+05 2011 +4 AM +04/+05 +Z Atlantic/Azores -1:42:40 - LMT 1884 +-1:54:32 - HMT 1912 Ja 1 2u +-2 p -02/-01 1942 Ap 25 22s +-2 p +00 1942 Au 15 22s +-2 p -02/-01 1943 Ap 17 22s +-2 p +00 1943 Au 28 22s +-2 p -02/-01 1944 Ap 22 22s +-2 p +00 1944 Au 26 22s +-2 p -02/-01 1945 Ap 21 22s +-2 p +00 1945 Au 25 22s +-2 p -02/-01 1966 Ap 3 2 +-1 p -01/+00 1983 S 25 1s +-1 W- -01/+00 1992 S 27 1s +0 E WE%sT 1993 Mar 28 1u +-1 E -01/+00 +Z Atlantic/Bermuda -4:19:18 - LMT 1890 +-4:19:18 Be BMT/BST 1930 Ja 1 2 +-4 Be A%sT 1974 Ap 28 2 +-4 C A%sT 1976 +-4 u A%sT +Z Atlantic/Canary -1:1:36 - LMT 1922 Mar +-1 - -01 1946 S 30 1 +0 - WET 1980 Ap 6 0s +0 1 WEST 1980 S 28 1u +0 E WE%sT +Z Atlantic/Cape_Verde -1:34:4 - LMT 1912 Ja 1 2u +-2 - -02 1942 S +-2 1 -01 1945 O 15 +-2 - -02 1975 N 25 2 +-1 - -01 +Z Atlantic/Faroe -0:27:4 - LMT 1908 Ja 11 +0 - WET 1981 +0 E WE%sT +Z Atlantic/Madeira -1:7:36 - LMT 1884 +-1:7:36 - FMT 1912 Ja 1 1u +-1 p -01/+00 1942 Ap 25 22s +-1 p +01 1942 Au 15 22s +-1 p -01/+00 1943 Ap 17 22s +-1 p +01 1943 Au 28 22s +-1 p -01/+00 1944 Ap 22 22s +-1 p +01 1944 Au 26 22s +-1 p -01/+00 1945 Ap 21 22s +-1 p +01 1945 Au 25 22s +-1 p -01/+00 1966 Ap 3 2 +0 p WE%sT 1983 S 25 1s +0 E WE%sT +Z Atlantic/South_Georgia -2:26:8 - LMT 1890 +-2 - -02 +Z Atlantic/Stanley -3:51:24 - LMT 1890 +-3:51:24 - SMT 1912 Mar 12 +-4 FK -04/-03 1983 May +-3 FK -03/-02 1985 S 15 +-4 FK -04/-03 2010 S 5 2 +-3 - -03 +Z Australia/Adelaide 9:14:20 - LMT 1895 F +9 - ACST 1899 May +9:30 AU AC%sT 1971 +9:30 AS AC%sT +Z Australia/Brisbane 10:12:8 - LMT 1895 +10 AU AE%sT 1971 +10 AQ AE%sT +Z Australia/Broken_Hill 9:25:48 - LMT 1895 F +10 - AEST 1896 Au 23 +9 - ACST 1899 May +9:30 AU AC%sT 1971 +9:30 AN AC%sT 2000 +9:30 AS AC%sT +Z Australia/Darwin 8:43:20 - LMT 1895 F +9 - ACST 1899 May +9:30 AU AC%sT +Z Australia/Eucla 8:35:28 - LMT 1895 D +8:45 AU +0845/+0945 1943 Jul +8:45 AW +0845/+0945 +Z Australia/Hobart 9:49:16 - LMT 1895 S +10 AT AE%sT 1919 O 24 +10 AU AE%sT 1967 +10 AT AE%sT +Z Australia/Lindeman 9:55:56 - LMT 1895 +10 AU AE%sT 1971 +10 AQ AE%sT 1992 Jul +10 Ho AE%sT +Z Australia/Lord_Howe 10:36:20 - LMT 1895 F +10 - AEST 1981 Mar +10:30 LH +1030/+1130 1985 Jul +10:30 LH +1030/+11 +Z Australia/Melbourne 9:39:52 - LMT 1895 F +10 AU AE%sT 1971 +10 AV AE%sT +Z Australia/Perth 7:43:24 - LMT 1895 D +8 AU AW%sT 1943 Jul +8 AW AW%sT +Z Australia/Sydney 10:4:52 - LMT 1895 F +10 AU AE%sT 1971 +10 AN AE%sT +Z CET 1 c CE%sT +Z CST6CDT -6 u C%sT +Z EET 2 E EE%sT +Z EST -5 - EST +Z EST5EDT -5 u E%sT Z Etc/GMT 0 - GMT -L Etc/GMT GMT -Z Etc/GMT-14 14 - +14 -Z Etc/GMT-13 13 - +13 -Z Etc/GMT-12 12 - +12 -Z Etc/GMT-11 11 - +11 -Z Etc/GMT-10 10 - +10 -Z Etc/GMT-9 9 - +09 -Z Etc/GMT-8 8 - +08 -Z Etc/GMT-7 7 - +07 -Z Etc/GMT-6 6 - +06 -Z Etc/GMT-5 5 - +05 -Z Etc/GMT-4 4 - +04 -Z Etc/GMT-3 3 - +03 -Z Etc/GMT-2 2 - +02 -Z Etc/GMT-1 1 - +01 Z Etc/GMT+1 -1 - -01 +Z Etc/GMT+10 -10 - -10 +Z Etc/GMT+11 -11 - -11 +Z Etc/GMT+12 -12 - -12 Z Etc/GMT+2 -2 - -02 Z Etc/GMT+3 -3 - -03 Z Etc/GMT+4 -4 - -04 @@ -4034,10 +3591,463 @@ Z Etc/GMT+6 -6 - -06 Z Etc/GMT+7 -7 - -07 Z Etc/GMT+8 -8 - -08 Z Etc/GMT+9 -9 - -09 -Z Etc/GMT+10 -10 - -10 -Z Etc/GMT+11 -11 - -11 -Z Etc/GMT+12 -12 - -12 +Z Etc/GMT-1 1 - +01 +Z Etc/GMT-10 10 - +10 +Z Etc/GMT-11 11 - +11 +Z Etc/GMT-12 12 - +12 +Z Etc/GMT-13 13 - +13 +Z Etc/GMT-14 14 - +14 +Z Etc/GMT-2 2 - +02 +Z Etc/GMT-3 3 - +03 +Z Etc/GMT-4 4 - +04 +Z Etc/GMT-5 5 - +05 +Z Etc/GMT-6 6 - +06 +Z Etc/GMT-7 7 - +07 +Z Etc/GMT-8 8 - +08 +Z Etc/GMT-9 9 - +09 +Z Etc/UTC 0 - UTC +Z Europe/Andorra 0:6:4 - LMT 1901 +0 - WET 1946 S 30 +1 - CET 1985 Mar 31 2 +1 E CE%sT +Z Europe/Astrakhan 3:12:12 - LMT 1924 May +3 - +03 1930 Jun 21 +4 R +04/+05 1989 Mar 26 2s +3 R +03/+04 1991 Mar 31 2s +4 - +04 1992 Mar 29 2s +3 R +03/+04 2011 Mar 27 2s +4 - +04 2014 O 26 2s +3 - +03 2016 Mar 27 2s +4 - +04 +Z Europe/Athens 1:34:52 - LMT 1895 S 14 +1:34:52 - AMT 1916 Jul 28 0:1 +2 g EE%sT 1941 Ap 30 +1 g CE%sT 1944 Ap 4 +2 g EE%sT 1981 +2 E EE%sT +Z Europe/Belgrade 1:22 - LMT 1884 +1 - CET 1941 Ap 18 23 +1 c CE%sT 1945 +1 - CET 1945 May 8 2s +1 1 CEST 1945 S 16 2s +1 - CET 1982 N 27 +1 E CE%sT +Z Europe/Berlin 0:53:28 - LMT 1893 Ap +1 c CE%sT 1945 May 24 2 +1 So CE%sT 1946 +1 DE CE%sT 1980 +1 E CE%sT +Z Europe/Brussels 0:17:30 - LMT 1880 +0:17:30 - BMT 1892 May 1 0:17:30 +0 - WET 1914 N 8 +1 - CET 1916 May +1 c CE%sT 1918 N 11 11u +0 b WE%sT 1940 May 20 2s +1 c CE%sT 1944 S 3 +1 b CE%sT 1977 +1 E CE%sT +Z Europe/Bucharest 1:44:24 - LMT 1891 O +1:44:24 - BMT 1931 Jul 24 +2 z EE%sT 1981 Mar 29 2s +2 c EE%sT 1991 +2 z EE%sT 1994 +2 e EE%sT 1997 +2 E EE%sT +Z Europe/Budapest 1:16:20 - LMT 1890 N +1 c CE%sT 1918 +1 h CE%sT 1941 Ap 7 23 +1 c CE%sT 1945 +1 h CE%sT 1984 +1 E CE%sT +Z Europe/Chisinau 1:55:20 - LMT 1880 +1:55 - CMT 1918 F 15 +1:44:24 - BMT 1931 Jul 24 +2 z EE%sT 1940 Au 15 +2 1 EEST 1941 Jul 17 +1 c CE%sT 1944 Au 24 +3 R MSK/MSD 1990 May 6 2 +2 R EE%sT 1992 +2 e EE%sT 1997 +2 MD EE%sT +Z Europe/Dublin -0:25:21 - LMT 1880 Au 2 +-0:25:21 - DMT 1916 May 21 2s +-0:25:21 1 IST 1916 O 1 2s +0 G %s 1921 D 6 +0 G GMT/IST 1940 F 25 2s +0 1 IST 1946 O 6 2s +0 - GMT 1947 Mar 16 2s +0 1 IST 1947 N 2 2s +0 - GMT 1948 Ap 18 2s +0 G GMT/IST 1968 O 27 +1 IE IST/GMT +Z Europe/Gibraltar -0:21:24 - LMT 1880 Au 2 +0 G %s 1957 Ap 14 2 +1 - CET 1982 +1 E CE%sT +Z Europe/Helsinki 1:39:49 - LMT 1878 May 31 +1:39:49 - HMT 1921 May +2 FI EE%sT 1983 +2 E EE%sT +Z Europe/Istanbul 1:55:52 - LMT 1880 +1:56:56 - IMT 1910 O +2 T EE%sT 1978 Jun 29 +3 T +03/+04 1984 N 1 2 +2 T EE%sT 2007 +2 E EE%sT 2011 Mar 27 1u +2 - EET 2011 Mar 28 1u +2 E EE%sT 2014 Mar 30 1u +2 - EET 2014 Mar 31 1u +2 E EE%sT 2015 O 25 1u +2 1 EEST 2015 N 8 1u +2 E EE%sT 2016 S 7 +3 - +03 +Z Europe/Kaliningrad 1:22 - LMT 1893 Ap +1 c CE%sT 1945 Ap 10 +2 O EE%sT 1946 Ap 7 +3 R MSK/MSD 1989 Mar 26 2s +2 R EE%sT 2011 Mar 27 2s +3 - +03 2014 O 26 2s +2 - EET +Z Europe/Kirov 3:18:48 - LMT 1919 Jul 1 0u +3 - +03 1930 Jun 21 +4 R +04/+05 1989 Mar 26 2s +3 R MSK/MSD 1991 Mar 31 2s +4 - +04 1992 Mar 29 2s +3 R MSK/MSD 2011 Mar 27 2s +4 - MSK 2014 O 26 2s +3 - MSK +Z Europe/Kyiv 2:2:4 - LMT 1880 +2:2:4 - KMT 1924 May 2 +2 - EET 1930 Jun 21 +3 - MSK 1941 S 20 +1 c CE%sT 1943 N 6 +3 R MSK/MSD 1990 Jul 1 2 +2 1 EEST 1991 S 29 3 +2 c EE%sT 1996 May 13 +2 E EE%sT +Z Europe/Lisbon -0:36:45 - LMT 1884 +-0:36:45 - LMT 1912 Ja 1 0u +0 p WE%sT 1966 Ap 3 2 +1 - CET 1976 S 26 1 +0 p WE%sT 1983 S 25 1s +0 W- WE%sT 1992 S 27 1s +1 E CE%sT 1996 Mar 31 1u +0 E WE%sT +Z Europe/London -0:1:15 - LMT 1847 D +0 G %s 1968 O 27 +1 - BST 1971 O 31 2u +0 G %s 1996 +0 E GMT/BST +Z Europe/Madrid -0:14:44 - LMT 1901 Ja 1 0u +0 s WE%sT 1940 Mar 16 23 +1 s CE%sT 1979 +1 E CE%sT +Z Europe/Malta 0:58:4 - LMT 1893 N 2 +1 I CE%sT 1973 Mar 31 +1 MT CE%sT 1981 +1 E CE%sT +Z Europe/Minsk 1:50:16 - LMT 1880 +1:50 - MMT 1924 May 2 +2 - EET 1930 Jun 21 +3 - MSK 1941 Jun 28 +1 c CE%sT 1944 Jul 3 +3 R MSK/MSD 1990 +3 - MSK 1991 Mar 31 2s +2 R EE%sT 2011 Mar 27 2s +3 - +03 +Z Europe/Moscow 2:30:17 - LMT 1880 +2:30:17 - MMT 1916 Jul 3 +2:31:19 R %s 1919 Jul 1 0u +3 R %s 1921 O +3 R MSK/MSD 1922 O +2 - EET 1930 Jun 21 +3 R MSK/MSD 1991 Mar 31 2s +2 R EE%sT 1992 Ja 19 2s +3 R MSK/MSD 2011 Mar 27 2s +4 - MSK 2014 O 26 2s +3 - MSK +Z Europe/Paris 0:9:21 - LMT 1891 Mar 16 +0:9:21 - PMT 1911 Mar 11 +0 F WE%sT 1940 Jun 14 23 +1 c CE%sT 1944 Au 25 +0 F WE%sT 1945 S 16 3 +1 F CE%sT 1977 +1 E CE%sT +Z Europe/Prague 0:57:44 - LMT 1850 +0:57:44 - PMT 1891 O +1 c CE%sT 1945 May 9 +1 CZ CE%sT 1946 D 1 3 +1 -1 GMT 1947 F 23 2 +1 CZ CE%sT 1979 +1 E CE%sT +Z Europe/Riga 1:36:34 - LMT 1880 +1:36:34 - RMT 1918 Ap 15 2 +1:36:34 1 LST 1918 S 16 3 +1:36:34 - RMT 1919 Ap 1 2 +1:36:34 1 LST 1919 May 22 3 +1:36:34 - RMT 1926 May 11 +2 - EET 1940 Au 5 +3 - MSK 1941 Jul +1 c CE%sT 1944 O 13 +3 R MSK/MSD 1989 Mar lastSu 2s +2 1 EEST 1989 S lastSu 2s +2 LV EE%sT 1997 Ja 21 +2 E EE%sT 2000 F 29 +2 - EET 2001 Ja 2 +2 E EE%sT +Z Europe/Rome 0:49:56 - LMT 1866 D 12 +0:49:56 - RMT 1893 O 31 23u +1 I CE%sT 1943 S 10 +1 c CE%sT 1944 Jun 4 +1 I CE%sT 1980 +1 E CE%sT +Z Europe/Samara 3:20:20 - LMT 1919 Jul 1 0u +3 - +03 1930 Jun 21 +4 - +04 1935 Ja 27 +4 R +04/+05 1989 Mar 26 2s +3 R +03/+04 1991 Mar 31 2s +2 R +02/+03 1991 S 29 2s +3 - +03 1991 O 20 3 +4 R +04/+05 2010 Mar 28 2s +3 R +03/+04 2011 Mar 27 2s +4 - +04 +Z Europe/Saratov 3:4:18 - LMT 1919 Jul 1 0u +3 - +03 1930 Jun 21 +4 R +04/+05 1988 Mar 27 2s +3 R +03/+04 1991 Mar 31 2s +4 - +04 1992 Mar 29 2s +3 R +03/+04 2011 Mar 27 2s +4 - +04 2014 O 26 2s +3 - +03 2016 D 4 2s +4 - +04 +Z Europe/Simferopol 2:16:24 - LMT 1880 +2:16 - SMT 1924 May 2 +2 - EET 1930 Jun 21 +3 - MSK 1941 N +1 c CE%sT 1944 Ap 13 +3 R MSK/MSD 1990 +3 - MSK 1990 Jul 1 2 +2 - EET 1992 Mar 20 +2 c EE%sT 1994 May +3 c MSK/MSD 1996 Mar 31 0s +3 1 MSD 1996 O 27 3s +3 - MSK 1997 Mar lastSu 1u +2 E EE%sT 2014 Mar 30 2 +4 - MSK 2014 O 26 2s +3 - MSK +Z Europe/Sofia 1:33:16 - LMT 1880 +1:56:56 - IMT 1894 N 30 +2 - EET 1942 N 2 3 +1 c CE%sT 1945 +1 - CET 1945 Ap 2 3 +2 - EET 1979 Mar 31 23 +2 BG EE%sT 1982 S 26 3 +2 c EE%sT 1991 +2 e EE%sT 1997 +2 E EE%sT +Z Europe/Tallinn 1:39 - LMT 1880 +1:39 - TMT 1918 F +1 c CE%sT 1919 Jul +1:39 - TMT 1921 May +2 - EET 1940 Au 6 +3 - MSK 1941 S 15 +1 c CE%sT 1944 S 22 +3 R MSK/MSD 1989 Mar 26 2s +2 1 EEST 1989 S 24 2s +2 c EE%sT 1998 S 22 +2 E EE%sT 1999 O 31 4 +2 - EET 2002 F 21 +2 E EE%sT +Z Europe/Tirane 1:19:20 - LMT 1914 +1 - CET 1940 Jun 16 +1 q CE%sT 1984 Jul +1 E CE%sT +Z Europe/Ulyanovsk 3:13:36 - LMT 1919 Jul 1 0u +3 - +03 1930 Jun 21 +4 R +04/+05 1989 Mar 26 2s +3 R +03/+04 1991 Mar 31 2s +2 R +02/+03 1992 Ja 19 2s +3 R +03/+04 2011 Mar 27 2s +4 - +04 2014 O 26 2s +3 - +03 2016 Mar 27 2s +4 - +04 +Z Europe/Vienna 1:5:21 - LMT 1893 Ap +1 c CE%sT 1920 +1 a CE%sT 1940 Ap 1 2s +1 c CE%sT 1945 Ap 2 2s +1 1 CEST 1945 Ap 12 2s +1 - CET 1946 +1 a CE%sT 1981 +1 E CE%sT +Z Europe/Vilnius 1:41:16 - LMT 1880 +1:24 - WMT 1917 +1:35:36 - KMT 1919 O 10 +1 - CET 1920 Jul 12 +2 - EET 1920 O 9 +1 - CET 1940 Au 3 +3 - MSK 1941 Jun 24 +1 c CE%sT 1944 Au +3 R MSK/MSD 1989 Mar 26 2s +2 R EE%sT 1991 S 29 2s +2 c EE%sT 1998 +2 - EET 1998 Mar 29 1u +1 E CE%sT 1999 O 31 1u +2 - EET 2003 +2 E EE%sT +Z Europe/Volgograd 2:57:40 - LMT 1920 Ja 3 +3 - +03 1930 Jun 21 +4 - +04 1961 N 11 +4 R +04/+05 1988 Mar 27 2s +3 R MSK/MSD 1991 Mar 31 2s +4 - +04 1992 Mar 29 2s +3 R MSK/MSD 2011 Mar 27 2s +4 - MSK 2014 O 26 2s +3 - MSK 2018 O 28 2s +4 - +04 2020 D 27 2s +3 - MSK +Z Europe/Warsaw 1:24 - LMT 1880 +1:24 - WMT 1915 Au 5 +1 c CE%sT 1918 S 16 3 +2 O EE%sT 1922 Jun +1 O CE%sT 1940 Jun 23 2 +1 c CE%sT 1944 O +1 O CE%sT 1977 +1 W- CE%sT 1988 +1 E CE%sT +Z Europe/Zurich 0:34:8 - LMT 1853 Jul 16 +0:29:46 - BMT 1894 Jun +1 CH CE%sT 1981 +1 E CE%sT Z Factory 0 - -00 +Z HST -10 - HST +Z Indian/Chagos 4:49:40 - LMT 1907 +5 - +05 1996 +6 - +06 +Z Indian/Maldives 4:54 - LMT 1880 +4:54 - MMT 1960 +5 - +05 +Z Indian/Mauritius 3:50 - LMT 1907 +4 MU +04/+05 +Z MET 1 c ME%sT +Z MST -7 - MST +Z MST7MDT -7 u M%sT +Z PST8PDT -8 u P%sT +Z Pacific/Apia 12:33:4 - LMT 1892 Jul 5 +-11:26:56 - LMT 1911 +-11:30 - -1130 1950 +-11 WS -11/-10 2011 D 29 24 +13 WS +13/+14 +Z Pacific/Auckland 11:39:4 - LMT 1868 N 2 +11:30 NZ NZ%sT 1946 +12 NZ NZ%sT +Z Pacific/Bougainville 10:22:16 - LMT 1880 +9:48:32 - PMMT 1895 +10 - +10 1942 Jul +9 - +09 1945 Au 21 +10 - +10 2014 D 28 2 +11 - +11 +Z Pacific/Chatham 12:13:48 - LMT 1868 N 2 +12:15 - +1215 1946 +12:45 k +1245/+1345 +Z Pacific/Easter -7:17:28 - LMT 1890 +-7:17:28 - EMT 1932 S +-7 x -07/-06 1982 Mar 14 3u +-6 x -06/-05 +Z Pacific/Efate 11:13:16 - LMT 1912 Ja 13 +11 VU +11/+12 +Z Pacific/Fakaofo -11:24:56 - LMT 1901 +-11 - -11 2011 D 30 +13 - +13 +Z Pacific/Fiji 11:55:44 - LMT 1915 O 26 +12 FJ +12/+13 +Z Pacific/Galapagos -5:58:24 - LMT 1931 +-5 - -05 1986 +-6 EC -06/-05 +Z Pacific/Gambier -8:59:48 - LMT 1912 O +-9 - -09 +Z Pacific/Guadalcanal 10:39:48 - LMT 1912 O +11 - +11 +Z Pacific/Guam -14:21 - LMT 1844 D 31 +9:39 - LMT 1901 +10 - GST 1941 D 10 +9 - +09 1944 Jul 31 +10 Gu G%sT 2000 D 23 +10 - ChST +Z Pacific/Honolulu -10:31:26 - LMT 1896 Ja 13 12 +-10:30 - HST 1933 Ap 30 2 +-10:30 1 HDT 1933 May 21 12 +-10:30 u H%sT 1947 Jun 8 2 +-10 - HST +Z Pacific/Kanton 0 - -00 1937 Au 31 +-12 - -12 1979 O +-11 - -11 1994 D 31 +13 - +13 +Z Pacific/Kiritimati -10:29:20 - LMT 1901 +-10:40 - -1040 1979 O +-10 - -10 1994 D 31 +14 - +14 +Z Pacific/Kosrae -13:8:4 - LMT 1844 D 31 +10:51:56 - LMT 1901 +11 - +11 1914 O +9 - +09 1919 F +11 - +11 1937 +10 - +10 1941 Ap +9 - +09 1945 Au +11 - +11 1969 O +12 - +12 1999 +11 - +11 +Z Pacific/Kwajalein 11:9:20 - LMT 1901 +11 - +11 1937 +10 - +10 1941 Ap +9 - +09 1944 F 6 +11 - +11 1969 O +-12 - -12 1993 Au 20 24 +12 - +12 +Z Pacific/Marquesas -9:18 - LMT 1912 O +-9:30 - -0930 +Z Pacific/Nauru 11:7:40 - LMT 1921 Ja 15 +11:30 - +1130 1942 Au 29 +9 - +09 1945 S 8 +11:30 - +1130 1979 F 10 2 +12 - +12 +Z Pacific/Niue -11:19:40 - LMT 1952 O 16 +-11:20 - -1120 1964 Jul +-11 - -11 +Z Pacific/Norfolk 11:11:52 - LMT 1901 +11:12 - +1112 1951 +11:30 - +1130 1974 O 27 2s +11:30 1 +1230 1975 Mar 2 2s +11:30 - +1130 2015 O 4 2s +11 - +11 2019 Jul +11 AN +11/+12 +Z Pacific/Noumea 11:5:48 - LMT 1912 Ja 13 +11 NC +11/+12 +Z Pacific/Pago_Pago 12:37:12 - LMT 1892 Jul 5 +-11:22:48 - LMT 1911 +-11 - SST +Z Pacific/Palau -15:2:4 - LMT 1844 D 31 +8:57:56 - LMT 1901 +9 - +09 +Z Pacific/Pitcairn -8:40:20 - LMT 1901 +-8:30 - -0830 1998 Ap 27 +-8 - -08 +Z Pacific/Port_Moresby 9:48:40 - LMT 1880 +9:48:32 - PMMT 1895 +10 - +10 +Z Pacific/Rarotonga 13:20:56 - LMT 1899 D 26 +-10:39:4 - LMT 1952 O 16 +-10:30 - -1030 1978 N 12 +-10 CK -10/-0930 +Z Pacific/Tahiti -9:58:16 - LMT 1912 O +-10 - -10 +Z Pacific/Tarawa 11:32:4 - LMT 1901 +12 - +12 +Z Pacific/Tongatapu 12:19:12 - LMT 1945 S 10 +12:20 - +1220 1961 +13 - +13 1999 +13 TO +13/+14 +Z WET 0 E WE%sT +L Etc/GMT GMT L Australia/Sydney Australia/ACT L Australia/Lord_Howe Australia/LHI L Australia/Sydney Australia/NSW @@ -4185,7 +4195,6 @@ L America/Puerto_Rico America/Tortola L Pacific/Port_Moresby Antarctica/DumontDUrville L Pacific/Auckland Antarctica/McMurdo L Asia/Riyadh Antarctica/Syowa -L Asia/Urumqi Antarctica/Vostok L Europe/Berlin Arctic/Longyearbyen L Asia/Riyadh Asia/Aden L Asia/Qatar Asia/Bahrain diff --git a/lib/pytz/zoneinfo/zone.tab b/lib/pytz/zoneinfo/zone.tab index dbcb6179..3fa9306a 100644 --- a/lib/pytz/zoneinfo/zone.tab +++ b/lib/pytz/zoneinfo/zone.tab @@ -48,7 +48,7 @@ AR -3124-06411 America/Argentina/Cordoba Argentina (most areas: CB, CC, CN, ER, AR -2447-06525 America/Argentina/Salta Salta (SA, LP, NQ, RN) AR -2411-06518 America/Argentina/Jujuy Jujuy (JY) AR -2649-06513 America/Argentina/Tucuman Tucuman (TM) -AR -2828-06547 America/Argentina/Catamarca Catamarca (CT); Chubut (CH) +AR -2828-06547 America/Argentina/Catamarca Catamarca (CT), Chubut (CH) AR -2926-06651 America/Argentina/La_Rioja La Rioja (LR) AR -3132-06831 America/Argentina/San_Juan San Juan (SJ) AR -3253-06849 America/Argentina/Mendoza Mendoza (MZ) @@ -87,7 +87,7 @@ BN +0456+11455 Asia/Brunei BO -1630-06809 America/La_Paz BQ +120903-0681636 America/Kralendijk BR -0351-03225 America/Noronha Atlantic islands -BR -0127-04829 America/Belem Para (east); Amapa +BR -0127-04829 America/Belem Para (east), Amapa BR -0343-03830 America/Fortaleza Brazil (northeast: MA, PI, CE, RN, PB) BR -0803-03454 America/Recife Pernambuco BR -0712-04812 America/Araguaina Tocantins @@ -107,21 +107,21 @@ BT +2728+08939 Asia/Thimphu BW -2439+02555 Africa/Gaborone BY +5354+02734 Europe/Minsk BZ +1730-08812 America/Belize -CA +4734-05243 America/St_Johns Newfoundland; Labrador (southeast) -CA +4439-06336 America/Halifax Atlantic - NS (most areas); PE +CA +4734-05243 America/St_Johns Newfoundland, Labrador (SE) +CA +4439-06336 America/Halifax Atlantic - NS (most areas), PE CA +4612-05957 America/Glace_Bay Atlantic - NS (Cape Breton) CA +4606-06447 America/Moncton Atlantic - New Brunswick CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas) CA +5125-05707 America/Blanc-Sablon AST - QC (Lower North Shore) -CA +4339-07923 America/Toronto Eastern - ON, QC (most areas) +CA +4339-07923 America/Toronto Eastern - ON & QC (most areas) CA +6344-06828 America/Iqaluit Eastern - NU (most areas) -CA +484531-0913718 America/Atikokan EST - ON (Atikokan); NU (Coral H) -CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba +CA +484531-0913718 America/Atikokan EST - ON (Atikokan), NU (Coral H) +CA +4953-09709 America/Winnipeg Central - ON (west), Manitoba CA +744144-0944945 America/Resolute Central - NU (Resolute) CA +624900-0920459 America/Rankin_Inlet Central - NU (central) CA +5024-10439 America/Regina CST - SK (most areas) CA +5017-10750 America/Swift_Current CST - SK (midwest) -CA +5333-11328 America/Edmonton Mountain - AB; BC (E); NT (E); SK (W) +CA +5333-11328 America/Edmonton Mountain - AB, BC(E), NT(E), SK(W) CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west) CA +682059-1334300 America/Inuvik Mountain - NT (west) CA +4906-11631 America/Creston MST - BC (Creston) @@ -207,8 +207,8 @@ HT +1832-07220 America/Port-au-Prince HU +4730+01905 Europe/Budapest ID -0610+10648 Asia/Jakarta Java, Sumatra ID -0002+10920 Asia/Pontianak Borneo (west, central) -ID -0507+11924 Asia/Makassar Borneo (east, south); Sulawesi/Celebes, Bali, Nusa Tengarra; Timor (west) -ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya); Malukus/Moluccas +ID -0507+11924 Asia/Makassar Borneo (east, south), Sulawesi/Celebes, Bali, Nusa Tengarra, Timor (west) +ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya), Malukus/Moluccas IE +5320-00615 Europe/Dublin IL +314650+0351326 Asia/Jerusalem IM +5409-00428 Europe/Isle_of_Man @@ -355,7 +355,7 @@ RU +4310+13156 Asia/Vladivostok MSK+07 - Amur River RU +643337+1431336 Asia/Ust-Nera MSK+07 - Oymyakonsky RU +5934+15048 Asia/Magadan MSK+08 - Magadan RU +4658+14242 Asia/Sakhalin MSK+08 - Sakhalin Island -RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E); N Kuril Is +RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E), N Kuril Is RU +5301+15839 Asia/Kamchatka MSK+09 - Kamchatka RU +6445+17729 Asia/Anadyr MSK+09 - Bering Sea RW -0157+03004 Africa/Kigali @@ -418,7 +418,7 @@ US +470659-1011757 America/North_Dakota/Center Central - ND (Oliver) US +465042-1012439 America/North_Dakota/New_Salem Central - ND (Morton rural) US +471551-1014640 America/North_Dakota/Beulah Central - ND (Mercer) US +394421-1045903 America/Denver Mountain (most areas) -US +433649-1161209 America/Boise Mountain - ID (south); OR (east) +US +433649-1161209 America/Boise Mountain - ID (south), OR (east) US +332654-1120424 America/Phoenix MST - AZ (except Navajo) US +340308-1181434 America/Los_Angeles Pacific US +611305-1495401 America/Anchorage Alaska (most areas) diff --git a/lib/pytz/zoneinfo/zone1970.tab b/lib/pytz/zoneinfo/zone1970.tab index 1f1cecb8..abd94897 100644 --- a/lib/pytz/zoneinfo/zone1970.tab +++ b/lib/pytz/zoneinfo/zone1970.tab @@ -37,7 +37,7 @@ #country- #codes coordinates TZ comments AD +4230+00131 Europe/Andorra -AE,OM,RE,SC,TF +2518+05518 Asia/Dubai Crozet, Scattered Is +AE,OM,RE,SC,TF +2518+05518 Asia/Dubai Crozet AF +3431+06912 Asia/Kabul AL +4120+01950 Europe/Tirane AM +4011+04430 Asia/Yerevan @@ -47,12 +47,13 @@ AQ -6736+06253 Antarctica/Mawson Mawson AQ -6448-06406 Antarctica/Palmer Palmer AQ -6734-06808 Antarctica/Rothera Rothera AQ -720041+0023206 Antarctica/Troll Troll +AQ -7824+10654 Antarctica/Vostok Vostok AR -3436-05827 America/Argentina/Buenos_Aires Buenos Aires (BA, CF) AR -3124-06411 America/Argentina/Cordoba most areas: CB, CC, CN, ER, FM, MN, SE, SF AR -2447-06525 America/Argentina/Salta Salta (SA, LP, NQ, RN) AR -2411-06518 America/Argentina/Jujuy Jujuy (JY) AR -2649-06513 America/Argentina/Tucuman Tucumán (TM) -AR -2828-06547 America/Argentina/Catamarca Catamarca (CT); Chubut (CH) +AR -2828-06547 America/Argentina/Catamarca Catamarca (CT), Chubut (CH) AR -2926-06651 America/Argentina/La_Rioja La Rioja (LR) AR -3132-06831 America/Argentina/San_Juan San Juan (SJ) AR -3253-06849 America/Argentina/Mendoza Mendoza (MZ) @@ -81,7 +82,7 @@ BG +4241+02319 Europe/Sofia BM +3217-06446 Atlantic/Bermuda BO -1630-06809 America/La_Paz BR -0351-03225 America/Noronha Atlantic islands -BR -0127-04829 America/Belem Pará (east); Amapá +BR -0127-04829 America/Belem Pará (east), Amapá BR -0343-03830 America/Fortaleza Brazil (northeast: MA, PI, CE, RN, PB) BR -0803-03454 America/Recife Pernambuco BR -0712-04812 America/Araguaina Tocantins @@ -99,19 +100,19 @@ BR -0958-06748 America/Rio_Branco Acre BT +2728+08939 Asia/Thimphu BY +5354+02734 Europe/Minsk BZ +1730-08812 America/Belize -CA +4734-05243 America/St_Johns Newfoundland; Labrador (southeast) -CA +4439-06336 America/Halifax Atlantic - NS (most areas); PE +CA +4734-05243 America/St_Johns Newfoundland, Labrador (SE) +CA +4439-06336 America/Halifax Atlantic - NS (most areas), PE CA +4612-05957 America/Glace_Bay Atlantic - NS (Cape Breton) CA +4606-06447 America/Moncton Atlantic - New Brunswick CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas) -CA,BS +4339-07923 America/Toronto Eastern - ON, QC (most areas) +CA,BS +4339-07923 America/Toronto Eastern - ON & QC (most areas) CA +6344-06828 America/Iqaluit Eastern - NU (most areas) -CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba +CA +4953-09709 America/Winnipeg Central - ON (west), Manitoba CA +744144-0944945 America/Resolute Central - NU (Resolute) CA +624900-0920459 America/Rankin_Inlet Central - NU (central) CA +5024-10439 America/Regina CST - SK (most areas) CA +5017-10750 America/Swift_Current CST - SK (midwest) -CA +5333-11328 America/Edmonton Mountain - AB; BC (E); NT (E); SK (W) +CA +5333-11328 America/Edmonton Mountain - AB, BC(E), NT(E), SK(W) CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west) CA +682059-1334300 America/Inuvik Mountain - NT (west) CA +5546-12014 America/Dawson_Creek MST - BC (Dawson Cr, Ft St John) @@ -126,7 +127,7 @@ CL -3327-07040 America/Santiago most of Chile CL -5309-07055 America/Punta_Arenas Region of Magallanes CL -2709-10926 Pacific/Easter Easter Island CN +3114+12128 Asia/Shanghai Beijing Time -CN,AQ +4348+08735 Asia/Urumqi Xinjiang Time, Vostok +CN +4348+08735 Asia/Urumqi Xinjiang Time CO +0436-07405 America/Bogota CR +0956-08405 America/Costa_Rica CU +2308-08222 America/Havana @@ -171,8 +172,8 @@ HT +1832-07220 America/Port-au-Prince HU +4730+01905 Europe/Budapest ID -0610+10648 Asia/Jakarta Java, Sumatra ID -0002+10920 Asia/Pontianak Borneo (west, central) -ID -0507+11924 Asia/Makassar Borneo (east, south); Sulawesi/Celebes, Bali, Nusa Tengarra; Timor (west) -ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya); Malukus/Moluccas +ID -0507+11924 Asia/Makassar Borneo (east, south), Sulawesi/Celebes, Bali, Nusa Tengarra, Timor (west) +ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya), Malukus/Moluccas IE +5320-00615 Europe/Dublin IL +314650+0351326 Asia/Jerusalem IN +2232+08822 Asia/Kolkata @@ -251,7 +252,7 @@ PK +2452+06703 Asia/Karachi PL +5215+02100 Europe/Warsaw PM +4703-05620 America/Miquelon PN -2504-13005 Pacific/Pitcairn -PR,AG,CA,AI,AW,BL,BQ,CW,DM,GD,GP,KN,LC,MF,MS,SX,TT,VC,VG,VI +182806-0660622 America/Puerto_Rico AST +PR,AG,CA,AI,AW,BL,BQ,CW,DM,GD,GP,KN,LC,MF,MS,SX,TT,VC,VG,VI +182806-0660622 America/Puerto_Rico AST - QC (Lower North Shore) PS +3130+03428 Asia/Gaza Gaza Strip PS +313200+0350542 Asia/Hebron West Bank PT +3843-00908 Europe/Lisbon Portugal (mainland) @@ -287,7 +288,7 @@ RU +4310+13156 Asia/Vladivostok MSK+07 - Amur River RU +643337+1431336 Asia/Ust-Nera MSK+07 - Oymyakonsky RU +5934+15048 Asia/Magadan MSK+08 - Magadan RU +4658+14242 Asia/Sakhalin MSK+08 - Sakhalin Island -RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E); N Kuril Is +RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E), N Kuril Is RU +5301+15839 Asia/Kamchatka MSK+09 - Kamchatka RU +6445+17729 Asia/Anadyr MSK+09 - Bering Sea SA,AQ,KW,YE +2438+04643 Asia/Riyadh Syowa @@ -329,7 +330,7 @@ US +470659-1011757 America/North_Dakota/Center Central - ND (Oliver) US +465042-1012439 America/North_Dakota/New_Salem Central - ND (Morton rural) US +471551-1014640 America/North_Dakota/Beulah Central - ND (Mercer) US +394421-1045903 America/Denver Mountain (most areas) -US +433649-1161209 America/Boise Mountain - ID (south); OR (east) +US +433649-1161209 America/Boise Mountain - ID (south), OR (east) US,CA +332654-1120424 America/Phoenix MST - AZ (most areas), Creston BC US +340308-1181434 America/Los_Angeles Pacific US +611305-1495401 America/Anchorage Alaska (most areas) diff --git a/lib/pytz/zoneinfo/zonenow.tab b/lib/pytz/zoneinfo/zonenow.tab new file mode 100644 index 00000000..b6f29109 --- /dev/null +++ b/lib/pytz/zoneinfo/zonenow.tab @@ -0,0 +1,303 @@ +# tzdb timezone descriptions, for users who do not care about old timestamps +# +# This file is in the public domain. +# +# From Paul Eggert (2023-12-18): +# This file contains a table where each row stands for a timezone +# where civil timestamps are predicted to agree from now on. +# This file is like zone1970.tab (see zone1970.tab's coments), +# but with the following changes: +# +# 1. Each timezone corresponds to a set of clocks that are planned +# to agree from now on. This is a larger set of clocks than in +# zone1970.tab, where each timezone's clocks must agree from 1970 on. +# 2. The first column is irrelevant and ignored. +# 3. The table is sorted in a different way: +# first by standard time UTC offset; +# then, if DST is used, by daylight saving UTC offset; +# then by time zone abbreviation. +# 4. Every timezone has a nonempty comments column, with wording +# distinguishing the timezone only from other timezones with the +# same UTC offset at some point during the year. +# +# The format of this table is experimental, and may change in future versions. +# +# This table is intended as an aid for users, to help them select timezones +# appropriate for their practical needs. It is not intended to take or +# endorse any position on legal or territorial claims. +# +#XX coordinates TZ comments +# +# -11 - SST +XX -1416-17042 Pacific/Pago_Pago Midway; Samoa ("SST") +# +# -11 +XX -1901-16955 Pacific/Niue Niue +# +# -10 - HST +XX +211825-1575130 Pacific/Honolulu Hawaii ("HST") +# +# -10 +XX -1732-14934 Pacific/Tahiti Tahiti; Cook Islands +# +# -10/-09 - HST / HDT (North America DST) +XX +515248-1763929 America/Adak western Aleutians in Alaska ("HST/HDT") +# +# -09:30 +XX -0900-13930 Pacific/Marquesas Marquesas +# +# -09 +XX -2308-13457 Pacific/Gambier Gambier +# +# -09/-08 - AKST/AKDT (North America DST) +XX +611305-1495401 America/Anchorage most of Alaska ("AKST/AKDT") +# +# -08 +XX -2504-13005 Pacific/Pitcairn Pitcairn +# +# -08/-07 - PST/PDT (North America DST) +XX +340308-1181434 America/Los_Angeles Pacific ("PST/PDT") - US & Canada; Mexico near US border +# +# -07 - MST +XX +332654-1120424 America/Phoenix Mountain Standard ("MST") - Arizona; western Mexico; Yukon +# +# -07/-06 - MST/MDT (North America DST) +XX +394421-1045903 America/Denver Mountain ("MST/MDT") - US & Canada; Mexico near US border +# +# -06 +XX -0054-08936 Pacific/Galapagos Galápagos +# +# -06 - CST +XX +1924-09909 America/Mexico_City Central Standard ("CST") - Saskatchewan; central Mexico; Central America +# +# -06/-05 (Chile DST) +XX -2709-10926 Pacific/Easter Easter Island +# +# -06/-05 - CST/CDT (North America DST) +XX +415100-0873900 America/Chicago Central ("CST/CDT") - US & Canada; Mexico near US border +# +# -05 +XX -1203-07703 America/Lima eastern South America +# +# -05 - EST +XX +175805-0764736 America/Jamaica Eastern Standard ("EST") - Caymans; Jamaica; eastern Mexico; Panama +# +# -05/-04 - CST/CDT (Cuba DST) +XX +2308-08222 America/Havana Cuba +# +# -05/-04 - EST/EDT (North America DST) +XX +404251-0740023 America/New_York Eastern ("EST/EDT") - US & Canada +# +# -04 +XX +1030-06656 America/Caracas western South America +# +# -04 - AST +XX +1828-06954 America/Santo_Domingo Atlantic Standard ("AST") - eastern Caribbean +# +# -04/-03 (Chile DST) +XX -3327-07040 America/Santiago most of Chile +# +# -04/-03 (Paraguay DST) +XX -2516-05740 America/Asuncion Paraguay +# +# -04/-03 - AST/ADT (North America DST) +XX +4439-06336 America/Halifax Atlantic ("AST/ADT") - Canada; Bermuda +# +# -03:30/-02:30 - NST/NDT (North America DST) +XX +4734-05243 America/St_Johns Newfoundland ("NST/NDT") +# +# -03 +XX -2332-04637 America/Sao_Paulo eastern South America +# +# -03/-02 (North America DST) +XX +4703-05620 America/Miquelon St Pierre & Miquelon +# +# -02 +XX -0351-03225 America/Noronha Fernando de Noronha; South Georgia +# +# -02/-01 (EU DST) +XX +6411-05144 America/Nuuk most of Greenland +# +# -01 +XX +1455-02331 Atlantic/Cape_Verde Cape Verde +# +# -01/+00 (EU DST) +XX +3744-02540 Atlantic/Azores Azores +# -01/+00 (EU DST) until 2024-03-31; then -02/-01 (EU DST) +XX +7029-02158 America/Scoresbysund Ittoqqortoormiit +# +# +00 - GMT +XX +0519-00402 Africa/Abidjan far western Africa; Iceland ("GMT") +# +# +00/+01 - GMT/BST (EU DST) +XX +513030-0000731 Europe/London United Kingdom ("GMT/BST") +# +# +00/+01 - WET/WEST (EU DST) +XX +3843-00908 Europe/Lisbon western Europe ("WET/WEST") +# +# +00/+02 - Troll DST +XX -720041+0023206 Antarctica/Troll Troll Station in Antarctica +# +# +01 - CET +XX +3647+00303 Africa/Algiers Algeria, Tunisia ("CET") +# +# +01 - WAT +XX +0627+00324 Africa/Lagos western Africa ("WAT") +# +# +01/+00 - IST/GMT (EU DST in reverse) +XX +5320-00615 Europe/Dublin Ireland ("IST/GMT") +# +# +01/+00 - (Morocco DST) +XX +3339-00735 Africa/Casablanca Morocco +# +# +01/+02 - CET/CEST (EU DST) +XX +4852+00220 Europe/Paris central Europe ("CET/CEST") +# +# +02 - CAT +XX -2558+03235 Africa/Maputo central Africa ("CAT") +# +# +02 - EET +XX +3254+01311 Africa/Tripoli Libya; Kaliningrad ("EET") +# +# +02 - SAST +XX -2615+02800 Africa/Johannesburg southern Africa ("SAST") +# +# +02/+03 - EET/EEST (EU DST) +XX +3758+02343 Europe/Athens eastern Europe ("EET/EEST") +# +# +02/+03 - EET/EEST (Egypt DST) +XX +3003+03115 Africa/Cairo Egypt +# +# +02/+03 - EET/EEST (Lebanon DST) +XX +3353+03530 Asia/Beirut Lebanon +# +# +02/+03 - EET/EEST (Moldova DST) +XX +4700+02850 Europe/Chisinau Moldova +# +# +02/+03 - EET/EEST (Palestine DST) +XX +3130+03428 Asia/Gaza Palestine +# +# +02/+03 - IST/IDT (Israel DST) +XX +314650+0351326 Asia/Jerusalem Israel +# +# +03 +XX +4101+02858 Europe/Istanbul Near East; Belarus +# +# +03 - EAT +XX -0117+03649 Africa/Nairobi eastern Africa ("EAT") +# +# +03 - MSK +XX +554521+0373704 Europe/Moscow Moscow ("MSK") +# +# +03:30 +XX +3540+05126 Asia/Tehran Iran +# +# +04 +XX +2518+05518 Asia/Dubai Russia; Caucasus; Persian Gulf; Seychelles; Réunion +# +# +04:30 +XX +3431+06912 Asia/Kabul Afghanistan +# +# +05 +XX +4120+06918 Asia/Tashkent Russia; west Kazakhstan; Tajikistan; Turkmenistan; Uzbekistan; Maldives +# +# +05 - PKT +XX +2452+06703 Asia/Karachi Pakistan ("PKT") +# +# +05:30 +XX +0656+07951 Asia/Colombo Sri Lanka +# +# +05:30 - IST +XX +2232+08822 Asia/Kolkata India ("IST") +# +# +05:45 +XX +2743+08519 Asia/Kathmandu Nepal +# +# +06 +XX +2343+09025 Asia/Dhaka Russia; Kyrgyzstan; Bhutan; Bangladesh; Chagos +# +06 until 2024-03-01; then +05 +XX +4315+07657 Asia/Almaty Kazakhstan (except western areas) +# +# +06:30 +XX +1647+09610 Asia/Yangon Myanmar; Cocos +# +# +07 +XX +1345+10031 Asia/Bangkok Russia; Indochina; Christmas Island +# +# +07 - WIB +XX -0610+10648 Asia/Jakarta Indonesia ("WIB") +# +# +08 +XX +0117+10351 Asia/Singapore Russia; Brunei; Malaysia; Singapore +# +# +08 - AWST +XX -3157+11551 Australia/Perth Western Australia ("AWST") +# +# +08 - CST +XX +3114+12128 Asia/Shanghai China ("CST") +# +# +08 - HKT +XX +2217+11409 Asia/Hong_Kong Hong Kong ("HKT") +# +# +08 - PHT +XX +1435+12100 Asia/Manila Philippines ("PHT") +# +# +08 - WITA +XX -0507+11924 Asia/Makassar Indonesia ("WITA") +# +# +08:45 +XX -3143+12852 Australia/Eucla Eucla +# +# +09 +XX +5203+11328 Asia/Chita Russia; Palau; East Timor +# +# +09 - JST +XX +353916+1394441 Asia/Tokyo Japan ("JST") +# +# +09 - KST +XX +3733+12658 Asia/Seoul Korea ("KST") +# +# +09 - WIT +XX -0232+14042 Asia/Jayapura Indonesia ("WIT") +# +# +09:30 - ACST +XX -1228+13050 Australia/Darwin Northern Territory ("ACST") +# +# +09:30/+10:30 - ACST/ACDT (Australia DST) +XX -3455+13835 Australia/Adelaide South Australia ("ACST/ACDT") +# +# +10 +XX +4310+13156 Asia/Vladivostok Russia; Yap; Chuuk; Papua New Guinea; Dumont d'Urville +# +# +10 - AEST +XX -2728+15302 Australia/Brisbane Queensland ("AEST") +# +# +10 - ChST +XX +1328+14445 Pacific/Guam Mariana Islands ("ChST") +# +# +10/+11 - AEST/AEDT (Australia DST) +XX -3352+15113 Australia/Sydney southeast Australia ("AEST/AEDT") +# +# +10:30/+11 +XX -3133+15905 Australia/Lord_Howe Lord Howe Island +# +# +11 +XX -0613+15534 Pacific/Bougainville Russia; Kosrae; Bougainville; Solomons +# +# +11/+12 (Australia DST) +XX -2903+16758 Pacific/Norfolk Norfolk Island +# +# +12 +XX +5301+15839 Asia/Kamchatka Russia; Tuvalu; Fiji; etc. +# +# +12/+13 (New Zealand DST) +XX -3652+17446 Pacific/Auckland New Zealand ("NZST/NZDT") +# +# +12:45/+13:45 (Chatham DST) +XX -4357-17633 Pacific/Chatham Chatham Islands +# +# +13 +XX -210800-1751200 Pacific/Tongatapu Kanton; Tokelau; Samoa (western); Tonga +# +# +14 +XX +0152-15720 Pacific/Kiritimati Kiritimati diff --git a/requirements.txt b/requirements.txt index bdf83410..29f2c784 100644 --- a/requirements.txt +++ b/requirements.txt @@ -35,7 +35,7 @@ PyJWT==2.8.0 pyparsing==3.1.1 python-dateutil==2.8.2 python-twitter==3.5 -pytz==2023.3 +pytz==2024.1 requests==2.31.0 requests-oauthlib==1.3.1 rumps==0.4.0; platform_system == "Darwin" From 4468c3e4af05b2af04ab6241891ed545e7a2890a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Mar 2024 15:22:16 -0700 Subject: [PATCH 09/13] Bump mako from 1.2.4 to 1.3.2 (#2256) * Bump mako from 1.2.4 to 1.3.2 Bumps [mako](https://github.com/sqlalchemy/mako) from 1.2.4 to 1.3.2. - [Release notes](https://github.com/sqlalchemy/mako/releases) - [Changelog](https://github.com/sqlalchemy/mako/blob/main/CHANGES) - [Commits](https://github.com/sqlalchemy/mako/commits) --- updated-dependencies: - dependency-name: mako dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Update mako==1.3.2 --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> [skip ci] --- lib/mako/__init__.py | 4 ++-- lib/mako/_ast_util.py | 2 +- lib/mako/ast.py | 2 +- lib/mako/cache.py | 2 +- lib/mako/cmd.py | 3 +-- lib/mako/codegen.py | 4 +--- lib/mako/compat.py | 10 ++------ lib/mako/exceptions.py | 2 +- lib/mako/ext/autohandler.py | 2 +- lib/mako/ext/babelplugin.py | 2 +- lib/mako/ext/beaker_cache.py | 2 +- lib/mako/ext/extract.py | 2 +- lib/mako/ext/linguaplugin.py | 2 +- lib/mako/ext/preprocessors.py | 2 +- lib/mako/ext/pygmentplugin.py | 2 +- lib/mako/ext/turbogears.py | 2 +- lib/mako/filters.py | 2 +- lib/mako/lexer.py | 20 ++++++++++++---- lib/mako/lookup.py | 3 +-- lib/mako/parsetree.py | 2 +- lib/mako/pygen.py | 2 +- lib/mako/pyparser.py | 5 +--- lib/mako/runtime.py | 2 +- lib/mako/template.py | 3 +-- lib/mako/testing/assertions.py | 1 - lib/mako/testing/helpers.py | 4 ++++ lib/mako/util.py | 2 +- lib/markupsafe/__init__.py | 44 +++++++++++++++++++++++++++------- requirements.txt | 2 +- 29 files changed, 83 insertions(+), 54 deletions(-) diff --git a/lib/mako/__init__.py b/lib/mako/__init__.py index d7339219..d022cf82 100644 --- a/lib/mako/__init__.py +++ b/lib/mako/__init__.py @@ -1,8 +1,8 @@ # mako/__init__.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php -__version__ = "1.2.4" +__version__ = "1.3.2" diff --git a/lib/mako/_ast_util.py b/lib/mako/_ast_util.py index 95742835..63b8f228 100644 --- a/lib/mako/_ast_util.py +++ b/lib/mako/_ast_util.py @@ -1,5 +1,5 @@ # mako/_ast_util.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/ast.py b/lib/mako/ast.py index a3f3ee3e..e59df3eb 100644 --- a/lib/mako/ast.py +++ b/lib/mako/ast.py @@ -1,5 +1,5 @@ # mako/ast.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/cache.py b/lib/mako/cache.py index db21bb3e..bad25257 100644 --- a/lib/mako/cache.py +++ b/lib/mako/cache.py @@ -1,5 +1,5 @@ # mako/cache.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/cmd.py b/lib/mako/cmd.py index 93a6733f..3858a127 100755 --- a/lib/mako/cmd.py +++ b/lib/mako/cmd.py @@ -1,5 +1,5 @@ # mako/cmd.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php @@ -25,7 +25,6 @@ def _exit(): def cmdline(argv=None): - parser = ArgumentParser() parser.add_argument( "--var", diff --git a/lib/mako/codegen.py b/lib/mako/codegen.py index d1d2c20a..ce6f83aa 100644 --- a/lib/mako/codegen.py +++ b/lib/mako/codegen.py @@ -1,5 +1,5 @@ # mako/codegen.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php @@ -816,7 +816,6 @@ class _GenerateRenderMethod: ) or len(self.compiler.default_filters) ): - s = self.create_filter_callable( node.escapes_code.args, "%s" % node.text, True ) @@ -1181,7 +1180,6 @@ class _Identifiers: def visitBlockTag(self, node): if node is not self.node and not node.is_anonymous: - if isinstance(self.node, parsetree.DefTag): raise exceptions.CompileException( "Named block '%s' not allowed inside of def '%s'" diff --git a/lib/mako/compat.py b/lib/mako/compat.py index 48df30d6..18322159 100644 --- a/lib/mako/compat.py +++ b/lib/mako/compat.py @@ -1,17 +1,17 @@ # mako/compat.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php import collections +from importlib import metadata as importlib_metadata from importlib import util import inspect import sys win32 = sys.platform.startswith("win") pypy = hasattr(sys, "pypy_version_info") -py38 = sys.version_info >= (3, 8) ArgSpec = collections.namedtuple( "ArgSpec", ["args", "varargs", "keywords", "defaults"] @@ -62,12 +62,6 @@ def exception_name(exc): return exc.__class__.__name__ -if py38: - from importlib import metadata as importlib_metadata -else: - import importlib_metadata # noqa - - def importlib_metadata_get(group): ep = importlib_metadata.entry_points() if hasattr(ep, "select"): diff --git a/lib/mako/exceptions.py b/lib/mako/exceptions.py index 31c695fd..ca225677 100644 --- a/lib/mako/exceptions.py +++ b/lib/mako/exceptions.py @@ -1,5 +1,5 @@ # mako/exceptions.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/ext/autohandler.py b/lib/mako/ext/autohandler.py index 5bcfc285..dff9b6a8 100644 --- a/lib/mako/ext/autohandler.py +++ b/lib/mako/ext/autohandler.py @@ -1,5 +1,5 @@ # ext/autohandler.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/ext/babelplugin.py b/lib/mako/ext/babelplugin.py index 907d0b80..cdb37cdf 100644 --- a/lib/mako/ext/babelplugin.py +++ b/lib/mako/ext/babelplugin.py @@ -1,5 +1,5 @@ # ext/babelplugin.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/ext/beaker_cache.py b/lib/mako/ext/beaker_cache.py index 9aa35b06..590fbd01 100644 --- a/lib/mako/ext/beaker_cache.py +++ b/lib/mako/ext/beaker_cache.py @@ -1,5 +1,5 @@ # ext/beaker_cache.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/ext/extract.py b/lib/mako/ext/extract.py index 9d33ee18..d03789db 100644 --- a/lib/mako/ext/extract.py +++ b/lib/mako/ext/extract.py @@ -1,5 +1,5 @@ # ext/extract.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/ext/linguaplugin.py b/lib/mako/ext/linguaplugin.py index efb04c70..22077e66 100644 --- a/lib/mako/ext/linguaplugin.py +++ b/lib/mako/ext/linguaplugin.py @@ -1,5 +1,5 @@ # ext/linguaplugin.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/ext/preprocessors.py b/lib/mako/ext/preprocessors.py index 80403ecd..6d1aaf5d 100644 --- a/lib/mako/ext/preprocessors.py +++ b/lib/mako/ext/preprocessors.py @@ -1,5 +1,5 @@ # ext/preprocessors.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/ext/pygmentplugin.py b/lib/mako/ext/pygmentplugin.py index 9acbf4cd..f422623d 100644 --- a/lib/mako/ext/pygmentplugin.py +++ b/lib/mako/ext/pygmentplugin.py @@ -1,5 +1,5 @@ # ext/pygmentplugin.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/ext/turbogears.py b/lib/mako/ext/turbogears.py index 2ebf0746..2a3ec7d7 100644 --- a/lib/mako/ext/turbogears.py +++ b/lib/mako/ext/turbogears.py @@ -1,5 +1,5 @@ # ext/turbogears.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/filters.py b/lib/mako/filters.py index af202f3f..2a4b4386 100644 --- a/lib/mako/filters.py +++ b/lib/mako/filters.py @@ -1,5 +1,5 @@ # mako/filters.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/lexer.py b/lib/mako/lexer.py index 75182f85..9d1f5f30 100644 --- a/lib/mako/lexer.py +++ b/lib/mako/lexer.py @@ -1,5 +1,5 @@ # mako/lexer.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php @@ -247,6 +247,8 @@ class Lexer: continue if self.match_python_block(): continue + if self.match_percent(): + continue if self.match_text(): continue @@ -352,14 +354,24 @@ class Lexer: else: return True + def match_percent(self): + match = self.match(r"(?<=^)(\s*)%%(%*)", re.M) + if match: + self.append_node( + parsetree.Text, match.group(1) + "%" + match.group(2) + ) + return True + else: + return False + def match_text(self): match = self.match( r""" (.*?) # anything, followed by: ( - (?<=\n)(?=[ \t]*(?=%|\#\#)) # an eval or line-based - # comment preceded by a - # consumed newline and whitespace + (?<=\n)(?=[ \t]*(?=%|\#\#)) # an eval or line-based + # comment, preceded by a + # consumed newline and whitespace | (?=\${) # an expression | diff --git a/lib/mako/lookup.py b/lib/mako/lookup.py index f7410ce3..d916db77 100644 --- a/lib/mako/lookup.py +++ b/lib/mako/lookup.py @@ -1,5 +1,5 @@ # mako/lookup.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php @@ -178,7 +178,6 @@ class TemplateLookup(TemplateCollection): lexer_cls=None, include_error_handler=None, ): - self.directories = [ posixpath.normpath(d) for d in util.to_list(directories, ()) ] diff --git a/lib/mako/parsetree.py b/lib/mako/parsetree.py index c5a12d1d..04686ece 100644 --- a/lib/mako/parsetree.py +++ b/lib/mako/parsetree.py @@ -1,5 +1,5 @@ # mako/parsetree.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/pygen.py b/lib/mako/pygen.py index 57c69793..820e101d 100644 --- a/lib/mako/pygen.py +++ b/lib/mako/pygen.py @@ -1,5 +1,5 @@ # mako/pygen.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/pyparser.py b/lib/mako/pyparser.py index d9b090c6..9b63dc33 100644 --- a/lib/mako/pyparser.py +++ b/lib/mako/pyparser.py @@ -1,5 +1,5 @@ # mako/pyparser.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php @@ -64,7 +64,6 @@ class FindIdentifiers(_ast_util.NodeVisitor): self._add_declared(node.name) def visit_Assign(self, node): - # flip around the visiting of Assign so the expression gets # evaluated first, in the case of a clause like "x=x+5" (x # is undeclared) @@ -99,7 +98,6 @@ class FindIdentifiers(_ast_util.NodeVisitor): yield arg def _visit_function(self, node, islambda): - # push function state onto stack. dont log any more # identifiers as "declared" until outside of the function, # but keep logging identifiers as "undeclared". track @@ -122,7 +120,6 @@ class FindIdentifiers(_ast_util.NodeVisitor): self.local_ident_stack = local_ident_stack def visit_For(self, node): - # flip around visit self.visit(node.iter) diff --git a/lib/mako/runtime.py b/lib/mako/runtime.py index 6d7fa684..23401b70 100644 --- a/lib/mako/runtime.py +++ b/lib/mako/runtime.py @@ -530,7 +530,7 @@ class Namespace: def _populate(self, d, l): for ident in l: if ident == "*": - for (k, v) in self._get_star(): + for k, v in self._get_star(): d[k] = v else: d[ident] = getattr(self, ident) diff --git a/lib/mako/template.py b/lib/mako/template.py index 8c70731d..e2771727 100644 --- a/lib/mako/template.py +++ b/lib/mako/template.py @@ -1,5 +1,5 @@ # mako/template.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php @@ -26,7 +26,6 @@ from mako.lexer import Lexer class Template: - r"""Represents a compiled template. :class:`.Template` includes a reference to the original diff --git a/lib/mako/testing/assertions.py b/lib/mako/testing/assertions.py index 14ea6352..22221cd2 100644 --- a/lib/mako/testing/assertions.py +++ b/lib/mako/testing/assertions.py @@ -103,7 +103,6 @@ def _assert_raises( check_context=False, cause_cls=None, ): - with _expect_raises(except_cls, msg, check_context, cause_cls) as ec: callable_(*args, **kwargs) return ec.error diff --git a/lib/mako/testing/helpers.py b/lib/mako/testing/helpers.py index 77cca367..5ae9d38d 100644 --- a/lib/mako/testing/helpers.py +++ b/lib/mako/testing/helpers.py @@ -19,6 +19,10 @@ def result_lines(result): ] +def result_raw_lines(result): + return [x for x in re.split(r"\r?\n", result) if x.strip() != ""] + + def make_path( filespec: Union[Path, str], make_absolute: bool = True, diff --git a/lib/mako/util.py b/lib/mako/util.py index 5fb683b4..91188cac 100644 --- a/lib/mako/util.py +++ b/lib/mako/util.py @@ -1,5 +1,5 @@ # mako/util.py -# Copyright 2006-2022 the Mako authors and contributors +# Copyright 2006-2024 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/markupsafe/__init__.py b/lib/markupsafe/__init__.py index 21d31960..b40f24c6 100644 --- a/lib/markupsafe/__init__.py +++ b/lib/markupsafe/__init__.py @@ -1,5 +1,4 @@ import functools -import re import string import sys import typing as t @@ -14,10 +13,7 @@ if t.TYPE_CHECKING: _P = te.ParamSpec("_P") -__version__ = "2.1.3" - -_strip_comments_re = re.compile(r"", re.DOTALL) -_strip_tags_re = re.compile(r"<.*?>", re.DOTALL) +__version__ = "2.1.5" def _simple_escaping_wrapper(func: "t.Callable[_P, str]") -> "t.Callable[_P, Markup]": @@ -162,9 +158,41 @@ class Markup(str): >>> Markup("Main »\tAbout").striptags() 'Main » About' """ - # Use two regexes to avoid ambiguous matches. - value = _strip_comments_re.sub("", self) - value = _strip_tags_re.sub("", value) + value = str(self) + + # Look for comments then tags separately. Otherwise, a comment that + # contains a tag would end early, leaving some of the comment behind. + + while True: + # keep finding comment start marks + start = value.find("", start) + + if end == -1: + break + + value = f"{value[:start]}{value[end + 3:]}" + + # remove tags using the same method + while True: + start = value.find("<") + + if start == -1: + break + + end = value.find(">", start) + + if end == -1: + break + + value = f"{value[:start]}{value[end + 1:]}" + + # collapse spaces value = " ".join(value.split()) return self.__class__(value).unescape() diff --git a/requirements.txt b/requirements.txt index 29f2c784..32bd430e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -22,7 +22,7 @@ importlib-metadata==6.8.0 importlib-resources==6.0.1 git+https://github.com/Tautulli/ipwhois.git@master#egg=ipwhois IPy==1.01 -Mako==1.2.4 +Mako==1.3.2 MarkupSafe==2.1.3 musicbrainzngs==0.7.1 packaging==23.1 From a4cfc6323da91472eb70cbb32a1dde21e0373271 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Mar 2024 15:23:15 -0700 Subject: [PATCH 10/13] Bump certifi from 2023.7.22 to 2024.2.2 (#2257) * Bump certifi from 2023.7.22 to 2024.2.2 Bumps [certifi](https://github.com/certifi/python-certifi) from 2023.7.22 to 2024.2.2. - [Commits](https://github.com/certifi/python-certifi/compare/2023.07.22...2024.02.02) --- updated-dependencies: - dependency-name: certifi dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Update certifi==2024.2.2 --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> [skip ci] --- lib/certifi/__init__.py | 2 +- lib/certifi/cacert.pem | 321 +++++++++++++++++++++++++++++++--------- lib/certifi/core.py | 6 + requirements.txt | 2 +- 4 files changed, 258 insertions(+), 73 deletions(-) diff --git a/lib/certifi/__init__.py b/lib/certifi/__init__.py index 8ce89cef..1c91f3ec 100644 --- a/lib/certifi/__init__.py +++ b/lib/certifi/__init__.py @@ -1,4 +1,4 @@ from .core import contents, where __all__ = ["contents", "where"] -__version__ = "2023.07.22" +__version__ = "2024.02.02" diff --git a/lib/certifi/cacert.pem b/lib/certifi/cacert.pem index 02123695..fac3c319 100644 --- a/lib/certifi/cacert.pem +++ b/lib/certifi/cacert.pem @@ -245,34 +245,6 @@ mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK 4SVhM7JZG+Ju1zdXtg2pEto= -----END CERTIFICATE----- -# Issuer: O=SECOM Trust.net OU=Security Communication RootCA1 -# Subject: O=SECOM Trust.net OU=Security Communication RootCA1 -# Label: "Security Communication Root CA" -# Serial: 0 -# MD5 Fingerprint: f1:bc:63:6a:54:e0:b5:27:f5:cd:e7:1a:e3:4d:6e:4a -# SHA1 Fingerprint: 36:b1:2b:49:f9:81:9e:d7:4c:9e:bc:38:0f:c6:56:8f:5d:ac:b2:f7 -# SHA256 Fingerprint: e7:5e:72:ed:9f:56:0e:ec:6e:b4:80:00:73:a4:3f:c3:ad:19:19:5a:39:22:82:01:78:95:97:4a:99:02:6b:6c ------BEGIN CERTIFICATE----- -MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY -MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t -dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 -WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD -VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 -9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ -DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 -Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N -QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ -xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G -A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T -AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG -kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr -Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 -Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU -JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot -RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== ------END CERTIFICATE----- - # Issuer: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com # Subject: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com # Label: "XRamp Global CA Root" @@ -881,49 +853,6 @@ Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH WD9f -----END CERTIFICATE----- -# Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 -# Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 -# Label: "Autoridad de Certificacion Firmaprofesional CIF A62634068" -# Serial: 6047274297262753887 -# MD5 Fingerprint: 73:3a:74:7a:ec:bb:a3:96:a6:c2:e4:e2:c8:9b:c0:c3 -# SHA1 Fingerprint: ae:c5:fb:3f:c8:e1:bf:c4:e5:4f:03:07:5a:9a:e8:00:b7:f7:b6:fa -# SHA256 Fingerprint: 04:04:80:28:bf:1f:28:64:d4:8f:9a:d4:d8:32:94:36:6a:82:88:56:55:3f:3b:14:30:3f:90:14:7f:5d:40:ef ------BEGIN CERTIFICATE----- -MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE -BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h -cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy -MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg -Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 -thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM -cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG -L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i -NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h -X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b -m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy -Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja -EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T -KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF -6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh -OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD -VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD -VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp -cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv -ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl -AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF -661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9 -am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1 -ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481 -PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS -3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k -SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF -3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM -ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g -StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz -Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB -jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V ------END CERTIFICATE----- - # Issuer: CN=Izenpe.com O=IZENPE S.A. # Subject: CN=Izenpe.com O=IZENPE S.A. # Label: "Izenpe.com" @@ -4633,3 +4562,253 @@ o7Ey7Nmj1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5 dDTedk+SKlOxJTnbPP/lPqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcE oji2jbDwN/zIIX8/syQbPYtuzE2wFg2WHYMfRsCbvUOZ58SWLs5fyQ== -----END CERTIFICATE----- + +# Issuer: CN=TrustAsia Global Root CA G3 O=TrustAsia Technologies, Inc. +# Subject: CN=TrustAsia Global Root CA G3 O=TrustAsia Technologies, Inc. +# Label: "TrustAsia Global Root CA G3" +# Serial: 576386314500428537169965010905813481816650257167 +# MD5 Fingerprint: 30:42:1b:b7:bb:81:75:35:e4:16:4f:53:d2:94:de:04 +# SHA1 Fingerprint: 63:cf:b6:c1:27:2b:56:e4:88:8e:1c:23:9a:b6:2e:81:47:24:c3:c7 +# SHA256 Fingerprint: e0:d3:22:6a:eb:11:63:c2:e4:8f:f9:be:3b:50:b4:c6:43:1b:e7:bb:1e:ac:c5:c3:6b:5d:5e:c5:09:03:9a:08 +-----BEGIN CERTIFICATE----- +MIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEM +BQAwWjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dp +ZXMsIEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAe +Fw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEwMTlaMFoxCzAJBgNVBAYTAkNOMSUw +IwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtU +cnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNS +T1QY4SxzlZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqK +AtCWHwDNBSHvBm3dIZwZQ0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1 +nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/VP68czH5GX6zfZBCK70bwkPAPLfSIC7Ep +qq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1AgdB4SQXMeJNnKziyhWTXA +yB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm9WAPzJMs +hH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gX +zhqcD0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAv +kV34PmVACxmZySYgWmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msT +f9FkPz2ccEblooV7WIQn3MSAPmeamseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jA +uPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCFTIcQcf+eQxuulXUtgQIDAQAB +o2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj7zjKsK5Xf/Ih +MBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E +BAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4 +wM8zAQLpw6o1D/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2 +XFNFV1pF1AWZLy4jVe5jaN/TG3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1 +JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNjduMNhXJEIlU/HHzp/LgV6FL6qj6j +ITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstlcHboCoWASzY9M/eV +VHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys+TIx +xHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1on +AX1daBli2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d +7XB4tmBZrOFdRWOPyN9yaFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2Ntjj +gKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsASZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV ++Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFRJQJ6+N1rZdVtTTDIZbpo +FGWsJwt0ivKH +-----END CERTIFICATE----- + +# Issuer: CN=TrustAsia Global Root CA G4 O=TrustAsia Technologies, Inc. +# Subject: CN=TrustAsia Global Root CA G4 O=TrustAsia Technologies, Inc. +# Label: "TrustAsia Global Root CA G4" +# Serial: 451799571007117016466790293371524403291602933463 +# MD5 Fingerprint: 54:dd:b2:d7:5f:d8:3e:ed:7c:e0:0b:2e:cc:ed:eb:eb +# SHA1 Fingerprint: 57:73:a5:61:5d:80:b2:e6:ac:38:82:fc:68:07:31:ac:9f:b5:92:5a +# SHA256 Fingerprint: be:4b:56:cb:50:56:c0:13:6a:52:6d:f4:44:50:8d:aa:36:a0:b5:4f:42:e4:ac:38:f7:2a:f4:70:e4:79:65:4c +-----BEGIN CERTIFICATE----- +MIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMw +WjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs +IEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0y +MTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJaMFoxCzAJBgNVBAYTAkNOMSUwIwYD +VQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtUcnVz +dEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATx +s8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbw +LxYI+hW8m7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJij +YzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mD +pm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/pDHel4NZg6ZvccveMA4GA1UdDwEB/wQE +AwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AAbbd+NvBNEU/zy4k6LHiR +UKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xkdUfFVZDj +/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA== +-----END CERTIFICATE----- + +# Issuer: CN=CommScope Public Trust ECC Root-01 O=CommScope +# Subject: CN=CommScope Public Trust ECC Root-01 O=CommScope +# Label: "CommScope Public Trust ECC Root-01" +# Serial: 385011430473757362783587124273108818652468453534 +# MD5 Fingerprint: 3a:40:a7:fc:03:8c:9c:38:79:2f:3a:a2:6c:b6:0a:16 +# SHA1 Fingerprint: 07:86:c0:d8:dd:8e:c0:80:98:06:98:d0:58:7a:ef:de:a6:cc:a2:5d +# SHA256 Fingerprint: 11:43:7c:da:7b:b4:5e:41:36:5f:45:b3:9a:38:98:6b:0d:e0:0d:ef:34:8e:0c:7b:b0:87:36:33:80:0b:c3:8b +-----BEGIN CERTIFICATE----- +MIICHTCCAaOgAwIBAgIUQ3CCd89NXTTxyq4yLzf39H91oJ4wCgYIKoZIzj0EAwMw +TjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29t +bVNjb3BlIFB1YmxpYyBUcnVzdCBFQ0MgUm9vdC0wMTAeFw0yMTA0MjgxNzM1NDNa +Fw00NjA0MjgxNzM1NDJaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21tU2Nv +cGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgRUNDIFJvb3QtMDEw +djAQBgcqhkjOPQIBBgUrgQQAIgNiAARLNumuV16ocNfQj3Rid8NeeqrltqLxeP0C +flfdkXmcbLlSiFS8LwS+uM32ENEp7LXQoMPwiXAZu1FlxUOcw5tjnSCDPgYLpkJE +hRGnSjot6dZoL0hOUysHP029uax3OVejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSOB2LAUN3GGQYARnQE9/OufXVNMDAKBggq +hkjOPQQDAwNoADBlAjEAnDPfQeMjqEI2Jpc1XHvr20v4qotzVRVcrHgpD7oh2MSg +2NED3W3ROT3Ek2DS43KyAjB8xX6I01D1HiXo+k515liWpDVfG2XqYZpwI7UNo5uS +Um9poIyNStDuiw7LR47QjRE= +-----END CERTIFICATE----- + +# Issuer: CN=CommScope Public Trust ECC Root-02 O=CommScope +# Subject: CN=CommScope Public Trust ECC Root-02 O=CommScope +# Label: "CommScope Public Trust ECC Root-02" +# Serial: 234015080301808452132356021271193974922492992893 +# MD5 Fingerprint: 59:b0:44:d5:65:4d:b8:5c:55:19:92:02:b6:d1:94:b2 +# SHA1 Fingerprint: 3c:3f:ef:57:0f:fe:65:93:86:9e:a0:fe:b0:f6:ed:8e:d1:13:c7:e5 +# SHA256 Fingerprint: 2f:fb:7f:81:3b:bb:b3:c8:9a:b4:e8:16:2d:0f:16:d7:15:09:a8:30:cc:9d:73:c2:62:e5:14:08:75:d1:ad:4a +-----BEGIN CERTIFICATE----- +MIICHDCCAaOgAwIBAgIUKP2ZYEFHpgE6yhR7H+/5aAiDXX0wCgYIKoZIzj0EAwMw +TjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29t +bVNjb3BlIFB1YmxpYyBUcnVzdCBFQ0MgUm9vdC0wMjAeFw0yMTA0MjgxNzQ0NTRa +Fw00NjA0MjgxNzQ0NTNaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21tU2Nv +cGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgRUNDIFJvb3QtMDIw +djAQBgcqhkjOPQIBBgUrgQQAIgNiAAR4MIHoYx7l63FRD/cHB8o5mXxO1Q/MMDAL +j2aTPs+9xYa9+bG3tD60B8jzljHz7aRP+KNOjSkVWLjVb3/ubCK1sK9IRQq9qEmU +v4RDsNuESgMjGWdqb8FuvAY5N9GIIvejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTmGHX/72DehKT1RsfeSlXjMjZ59TAKBggq +hkjOPQQDAwNnADBkAjAmc0l6tqvmSfR9Uj/UQQSugEODZXW5hYA4O9Zv5JOGq4/n +ich/m35rChJVYaoR4HkCMHfoMXGsPHED1oQmHhS48zs73u1Z/GtMMH9ZzkXpc2AV +mkzw5l4lIhVtwodZ0LKOag== +-----END CERTIFICATE----- + +# Issuer: CN=CommScope Public Trust RSA Root-01 O=CommScope +# Subject: CN=CommScope Public Trust RSA Root-01 O=CommScope +# Label: "CommScope Public Trust RSA Root-01" +# Serial: 354030733275608256394402989253558293562031411421 +# MD5 Fingerprint: 0e:b4:15:bc:87:63:5d:5d:02:73:d4:26:38:68:73:d8 +# SHA1 Fingerprint: 6d:0a:5f:f7:b4:23:06:b4:85:b3:b7:97:64:fc:ac:75:f5:33:f2:93 +# SHA256 Fingerprint: 02:bd:f9:6e:2a:45:dd:9b:f1:8f:c7:e1:db:df:21:a0:37:9b:a3:c9:c2:61:03:44:cf:d8:d6:06:fe:c1:ed:81 +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIUPgNJgXUWdDGOTKvVxZAplsU5EN0wDQYJKoZIhvcNAQEL +BQAwTjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwi +Q29tbVNjb3BlIFB1YmxpYyBUcnVzdCBSU0EgUm9vdC0wMTAeFw0yMTA0MjgxNjQ1 +NTRaFw00NjA0MjgxNjQ1NTNaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21t +U2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgUlNBIFJvb3Qt +MDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwSGWjDR1C45FtnYSk +YZYSwu3D2iM0GXb26v1VWvZVAVMP8syMl0+5UMuzAURWlv2bKOx7dAvnQmtVzslh +suitQDy6uUEKBU8bJoWPQ7VAtYXR1HHcg0Hz9kXHgKKEUJdGzqAMxGBWBB0HW0al +DrJLpA6lfO741GIDuZNqihS4cPgugkY4Iw50x2tBt9Apo52AsH53k2NC+zSDO3Oj +WiE260f6GBfZumbCk6SP/F2krfxQapWsvCQz0b2If4b19bJzKo98rwjyGpg/qYFl +P8GMicWWMJoKz/TUyDTtnS+8jTiGU+6Xn6myY5QXjQ/cZip8UlF1y5mO6D1cv547 +KI2DAg+pn3LiLCuz3GaXAEDQpFSOm117RTYm1nJD68/A6g3czhLmfTifBSeolz7p +UcZsBSjBAg/pGG3svZwG1KdJ9FQFa2ww8esD1eo9anbCyxooSU1/ZOD6K9pzg4H/ +kQO9lLvkuI6cMmPNn7togbGEW682v3fuHX/3SZtS7NJ3Wn2RnU3COS3kuoL4b/JO +Hg9O5j9ZpSPcPYeoKFgo0fEbNttPxP/hjFtyjMcmAyejOQoBqsCyMWCDIqFPEgkB +Ea801M/XrmLTBQe0MXXgDW1XT2mH+VepuhX2yFJtocucH+X8eKg1mp9BFM6ltM6U +CBwJrVbl2rZJmkrqYxhTnCwuwwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUN12mmnQywsL5x6YVEFm45P3luG0wDQYJ +KoZIhvcNAQELBQADggIBAK+nz97/4L1CjU3lIpbfaOp9TSp90K09FlxD533Ahuh6 +NWPxzIHIxgvoLlI1pKZJkGNRrDSsBTtXAOnTYtPZKdVUvhwQkZyybf5Z/Xn36lbQ +nmhUQo8mUuJM3y+Xpi/SB5io82BdS5pYV4jvguX6r2yBS5KPQJqTRlnLX3gWsWc+ +QgvfKNmwrZggvkN80V4aCRckjXtdlemrwWCrWxhkgPut4AZ9HcpZuPN4KWfGVh2v +trV0KnahP/t1MJ+UXjulYPPLXAziDslg+MkfFoom3ecnf+slpoq9uC02EJqxWE2a +aE9gVOX2RhOOiKy8IUISrcZKiX2bwdgt6ZYD9KJ0DLwAHb/WNyVntHKLr4W96ioD +j8z7PEQkguIBpQtZtjSNMgsSDesnwv1B10A8ckYpwIzqug/xBpMu95yo9GA+o/E4 +Xo4TwbM6l4c/ksp4qRyv0LAbJh6+cOx69TOY6lz/KwsETkPdY34Op054A5U+1C0w +lREQKC6/oAI+/15Z0wUOlV9TRe9rh9VIzRamloPh37MG88EU26fsHItdkJANclHn +YfkUyq+Dj7+vsQpZXdxc1+SWrVtgHdqul7I52Qb1dgAT+GhMIbA1xNxVssnBQVoc +icCMb3SgazNNtQEo/a2tiRc7ppqEvOuM6sRxJKi6KfkIsidWNTJf6jn7MZrVGczw +-----END CERTIFICATE----- + +# Issuer: CN=CommScope Public Trust RSA Root-02 O=CommScope +# Subject: CN=CommScope Public Trust RSA Root-02 O=CommScope +# Label: "CommScope Public Trust RSA Root-02" +# Serial: 480062499834624527752716769107743131258796508494 +# MD5 Fingerprint: e1:29:f9:62:7b:76:e2:96:6d:f3:d4:d7:0f:ae:1f:aa +# SHA1 Fingerprint: ea:b0:e2:52:1b:89:93:4c:11:68:f2:d8:9a:ac:22:4c:a3:8a:57:ae +# SHA256 Fingerprint: ff:e9:43:d7:93:42:4b:4f:7c:44:0c:1c:3d:64:8d:53:63:f3:4b:82:dc:87:aa:7a:9f:11:8f:c5:de:e1:01:f1 +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIUVBa/O345lXGN0aoApYYNK496BU4wDQYJKoZIhvcNAQEL +BQAwTjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwi +Q29tbVNjb3BlIFB1YmxpYyBUcnVzdCBSU0EgUm9vdC0wMjAeFw0yMTA0MjgxNzE2 +NDNaFw00NjA0MjgxNzE2NDJaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21t +U2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgUlNBIFJvb3Qt +MDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDh+g77aAASyE3VrCLE +NQE7xVTlWXZjpX/rwcRqmL0yjReA61260WI9JSMZNRTpf4mnG2I81lDnNJUDMrG0 +kyI9p+Kx7eZ7Ti6Hmw0zdQreqjXnfuU2mKKuJZ6VszKWpCtYHu8//mI0SFHRtI1C +rWDaSWqVcN3SAOLMV2MCe5bdSZdbkk6V0/nLKR8YSvgBKtJjCW4k6YnS5cciTNxz +hkcAqg2Ijq6FfUrpuzNPDlJwnZXjfG2WWy09X6GDRl224yW4fKcZgBzqZUPckXk2 +LHR88mcGyYnJ27/aaL8j7dxrrSiDeS/sOKUNNwFnJ5rpM9kzXzehxfCrPfp4sOcs +n/Y+n2Dg70jpkEUeBVF4GiwSLFworA2iI540jwXmojPOEXcT1A6kHkIfhs1w/tku +FT0du7jyU1fbzMZ0KZwYszZ1OC4PVKH4kh+Jlk+71O6d6Ts2QrUKOyrUZHk2EOH5 +kQMreyBUzQ0ZGshBMjTRsJnhkB4BQDa1t/qp5Xd1pCKBXbCL5CcSD1SIxtuFdOa3 +wNemKfrb3vOTlycEVS8KbzfFPROvCgCpLIscgSjX74Yxqa7ybrjKaixUR9gqiC6v +wQcQeKwRoi9C8DfF8rhW3Q5iLc4tVn5V8qdE9isy9COoR+jUKgF4z2rDN6ieZdIs +5fq6M8EGRPbmz6UNp2YINIos8wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUR9DnsSL/nSz12Vdgs7GxcJXvYXowDQYJ +KoZIhvcNAQELBQADggIBAIZpsU0v6Z9PIpNojuQhmaPORVMbc0RTAIFhzTHjCLqB +KCh6krm2qMhDnscTJk3C2OVVnJJdUNjCK9v+5qiXz1I6JMNlZFxHMaNlNRPDk7n3 ++VGXu6TwYofF1gbTl4MgqX67tiHCpQ2EAOHyJxCDut0DgdXdaMNmEMjRdrSzbyme +APnCKfWxkxlSaRosTKCL4BWaMS/TiJVZbuXEs1DIFAhKm4sTg7GkcrI7djNB3Nyq +pgdvHSQSn8h2vS/ZjvQs7rfSOBAkNlEv41xdgSGn2rtO/+YHqP65DSdsu3BaVXoT +6fEqSWnHX4dXTEN5bTpl6TBcQe7rd6VzEojov32u5cSoHw2OHG1QAk8mGEPej1WF +sQs3BWDJVTkSBKEqz3EWnzZRSb9wO55nnPt7eck5HHisd5FUmrh1CoFSl+NmYWvt +PjgelmFV4ZFUjO2MJB+ByRCac5krFk5yAD9UG/iNuovnFNa2RU9g7Jauwy8CTl2d +lklyALKrdVwPaFsdZcJfMw8eD/A7hvWwTruc9+olBdytoptLFwG+Qt81IR2tq670 +v64fG9PiO/yzcnMcmyiQiRM9HcEARwmWmjgb3bHPDcK0RPOWlc4yOo80nOAXx17O +rg3bhzjlP1v9mxnhMUF6cKojawHhRUzNlM47ni3niAIi9G7oyOzWPPO5std3eqx7 +-----END CERTIFICATE----- + +# Issuer: CN=Telekom Security TLS ECC Root 2020 O=Deutsche Telekom Security GmbH +# Subject: CN=Telekom Security TLS ECC Root 2020 O=Deutsche Telekom Security GmbH +# Label: "Telekom Security TLS ECC Root 2020" +# Serial: 72082518505882327255703894282316633856 +# MD5 Fingerprint: c1:ab:fe:6a:10:2c:03:8d:bc:1c:22:32:c0:85:a7:fd +# SHA1 Fingerprint: c0:f8:96:c5:a9:3b:01:06:21:07:da:18:42:48:bc:e9:9d:88:d5:ec +# SHA256 Fingerprint: 57:8a:f4:de:d0:85:3f:4e:59:98:db:4a:ea:f9:cb:ea:8d:94:5f:60:b6:20:a3:8d:1a:3c:13:b2:bc:7b:a8:e1 +-----BEGIN CERTIFICATE----- +MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQsw +CQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBH +bWJIMSswKQYDVQQDDCJUZWxla29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIw +MB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIzNTk1OVowYzELMAkGA1UEBhMCREUx +JzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkgR21iSDErMCkGA1UE +AwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/O +tdKPD/M12kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDP +f8iAC8GXs7s1J8nCG6NCMEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6f +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cA +MGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZMo7k+5Dck2TOrbRBR2Di +z6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdUga/sf+Rn +27iQ7t0l +-----END CERTIFICATE----- + +# Issuer: CN=Telekom Security TLS RSA Root 2023 O=Deutsche Telekom Security GmbH +# Subject: CN=Telekom Security TLS RSA Root 2023 O=Deutsche Telekom Security GmbH +# Label: "Telekom Security TLS RSA Root 2023" +# Serial: 44676229530606711399881795178081572759 +# MD5 Fingerprint: bf:5b:eb:54:40:cd:48:71:c4:20:8d:7d:de:0a:42:f2 +# SHA1 Fingerprint: 54:d3:ac:b3:bd:57:56:f6:85:9d:ce:e5:c3:21:e2:d4:ad:83:d0:93 +# SHA256 Fingerprint: ef:c6:5c:ad:bb:59:ad:b6:ef:e8:4d:a2:23:11:b3:56:24:b7:1b:3b:1e:a0:da:8b:66:55:17:4e:c8:97:86:46 +-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBj +MQswCQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0 +eSBHbWJIMSswKQYDVQQDDCJUZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAy +MDIzMB4XDTIzMDMyODEyMTY0NVoXDTQ4MDMyNzIzNTk1OVowYzELMAkGA1UEBhMC +REUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkgR21iSDErMCkG +A1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgUlNBIFJvb3QgMjAyMzCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAO01oYGA88tKaVvC+1GDrib94W7zgRJ9 +cUD/h3VCKSHtgVIs3xLBGYSJwb3FKNXVS2xE1kzbB5ZKVXrKNoIENqil/Cf2SfHV +cp6R+SPWcHu79ZvB7JPPGeplfohwoHP89v+1VmLhc2o0mD6CuKyVU/QBoCcHcqMA +U6DksquDOFczJZSfvkgdmOGjup5czQRxUX11eKvzWarE4GC+j4NSuHUaQTXtvPM6 +Y+mpFEXX5lLRbtLevOP1Czvm4MS9Q2QTps70mDdsipWol8hHD/BeEIvnHRz+sTug +BTNoBUGCwQMrAcjnj02r6LX2zWtEtefdi+zqJbQAIldNsLGyMcEWzv/9FIS3R/qy +8XDe24tsNlikfLMR0cN3f1+2JeANxdKz+bi4d9s3cXFH42AYTyS2dTd4uaNir73J +co4vzLuu2+QVUhkHM/tqty1LkCiCc/4YizWN26cEar7qwU02OxY2kTLvtkCJkUPg +8qKrBC7m8kwOFjQgrIfBLX7JZkcXFBGk8/ehJImr2BrIoVyxo/eMbcgByU/J7MT8 +rFEz0ciD0cmfHdRHNCk+y7AO+oMLKFjlKdw/fKifybYKu6boRhYPluV75Gp6SG12 +mAWl3G0eQh5C2hrgUve1g8Aae3g1LDj1H/1Joy7SWWO/gLCMk3PLNaaZlSJhZQNg ++y+TS/qanIA7AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtqeX +gj10hZv3PJ+TmpV5dVKMbUcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS2 +p5eCPXSFm/c8n5OalXl1UoxtRzANBgkqhkiG9w0BAQwFAAOCAgEAqMxhpr51nhVQ +pGv7qHBFfLp+sVr8WyP6Cnf4mHGCDG3gXkaqk/QeoMPhk9tLrbKmXauw1GLLXrtm +9S3ul0A8Yute1hTWjOKWi0FpkzXmuZlrYrShF2Y0pmtjxrlO8iLpWA1WQdH6DErw +M807u20hOq6OcrXDSvvpfeWxm4bu4uB9tPcy/SKE8YXJN3nptT+/XOR0so8RYgDd +GGah2XsjX/GO1WfoVNpbOms2b/mBsTNHM3dA+VKq3dSDz4V4mZqTuXNnQkYRIer+ +CqkbGmVps4+uFrb2S1ayLfmlyOw7YqPta9BO1UAJpB+Y1zqlklkg5LB9zVtzaL1t +xKITDmcZuI1CfmwMmm6gJC3VRRvcxAIU/oVbZZfKTpBQCHpCNfnqwmbU+AGuHrS+ +w6jv/naaoqYfRvaE7fzbzsQCzndILIyy7MMAo+wsVRjBfhnu4S/yrYObnqsZ38aK +L4x35bcF7DvB7L6Gs4a8wPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+lj +X273CXE2whJdV/LItM3z7gLfEdxquVeEHVlNjM7IDiPCtyaaEBRx/pOyiriA8A4Q +ntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0o82bNSQ3+pCTE4FCxpgm +dTdmQRCsu/WU48IxK63nI1bMNSWSs1A= +-----END CERTIFICATE----- diff --git a/lib/certifi/core.py b/lib/certifi/core.py index de028981..91f538bb 100644 --- a/lib/certifi/core.py +++ b/lib/certifi/core.py @@ -5,6 +5,10 @@ certifi.py This module returns the installation location of cacert.pem or its contents. """ import sys +import atexit + +def exit_cacert_ctx() -> None: + _CACERT_CTX.__exit__(None, None, None) # type: ignore[union-attr] if sys.version_info >= (3, 11): @@ -35,6 +39,7 @@ if sys.version_info >= (3, 11): # we will also store that at the global level as well. _CACERT_CTX = as_file(files("certifi").joinpath("cacert.pem")) _CACERT_PATH = str(_CACERT_CTX.__enter__()) + atexit.register(exit_cacert_ctx) return _CACERT_PATH @@ -70,6 +75,7 @@ elif sys.version_info >= (3, 7): # we will also store that at the global level as well. _CACERT_CTX = get_path("certifi", "cacert.pem") _CACERT_PATH = str(_CACERT_CTX.__enter__()) + atexit.register(exit_cacert_ctx) return _CACERT_PATH diff --git a/requirements.txt b/requirements.txt index 32bd430e..53efa2e8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,7 +5,7 @@ backports.functools-lru-cache==1.6.6 backports.zoneinfo==0.2.1;python_version<"3.9" beautifulsoup4==4.12.2 bleach==6.1.0 -certifi==2023.7.22 +certifi==2024.2.2 cheroot==10.0.0 cherrypy==18.8.0 cloudinary==1.34.0 From 13eb0fd6dbd2fe3efc108b3363979ad3e4b2d66d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Mar 2024 15:23:44 -0700 Subject: [PATCH 11/13] Bump platformdirs from 3.11.0 to 4.2.0 (#2258) * Bump platformdirs from 3.11.0 to 4.2.0 Bumps [platformdirs](https://github.com/platformdirs/platformdirs) from 3.11.0 to 4.2.0. - [Release notes](https://github.com/platformdirs/platformdirs/releases) - [Changelog](https://github.com/platformdirs/platformdirs/blob/main/CHANGES.rst) - [Commits](https://github.com/platformdirs/platformdirs/compare/3.11.0...4.2.0) --- updated-dependencies: - dependency-name: platformdirs dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Update platformdirs==4.2.0 --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> [skip ci] --- lib/platformdirs/__init__.py | 7 ++-- lib/platformdirs/__main__.py | 1 + lib/platformdirs/android.py | 1 + lib/platformdirs/api.py | 48 ++++++++++++++++++++++---- lib/platformdirs/macos.py | 1 + lib/platformdirs/unix.py | 65 +++++++++++++++++++++++------------- lib/platformdirs/version.py | 4 +-- lib/platformdirs/windows.py | 1 + requirements.txt | 2 +- 9 files changed, 93 insertions(+), 37 deletions(-) diff --git a/lib/platformdirs/__init__.py b/lib/platformdirs/__init__.py index 3d5a5bda..75c8bff9 100644 --- a/lib/platformdirs/__init__.py +++ b/lib/platformdirs/__init__.py @@ -2,6 +2,7 @@ Utilities for determining application-specific dirs. See for details and usage. """ + from __future__ import annotations import os @@ -14,11 +15,7 @@ from .version import __version_tuple__ as __version_info__ if TYPE_CHECKING: from pathlib import Path - - if sys.version_info >= (3, 8): # pragma: no cover (py38+) - from typing import Literal - else: # pragma: no cover (py38+) - from typing_extensions import Literal + from typing import Literal def _set_platform_dir_class() -> type[PlatformDirsABC]: diff --git a/lib/platformdirs/__main__.py b/lib/platformdirs/__main__.py index 3cefedbd..4bf27c9c 100644 --- a/lib/platformdirs/__main__.py +++ b/lib/platformdirs/__main__.py @@ -1,4 +1,5 @@ """Main entry point.""" + from __future__ import annotations from platformdirs import PlatformDirs, __version__ diff --git a/lib/platformdirs/android.py b/lib/platformdirs/android.py index 572559f8..4acdb638 100644 --- a/lib/platformdirs/android.py +++ b/lib/platformdirs/android.py @@ -1,4 +1,5 @@ """Android.""" + from __future__ import annotations import os diff --git a/lib/platformdirs/api.py b/lib/platformdirs/api.py index aa9ce7b9..031a38a3 100644 --- a/lib/platformdirs/api.py +++ b/lib/platformdirs/api.py @@ -1,4 +1,5 @@ """Base API.""" + from __future__ import annotations import os @@ -7,12 +8,7 @@ from pathlib import Path from typing import TYPE_CHECKING if TYPE_CHECKING: - import sys - - if sys.version_info >= (3, 8): # pragma: no cover (py38+) - from typing import Literal - else: # pragma: no cover (py38+) - from typing_extensions import Literal + from typing import Iterator, Literal class PlatformDirsABC(ABC): @@ -241,3 +237,43 @@ class PlatformDirsABC(ABC): def site_runtime_path(self) -> Path: """:return: runtime path shared by users""" return Path(self.site_runtime_dir) + + def iter_config_dirs(self) -> Iterator[str]: + """:yield: all user and site configuration directories.""" + yield self.user_config_dir + yield self.site_config_dir + + def iter_data_dirs(self) -> Iterator[str]: + """:yield: all user and site data directories.""" + yield self.user_data_dir + yield self.site_data_dir + + def iter_cache_dirs(self) -> Iterator[str]: + """:yield: all user and site cache directories.""" + yield self.user_cache_dir + yield self.site_cache_dir + + def iter_runtime_dirs(self) -> Iterator[str]: + """:yield: all user and site runtime directories.""" + yield self.user_runtime_dir + yield self.site_runtime_dir + + def iter_config_paths(self) -> Iterator[Path]: + """:yield: all user and site configuration paths.""" + for path in self.iter_config_dirs(): + yield Path(path) + + def iter_data_paths(self) -> Iterator[Path]: + """:yield: all user and site data paths.""" + for path in self.iter_data_dirs(): + yield Path(path) + + def iter_cache_paths(self) -> Iterator[Path]: + """:yield: all user and site cache paths.""" + for path in self.iter_cache_dirs(): + yield Path(path) + + def iter_runtime_paths(self) -> Iterator[Path]: + """:yield: all user and site runtime paths.""" + for path in self.iter_runtime_dirs(): + yield Path(path) diff --git a/lib/platformdirs/macos.py b/lib/platformdirs/macos.py index c01ce163..b7b48808 100644 --- a/lib/platformdirs/macos.py +++ b/lib/platformdirs/macos.py @@ -1,4 +1,5 @@ """macOS.""" + from __future__ import annotations import os.path diff --git a/lib/platformdirs/unix.py b/lib/platformdirs/unix.py index 1d0174f2..ca4728e6 100644 --- a/lib/platformdirs/unix.py +++ b/lib/platformdirs/unix.py @@ -1,10 +1,12 @@ """Unix.""" + from __future__ import annotations import os import sys from configparser import ConfigParser from pathlib import Path +from typing import Iterator from .api import PlatformDirsABC @@ -43,24 +45,24 @@ class Unix(PlatformDirsABC): return self._append_app_name_and_version(path) @property - def site_data_dir(self) -> str: - """ - :return: data directories shared by users (if `multipath ` is - enabled and ``XDG_DATA_DIR`` is set and a multi path the response is also a multi path separated by the OS - path separator), e.g. ``/usr/local/share/$appname/$version`` or ``/usr/share/$appname/$version`` - """ - # XDG default for $XDG_DATA_DIRS; only first, if multipath is False + def _site_data_dirs(self) -> list[str]: path = os.environ.get("XDG_DATA_DIRS", "") if not path.strip(): path = f"/usr/local/share{os.pathsep}/usr/share" - return self._with_multi_path(path) + return [self._append_app_name_and_version(p) for p in path.split(os.pathsep)] - def _with_multi_path(self, path: str) -> str: - path_list = path.split(os.pathsep) + @property + def site_data_dir(self) -> str: + """ + :return: data directories shared by users (if `multipath ` is + enabled and ``XDG_DATA_DIRS`` is set and a multi path the response is also a multi path separated by the + OS path separator), e.g. ``/usr/local/share/$appname/$version`` or ``/usr/share/$appname/$version`` + """ + # XDG default for $XDG_DATA_DIRS; only first, if multipath is False + dirs = self._site_data_dirs if not self.multipath: - path_list = path_list[0:1] - path_list = [self._append_app_name_and_version(os.path.expanduser(p)) for p in path_list] # noqa: PTH111 - return os.pathsep.join(path_list) + return dirs[0] + return os.pathsep.join(dirs) @property def user_config_dir(self) -> str: @@ -74,17 +76,24 @@ class Unix(PlatformDirsABC): return self._append_app_name_and_version(path) @property - def site_config_dir(self) -> str: - """ - :return: config directories shared by users (if `multipath ` - is enabled and ``XDG_DATA_DIR`` is set and a multi path the response is also a multi path separated by the OS - path separator), e.g. ``/etc/xdg/$appname/$version`` - """ - # XDG default for $XDG_CONFIG_DIRS only first, if multipath is False + def _site_config_dirs(self) -> list[str]: path = os.environ.get("XDG_CONFIG_DIRS", "") if not path.strip(): path = "/etc/xdg" - return self._with_multi_path(path) + return [self._append_app_name_and_version(p) for p in path.split(os.pathsep)] + + @property + def site_config_dir(self) -> str: + """ + :return: config directories shared by users (if `multipath ` + is enabled and ``XDG_CONFIG_DIRS`` is set and a multi path the response is also a multi path separated by + the OS path separator), e.g. ``/etc/xdg/$appname/$version`` + """ + # XDG default for $XDG_CONFIG_DIRS only first, if multipath is False + dirs = self._site_config_dirs + if not self.multipath: + return dirs[0] + return os.pathsep.join(dirs) @property def user_cache_dir(self) -> str: @@ -99,8 +108,8 @@ class Unix(PlatformDirsABC): @property def site_cache_dir(self) -> str: - """:return: cache directory shared by users, e.g. ``/var/tmp/$appname/$version``""" - return self._append_app_name_and_version("/var/tmp") # noqa: S108 + """:return: cache directory shared by users, e.g. ``/var/cache/$appname/$version``""" + return self._append_app_name_and_version("/var/cache") @property def user_state_dir(self) -> str: @@ -215,6 +224,16 @@ class Unix(PlatformDirsABC): directory = directory.split(os.pathsep)[0] return Path(directory) + def iter_config_dirs(self) -> Iterator[str]: + """:yield: all user and site configuration directories.""" + yield self.user_config_dir + yield from self._site_config_dirs + + def iter_data_dirs(self) -> Iterator[str]: + """:yield: all user and site data directories.""" + yield self.user_data_dir + yield from self._site_data_dirs + def _get_user_media_dir(env_var: str, fallback_tilde_path: str) -> str: media_dir = _get_user_dirs_folder(env_var) diff --git a/lib/platformdirs/version.py b/lib/platformdirs/version.py index c2ef2084..cc1e3456 100644 --- a/lib/platformdirs/version.py +++ b/lib/platformdirs/version.py @@ -12,5 +12,5 @@ __version__: str __version_tuple__: VERSION_TUPLE version_tuple: VERSION_TUPLE -__version__ = version = '3.11.0' -__version_tuple__ = version_tuple = (3, 11, 0) +__version__ = version = '4.2.0' +__version_tuple__ = version_tuple = (4, 2, 0) diff --git a/lib/platformdirs/windows.py b/lib/platformdirs/windows.py index 751143ad..c62d0c8d 100644 --- a/lib/platformdirs/windows.py +++ b/lib/platformdirs/windows.py @@ -1,4 +1,5 @@ """Windows.""" + from __future__ import annotations import ctypes diff --git a/requirements.txt b/requirements.txt index 53efa2e8..a1f27d23 100644 --- a/requirements.txt +++ b/requirements.txt @@ -27,7 +27,7 @@ MarkupSafe==2.1.3 musicbrainzngs==0.7.1 packaging==23.1 paho-mqtt==1.6.1 -platformdirs==3.11.0 +platformdirs==4.2.0 plexapi==4.15.10 portend==3.2.0 profilehooks==1.12.0 From b7836102a9323bb740559ba2e8ee590e543b8a7c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Mar 2024 15:24:05 -0700 Subject: [PATCH 12/13] Bump backports-functools-lru-cache from 1.6.6 to 2.0.0 (#2263) * Bump backports-functools-lru-cache from 1.6.6 to 2.0.0 Bumps [backports-functools-lru-cache](https://github.com/jaraco/backports.functools_lru_cache) from 1.6.6 to 2.0.0. - [Release notes](https://github.com/jaraco/backports.functools_lru_cache/releases) - [Changelog](https://github.com/jaraco/backports.functools_lru_cache/blob/main/NEWS.rst) - [Commits](https://github.com/jaraco/backports.functools_lru_cache/compare/v1.6.6...v2.0.0) --- updated-dependencies: - dependency-name: backports-functools-lru-cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Update backports-functools-lru-cache==2.0.0 --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> [skip ci] --- lib/backports/functools_lru_cache.py | 274 ++++++++++++++++----------- requirements.txt | 2 +- 2 files changed, 162 insertions(+), 114 deletions(-) diff --git a/lib/backports/functools_lru_cache.py b/lib/backports/functools_lru_cache.py index 1b83fe99..e372cff3 100644 --- a/lib/backports/functools_lru_cache.py +++ b/lib/backports/functools_lru_cache.py @@ -26,6 +26,12 @@ def update_wrapper( class _HashedSeq(list): + """This class guarantees that hash() will be called no more than once + per element. This is important because the lru_cache() will hash + the key multiple times on a cache miss. + + """ + __slots__ = 'hashvalue' def __init__(self, tup, hash=hash): @@ -41,45 +47,57 @@ def _make_key( kwds, typed, kwd_mark=(object(),), - fasttypes=set([int, str, frozenset, type(None)]), - sorted=sorted, + fasttypes={int, str}, tuple=tuple, type=type, len=len, ): - 'Make a cache key from optionally typed positional and keyword arguments' + """Make a cache key from optionally typed positional and keyword arguments + + The key is constructed in a way that is flat as possible rather than + as a nested structure that would take more memory. + + If there is only a single argument and its data type is known to cache + its hash value, then that argument is returned without a wrapper. This + saves space and improves lookup speed. + + """ + # All of code below relies on kwds preserving the order input by the user. + # Formerly, we sorted() the kwds before looping. The new way is *much* + # faster; however, it means that f(x=1, y=2) will now be treated as a + # distinct call from f(y=2, x=1) which will be cached separately. key = args if kwds: - sorted_items = sorted(kwds.items()) key += kwd_mark - for item in sorted_items: + for item in kwds.items(): key += item if typed: key += tuple(type(v) for v in args) if kwds: - key += tuple(type(v) for k, v in sorted_items) + key += tuple(type(v) for v in kwds.values()) elif len(key) == 1 and type(key[0]) in fasttypes: return key[0] return _HashedSeq(key) -def lru_cache(maxsize=100, typed=False): # noqa: C901 +def lru_cache(maxsize=128, typed=False): """Least-recently-used cache decorator. If *maxsize* is set to None, the LRU features are disabled and the cache can grow without bound. If *typed* is True, arguments of different types will be cached separately. - For example, f(3.0) and f(3) will be treated as distinct calls with - distinct results. + For example, f(decimal.Decimal("3.0")) and f(3.0) will be treated as + distinct calls with distinct results. Some types such as str and int may + be cached separately even when typed is false. Arguments to the cached function must be hashable. - View the cache statistics named tuple (hits, misses, maxsize, currsize) with - f.cache_info(). Clear the cache and statistics with f.cache_clear(). + View the cache statistics named tuple (hits, misses, maxsize, currsize) + with f.cache_info(). Clear the cache and statistics with f.cache_clear(). Access the underlying function with f.__wrapped__. - See: http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used + See: https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU) """ @@ -88,108 +106,138 @@ def lru_cache(maxsize=100, typed=False): # noqa: C901 # The internals of the lru_cache are encapsulated for thread safety and # to allow the implementation to change (including a possible C version). + if isinstance(maxsize, int): + # Negative maxsize is treated as 0 + if maxsize < 0: + maxsize = 0 + elif callable(maxsize) and isinstance(typed, bool): + # The user_function was passed in directly via the maxsize argument + user_function, maxsize = maxsize, 128 + wrapper = _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo) + wrapper.cache_parameters = lambda: {'maxsize': maxsize, 'typed': typed} + return update_wrapper(wrapper, user_function) + elif maxsize is not None: + raise TypeError('Expected first argument to be an integer, a callable, or None') + def decorating_function(user_function): - cache = dict() - stats = [0, 0] # make statistics updateable non-locally - HITS, MISSES = 0, 1 # names for the stats fields - make_key = _make_key - cache_get = cache.get # bound method to lookup key or return None - _len = len # localize the global len() function - lock = RLock() # because linkedlist updates aren't threadsafe - root = [] # root of the circular doubly linked list - root[:] = [root, root, None, None] # initialize by pointing to self - nonlocal_root = [root] # make updateable non-locally - PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names for the link fields - - if maxsize == 0: - - def wrapper(*args, **kwds): - # no caching, just do a statistics update after a successful call - result = user_function(*args, **kwds) - stats[MISSES] += 1 - return result - - elif maxsize is None: - - def wrapper(*args, **kwds): - # simple caching without ordering or size limit - key = make_key(args, kwds, typed) - result = cache_get( - key, root - ) # root used here as a unique not-found sentinel - if result is not root: - stats[HITS] += 1 - return result - result = user_function(*args, **kwds) - cache[key] = result - stats[MISSES] += 1 - return result - - else: - - def wrapper(*args, **kwds): - # size limited caching that tracks accesses by recency - key = make_key(args, kwds, typed) if kwds or typed else args - with lock: - link = cache_get(key) - if link is not None: - # record recent use of the key by moving it - # to the front of the list - (root,) = nonlocal_root - link_prev, link_next, key, result = link - link_prev[NEXT] = link_next - link_next[PREV] = link_prev - last = root[PREV] - last[NEXT] = root[PREV] = link - link[PREV] = last - link[NEXT] = root - stats[HITS] += 1 - return result - result = user_function(*args, **kwds) - with lock: - (root,) = nonlocal_root - if key in cache: - # getting here means that this same key was added to the - # cache while the lock was released. since the link - # update is already done, we need only return the - # computed result and update the count of misses. - pass - elif _len(cache) >= maxsize: - # use the old root to store the new key and result - oldroot = root - oldroot[KEY] = key - oldroot[RESULT] = result - # empty the oldest link and make it the new root - root = nonlocal_root[0] = oldroot[NEXT] - oldkey = root[KEY] - root[KEY] = root[RESULT] = None - # now update the cache dictionary for the new links - del cache[oldkey] - cache[key] = oldroot - else: - # put result in a new link at the front of the list - last = root[PREV] - link = [last, root, key, result] - last[NEXT] = root[PREV] = cache[key] = link - stats[MISSES] += 1 - return result - - def cache_info(): - """Report cache statistics""" - with lock: - return _CacheInfo(stats[HITS], stats[MISSES], maxsize, len(cache)) - - def cache_clear(): - """Clear the cache and cache statistics""" - with lock: - cache.clear() - root = nonlocal_root[0] - root[:] = [root, root, None, None] - stats[:] = [0, 0] - - wrapper.__wrapped__ = user_function - wrapper.cache_info = cache_info - wrapper.cache_clear = cache_clear + wrapper = _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo) + wrapper.cache_parameters = lambda: {'maxsize': maxsize, 'typed': typed} return update_wrapper(wrapper, user_function) return decorating_function + + +def _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo): + # Constants shared by all lru cache instances: + sentinel = object() # unique object used to signal cache misses + make_key = _make_key # build a key from the function arguments + PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names for the link fields + + cache = {} + hits = misses = 0 + full = False + cache_get = cache.get # bound method to lookup a key or return None + cache_len = cache.__len__ # get cache size without calling len() + lock = RLock() # because linkedlist updates aren't threadsafe + root = [] # root of the circular doubly linked list + root[:] = [root, root, None, None] # initialize by pointing to self + + if maxsize == 0: + + def wrapper(*args, **kwds): + # No caching -- just a statistics update + nonlocal misses + misses += 1 + result = user_function(*args, **kwds) + return result + + elif maxsize is None: + + def wrapper(*args, **kwds): + # Simple caching without ordering or size limit + nonlocal hits, misses + key = make_key(args, kwds, typed) + result = cache_get(key, sentinel) + if result is not sentinel: + hits += 1 + return result + misses += 1 + result = user_function(*args, **kwds) + cache[key] = result + return result + + else: + + def wrapper(*args, **kwds): + # Size limited caching that tracks accesses by recency + nonlocal root, hits, misses, full + key = make_key(args, kwds, typed) + with lock: + link = cache_get(key) + if link is not None: + # Move the link to the front of the circular queue + link_prev, link_next, _key, result = link + link_prev[NEXT] = link_next + link_next[PREV] = link_prev + last = root[PREV] + last[NEXT] = root[PREV] = link + link[PREV] = last + link[NEXT] = root + hits += 1 + return result + misses += 1 + result = user_function(*args, **kwds) + with lock: + if key in cache: + # Getting here means that this same key was added to the + # cache while the lock was released. Since the link + # update is already done, we need only return the + # computed result and update the count of misses. + pass + elif full: + # Use the old root to store the new key and result. + oldroot = root + oldroot[KEY] = key + oldroot[RESULT] = result + # Empty the oldest link and make it the new root. + # Keep a reference to the old key and old result to + # prevent their ref counts from going to zero during the + # update. That will prevent potentially arbitrary object + # clean-up code (i.e. __del__) from running while we're + # still adjusting the links. + root = oldroot[NEXT] + oldkey = root[KEY] + root[KEY] = root[RESULT] = None + # Now update the cache dictionary. + del cache[oldkey] + # Save the potentially reentrant cache[key] assignment + # for last, after the root and links have been put in + # a consistent state. + cache[key] = oldroot + else: + # Put result in a new link at the front of the queue. + last = root[PREV] + link = [last, root, key, result] + last[NEXT] = root[PREV] = cache[key] = link + # Use the cache_len bound method instead of the len() function + # which could potentially be wrapped in an lru_cache itself. + full = cache_len() >= maxsize + return result + + def cache_info(): + """Report cache statistics""" + with lock: + return _CacheInfo(hits, misses, maxsize, cache_len()) + + def cache_clear(): + """Clear the cache and cache statistics""" + nonlocal hits, misses, full + with lock: + cache.clear() + root[:] = [root, root, None, None] + hits = misses = 0 + full = False + + wrapper.cache_info = cache_info + wrapper.cache_clear = cache_clear + return wrapper diff --git a/requirements.txt b/requirements.txt index a1f27d23..a953a789 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ apscheduler==3.10.1 arrow==1.3.0 backports.csv==1.0.7 -backports.functools-lru-cache==1.6.6 +backports.functools-lru-cache==2.0.0 backports.zoneinfo==0.2.1;python_version<"3.9" beautifulsoup4==4.12.2 bleach==6.1.0 From aca7e727157829edefaef01de96cc890916c61ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Mar 2024 15:24:31 -0700 Subject: [PATCH 13/13] Bump distro from 1.8.0 to 1.9.0 (#2262) * Bump distro from 1.8.0 to 1.9.0 Bumps [distro](https://github.com/python-distro/distro) from 1.8.0 to 1.9.0. - [Release notes](https://github.com/python-distro/distro/releases) - [Changelog](https://github.com/python-distro/distro/blob/master/CHANGELOG.md) - [Commits](https://github.com/python-distro/distro/compare/v1.8.0...v1.9.0) --- updated-dependencies: - dependency-name: distro dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Update distro==1.9.0 --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> [skip ci] --- lib/distro/distro.py | 12 ++++++++---- requirements.txt | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/distro/distro.py b/lib/distro/distro.py index 89e18680..78ccdfa4 100644 --- a/lib/distro/distro.py +++ b/lib/distro/distro.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright 2015,2016,2017 Nir Cohen +# Copyright 2015-2021 Nir Cohen # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -55,7 +55,7 @@ except ImportError: # Python 3.7 TypedDict = dict -__version__ = "1.8.0" +__version__ = "1.9.0" class VersionDict(TypedDict): @@ -125,6 +125,7 @@ _DISTRO_RELEASE_BASENAME_PATTERN = re.compile(r"(\w+)[-_](release|version)$") # Base file names to be looked up for if _UNIXCONFDIR is not readable. _DISTRO_RELEASE_BASENAMES = [ "SuSE-release", + "altlinux-release", "arch-release", "base-release", "centos-release", @@ -151,6 +152,8 @@ _DISTRO_RELEASE_IGNORE_BASENAMES = ( "system-release", "plesk-release", "iredmail-release", + "board-release", + "ec2_version", ) @@ -243,6 +246,7 @@ def id() -> str: "rocky" Rocky Linux "aix" AIX "guix" Guix System + "altlinux" ALT Linux ============== ========================================= If you have a need to get distros for reliable IDs added into this set, @@ -991,10 +995,10 @@ class LinuxDistribution: For details, see :func:`distro.info`. """ - return dict( + return InfoDict( id=self.id(), version=self.version(pretty, best), - version_parts=dict( + version_parts=VersionDict( major=self.major_version(best), minor=self.minor_version(best), build_number=self.build_number(best), diff --git a/requirements.txt b/requirements.txt index a953a789..fe84492e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,7 @@ certifi==2024.2.2 cheroot==10.0.0 cherrypy==18.8.0 cloudinary==1.34.0 -distro==1.8.0 +distro==1.9.0 dnspython==2.4.2 facebook-sdk==3.1.0 future==0.18.3

+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 literal 174394 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 z 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 z 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