From b175dabe7729ea4bac2d4c8eff164682afb3000a Mon Sep 17 00:00:00 2001 From: Aweryc Date: Mon, 14 Jul 2025 13:00:09 +0300 Subject: [PATCH 1/6] Convenience Functionality for BusinessOpeningHours -check if the business is open at a given time -get the opening hours for a given day --- changes/unreleased/48XX._.toml | 5 + pyproject.toml | 5 + src/telegram/__main__.py | 4 +- src/telegram/_business.py | 89 ++++++++- .../_passport/encryptedpassportelement.py | 1 - src/telegram/_payment/stars/staramount.py | 1 - src/telegram/_utils/datetime.py | 25 +++ src/telegram/_utils/enum.py | 2 +- tests/_utils/test_datetime.py | 54 +++++- tests/test_business_classes.py | 177 ++++++++++++++++++ 10 files changed, 355 insertions(+), 8 deletions(-) create mode 100644 changes/unreleased/48XX._.toml diff --git a/changes/unreleased/48XX._.toml b/changes/unreleased/48XX._.toml new file mode 100644 index 00000000000..fa083bd43a0 --- /dev/null +++ b/changes/unreleased/48XX._.toml @@ -0,0 +1,5 @@ +features = "Added a two methods for BusinessOpeningHours" +[[pull_requests]] +uid = "4326" +author_uid = "Aweryc" +closes_threads = ["4194, 4326"] \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 66589c25b0e..25d18172d19 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,7 +38,12 @@ classifiers = [ "Programming Language :: Python :: 3.13", ] dependencies = [ + "black>=25.1.0", "httpx >=0.27,<0.29", + "pre-commit>=4.2.0", + "pytest>=8.3.5", + "pytz>=2025.2", + "ruff==0.11.9", ] [project.urls] diff --git a/src/telegram/__main__.py b/src/telegram/__main__.py index 7d291b2ae1e..c685c0a389a 100644 --- a/src/telegram/__main__.py +++ b/src/telegram/__main__.py @@ -17,7 +17,7 @@ # You should have received a copy of the GNU Lesser Public License # along with this program. If not, see [http://www.gnu.org/licenses/]. # pylint: disable=missing-module-docstring -# ruff: noqa: T201, D100, S603, S607 +# ruff: noqa: T201, D100, S607 import subprocess import sys from typing import Optional @@ -28,7 +28,7 @@ def _git_revision() -> Optional[str]: try: - output = subprocess.check_output( + output = subprocess.check_output( # noqa: S603 ["git", "describe", "--long", "--tags"], stderr=subprocess.STDOUT ) except (subprocess.SubprocessError, OSError): diff --git a/src/telegram/_business.py b/src/telegram/_business.py index dd055426654..7846955af7e 100644 --- a/src/telegram/_business.py +++ b/src/telegram/_business.py @@ -21,6 +21,7 @@ import datetime as dtm from collections.abc import Sequence from typing import TYPE_CHECKING, Optional +from zoneinfo import ZoneInfo from telegram._chat import Chat from telegram._files.location import Location @@ -28,7 +29,7 @@ from telegram._telegramobject import TelegramObject from telegram._user import User from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg -from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp +from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp, verify_timezone from telegram._utils.types import JSONDict from telegram._utils.warnings import warn from telegram._utils.warnings_transition import ( @@ -494,7 +495,7 @@ class BusinessOpeningHoursInterval(TelegramObject): Examples: A day has (24 * 60 =) 1440 minutes, a week has (7 * 1440 =) 10080 minutes. - Starting the the minute's sequence from Monday, example values of + Starting the minute's sequence from Monday, example values of :attr:`opening_minute`, :attr:`closing_minute` will map to the following day times: * Monday - 8am to 8:30pm: @@ -616,6 +617,90 @@ def __init__( self._freeze() + def get_opening_hours_for_day( + self, date: dtm.date, time_zone: Optional[ZoneInfo] = None + ) -> tuple[tuple[dtm.datetime, dtm.datetime], ...]: + """Returns the opening hours intervals for a specific day as datetime objects. + + .. versionadded:: NEXT.VERSION + + + Objects of this class are comparable in terms of equality. + Two objects of this class are considered equal, if their + :attr:`time_zone_name` and :attr:`opening_hours` are equal. + Args: + date (:obj:`datetime.date`): The date to get opening hours for. + Only the weekday component + is used to determine matching opening intervals. + time_zone (:obj:`zoneinfo.ZoneInfo`, optional): Timezone to use for the returned + datetime objects. If not specified, the returned datetime objects + will be timezone-naive. + + Returns: + tuple[tuple[:obj:`datetime.datetime`, :obj:`datetime.datetime`], ...]: + A tuple of datetime pairs representing opening and closing times for the specified day. + Each pair consists of (opening_time, closing_time). Returns an empty tuple if there are + no opening hours for the given day. + """ + + week_day = date.weekday() + res = [] + + for interval in self.opening_hours: + int_open = interval.opening_time + int_close = interval.closing_time + if int_open[0] == week_day: + res.append( + ( + dtm.datetime( + year=date.year, + month=date.month, + day=date.day, + hour=int_open[1], + minute=int_open[2], + tzinfo=verify_timezone(time_zone), + ), + dtm.datetime( + year=date.year, + month=date.month, + day=date.day, + hour=int_close[1], + minute=int_close[2], + tzinfo=verify_timezone(time_zone), + ), + ) + ) + + return tuple(res) + + def is_open(self, dt: dtm.datetime) -> bool: + """Check if the business is open at the specified datetime. + + .. versionadded:: NEXT.VERSION + + Args: + dt (:obj:`datetime.datetime`): The datetime to check. + If timezone-aware, the check will be performed in that timezone. + If timezone-naive, the check will be performed in the + timezone specified by :attr:`time_zone_name`. + Returns: + :obj:`bool`: True if the business is open at the specified time, False otherwise. + """ + + if dt.tzinfo is None: + dt_utc = dt + else: + dt_utc = dt.astimezone(verify_timezone(ZoneInfo(self.time_zone_name))) + + weekday = dt_utc.weekday() + minute_of_week = weekday * 1440 + dt_utc.hour * 60 + dt_utc.minute + + for interval in self.opening_hours: + if interval.opening_minute <= minute_of_week < interval.closing_minute: + return True + + return False + @classmethod def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "BusinessOpeningHours": """See :meth:`telegram.TelegramObject.de_json`.""" diff --git a/src/telegram/_passport/encryptedpassportelement.py b/src/telegram/_passport/encryptedpassportelement.py index c231c51640b..65f88e7a69b 100644 --- a/src/telegram/_passport/encryptedpassportelement.py +++ b/src/telegram/_passport/encryptedpassportelement.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# flake8: noqa: E501 # A library that provides a Python interface to the Telegram Bot API # Copyright (C) 2015-2025 # Leandro Toledo de Souza diff --git a/src/telegram/_payment/stars/staramount.py b/src/telegram/_payment/stars/staramount.py index a8d61b2a118..c78a4aa9aba 100644 --- a/src/telegram/_payment/stars/staramount.py +++ b/src/telegram/_payment/stars/staramount.py @@ -16,7 +16,6 @@ # # You should have received a copy of the GNU Lesser Public License # along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=redefined-builtin """This module contains an object that represents a Telegram StarAmount.""" diff --git a/src/telegram/_utils/datetime.py b/src/telegram/_utils/datetime.py index 8e6ebdda1b4..bd941b2a5b6 100644 --- a/src/telegram/_utils/datetime.py +++ b/src/telegram/_utils/datetime.py @@ -30,8 +30,11 @@ import contextlib import datetime as dtm import time +import zoneinfo from typing import TYPE_CHECKING, Optional, Union +from telegram.error import TelegramError + if TYPE_CHECKING: from telegram import Bot @@ -224,3 +227,25 @@ def _datetime_to_float_timestamp(dt_obj: dtm.datetime) -> float: if dt_obj.tzinfo is None: dt_obj = dt_obj.replace(tzinfo=dtm.timezone.utc) return dt_obj.timestamp() + + +def verify_timezone( + tz: Optional[Union[dtm.tzinfo, zoneinfo.ZoneInfo]], +) -> Optional[Union[zoneinfo.ZoneInfo, dtm.tzinfo]]: + """ + Verifies that the given timezone is a valid timezone. + """ + + if tz is None: + return None + if isinstance(tz, (dtm.tzinfo, zoneinfo.ZoneInfo)): + return tz + + try: + return zoneinfo.ZoneInfo(tz) + except zoneinfo.ZoneInfoNotFoundError as err: + raise TelegramError( + f"No time zone found with key {tz}. " + f"Make sure to use a valid time zone name and " + f"correct install tzdata (https://pypi.org/project/tzdata/)" + ) from err diff --git a/src/telegram/_utils/enum.py b/src/telegram/_utils/enum.py index 58362870f7e..52e21eb46f5 100644 --- a/src/telegram/_utils/enum.py +++ b/src/telegram/_utils/enum.py @@ -60,7 +60,7 @@ def __str__(self) -> str: # Apply the __repr__ modification and __str__ fix to IntEnum -class IntEnum(_enum.IntEnum): # pylint: disable=invalid-slots +class IntEnum(_enum.IntEnum): """Helper class for int enums where ``str(member)`` prints the value, but ``repr(member)`` gives ``EnumName.MEMBER_NAME``. """ diff --git a/tests/_utils/test_datetime.py b/tests/_utils/test_datetime.py index dfcaca67587..d1b9aaea91d 100644 --- a/tests/_utils/test_datetime.py +++ b/tests/_utils/test_datetime.py @@ -23,6 +23,8 @@ import pytest from telegram._utils import datetime as tg_dtm +from telegram._utils.datetime import verify_timezone +from telegram.error import TelegramError from telegram.ext import Defaults # sample time specification values categorised into absolute / delta / time-of-day @@ -168,7 +170,7 @@ def test_to_timestamp(self): assert tg_dtm.to_timestamp(i) == int(tg_dtm.to_float_timestamp(i)), f"Failed for {i}" def test_to_timestamp_none(self): - # this 'convenience' behaviour has been left left for backwards compatibility + # this 'convenience' behaviour has been left for backwards compatibility assert tg_dtm.to_timestamp(None) is None def test_from_timestamp_none(self): @@ -192,3 +194,53 @@ def test_extract_tzinfo_from_defaults(self, tz_bot, bot, raw_bot): assert tg_dtm.extract_tzinfo_from_defaults(tz_bot) == tz_bot.defaults.tzinfo assert tg_dtm.extract_tzinfo_from_defaults(bot) is None assert tg_dtm.extract_tzinfo_from_defaults(raw_bot) is None + + def test_with_zoneinfo_object(self): + """Test with a valid zoneinfo.ZoneInfo object.""" + tz = zoneinfo.ZoneInfo("Europe/Paris") + result = verify_timezone(tz) + assert result == tz + + def test_with_datetime_tzinfo(self): + """Test with a datetime.tzinfo object.""" + + class CustomTZ(dtm.tzinfo): + def utcoffset(self, dt): + return dtm.timedelta(hours=2) + + def dst(self, dt): + return dtm.timedelta(0) + + tz = CustomTZ() + result = verify_timezone(tz) + assert result == tz + + def test_with_valid_timezone_string(self): + """Test with a valid timezone string.""" + tz = "Asia/Tokyo" + result = verify_timezone(tz) + assert isinstance(result, zoneinfo.ZoneInfo) + assert str(result) == "Asia/Tokyo" + + def test_with_none(self): + """Test with None input.""" + assert verify_timezone(None) is None + + def test_with_invalid_timezone_string(self): + """Test with an invalid timezone string.""" + with pytest.raises(TelegramError, match="No time zone found"): + verify_timezone("Invalid/Timezone") + + def test_with_empty_string(self): + """Test with empty string input.""" + with pytest.raises(TelegramError, match="No time zone found"): + verify_timezone("") + + def test_with_non_timezone_object(self): + """Test with an object that isn't a timezone.""" + with pytest.raises(TelegramError, match="No time zone found"): + verify_timezone(123) # integer + with pytest.raises(TelegramError, match="No time zone found"): + verify_timezone({"key": "value"}) # dict + with pytest.raises(TelegramError, match="No time zone found"): + verify_timezone([]) # empty list diff --git a/tests/test_business_classes.py b/tests/test_business_classes.py index aabf60064c6..afb8f60b765 100644 --- a/tests/test_business_classes.py +++ b/tests/test_business_classes.py @@ -17,6 +17,7 @@ # You should have received a copy of the GNU Lesser Public License # along with this program. If not, see [http://www.gnu.org/licenses/]. import datetime as dtm +from zoneinfo import ZoneInfo import pytest @@ -589,3 +590,179 @@ def test_equality(self): assert boh1 != boh3 assert hash(boh1) != hash(boh3) + + +class TestBusinessOpeningHoursGetOpeningHoursForDayWithoutRequest: + @pytest.fixture + def sample_opening_hours(self): + # Monday 8am-8:30pm (480-1230) + # Tuesday 24 hours (1440-2879) + # Sunday 12am-11:58pm (8640-10078) + intervals = [ + BusinessOpeningHoursInterval(480, 1230), # Monday 8am-8:30pm + BusinessOpeningHoursInterval(1440, 2879), # Tuesday 24 hours + BusinessOpeningHoursInterval(8640, 10078), # Sunday 12am-11:58pm + ] + return BusinessOpeningHours(time_zone_name="UTC", opening_hours=intervals) + + def test_monday_opening_hours(self, sample_opening_hours): + # Test for Monday + test_date = dtm.date(2023, 11, 6) # Monday + time_zone = ZoneInfo("UTC") + result = sample_opening_hours.get_opening_hours_for_day(test_date, time_zone) + + expected = ( + dtm.datetime(2023, 11, 6, 8, 0, tzinfo=time_zone), + dtm.datetime(2023, 11, 6, 20, 30, tzinfo=time_zone), + ) + + assert result == expected + + def test_tuesday_24_hours(self, sample_opening_hours): + # Test for Tuesday (24 hours) + test_date = dtm.date(2023, 11, 7) # Tuesday + time_zone = ZoneInfo("UTC") + result = sample_opening_hours.get_opening_hours_for_day(test_date, time_zone) + + expected = ( + dtm.datetime(2023, 11, 7, 0, 0, tzinfo=time_zone), + dtm.datetime(2023, 11, 7, 23, 59, tzinfo=time_zone), + ) + + assert result == expected + + def test_sunday_opening_hours(self, sample_opening_hours): + # Test for Sunday + test_date = dtm.date(2023, 11, 12) # Sunday + time_zone = ZoneInfo("UTC") + result = sample_opening_hours.get_opening_hours_for_day(test_date, time_zone) + + expected = ( + dtm.datetime(2023, 11, 12, 0, 0, tzinfo=time_zone), + dtm.datetime(2023, 11, 12, 23, 58, tzinfo=time_zone), + ) + + assert result == expected + + def test_day_with_no_opening_hours(self, sample_opening_hours): + # Test for Wednesday (no opening hours defined) + test_date = dtm.date(2023, 11, 8) # Wednesday + time_zone = ZoneInfo("UTC") + result = sample_opening_hours.get_opening_hours_for_day(test_date, time_zone) + + assert result == () + + def test_multiple_intervals_same_day(self): + # Test with multiple intervals on the same day + intervals = [ + BusinessOpeningHoursInterval(480, 720), # Monday 8am-12pm + BusinessOpeningHoursInterval(900, 1230), # Monday 3pm-8:30pm + ] + opening_hours = BusinessOpeningHours(time_zone_name="UTC", opening_hours=intervals) + + test_date = dtm.date(2023, 11, 6) # Monday + time_zone = ZoneInfo("UTC") + result = opening_hours.get_opening_hours_for_day(test_date, time_zone) + + expected = ( + dtm.datetime(2023, 11, 6, 8, 0, tzinfo=time_zone), + dtm.datetime(2023, 11, 6, 12, 0, tzinfo=time_zone), + dtm.datetime(2023, 11, 6, 15, 0, tzinfo=time_zone), + dtm.datetime(2023, 11, 6, 20, 30, tzinfo=time_zone), + ) + + assert result == expected + + def test_timezone_conversion(self, sample_opening_hours): + # Test that timezone is properly applied + test_date = dtm.date(2023, 11, 6) # Monday + time_zone = ZoneInfo("America/New_York") + result = sample_opening_hours.get_opening_hours_for_day(test_date, time_zone) + + expected = ( + dtm.datetime(2023, 11, 6, 8, 0, tzinfo=time_zone), + dtm.datetime(2023, 11, 6, 20, 30, tzinfo=time_zone), + ) + + assert result == expected + assert result[0].tzinfo == time_zone + assert result[1].tzinfo == time_zone + + def test_no_timezone_provided(self, sample_opening_hours): + # Test when no timezone is provided + test_date = dtm.date(2023, 11, 6) # Monday + result = sample_opening_hours.get_opening_hours_for_day(test_date) + + expected = ( + dtm.datetime(2023, 11, 6, 8, 0, tzinfo=None), + dtm.datetime(2023, 11, 6, 20, 30, tzinfo=None), + ) + + assert result == expected + + +class TestBusinessOpeningHoursIsOpenWithoutRequest: + @pytest.fixture + def sample_opening_hours(self): + # Monday 8am-8:30pm (480-1230) + # Tuesday 24 hours (1440-2879) + # Sunday 12am-11:58pm (8640-10078) + intervals = [ + BusinessOpeningHoursInterval(480, 1230), # Monday 8am-8:30pm UTC + BusinessOpeningHoursInterval(1440, 2879), # Tuesday 24 hours UTC + BusinessOpeningHoursInterval(8640, 10078), # Sunday 12am-11:58pm UTC + ] + return BusinessOpeningHours(time_zone_name="UTC", opening_hours=intervals) + + def test_is_open_during_business_hours(self, sample_opening_hours): + # Monday 10am UTC (within 8am-8:30pm) + dt = dtm.datetime(2023, 11, 6, 10, 0, tzinfo=ZoneInfo("UTC")) + assert sample_opening_hours.is_open(dt) is True + + def test_is_open_at_opening_time(self, sample_opening_hours): + # Monday exactly 8am UTC + dt = dtm.datetime(2023, 11, 6, 8, 0, tzinfo=ZoneInfo("UTC")) + assert sample_opening_hours.is_open(dt) is True + + def test_is_closed_at_closing_time(self, sample_opening_hours): + # Monday exactly 8:30pm UTC (closing time is exclusive) + dt = dtm.datetime(2023, 11, 6, 20, 30, tzinfo=ZoneInfo("UTC")) + assert sample_opening_hours.is_open(dt) is False + + def test_is_closed_outside_business_hours(self, sample_opening_hours): + # Monday 7am UTC (before opening) + dt = dtm.datetime(2023, 11, 6, 7, 0, tzinfo=ZoneInfo("UTC")) + assert sample_opening_hours.is_open(dt) is False + + def test_is_open_24h_day(self, sample_opening_hours): + # Tuesday 3am UTC (24h opening) + dt = dtm.datetime(2023, 11, 7, 3, 0, tzinfo=ZoneInfo("UTC")) + assert sample_opening_hours.is_open(dt) is True + + def test_is_closed_on_day_with_no_hours(self, sample_opening_hours): + # Wednesday (no opening hours) + dt = dtm.datetime(2023, 11, 8, 12, 0, tzinfo=ZoneInfo("UTC")) + assert sample_opening_hours.is_open(dt) is False + + def test_timezone_conversion(self, sample_opening_hours): + # Monday 10am UTC is 6am EDT (should be closed) + dt = dtm.datetime(2023, 11, 6, 6, 0, tzinfo=ZoneInfo("America/New_York")) + assert sample_opening_hours.is_open(dt) is False + + # Monday 10am EDT is 2pm UTC (should be open) + dt = dtm.datetime(2023, 11, 6, 10, 0, tzinfo=ZoneInfo("America/New_York")) + assert sample_opening_hours.is_open(dt) is True + + def test_naive_datetime_uses_business_timezone(self, sample_opening_hours): + # Naive datetime - should be interpreted as UTC (business timezone) + dt = dtm.datetime(2023, 11, 6, 10, 0) # 10am naive + assert sample_opening_hours.is_open(dt) is True + + def test_boundary_conditions(self, sample_opening_hours): + # Sunday 11:58pm UTC (should be open) + dt = dtm.datetime(2023, 11, 12, 23, 57, tzinfo=ZoneInfo("UTC")) + assert sample_opening_hours.is_open(dt) is True + + # Sunday 11:59pm UTC (should be closed) + dt = dtm.datetime(2023, 11, 12, 23, 59, tzinfo=ZoneInfo("UTC")) + assert sample_opening_hours.is_open(dt) is False From 73def0ae6d805584349a3f1b45304c0340c41ee8 Mon Sep 17 00:00:00 2001 From: Aweryc <93672316+Aweryc@users.noreply.github.com> Date: Thu, 17 Jul 2025 11:53:47 +0300 Subject: [PATCH 2/6] Revert enum.py --- src/telegram/_utils/enum.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/telegram/_utils/enum.py b/src/telegram/_utils/enum.py index 52e21eb46f5..58362870f7e 100644 --- a/src/telegram/_utils/enum.py +++ b/src/telegram/_utils/enum.py @@ -60,7 +60,7 @@ def __str__(self) -> str: # Apply the __repr__ modification and __str__ fix to IntEnum -class IntEnum(_enum.IntEnum): +class IntEnum(_enum.IntEnum): # pylint: disable=invalid-slots """Helper class for int enums where ``str(member)`` prints the value, but ``repr(member)`` gives ``EnumName.MEMBER_NAME``. """ From 0a70348d9442e9f50881c45c3ee47059b2023d4d Mon Sep 17 00:00:00 2001 From: Aweryc <93672316+Aweryc@users.noreply.github.com> Date: Thu, 17 Jul 2025 11:56:02 +0300 Subject: [PATCH 3/6] Proper re-raise zoneinfo.ZoneInfoNotFoundError --- src/telegram/_utils/datetime.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/telegram/_utils/datetime.py b/src/telegram/_utils/datetime.py index bd941b2a5b6..fb2f0724ba6 100644 --- a/src/telegram/_utils/datetime.py +++ b/src/telegram/_utils/datetime.py @@ -244,7 +244,7 @@ def verify_timezone( try: return zoneinfo.ZoneInfo(tz) except zoneinfo.ZoneInfoNotFoundError as err: - raise TelegramError( + raise zoneinfo.ZoneInfoNotFoundError( f"No time zone found with key {tz}. " f"Make sure to use a valid time zone name and " f"correct install tzdata (https://pypi.org/project/tzdata/)" From 99634d090ea74b6e3124d4228d18aee9a9fb2c31 Mon Sep 17 00:00:00 2001 From: Aweryc <93672316+Aweryc@users.noreply.github.com> Date: Thu, 17 Jul 2025 11:57:09 +0300 Subject: [PATCH 4/6] Update datetime.py --- src/telegram/_utils/datetime.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/telegram/_utils/datetime.py b/src/telegram/_utils/datetime.py index fb2f0724ba6..57aa683c977 100644 --- a/src/telegram/_utils/datetime.py +++ b/src/telegram/_utils/datetime.py @@ -33,8 +33,6 @@ import zoneinfo from typing import TYPE_CHECKING, Optional, Union -from telegram.error import TelegramError - if TYPE_CHECKING: from telegram import Bot From 86540bfcb244f56e8b98383bee7e8367b6d5cc39 Mon Sep 17 00:00:00 2001 From: Aweryc Date: Thu, 17 Jul 2025 12:01:52 +0300 Subject: [PATCH 5/6] Rename change file .toml --- .../unreleased/{48XX._.toml => 4861.HEoGVs2mYXWzqMahi6SEhV.toml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename changes/unreleased/{48XX._.toml => 4861.HEoGVs2mYXWzqMahi6SEhV.toml} (100%) diff --git a/changes/unreleased/48XX._.toml b/changes/unreleased/4861.HEoGVs2mYXWzqMahi6SEhV.toml similarity index 100% rename from changes/unreleased/48XX._.toml rename to changes/unreleased/4861.HEoGVs2mYXWzqMahi6SEhV.toml From 6ff094d7baa8e444828b2f60a027161d1151c607 Mon Sep 17 00:00:00 2001 From: Aweryc Date: Thu, 17 Jul 2025 12:06:09 +0300 Subject: [PATCH 6/6] revert pyproject.toml edit 4861.HEoGVs2mYXWzqMahi6SEhV.toml --- changes/unreleased/4861.HEoGVs2mYXWzqMahi6SEhV.toml | 2 +- pyproject.toml | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/changes/unreleased/4861.HEoGVs2mYXWzqMahi6SEhV.toml b/changes/unreleased/4861.HEoGVs2mYXWzqMahi6SEhV.toml index fa083bd43a0..b511be65416 100644 --- a/changes/unreleased/4861.HEoGVs2mYXWzqMahi6SEhV.toml +++ b/changes/unreleased/4861.HEoGVs2mYXWzqMahi6SEhV.toml @@ -2,4 +2,4 @@ features = "Added a two methods for BusinessOpeningHours" [[pull_requests]] uid = "4326" author_uid = "Aweryc" -closes_threads = ["4194, 4326"] \ No newline at end of file +closes_threads = ["4194"] \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 25d18172d19..66589c25b0e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,12 +38,7 @@ classifiers = [ "Programming Language :: Python :: 3.13", ] dependencies = [ - "black>=25.1.0", "httpx >=0.27,<0.29", - "pre-commit>=4.2.0", - "pytest>=8.3.5", - "pytz>=2025.2", - "ruff==0.11.9", ] [project.urls] pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy