Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions forecasting_tools/data_models/user_response.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from __future__ import annotations

from pydantic import BaseModel


class UserResponse(BaseModel):
id: int
username: str


class TokenResponse(BaseModel):
token: str


class TokenUserResponse(UserResponse, TokenResponse):
pass
58 changes: 58 additions & 0 deletions forecasting_tools/helpers/metaculus_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@
MetaculusQuestion,
QuestionBasicType,
)
from forecasting_tools.data_models.user_response import (
TokenResponse,
TokenUserResponse,
UserResponse,
)
from forecasting_tools.util.misc import (
add_timezone_to_dates_in_base_model,
raise_for_status_with_additional_info,
Expand Down Expand Up @@ -152,6 +157,59 @@ def __init__(
self.sleep_time_between_requests_min = sleep_seconds_between_requests
self.sleep_jitter_seconds = sleep_jitter_seconds

@retry_with_exponential_backoff()
def get_user_bots(self) -> list[UserResponse]:
self._sleep_between_requests()
response = requests.get(
f"{self.base_url}/users/me/bots/",
**self._get_auth_headers(), # type: ignore
timeout=self.timeout,
)
raise_for_status_with_additional_info(response)
content = json.loads(response.content)
bots = [
UserResponse(id=bot_data["id"], username=bot_data["username"])
for bot_data in content
]
logger.info(f"Retrieved {len(bots)} bots for current user")
return bots

@retry_with_exponential_backoff()
def get_bot_token(self, bot_id: int) -> TokenResponse:
self._sleep_between_requests()
response = requests.get(
f"{self.base_url}/users/me/bots/{bot_id}/token/",
**self._get_auth_headers(), # type: ignore
timeout=self.timeout,
)
raise_for_status_with_additional_info(response)
content = json.loads(response.content)
token_response = TokenResponse(token=content["token"])
logger.info(f"Retrieved token for bot {bot_id}")
return token_response

@retry_with_exponential_backoff()
def create_bot(self, username: str) -> TokenUserResponse:
self._sleep_between_requests()
response = requests.post(
f"{self.base_url}/users/me/bots/create/",
json={"username": username},
**self._get_auth_headers(), # type: ignore
timeout=self.timeout,
)
raise_for_status_with_additional_info(response)
content = json.loads(response.content)

# Combine token and user data for TokenUserResponse
combined_data = {
"token": content["token"],
"id": content["user"]["id"],
"username": content["user"]["username"],
}
bot_response = TokenUserResponse(**combined_data)
logger.info(f"Created bot with username '{username}' and id {bot_response.id}")
return bot_response

@retry_with_exponential_backoff()
def post_question_comment(
self,
Expand Down