pysportbot 0.0.1__tar.gz → 0.0.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pysportbot-0.0.1 → pysportbot-0.0.3}/PKG-INFO +9 -8
- {pysportbot-0.0.1 → pysportbot-0.0.3}/README.md +5 -4
- {pysportbot-0.0.1 → pysportbot-0.0.3}/pyproject.toml +3 -3
- {pysportbot-0.0.1 → pysportbot-0.0.3}/pysportbot/__init__.py +5 -2
- {pysportbot-0.0.1 → pysportbot-0.0.3}/pysportbot/centres.py +3 -2
- {pysportbot-0.0.1 → pysportbot-0.0.3}/pysportbot/service/__main__.py +3 -1
- {pysportbot-0.0.1 → pysportbot-0.0.3}/pysportbot/service/service.py +6 -4
- {pysportbot-0.0.1 → pysportbot-0.0.3}/pysportbot/utils/logger.py +39 -4
- {pysportbot-0.0.1 → pysportbot-0.0.3}/LICENSE +0 -0
- {pysportbot-0.0.1 → pysportbot-0.0.3}/pysportbot/activities.py +0 -0
- {pysportbot-0.0.1 → pysportbot-0.0.3}/pysportbot/authenticator.py +0 -0
- {pysportbot-0.0.1 → pysportbot-0.0.3}/pysportbot/bookings.py +0 -0
- {pysportbot-0.0.1 → pysportbot-0.0.3}/pysportbot/endpoints.py +0 -0
- {pysportbot-0.0.1 → pysportbot-0.0.3}/pysportbot/service/__init__.py +0 -0
- {pysportbot-0.0.1 → pysportbot-0.0.3}/pysportbot/service/booking.py +0 -0
- {pysportbot-0.0.1 → pysportbot-0.0.3}/pysportbot/service/config_loader.py +0 -0
- {pysportbot-0.0.1 → pysportbot-0.0.3}/pysportbot/service/config_validator.py +0 -0
- {pysportbot-0.0.1 → pysportbot-0.0.3}/pysportbot/service/scheduling.py +0 -0
- {pysportbot-0.0.1 → pysportbot-0.0.3}/pysportbot/session.py +0 -0
- {pysportbot-0.0.1 → pysportbot-0.0.3}/pysportbot/utils/__init__.py +0 -0
- {pysportbot-0.0.1 → pysportbot-0.0.3}/pysportbot/utils/errors.py +0 -0
- {pysportbot-0.0.1 → pysportbot-0.0.3}/pysportbot/utils/time.py +0 -0
@@ -1,8 +1,8 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: pysportbot
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.3
|
4
4
|
Summary: A python-based bot for automatic resasports slot booking
|
5
|
-
Home-page: https://github.com/jbeirer/
|
5
|
+
Home-page: https://github.com/jbeirer/resasports-bot
|
6
6
|
Author: Joshua Falco Beirer
|
7
7
|
Author-email: jbeirer@cern.ch
|
8
8
|
Requires-Python: >=3.9,<3.13
|
@@ -16,8 +16,8 @@ Requires-Dist: pandas (>=2.2.3,<3.0.0)
|
|
16
16
|
Requires-Dist: pytz (>=2024.2,<2025.0)
|
17
17
|
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
18
18
|
Requires-Dist: schedule (>=1.2.2,<2.0.0)
|
19
|
-
Project-URL: Documentation, https://jbeirer.github.io/
|
20
|
-
Project-URL: Repository, https://github.com/jbeirer/
|
19
|
+
Project-URL: Documentation, https://jbeirer.github.io/resasports-bot/
|
20
|
+
Project-URL: Repository, https://github.com/jbeirer/resasports-bot
|
21
21
|
Description-Content-Type: text/markdown
|
22
22
|
|
23
23
|
# No queues. Just gains.
|
@@ -44,8 +44,8 @@ pip install pysportbot
|
|
44
44
|
```python
|
45
45
|
from pysportbot import SportBot
|
46
46
|
|
47
|
-
# Create bot instance, will list available centres
|
48
|
-
bot = SportBot(log_level='INFO', print_centres=False)
|
47
|
+
# Create bot instance, will list available centres if requested
|
48
|
+
bot = SportBot(log_level='INFO', print_centres=False, time_zone = 'Europe/Madrid')
|
49
49
|
|
50
50
|
# Connect to service with email and password as well as the name of the centre
|
51
51
|
bot.login('email', 'password', 'centre')
|
@@ -59,7 +59,7 @@ bot.daily_slots(activity='YourFavouriteGymClass', day = '2025-01-03', limit = 10
|
|
59
59
|
# Book an activity slot on a specific day and time
|
60
60
|
bot.book(activity='YourFavouriteGymClass', start_time = '2024-12-30 07:00:00')
|
61
61
|
|
62
|
-
# Cancel an activity slot
|
62
|
+
# Cancel an activity slot on a specific day and time
|
63
63
|
bot.cancel(activity='YourFavouriteGymClass', start_time = '2024-12-30 07:00:00')
|
64
64
|
```
|
65
65
|
|
@@ -139,7 +139,8 @@ python -m pysportbot.service --help
|
|
139
139
|
Currently supported options include
|
140
140
|
1. ```--retry-attempts``` sets the number of retries attempted in case a booking attempt fails
|
141
141
|
2. ```--retry-delay-minutes``` sets the delay in minutes between retries for weekly bookings
|
142
|
-
3. ```--
|
142
|
+
3. ```--time-zone``` sets the time zone for the service (e.g. Europe/Madrid)
|
143
|
+
4. ```--log-level``` sets the log-level of the service (e.g. DEBUG, INFO, WARNING, ERROR)
|
143
144
|
|
144
145
|
## LICENSE
|
145
146
|
|
@@ -22,8 +22,8 @@ pip install pysportbot
|
|
22
22
|
```python
|
23
23
|
from pysportbot import SportBot
|
24
24
|
|
25
|
-
# Create bot instance, will list available centres
|
26
|
-
bot = SportBot(log_level='INFO', print_centres=False)
|
25
|
+
# Create bot instance, will list available centres if requested
|
26
|
+
bot = SportBot(log_level='INFO', print_centres=False, time_zone = 'Europe/Madrid')
|
27
27
|
|
28
28
|
# Connect to service with email and password as well as the name of the centre
|
29
29
|
bot.login('email', 'password', 'centre')
|
@@ -37,7 +37,7 @@ bot.daily_slots(activity='YourFavouriteGymClass', day = '2025-01-03', limit = 10
|
|
37
37
|
# Book an activity slot on a specific day and time
|
38
38
|
bot.book(activity='YourFavouriteGymClass', start_time = '2024-12-30 07:00:00')
|
39
39
|
|
40
|
-
# Cancel an activity slot
|
40
|
+
# Cancel an activity slot on a specific day and time
|
41
41
|
bot.cancel(activity='YourFavouriteGymClass', start_time = '2024-12-30 07:00:00')
|
42
42
|
```
|
43
43
|
|
@@ -117,7 +117,8 @@ python -m pysportbot.service --help
|
|
117
117
|
Currently supported options include
|
118
118
|
1. ```--retry-attempts``` sets the number of retries attempted in case a booking attempt fails
|
119
119
|
2. ```--retry-delay-minutes``` sets the delay in minutes between retries for weekly bookings
|
120
|
-
3. ```--
|
120
|
+
3. ```--time-zone``` sets the time zone for the service (e.g. Europe/Madrid)
|
121
|
+
4. ```--log-level``` sets the log-level of the service (e.g. DEBUG, INFO, WARNING, ERROR)
|
121
122
|
|
122
123
|
## LICENSE
|
123
124
|
|
@@ -1,10 +1,10 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "pysportbot"
|
3
|
-
version = "v0.0.
|
3
|
+
version = "v0.0.3"
|
4
4
|
description = " A python-based bot for automatic resasports slot booking"
|
5
5
|
authors = ["Joshua Falco Beirer <jbeirer@cern.ch>"]
|
6
|
-
repository = "https://github.com/jbeirer/
|
7
|
-
documentation = "https://jbeirer.github.io/
|
6
|
+
repository = "https://github.com/jbeirer/resasports-bot"
|
7
|
+
documentation = "https://jbeirer.github.io/resasports-bot/"
|
8
8
|
readme = "README.md"
|
9
9
|
packages = [
|
10
10
|
{include = "pysportbot"}
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# pysportbot/sportbot.py
|
2
|
+
|
1
3
|
import logging
|
2
4
|
from typing import Optional
|
3
5
|
|
@@ -15,10 +17,12 @@ from .utils.logger import set_log_level, setup_logger
|
|
15
17
|
class SportBot:
|
16
18
|
"""Unified interface for interacting with the booking system."""
|
17
19
|
|
18
|
-
def __init__(self, log_level: str = "INFO", print_centres: bool = False) -> None:
|
20
|
+
def __init__(self, log_level: str = "INFO", print_centres: bool = False, time_zone: str = "Europe/Madrid") -> None:
|
19
21
|
setup_logger(log_level)
|
20
22
|
self._logger = logging.getLogger("SportBot")
|
21
23
|
self._logger.info("Initializing SportBot...")
|
24
|
+
self._logger.info(f"Log level: {log_level}")
|
25
|
+
self._logger.info(f"Time zone: {time_zone}")
|
22
26
|
self._centres = Centres(print_centres)
|
23
27
|
self._session: Session = Session()
|
24
28
|
self._auth: Optional[Authenticator] = None
|
@@ -32,7 +36,6 @@ class SportBot:
|
|
32
36
|
self._logger.info(f"Log level changed to {log_level}.")
|
33
37
|
|
34
38
|
def login(self, email: str, password: str, centre: str) -> None:
|
35
|
-
|
36
39
|
# Check if the selected centre is valid
|
37
40
|
self._centres.check_centre(centre)
|
38
41
|
self._logger.info(f"Selected centre: {centre}")
|
@@ -33,12 +33,13 @@ class Centres:
|
|
33
33
|
}
|
34
34
|
}
|
35
35
|
self._df_centres = self.fetch_centres()
|
36
|
-
if print_centres:
|
37
|
-
self.print_centres()
|
38
36
|
|
39
37
|
# list of centre (slugs)
|
40
38
|
self.centre_list = self._df_centres["slug"].tolist()
|
41
39
|
|
40
|
+
if print_centres:
|
41
|
+
self.print_centres()
|
42
|
+
|
42
43
|
def check_centre(self, centre: str) -> None:
|
43
44
|
"""
|
44
45
|
Set the user selected centre.
|
@@ -15,7 +15,8 @@ def main() -> None:
|
|
15
15
|
parser.add_argument(
|
16
16
|
"--retry-delay-minutes", type=int, default=2, help="Delay in minutes between retries for weekly bookings."
|
17
17
|
)
|
18
|
-
parser.add_argument("--
|
18
|
+
parser.add_argument("--time-zone", type=str, default="Europe/Madrid", help="Timezone for the service.")
|
19
|
+
parser.add_argument("--log-level", type=str, default="INFO", help="Logging level for the service.")
|
19
20
|
args = parser.parse_args()
|
20
21
|
|
21
22
|
config: Dict[str, Any] = load_config(args.config)
|
@@ -25,6 +26,7 @@ def main() -> None:
|
|
25
26
|
retry_attempts=args.retry_attempts,
|
26
27
|
retry_delay_minutes=args.retry_delay_minutes,
|
27
28
|
time_zone=args.time_zone,
|
29
|
+
log_level=args.log_level,
|
28
30
|
)
|
29
31
|
|
30
32
|
|
@@ -9,8 +9,6 @@ from pysportbot.utils.logger import get_logger
|
|
9
9
|
from .booking import schedule_bookings
|
10
10
|
from .config_validator import validate_activities, validate_config
|
11
11
|
|
12
|
-
logger = get_logger(__name__)
|
13
|
-
|
14
12
|
|
15
13
|
def run_service(
|
16
14
|
config: Dict[str, Any],
|
@@ -18,12 +16,16 @@ def run_service(
|
|
18
16
|
retry_attempts: int,
|
19
17
|
retry_delay_minutes: int,
|
20
18
|
time_zone: str = "Europe/Madrid",
|
19
|
+
log_level: str = "INFO",
|
21
20
|
) -> None:
|
21
|
+
# Initialize service logger
|
22
|
+
logger = get_logger(__name__)
|
23
|
+
logger.setLevel(log_level)
|
22
24
|
|
23
25
|
# Validate the configuration file
|
24
26
|
validate_config(config)
|
25
|
-
|
26
|
-
bot = SportBot()
|
27
|
+
# Initialize the SportBot instance
|
28
|
+
bot = SportBot(log_level=log_level, time_zone=time_zone)
|
27
29
|
bot.login(config["email"], config["password"], config["centre"])
|
28
30
|
|
29
31
|
# Validate the activities in the configuration file
|
@@ -1,5 +1,8 @@
|
|
1
1
|
import logging
|
2
|
-
from
|
2
|
+
from datetime import datetime
|
3
|
+
from typing import ClassVar, Optional
|
4
|
+
|
5
|
+
import pytz
|
3
6
|
|
4
7
|
from .errors import ErrorMessages
|
5
8
|
|
@@ -15,6 +18,32 @@ class ColorFormatter(logging.Formatter):
|
|
15
18
|
"RESET": "\033[0m", # Reset
|
16
19
|
}
|
17
20
|
|
21
|
+
def __init__(self, fmt: str, datefmt: str, tz: pytz.BaseTzInfo) -> None:
|
22
|
+
"""
|
23
|
+
Initialize the formatter with a specific timezone.
|
24
|
+
|
25
|
+
Args:
|
26
|
+
fmt (str): The log message format.
|
27
|
+
datefmt (str): The date format.
|
28
|
+
tz (pytz.BaseTzInfo): The timezone for log timestamps.
|
29
|
+
"""
|
30
|
+
super().__init__(fmt, datefmt)
|
31
|
+
self.timezone = tz
|
32
|
+
|
33
|
+
def formatTime(self, record: logging.LogRecord, datefmt: Optional[str] = None) -> str:
|
34
|
+
"""
|
35
|
+
Override to format the time in the desired timezone.
|
36
|
+
|
37
|
+
Args:
|
38
|
+
record (logging.LogRecord): The log record.
|
39
|
+
datefmt (Optional[str]): The date format.
|
40
|
+
|
41
|
+
Returns:
|
42
|
+
str: The formatted timestamp.
|
43
|
+
"""
|
44
|
+
record_time = datetime.fromtimestamp(record.created, self.timezone)
|
45
|
+
return record_time.strftime(datefmt or self.default_time_format)
|
46
|
+
|
18
47
|
def format(self, record: logging.LogRecord) -> str:
|
19
48
|
"""
|
20
49
|
Format the log record with color-coded log levels.
|
@@ -30,12 +59,13 @@ class ColorFormatter(logging.Formatter):
|
|
30
59
|
return super().format(record)
|
31
60
|
|
32
61
|
|
33
|
-
def setup_logger(level: str = "INFO") -> None:
|
62
|
+
def setup_logger(level: str = "INFO", timezone: str = "Europe/Madrid") -> None:
|
34
63
|
"""
|
35
|
-
Configure the root logger with color-coded output.
|
64
|
+
Configure the root logger with color-coded output in the specified timezone.
|
36
65
|
|
37
66
|
Args:
|
38
67
|
level (str): The desired logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL).
|
68
|
+
timezone (str): The desired timezone for log timestamps (e.g., Europe/Madrid).
|
39
69
|
"""
|
40
70
|
root_logger = logging.getLogger()
|
41
71
|
root_logger.setLevel(logging._nameToLevel[level.upper()])
|
@@ -43,7 +73,12 @@ def setup_logger(level: str = "INFO") -> None:
|
|
43
73
|
if not root_logger.hasHandlers(): # Avoid duplicate handlers
|
44
74
|
handler = logging.StreamHandler()
|
45
75
|
handler.setLevel(logging._nameToLevel[level.upper()])
|
46
|
-
|
76
|
+
tz = pytz.timezone(timezone)
|
77
|
+
formatter = ColorFormatter(
|
78
|
+
"[%(asctime)s] [%(levelname)s] %(message)s",
|
79
|
+
datefmt="%Y-%m-%d %H:%M:%S",
|
80
|
+
tz=tz,
|
81
|
+
)
|
47
82
|
handler.setFormatter(formatter)
|
48
83
|
root_logger.addHandler(handler)
|
49
84
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|