From ed6e1f148326bbb443f002ef02d5bf8adb4d03ca Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Wed, 18 Feb 2026 21:32:43 +0530 Subject: [PATCH 1/6] fix: docstrings --- chatwoot/__init__.py | 54 +++++++-------- chatwoot/_http.py | 20 +++--- chatwoot/client.py | 96 +++++++++++++------------- chatwoot/resources/agents.py | 46 ++++++------- chatwoot/resources/contacts.py | 70 +++++++++---------- chatwoot/resources/conversations.py | 100 ++++++++++++++-------------- chatwoot/resources/inboxes.py | 40 +++++------ chatwoot/resources/messages.py | 40 +++++------ chatwoot/resources/profile.py | 16 ++--- chatwoot/resources/teams.py | 72 ++++++++++---------- 10 files changed, 277 insertions(+), 277 deletions(-) diff --git a/chatwoot/__init__.py b/chatwoot/__init__.py index 6e29f90..b8fd36a 100644 --- a/chatwoot/__init__.py +++ b/chatwoot/__init__.py @@ -2,33 +2,33 @@ A modern, type-safe Python SDK for the Chatwoot API. -Example: - >>> from chatwoot import ChatwootClient - >>> - >>> client = ChatwootClient( - ... base_url="https://app.chatwoot.com", - ... api_token="your_api_token_here" - ... ) - >>> - >>> # Fetch your profile - >>> profile = client.profile.get() - >>> print(f"Logged in as: {profile.name}") - >>> - >>> # List open conversations - >>> conversations = client.conversations.list( - ... account_id=1, - ... status="open" - ... ) - >>> print(f"Open conversations: {len(conversations)}") - >>> - >>> # Send a message - >>> message = client.messages.create( - ... account_id=1, - ... conversation_id=42, - ... content="Hello from the Python SDK!" - ... ) - >>> - >>> client.close() +Examples: + from chatwoot import ChatwootClient + + client = ChatwootClient( + base_url="https://app.chatwoot.com", + api_token="your_api_token_here" + ) + + # Fetch your profile + profile = client.profile.get() + print(f"Logged in as: {profile.name}") + + # List open conversations + conversations = client.conversations.list( + account_id=1, + status="open" + ) + print(f"Open conversations: {len(conversations)}") + + # Send a message + message = client.messages.create( + account_id=1, + conversation_id=42, + content="Hello from the Python SDK!" + ) + + client.close() """ from chatwoot.client import AsyncChatwootClient, ChatwootClient diff --git a/chatwoot/_http.py b/chatwoot/_http.py index b6be348..f16832e 100644 --- a/chatwoot/_http.py +++ b/chatwoot/_http.py @@ -36,21 +36,21 @@ def _unwrap_response(self, data: dict[str, Any]) -> dict[str, Any] | list[Any]: """Unwrap API response to extract actual data. Chatwoot API returns data in various formats: - - {payload: [...]} - list response - - {data: {payload: [...]}} - nested list response - - {id: 1, ...} - single object response + - {payload: []} - list response + - {data: {payload: []}} - nested list response + - {id: 1, } - single object response """ if not isinstance(data, dict): return data - # {data: {payload: [...]}} or {data: ...} + # {data: {payload: []}} or {data: } if "data" in data: nested_data = data["data"] if isinstance(nested_data, dict) and "payload" in nested_data: return nested_data["payload"] return nested_data - # {payload: ...} + # {payload: } if "payload" in data: return data["payload"] @@ -206,21 +206,21 @@ def _unwrap_response(self, data: dict[str, Any]) -> dict[str, Any] | list[Any]: """Unwrap API response to extract actual data. Chatwoot API returns data in various formats: - - {payload: [...]} - list response - - {data: {payload: [...]}} - nested list response - - {id: 1, ...} - single object response + - {payload: []} - list response + - {data: {payload: []}} - nested list response + - {id: 1, } - single object response """ if not isinstance(data, dict): return data - # {data: {payload: [...]}} or {data: ...} + # {data: {payload: []}} or {data: } if "data" in data: nested_data = data["data"] if isinstance(nested_data, dict) and "payload" in nested_data: return nested_data["payload"] return nested_data - # {payload: ...} + # {payload: } if "payload" in data: return data["payload"] diff --git a/chatwoot/client.py b/chatwoot/client.py index f540d7a..d676252 100644 --- a/chatwoot/client.py +++ b/chatwoot/client.py @@ -19,29 +19,29 @@ class ChatwootClient: This is the main entry point for interacting with the Chatwoot API. All API operations are organized into resource-specific namespaces. - Example: - >>> client = ChatwootClient( - ... base_url="https://app.chatwoot.com", - ... api_token="your_api_token_here" - ... ) - >>> - >>> # Fetch user profile - >>> profile = client.profile.get() - >>> print(profile.name) - >>> - >>> # List conversations - >>> conversations = client.conversations.list(account_id=1, status="open") - >>> - >>> # Send a message - >>> message = client.messages.create( - ... account_id=1, - ... conversation_id=42, - ... content="Hello from SDK!" - ... ) - >>> - >>> # Use as context manager for automatic cleanup - >>> with ChatwootClient(base_url="...", api_token="...") as client: - ... profile = client.profile.get() + Examples: + client = ChatwootClient( + base_url="https://app.chatwoot.com", + api_token="your_api_token_here" + ) + + # Fetch user profile + profile = client.profile.get() + print(profile.name) + + # List conversations + conversations = client.conversations.list(account_id=1, status="open") + + # Send a message + message = client.messages.create( + account_id=1, + conversation_id=42, + content="Hello from SDK!" + ) + + # Use as context manager for automatic cleanup + with ChatwootClient(base_url="", api_token="") as client: + profile = client.profile.get() """ def __init__(self, base_url: str, api_token: str, timeout: float = 30.0): @@ -90,31 +90,31 @@ class AsyncChatwootClient: This is the async version of the Chatwoot client, using async/await patterns for non-blocking I/O operations. - Example: - >>> import asyncio - >>> - >>> async def main(): - ... client = AsyncChatwootClient( - ... base_url="https://app.chatwoot.com", - ... api_token="your_api_token_here" - ... ) - ... - ... # Fetch user profile - ... profile = await client.profile.get() - ... print(profile.name) - ... - ... # List conversations - ... conversations = await client.conversations.list( - ... account_id=1, - ... status="open" - ... ) - ... - ... await client.aclose() - >>> - >>> # Or use as async context manager - >>> async def main(): - ... async with AsyncChatwootClient(base_url="...", api_token="...") as client: - ... profile = await client.profile.get() + Examples: + import asyncio + + async def main(): + client = AsyncChatwootClient( + base_url="https://app.chatwoot.com", + api_token="your_api_token_here" + ) + + # Fetch user profile + profile = await client.profile.get() + print(profile.name) + + # List conversations + conversations = await client.conversations.list( + account_id=1, + status="open" + ) + + await client.aclose() + + # Or use as async context manager + async def main(): + async with AsyncChatwootClient(base_url="", api_token="") as client: + profile = await client.profile.get() """ def __init__(self, base_url: str, api_token: str, timeout: float = 30.0): diff --git a/chatwoot/resources/agents.py b/chatwoot/resources/agents.py index b7b3d5f..edbbc5d 100644 --- a/chatwoot/resources/agents.py +++ b/chatwoot/resources/agents.py @@ -24,10 +24,10 @@ def list(self, account_id: int) -> list[Agent]: ChatwootAuthError: If authentication fails ChatwootPermissionError: If user doesn't have access - Example: - >>> agents = client.agents.list(account_id=1) - >>> for agent in agents: - ... print(agent.name, agent.role) + Examples: + agents = client.agents.list(account_id=1) + for agent in agents: + print(agent.name, agent.role) """ response = self._http.get(f"/api/v1/accounts/{account_id}/agents") if isinstance(response, list): @@ -48,9 +48,9 @@ def get(self, account_id: int, agent_id: int) -> Agent: ChatwootNotFoundError: If agent not found ChatwootAuthError: If authentication fails - Example: - >>> agent = client.agents.get(account_id=1, agent_id=10) - >>> print(agent.email) + Examples: + agent = client.agents.get(account_id=1, agent_id=10) + print(agent.email) """ response = self._http.get(f"/api/v1/accounts/{account_id}/agents/{agent_id}") return Agent(**response) @@ -79,13 +79,13 @@ def add( ChatwootValidationError: If validation fails ChatwootAuthError: If authentication fails - Example: - >>> agent = client.agents.add( - ... account_id=1, - ... name="John Doe", - ... email="john@example.com", - ... role="agent" - ... ) + Examples: + agent = client.agents.add( + account_id=1, + name="John Doe", + email="john@example.com", + role="agent" + ) """ data = {"name": name, "email": email, "role": role, **kwargs} response = self._http.post(f"/api/v1/accounts/{account_id}/agents", json=data) @@ -111,13 +111,13 @@ def update( ChatwootNotFoundError: If agent not found ChatwootValidationError: If validation fails - Example: - >>> agent = client.agents.update( - ... account_id=1, - ... agent_id=10, - ... name="Jane Doe", - ... role="administrator" - ... ) + Examples: + agent = client.agents.update( + account_id=1, + agent_id=10, + name="Jane Doe", + role="administrator" + ) """ response = self._http.patch( f"/api/v1/accounts/{account_id}/agents/{agent_id}", @@ -136,8 +136,8 @@ def remove(self, account_id: int, agent_id: int) -> None: ChatwootNotFoundError: If agent not found ChatwootPermissionError: If user doesn't have permission - Example: - >>> client.agents.remove(account_id=1, agent_id=10) + Examples: + client.agents.remove(account_id=1, agent_id=10) """ self._http.delete(f"/api/v1/accounts/{account_id}/agents/{agent_id}") diff --git a/chatwoot/resources/contacts.py b/chatwoot/resources/contacts.py index 97c2ebd..65c6875 100644 --- a/chatwoot/resources/contacts.py +++ b/chatwoot/resources/contacts.py @@ -22,8 +22,8 @@ def list(self, account_id: int, contact_id: int) -> list[str]: Returns: List of label strings - Example: - >>> labels = client.contacts.labels.list(account_id=1, contact_id=100) + Examples: + labels = client.contacts.labels.list(account_id=1, contact_id=100) """ response = self._http.get( f"/api/v1/accounts/{account_id}/contacts/{contact_id}/labels" @@ -45,12 +45,12 @@ def add(self, account_id: int, contact_id: int, labels: list[str]) -> list[str]: Returns: Updated list of labels - Example: - >>> labels = client.contacts.labels.add( - ... account_id=1, - ... contact_id=100, - ... labels=["vip", "priority"] - ... ) + Examples: + labels = client.contacts.labels.add( + account_id=1, + contact_id=100, + labels=["vip", "priority"] + ) """ data = {"labels": labels} response = self._http.post( @@ -125,10 +125,10 @@ def list(self, account_id: int, page: int = 1) -> list[Contact]: Returns: List of Contact objects - Example: - >>> contacts = client.contacts.list(account_id=1, page=1) - >>> for contact in contacts: - ... print(contact.name, contact.email) + Examples: + contacts = client.contacts.list(account_id=1, page=1) + for contact in contacts: + print(contact.name, contact.email) """ params = {"page": page} response = self._http.get( @@ -148,8 +148,8 @@ def search(self, account_id: int, query: str) -> list[Contact]: Returns: List of matching Contact objects - Example: - >>> contacts = client.contacts.search(account_id=1, query="john@example.com") + Examples: + contacts = client.contacts.search(account_id=1, query="john@example.com") """ params = {"q": query} response = self._http.get( @@ -169,8 +169,8 @@ def get(self, account_id: int, contact_id: int) -> Contact: Returns: Contact object - Example: - >>> contact = client.contacts.get(account_id=1, contact_id=100) + Examples: + contact = client.contacts.get(account_id=1, contact_id=100) """ response = self._http.get( f"/api/v1/accounts/{account_id}/contacts/{contact_id}" @@ -193,14 +193,14 @@ def create( Returns: ContactCreateResponse with contact and contact_inbox - Example: - >>> result = client.contacts.create( - ... account_id=1, - ... inbox_id=5, - ... name="John Doe", - ... email="john@example.com", - ... ) - >>> print(result.contact.id, result.contact_inbox.source_id) + Examples: + result = client.contacts.create( + account_id=1, + inbox_id=5, + name="John Doe", + email="john@example.com", + ) + print(result.contact.id, result.contact_inbox.source_id) """ data = {"inbox_id": inbox_id, **kwargs} response = self._http.post(f"/api/v1/accounts/{account_id}/contacts", json=data) @@ -222,13 +222,13 @@ def update( Returns: Updated Contact object - Example: - >>> contact = client.contacts.update( - ... account_id=1, - ... contact_id=100, - ... name="Jane Doe", - ... custom_attributes={"plan": "premium"} - ... ) + Examples: + contact = client.contacts.update( + account_id=1, + contact_id=100, + name="Jane Doe", + custom_attributes={"plan": "premium"} + ) """ response = self._http.patch( f"/api/v1/accounts/{account_id}/contacts/{contact_id}", @@ -243,8 +243,8 @@ def delete(self, account_id: int, contact_id: int) -> None: account_id: The account ID contact_id: The contact ID - Example: - >>> client.contacts.delete(account_id=1, contact_id=100) + Examples: + client.contacts.delete(account_id=1, contact_id=100) """ self._http.delete(f"/api/v1/accounts/{account_id}/contacts/{contact_id}") @@ -258,8 +258,8 @@ def conversations(self, account_id: int, contact_id: int) -> list[Conversation]: Returns: List of Conversation objects for this contact - Example: - >>> conversations = client.contacts.conversations(account_id=1, contact_id=100) + Examples: + conversations = client.contacts.conversations(account_id=1, contact_id=100) """ response = self._http.get( f"/api/v1/accounts/{account_id}/contacts/{contact_id}/conversations" diff --git a/chatwoot/resources/conversations.py b/chatwoot/resources/conversations.py index b8d13c7..feef0fe 100644 --- a/chatwoot/resources/conversations.py +++ b/chatwoot/resources/conversations.py @@ -21,11 +21,11 @@ def list(self, account_id: int, conversation_id: int) -> list[str]: Returns: List of label strings - Example: - >>> labels = client.conversations.labels.list( - ... account_id=1, - ... conversation_id=42 - ... ) + Examples: + labels = client.conversations.labels.list( + account_id=1, + conversation_id=42 + ) """ response = self._http.get( f"/api/v1/accounts/{account_id}/conversations/{conversation_id}/labels" @@ -49,12 +49,12 @@ def add( Returns: Updated list of labels - Example: - >>> labels = client.conversations.labels.add( - ... account_id=1, - ... conversation_id=42, - ... labels=["urgent", "billing"] - ... ) + Examples: + labels = client.conversations.labels.add( + account_id=1, + conversation_id=42, + labels=["urgent", "billing"] + ) """ data = {"labels": labels} response = self._http.post( @@ -145,13 +145,13 @@ def list( Returns: List of Conversation objects - Example: - >>> conversations = client.conversations.list( - ... account_id=1, - ... status="open", - ... assignee_type="me", - ... page=1 - ... ) + Examples: + conversations = client.conversations.list( + account_id=1, + status="open", + assignee_type="me", + page=1 + ) """ params: dict[str, Any] = { "status": status, @@ -186,8 +186,8 @@ def get(self, account_id: int, conversation_id: int) -> Conversation: Returns: Conversation object - Example: - >>> conversation = client.conversations.get(account_id=1, conversation_id=42) + Examples: + conversation = client.conversations.get(account_id=1, conversation_id=42) """ response = self._http.get( f"/api/v1/accounts/{account_id}/conversations/{conversation_id}" @@ -214,13 +214,13 @@ def create( Returns: Created Conversation object - Example: - >>> conversation = client.conversations.create( - ... account_id=1, - ... source_id="user-123", - ... inbox_id=5, - ... contact_id=100 - ... ) + Examples: + conversation = client.conversations.create( + account_id=1, + source_id="user-123", + inbox_id=5, + contact_id=100 + ) """ data = { "source_id": source_id, @@ -258,13 +258,13 @@ def update( Returns: Updated Conversation object - Example: - >>> conversation = client.conversations.update( - ... account_id=1, - ... conversation_id=42, - ... status="resolved", - ... assignee_id=10 - ... ) + Examples: + conversation = client.conversations.update( + account_id=1, + conversation_id=42, + status="resolved", + assignee_id=10 + ) """ data = {**kwargs} if status is not None: @@ -296,12 +296,12 @@ def assign( Returns: Updated Conversation object - Example: - >>> conversation = client.conversations.assign( - ... account_id=1, - ... conversation_id=42, - ... assignee_id=10 - ... ) + Examples: + conversation = client.conversations.assign( + account_id=1, + conversation_id=42, + assignee_id=10 + ) """ return self.update(account_id, conversation_id, assignee_id=assignee_id) @@ -321,13 +321,13 @@ def toggle_status( Returns: ConversationToggleStatusResponse - Example: - >>> result = client.conversations.toggle_status( - ... account_id=1, - ... conversation_id=42, - ... status="resolved" - ... ) - >>> print(result.current_status) + Examples: + result = client.conversations.toggle_status( + account_id=1, + conversation_id=42, + status="resolved" + ) + print(result.current_status) """ data = {"status": status} response = self._http.post( @@ -352,9 +352,9 @@ def get_counts( Returns: Dictionary with conversation counts - Example: - >>> counts = client.conversations.get_counts(account_id=1, status="open") - >>> print(counts) + Examples: + counts = client.conversations.get_counts(account_id=1, status="open") + print(counts) """ params = {"status": status, **filters} response = self._http.get( diff --git a/chatwoot/resources/inboxes.py b/chatwoot/resources/inboxes.py index ccde770..4a51dc8 100644 --- a/chatwoot/resources/inboxes.py +++ b/chatwoot/resources/inboxes.py @@ -24,10 +24,10 @@ def list(self, account_id: int) -> list[Inbox]: ChatwootAuthError: If authentication fails ChatwootPermissionError: If user doesn't have access - Example: - >>> inboxes = client.inboxes.list(account_id=1) - >>> for inbox in inboxes: - ... print(inbox.name) + Examples: + inboxes = client.inboxes.list(account_id=1) + for inbox in inboxes: + print(inbox.name) """ response = self._http.get(f"/api/v1/accounts/{account_id}/inboxes") if isinstance(response, list): @@ -48,9 +48,9 @@ def get(self, account_id: int, inbox_id: int) -> Inbox: ChatwootNotFoundError: If inbox not found ChatwootAuthError: If authentication fails - Example: - >>> inbox = client.inboxes.get(account_id=1, inbox_id=5) - >>> print(inbox.name) + Examples: + inbox = client.inboxes.get(account_id=1, inbox_id=5) + print(inbox.name) """ response = self._http.get(f"/api/v1/accounts/{account_id}/inboxes/{inbox_id}") return Inbox(**response) @@ -77,12 +77,12 @@ def create( ChatwootValidationError: If validation fails ChatwootAuthError: If authentication fails - Example: - >>> inbox = client.inboxes.create( - ... account_id=1, - ... name="Support Inbox", - ... channel_type="api" - ... ) + Examples: + inbox = client.inboxes.create( + account_id=1, + name="Support Inbox", + channel_type="api" + ) """ data = {"name": name, "channel": {"type": channel_type, **kwargs}} response = self._http.post(f"/api/v1/accounts/{account_id}/inboxes", json=data) @@ -108,13 +108,13 @@ def update( ChatwootNotFoundError: If inbox not found ChatwootValidationError: If validation fails - Example: - >>> inbox = client.inboxes.update( - ... account_id=1, - ... inbox_id=5, - ... name="New Name", - ... enable_auto_assignment=True - ... ) + Examples: + inbox = client.inboxes.update( + account_id=1, + inbox_id=5, + name="New Name", + enable_auto_assignment=True + ) """ response = self._http.patch( f"/api/v1/accounts/{account_id}/inboxes/{inbox_id}", diff --git a/chatwoot/resources/messages.py b/chatwoot/resources/messages.py index bb5c5ee..d7478e7 100644 --- a/chatwoot/resources/messages.py +++ b/chatwoot/resources/messages.py @@ -21,10 +21,10 @@ def list(self, account_id: int, conversation_id: int) -> list[Message]: Returns: List of Message objects - Example: - >>> messages = client.messages.list(account_id=1, conversation_id=42) - >>> for msg in messages: - ... print(msg.content) + Examples: + messages = client.messages.list(account_id=1, conversation_id=42) + for msg in messages: + print(msg.content) """ response = self._http.get( f"/api/v1/accounts/{account_id}/conversations/{conversation_id}/messages" @@ -57,14 +57,14 @@ def create( Returns: Created Message object - Example: - >>> message = client.messages.create( - ... account_id=1, - ... conversation_id=42, - ... content="Hello, how can I help?", - ... message_type="outgoing", - ... private=False - ... ) + Examples: + message = client.messages.create( + account_id=1, + conversation_id=42, + content="Hello, how can I help?", + message_type="outgoing", + private=False + ) """ data = { "content": content, @@ -96,12 +96,12 @@ def update(self, account_id: int, message_id: int, content: str) -> Message: Returns: Updated Message object - Example: - >>> message = client.messages.update( - ... account_id=1, - ... message_id=123, - ... content="Updated message content" - ... ) + Examples: + message = client.messages.update( + account_id=1, + message_id=123, + content="Updated message content" + ) """ data = {"content": content} response = self._http.patch( @@ -117,8 +117,8 @@ def delete(self, account_id: int, message_id: int) -> None: account_id: The account ID message_id: The message ID - Example: - >>> client.messages.delete(account_id=1, message_id=123) + Examples: + client.messages.delete(account_id=1, message_id=123) """ self._http.delete(f"/api/v1/accounts/{account_id}/messages/{message_id}") diff --git a/chatwoot/resources/profile.py b/chatwoot/resources/profile.py index 613be8f..54bd72a 100644 --- a/chatwoot/resources/profile.py +++ b/chatwoot/resources/profile.py @@ -18,10 +18,10 @@ def get(self) -> Profile: Raises: ChatwootAuthError: If authentication fails - Example: - >>> client = ChatwootClient(base_url="...", api_token="...") - >>> profile = client.profile.get() - >>> print(profile.name) + Examples: + client = ChatwootClient(base_url="", api_token="") + profile = client.profile.get() + print(profile.name) """ response = self._http.get("/api/v1/profile") return Profile(**response) @@ -39,10 +39,10 @@ async def get(self) -> Profile: Raises: ChatwootAuthError: If authentication fails - Example: - >>> client = AsyncChatwootClient(base_url="...", api_token="...") - >>> profile = await client.profile.get() - >>> print(profile.name) + Examples: + client = AsyncChatwootClient(base_url="", api_token="") + profile = await client.profile.get() + print(profile.name) """ response = await self._http.get("/api/v1/profile") return Profile(**response) diff --git a/chatwoot/resources/teams.py b/chatwoot/resources/teams.py index 04fd3dc..b725f05 100644 --- a/chatwoot/resources/teams.py +++ b/chatwoot/resources/teams.py @@ -22,8 +22,8 @@ def list(self, account_id: int, team_id: int) -> list[Agent]: Returns: List of Agent objects in the team - Example: - >>> agents = client.teams.agents.list(account_id=1, team_id=5) + Examples: + agents = client.teams.agents.list(account_id=1, team_id=5) """ response = self._http.get( f"/api/v1/accounts/{account_id}/teams/{team_id}/team_members" @@ -40,12 +40,12 @@ def add(self, account_id: int, team_id: int, agent_ids: list[int]) -> None: team_id: The team ID agent_ids: List of agent IDs to add - Example: - >>> client.teams.agents.add( - ... account_id=1, - ... team_id=5, - ... agent_ids=[10, 11, 12] - ... ) + Examples: + client.teams.agents.add( + account_id=1, + team_id=5, + agent_ids=[10, 11, 12] + ) """ data = {"user_ids": agent_ids} self._http.post( @@ -61,12 +61,12 @@ def remove(self, account_id: int, team_id: int, agent_ids: list[int]) -> None: team_id: The team ID agent_ids: List of agent IDs to remove - Example: - >>> client.teams.agents.remove( - ... account_id=1, - ... team_id=5, - ... agent_ids=[10] - ... ) + Examples: + client.teams.agents.remove( + account_id=1, + team_id=5, + agent_ids=[10] + ) """ data = {"user_ids": agent_ids} self._http.delete( @@ -141,10 +141,10 @@ def list(self, account_id: int) -> list[Team]: Returns: List of Team objects - Example: - >>> teams = client.teams.list(account_id=1) - >>> for team in teams: - ... print(team.name) + Examples: + teams = client.teams.list(account_id=1) + for team in teams: + print(team.name) """ response = self._http.get(f"/api/v1/accounts/{account_id}/teams") if isinstance(response, list): @@ -161,9 +161,9 @@ def get(self, account_id: int, team_id: int) -> Team: Returns: Team object - Example: - >>> team = client.teams.get(account_id=1, team_id=5) - >>> print(team.description) + Examples: + team = client.teams.get(account_id=1, team_id=5) + print(team.description) """ response = self._http.get(f"/api/v1/accounts/{account_id}/teams/{team_id}") return Team(**response) @@ -184,13 +184,13 @@ def create( Returns: Created Team object - Example: - >>> team = client.teams.create( - ... account_id=1, - ... name="Support Team", - ... description="Customer support team", - ... allow_auto_assign=True - ... ) + Examples: + team = client.teams.create( + account_id=1, + name="Support Team", + description="Customer support team", + allow_auto_assign=True + ) """ data = {"name": name, **kwargs} response = self._http.post(f"/api/v1/accounts/{account_id}/teams", json=data) @@ -212,12 +212,12 @@ def update( Returns: Updated Team object - Example: - >>> team = client.teams.update( - ... account_id=1, - ... team_id=5, - ... name="New Team Name" - ... ) + Examples: + team = client.teams.update( + account_id=1, + team_id=5, + name="New Team Name" + ) """ response = self._http.patch( f"/api/v1/accounts/{account_id}/teams/{team_id}", @@ -232,8 +232,8 @@ def delete(self, account_id: int, team_id: int) -> None: account_id: The account ID team_id: The team ID - Example: - >>> client.teams.delete(account_id=1, team_id=5) + Examples: + client.teams.delete(account_id=1, team_id=5) """ self._http.delete(f"/api/v1/accounts/{account_id}/teams/{team_id}") From 50ba5cbe4ecdfa46323044c4daa95a72714b48cf Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Wed, 18 Feb 2026 21:37:22 +0530 Subject: [PATCH 2/6] feat: setup mkdocs --- Makefile | 8 +- docs/api/client.md | 9 + docs/api/exceptions.md | 14 + docs/api/resources/agents.md | 9 + docs/api/resources/contacts.md | 17 + docs/api/resources/conversations.md | 17 + docs/api/resources/inboxes.md | 9 + docs/api/resources/messages.md | 9 + docs/api/resources/profile.md | 9 + docs/api/resources/teams.md | 17 + docs/api/types.md | 55 +++ docs/index.md | 90 +++++ mkdocs.yml | 81 ++++ pyproject.toml | 4 + uv.lock | 562 ++++++++++++++++++++++++++++ 15 files changed, 909 insertions(+), 1 deletion(-) create mode 100644 docs/api/client.md create mode 100644 docs/api/exceptions.md create mode 100644 docs/api/resources/agents.md create mode 100644 docs/api/resources/contacts.md create mode 100644 docs/api/resources/conversations.md create mode 100644 docs/api/resources/inboxes.md create mode 100644 docs/api/resources/messages.md create mode 100644 docs/api/resources/profile.md create mode 100644 docs/api/resources/teams.md create mode 100644 docs/api/types.md create mode 100644 docs/index.md create mode 100644 mkdocs.yml diff --git a/Makefile b/Makefile index 14ba3ac..eeb03a1 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: build publish publish-test test clean +.PHONY: build publish publish-test test clean docs docs-serve build: clean uv build @@ -14,3 +14,9 @@ test: clean: rm -rf dist/ + +docs: + uv run --group docs mkdocs build + +docs-serve: + uv run --group docs mkdocs serve diff --git a/docs/api/client.md b/docs/api/client.md new file mode 100644 index 0000000..12e8b17 --- /dev/null +++ b/docs/api/client.md @@ -0,0 +1,9 @@ +# Client + +The main entry point for the SDK. Both clients expose the same resource namespaces — the only difference is sync vs async. + +::: chatwoot.client.ChatwootClient + +--- + +::: chatwoot.client.AsyncChatwootClient diff --git a/docs/api/exceptions.md b/docs/api/exceptions.md new file mode 100644 index 0000000..0dc04f2 --- /dev/null +++ b/docs/api/exceptions.md @@ -0,0 +1,14 @@ +# Exceptions + +All SDK exceptions inherit from `ChatwootError`. The exception hierarchy maps directly to HTTP status codes so you can catch as broadly or narrowly as needed. + +``` +ChatwootError +└── ChatwootAPIError + ├── ChatwootAuthError (401) + ├── ChatwootPermissionError (403) + ├── ChatwootNotFoundError (404) + └── ChatwootValidationError (400/422) +``` + +::: chatwoot.exceptions diff --git a/docs/api/resources/agents.md b/docs/api/resources/agents.md new file mode 100644 index 0000000..48ecc22 --- /dev/null +++ b/docs/api/resources/agents.md @@ -0,0 +1,9 @@ +# Agents + +List and manage agents in an account. + +::: chatwoot.resources.agents.AgentsResource + +--- + +::: chatwoot.resources.agents.AsyncAgentsResource diff --git a/docs/api/resources/contacts.md b/docs/api/resources/contacts.md new file mode 100644 index 0000000..c710aff --- /dev/null +++ b/docs/api/resources/contacts.md @@ -0,0 +1,17 @@ +# Contacts + +Create, search, and manage contacts and their labels. + +::: chatwoot.resources.contacts.ContactsResource + +--- + +::: chatwoot.resources.contacts.ContactLabelsResource + +--- + +::: chatwoot.resources.contacts.AsyncContactsResource + +--- + +::: chatwoot.resources.contacts.AsyncContactLabelsResource diff --git a/docs/api/resources/conversations.md b/docs/api/resources/conversations.md new file mode 100644 index 0000000..1b1359d --- /dev/null +++ b/docs/api/resources/conversations.md @@ -0,0 +1,17 @@ +# Conversations + +Manage conversations and their labels. + +::: chatwoot.resources.conversations.ConversationsResource + +--- + +::: chatwoot.resources.conversations.ConversationLabelsResource + +--- + +::: chatwoot.resources.conversations.AsyncConversationsResource + +--- + +::: chatwoot.resources.conversations.AsyncConversationLabelsResource diff --git a/docs/api/resources/inboxes.md b/docs/api/resources/inboxes.md new file mode 100644 index 0000000..c4b6260 --- /dev/null +++ b/docs/api/resources/inboxes.md @@ -0,0 +1,9 @@ +# Inboxes + +List and retrieve inbox configuration. + +::: chatwoot.resources.inboxes.InboxesResource + +--- + +::: chatwoot.resources.inboxes.AsyncInboxesResource diff --git a/docs/api/resources/messages.md b/docs/api/resources/messages.md new file mode 100644 index 0000000..3f0274f --- /dev/null +++ b/docs/api/resources/messages.md @@ -0,0 +1,9 @@ +# Messages + +Send and manage messages within conversations. + +::: chatwoot.resources.messages.MessagesResource + +--- + +::: chatwoot.resources.messages.AsyncMessagesResource diff --git a/docs/api/resources/profile.md b/docs/api/resources/profile.md new file mode 100644 index 0000000..c2d441d --- /dev/null +++ b/docs/api/resources/profile.md @@ -0,0 +1,9 @@ +# Profile + +Fetch the currently authenticated user's profile. + +::: chatwoot.resources.profile.ProfileResource + +--- + +::: chatwoot.resources.profile.AsyncProfileResource diff --git a/docs/api/resources/teams.md b/docs/api/resources/teams.md new file mode 100644 index 0000000..cffc58a --- /dev/null +++ b/docs/api/resources/teams.md @@ -0,0 +1,17 @@ +# Teams + +Manage teams and their agent memberships. + +::: chatwoot.resources.teams.TeamsResource + +--- + +::: chatwoot.resources.teams.TeamAgentsResource + +--- + +::: chatwoot.resources.teams.AsyncTeamsResource + +--- + +::: chatwoot.resources.teams.AsyncTeamAgentsResource diff --git a/docs/api/types.md b/docs/api/types.md new file mode 100644 index 0000000..76470f5 --- /dev/null +++ b/docs/api/types.md @@ -0,0 +1,55 @@ +# Types + +Pydantic models returned by SDK methods. All fields map 1:1 to Chatwoot API response fields. + +## Common + +::: chatwoot.types.common + +--- + +## Conversation + +::: chatwoot.types.conversation + +--- + +## Message + +::: chatwoot.types.message + +--- + +## Contact + +::: chatwoot.types.contact + +--- + +## Profile + +::: chatwoot.types.profile + +--- + +## Agent + +::: chatwoot.types.agent + +--- + +## Inbox + +::: chatwoot.types.inbox + +--- + +## Label + +::: chatwoot.types.label + +--- + +## Team + +::: chatwoot.types.team diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..5bfda7a --- /dev/null +++ b/docs/index.md @@ -0,0 +1,90 @@ +# Chatwoot Python SDK + +A modern, type-safe Python SDK for the [Chatwoot](https://www.chatwoot.com/) API. Provides both synchronous and asynchronous clients with full type hints and Pydantic models. + +## Features + +- **Type-safe** — Full type hints and Pydantic v2 models for all responses +- **Async support** — Both sync (`ChatwootClient`) and async (`AsyncChatwootClient`) clients +- **Comprehensive** — Covers all major Chatwoot API resources +- **Error handling** — Typed exceptions for every HTTP error class + +## Installation + +```bash +pip install chatwoot-sdk +# or +uv add chatwoot-sdk +``` + +## Quick Start + +```python +from chatwoot import ChatwootClient + +client = ChatwootClient( + base_url="https://app.chatwoot.com", + api_token="your_api_token_here" +) + +profile = client.profile.get() +print(f"Logged in as: {profile.name}") + +conversations = client.conversations.list(account_id=1, status="open") + +client.close() +``` + +### Context manager + +```python +with ChatwootClient(base_url="...", api_token="...") as client: + profile = client.profile.get() +``` + +### Async client + +```python +import asyncio +from chatwoot import AsyncChatwootClient + +async def main(): + async with AsyncChatwootClient(base_url="...", api_token="...") as client: + profile = await client.profile.get() + conversations = await client.conversations.list(account_id=1, status="open") + +asyncio.run(main()) +``` + +## Error Handling + +```python +from chatwoot import ( + ChatwootClient, + ChatwootAuthError, + ChatwootNotFoundError, + ChatwootValidationError, +) + +try: + conversation = client.conversations.get(account_id=1, conversation_id=999) +except ChatwootAuthError: + print("Bad token") +except ChatwootNotFoundError: + print("Conversation not found") +except ChatwootValidationError as e: + for err in e.errors or []: + print(f" {err['field']}: {err['message']}") +``` + +## API Resources + +| Resource | Description | +|---|---| +| `client.profile` | Current user profile | +| `client.conversations` | Conversation management | +| `client.messages` | Send and manage messages | +| `client.contacts` | Contact management | +| `client.inboxes` | Inbox configuration | +| `client.teams` | Team management | +| `client.agents` | Agent management | diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..9c80412 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,81 @@ +site_name: Chatwoot Python SDK +site_description: Python SDK for the Chatwoot API — type-safe, async-ready, minimal. +site_url: https://chatwoot.github.io/chatwoot-sdk-python/ +repo_url: https://github.com/chatwoot/chatwoot-sdk-python +repo_name: chatwoot/chatwoot-sdk-python +edit_uri: edit/main/docs/ + +theme: + name: material + palette: + - media: "(prefers-color-scheme: light)" + scheme: default + primary: indigo + accent: indigo + toggle: + icon: material/brightness-7 + name: Switch to dark mode + - media: "(prefers-color-scheme: dark)" + scheme: slate + primary: indigo + accent: indigo + toggle: + icon: material/brightness-4 + name: Switch to light mode + features: + - navigation.tabs + - navigation.sections + - navigation.top + - navigation.footer + - search.suggest + - search.highlight + - content.code.copy + - content.code.annotate + +plugins: + - search + - mkdocstrings: + handlers: + python: + options: + docstring_style: google + show_source: false + show_signature_annotations: true + show_root_heading: true + show_root_full_path: false + merge_init_into_class: true + members_order: source + separate_signature: true + show_if_no_docstring: false + filters: + - "!^_" + +nav: + - Home: index.md + - API Reference: + - Client: api/client.md + - Resources: + - Profile: api/resources/profile.md + - Conversations: api/resources/conversations.md + - Messages: api/resources/messages.md + - Contacts: api/resources/contacts.md + - Inboxes: api/resources/inboxes.md + - Teams: api/resources/teams.md + - Agents: api/resources/agents.md + - Types: api/types.md + - Exceptions: api/exceptions.md + +markdown_extensions: + - pymdownx.highlight: + anchor_linenums: true + line_spans: __span + pygments_lang_class: true + - pymdownx.superfences + - pymdownx.inlinehilite + - pymdownx.snippets + - admonition + - pymdownx.details + - attr_list + - md_in_html + - toc: + permalink: true diff --git a/pyproject.toml b/pyproject.toml index 3c89746..de5b6c9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,6 +44,10 @@ dev = [ "pytest-asyncio>=0.24.0", "ruff>=0.9.0", ] +docs = [ + "mkdocs-material>=9.5.0", + "mkdocstrings[python]>=0.27.0", +] [tool.pytest.ini_options] asyncio_mode = "auto" diff --git a/uv.lock b/uv.lock index 0639bfe..eba23ab 100644 --- a/uv.lock +++ b/uv.lock @@ -23,6 +23,29 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592 }, ] +[[package]] +name = "babel" +version = "2.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/b2/51899539b6ceeeb420d40ed3cd4b7a40519404f9baf3d4ac99dc413a834b/babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d", size = 9959554 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845 }, +] + +[[package]] +name = "backrefs" +version = "6.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/a6/e325ec73b638d3ede4421b5445d4a0b8b219481826cc079d510100af356c/backrefs-6.2.tar.gz", hash = "sha256:f44ff4d48808b243b6c0cdc6231e22195c32f77046018141556c66f8bab72a49", size = 7012303 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/39/3765df263e08a4df37f4f43cb5aa3c6c17a4bdd42ecfe841e04c26037171/backrefs-6.2-py310-none-any.whl", hash = "sha256:0fdc7b012420b6b144410342caeb8adc54c6866cf12064abc9bb211302e496f8", size = 381075 }, + { url = "https://files.pythonhosted.org/packages/0f/f0/35240571e1b67ffb19dafb29ab34150b6f59f93f717b041082cdb1bfceb1/backrefs-6.2-py311-none-any.whl", hash = "sha256:08aa7fae530c6b2361d7bdcbda1a7c454e330cc9dbcd03f5c23205e430e5c3be", size = 392874 }, + { url = "https://files.pythonhosted.org/packages/e3/63/77e8c9745b4d227cce9f5e0a6f68041278c5f9b18588b35905f5f19c1beb/backrefs-6.2-py312-none-any.whl", hash = "sha256:c3f4b9cb2af8cda0d87ab4f57800b57b95428488477be164dd2b47be54db0c90", size = 398787 }, + { url = "https://files.pythonhosted.org/packages/c5/71/c754b1737ad99102e03fa3235acb6cb6d3ac9d6f596cbc3e5f236705abd8/backrefs-6.2-py313-none-any.whl", hash = "sha256:12df81596ab511f783b7d87c043ce26bc5b0288cf3bb03610fe76b8189282b2b", size = 400747 }, + { url = "https://files.pythonhosted.org/packages/af/75/be12ba31a6eb20dccef2320cd8ccb3f7d9013b68ba4c70156259fee9e409/backrefs-6.2-py314-none-any.whl", hash = "sha256:e5f805ae09819caa1aa0623b4a83790e7028604aa2b8c73ba602c4454e665de7", size = 412602 }, + { url = "https://files.pythonhosted.org/packages/21/f8/d02f650c47d05034dcd6f9c8cf94f39598b7a89c00ecda0ecb2911bc27e9/backrefs-6.2-py39-none-any.whl", hash = "sha256:664e33cd88c6840b7625b826ecf2555f32d491800900f5a541f772c485f7cda7", size = 381077 }, +] + [[package]] name = "certifi" version = "2026.1.4" @@ -32,6 +55,79 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900 }, ] +[[package]] +name = "charset-normalizer" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/27/c6491ff4954e58a10f69ad90aca8a1b6fe9c5d3c6f380907af3c37435b59/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8", size = 206988 }, + { url = "https://files.pythonhosted.org/packages/94/59/2e87300fe67ab820b5428580a53cad894272dbb97f38a7a814a2a1ac1011/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0", size = 147324 }, + { url = "https://files.pythonhosted.org/packages/07/fb/0cf61dc84b2b088391830f6274cb57c82e4da8bbc2efeac8c025edb88772/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3", size = 142742 }, + { url = "https://files.pythonhosted.org/packages/62/8b/171935adf2312cd745d290ed93cf16cf0dfe320863ab7cbeeae1dcd6535f/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc", size = 160863 }, + { url = "https://files.pythonhosted.org/packages/09/73/ad875b192bda14f2173bfc1bc9a55e009808484a4b256748d931b6948442/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897", size = 157837 }, + { url = "https://files.pythonhosted.org/packages/6d/fc/de9cce525b2c5b94b47c70a4b4fb19f871b24995c728e957ee68ab1671ea/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381", size = 151550 }, + { url = "https://files.pythonhosted.org/packages/55/c2/43edd615fdfba8c6f2dfbd459b25a6b3b551f24ea21981e23fb768503ce1/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815", size = 149162 }, + { url = "https://files.pythonhosted.org/packages/03/86/bde4ad8b4d0e9429a4e82c1e8f5c659993a9a863ad62c7df05cf7b678d75/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0", size = 150019 }, + { url = "https://files.pythonhosted.org/packages/1f/86/a151eb2af293a7e7bac3a739b81072585ce36ccfb4493039f49f1d3cae8c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161", size = 143310 }, + { url = "https://files.pythonhosted.org/packages/b5/fe/43dae6144a7e07b87478fdfc4dbe9efd5defb0e7ec29f5f58a55aeef7bf7/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4", size = 162022 }, + { url = "https://files.pythonhosted.org/packages/80/e6/7aab83774f5d2bca81f42ac58d04caf44f0cc2b65fc6db2b3b2e8a05f3b3/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89", size = 149383 }, + { url = "https://files.pythonhosted.org/packages/4f/e8/b289173b4edae05c0dde07f69f8db476a0b511eac556dfe0d6bda3c43384/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569", size = 159098 }, + { url = "https://files.pythonhosted.org/packages/d8/df/fe699727754cae3f8478493c7f45f777b17c3ef0600e28abfec8619eb49c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224", size = 152991 }, + { url = "https://files.pythonhosted.org/packages/1a/86/584869fe4ddb6ffa3bd9f491b87a01568797fb9bd8933f557dba9771beaf/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a", size = 99456 }, + { url = "https://files.pythonhosted.org/packages/65/f6/62fdd5feb60530f50f7e38b4f6a1d5203f4d16ff4f9f0952962c044e919a/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016", size = 106978 }, + { url = "https://files.pythonhosted.org/packages/7a/9d/0710916e6c82948b3be62d9d398cb4fcf4e97b56d6a6aeccd66c4b2f2bd5/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1", size = 99969 }, + { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425 }, + { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162 }, + { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558 }, + { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497 }, + { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240 }, + { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471 }, + { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864 }, + { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647 }, + { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110 }, + { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839 }, + { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667 }, + { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535 }, + { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816 }, + { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694 }, + { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131 }, + { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390 }, + { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091 }, + { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936 }, + { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180 }, + { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346 }, + { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874 }, + { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076 }, + { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601 }, + { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376 }, + { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825 }, + { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583 }, + { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366 }, + { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300 }, + { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465 }, + { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404 }, + { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092 }, + { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408 }, + { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746 }, + { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889 }, + { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641 }, + { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779 }, + { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035 }, + { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542 }, + { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524 }, + { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395 }, + { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680 }, + { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045 }, + { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687 }, + { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014 }, + { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044 }, + { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940 }, + { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104 }, + { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743 }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402 }, +] + [[package]] name = "chatwoot-sdk" version = "0.1.0" @@ -47,6 +143,10 @@ dev = [ { name = "pytest-asyncio" }, { name = "ruff" }, ] +docs = [ + { name = "mkdocs-material" }, + { name = "mkdocstrings", extra = ["python"] }, +] [package.metadata] requires-dist = [ @@ -60,6 +160,22 @@ dev = [ { name = "pytest-asyncio", specifier = ">=0.24.0" }, { name = "ruff", specifier = ">=0.9.0" }, ] +docs = [ + { name = "mkdocs-material", specifier = ">=9.5.0" }, + { name = "mkdocstrings", extras = ["python"], specifier = ">=0.27.0" }, +] + +[[package]] +name = "click" +version = "8.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274 }, +] [[package]] name = "colorama" @@ -70,6 +186,50 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, ] +[[package]] +name = "ghp-import" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034 }, +] + +[[package]] +name = "griffe" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "griffecli" }, + { name = "griffelib" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/94/ee21d41e7eb4f823b94603b9d40f86d3c7fde80eacc2c3c71845476dddaa/griffe-2.0.0-py3-none-any.whl", hash = "sha256:5418081135a391c3e6e757a7f3f156f1a1a746cc7b4023868ff7d5e2f9a980aa", size = 5214 }, +] + +[[package]] +name = "griffecli" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama" }, + { name = "griffelib" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/ed/d93f7a447bbf7a935d8868e9617cbe1cadf9ee9ee6bd275d3040fbf93d60/griffecli-2.0.0-py3-none-any.whl", hash = "sha256:9f7cd9ee9b21d55e91689358978d2385ae65c22f307a63fb3269acf3f21e643d", size = 9345 }, +] + +[[package]] +name = "griffelib" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/51/c936033e16d12b627ea334aaaaf42229c37620d0f15593456ab69ab48161/griffelib-2.0.0-py3-none-any.whl", hash = "sha256:01284878c966508b6d6f1dbff9b6fa607bc062d8261c5c7253cb285b06422a7f", size = 142004 }, +] + [[package]] name = "h11" version = "0.16.0" @@ -125,6 +285,229 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484 }, ] +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 }, +] + +[[package]] +name = "markdown" +version = "3.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2b/f4/69fa6ed85ae003c2378ffa8f6d2e3234662abd02c10d216c0ba96081a238/markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950", size = 368805 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36", size = 108180 }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631 }, + { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058 }, + { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287 }, + { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940 }, + { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887 }, + { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692 }, + { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471 }, + { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923 }, + { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572 }, + { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077 }, + { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876 }, + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615 }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020 }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332 }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947 }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962 }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760 }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529 }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015 }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540 }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105 }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906 }, + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622 }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029 }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374 }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980 }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990 }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784 }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588 }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041 }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543 }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113 }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911 }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658 }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066 }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639 }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569 }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284 }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801 }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769 }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642 }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612 }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200 }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973 }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619 }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029 }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408 }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005 }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048 }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821 }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606 }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043 }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747 }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341 }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073 }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661 }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069 }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670 }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598 }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261 }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835 }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733 }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672 }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819 }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426 }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146 }, +] + +[[package]] +name = "mergedeep" +version = "1.3.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354 }, +] + +[[package]] +name = "mkdocs" +version = "1.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "ghp-import" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mergedeep" }, + { name = "mkdocs-get-deps" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "pyyaml" }, + { name = "pyyaml-env-tag" }, + { name = "watchdog" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/c6/bbd4f061bd16b378247f12953ffcb04786a618ce5e904b8c5a01a0309061/mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2", size = 3889159 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451 }, +] + +[[package]] +name = "mkdocs-autorefs" +version = "1.4.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/c0/f641843de3f612a6b48253f39244165acff36657a91cc903633d456ae1ac/mkdocs_autorefs-1.4.4.tar.gz", hash = "sha256:d54a284f27a7346b9c38f1f852177940c222da508e66edc816a0fa55fc6da197", size = 56588 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/de/a3e710469772c6a89595fc52816da05c1e164b4c866a89e3cb82fb1b67c5/mkdocs_autorefs-1.4.4-py3-none-any.whl", hash = "sha256:834ef5408d827071ad1bc69e0f39704fa34c7fc05bc8e1c72b227dfdc5c76089", size = 25530 }, +] + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mergedeep" }, + { name = "platformdirs" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/d4/029f984e8d3f3b6b726bd33cafc473b75e9e44c0f7e80a5b29abc466bdea/mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134", size = 9521 }, +] + +[[package]] +name = "mkdocs-material" +version = "9.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "babel" }, + { name = "backrefs" }, + { name = "colorama" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "mkdocs" }, + { name = "mkdocs-material-extensions" }, + { name = "paginate" }, + { name = "pygments" }, + { name = "pymdown-extensions" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/27/e2/2ffc356cd72f1473d07c7719d82a8f2cbd261666828614ecb95b12169f41/mkdocs_material-9.7.1.tar.gz", hash = "sha256:89601b8f2c3e6c6ee0a918cc3566cb201d40bf37c3cd3c2067e26fadb8cce2b8", size = 4094392 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/32/ed071cb721aca8c227718cffcf7bd539620e9799bbf2619e90c757bfd030/mkdocs_material-9.7.1-py3-none-any.whl", hash = "sha256:3f6100937d7d731f87f1e3e3b021c97f7239666b9ba1151ab476cabb96c60d5c", size = 9297166 }, +] + +[[package]] +name = "mkdocs-material-extensions" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/79/9b/9b4c96d6593b2a541e1cb8b34899a6d021d208bb357042823d4d2cabdbe7/mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443", size = 11847 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31", size = 8728 }, +] + +[[package]] +name = "mkdocstrings" +version = "1.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, + { name = "mkdocs-autorefs" }, + { name = "pymdown-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/46/62/0dfc5719514115bf1781f44b1d7f2a0923fcc01e9c5d7990e48a05c9ae5d/mkdocstrings-1.0.3.tar.gz", hash = "sha256:ab670f55040722b49bb45865b2e93b824450fb4aef638b00d7acb493a9020434", size = 100946 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/41/1cf02e3df279d2dd846a1bf235a928254eba9006dd22b4a14caa71aed0f7/mkdocstrings-1.0.3-py3-none-any.whl", hash = "sha256:0d66d18430c2201dc7fe85134277382baaa15e6b30979f3f3bdbabd6dbdb6046", size = 35523 }, +] + +[package.optional-dependencies] +python = [ + { name = "mkdocstrings-python" }, +] + +[[package]] +name = "mkdocstrings-python" +version = "2.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "griffe" }, + { name = "mkdocs-autorefs" }, + { name = "mkdocstrings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/25/84/78243847ad9d5c21d30a2842720425b17e880d99dfe824dee11d6b2149b4/mkdocstrings_python-2.0.2.tar.gz", hash = "sha256:4a32ccfc4b8d29639864698e81cfeb04137bce76bb9f3c251040f55d4b6e1ad8", size = 199124 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/31/7ee938abbde2322e553a2cb5f604cdd1e4728e08bba39c7ee6fae9af840b/mkdocstrings_python-2.0.2-py3-none-any.whl", hash = "sha256:31241c0f43d85a69306d704d5725786015510ea3f3c4bdfdb5a5731d83cdc2b0", size = 104900 }, +] + [[package]] name = "packaging" version = "26.0" @@ -134,6 +517,33 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366 }, ] +[[package]] +name = "paginate" +version = "0.5.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/46/68dde5b6bc00c1296ec6466ab27dddede6aec9af1b99090e1107091b3b84/paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945", size = 19252 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591", size = 13746 }, +] + +[[package]] +name = "pathspec" +version = "1.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fa/36/e27608899f9b8d4dff0617b2d9ab17ca5608956ca44461ac14ac48b44015/pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645", size = 131200 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206 }, +] + +[[package]] +name = "platformdirs" +version = "4.9.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/04/fea538adf7dbbd6d186f551d595961e564a3b6715bdf276b477460858672/platformdirs-4.9.2.tar.gz", hash = "sha256:9a33809944b9db043ad67ca0db94b14bf452cc6aeaac46a88ea55b26e2e9d291", size = 28394 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/31/05e764397056194206169869b50cf2fee4dbbbc71b344705b9c0d878d4d8/platformdirs-4.9.2-py3-none-any.whl", hash = "sha256:9170634f126f8efdae22fb58ae8a0eaa86f38365bc57897a6c4f781d1f5875bd", size = 21168 }, +] + [[package]] name = "pluggy" version = "1.6.0" @@ -256,6 +666,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217 }, ] +[[package]] +name = "pymdown-extensions" +version = "10.21" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ba/63/06673d1eb6d8f83c0ea1f677d770e12565fb516928b4109c9e2055656a9e/pymdown_extensions-10.21.tar.gz", hash = "sha256:39f4a020f40773f6b2ff31d2cd2546c2c04d0a6498c31d9c688d2be07e1767d5", size = 853363 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/2c/5b079febdc65e1c3fb2729bf958d18b45be7113828528e8a0b5850dd819a/pymdown_extensions-10.21-py3-none-any.whl", hash = "sha256:91b879f9f864d49794c2d9534372b10150e6141096c3908a455e45ca72ad9d3f", size = 268877 }, +] + [[package]] name = "pytest" version = "9.0.2" @@ -285,6 +708,100 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5", size = 15075 }, ] +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826 }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577 }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556 }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114 }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638 }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463 }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986 }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543 }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763 }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063 }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973 }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116 }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011 }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870 }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089 }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181 }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658 }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003 }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344 }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669 }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252 }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081 }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159 }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626 }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613 }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115 }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427 }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090 }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246 }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814 }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809 }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454 }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355 }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175 }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228 }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194 }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429 }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912 }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108 }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641 }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901 }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132 }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261 }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272 }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923 }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062 }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341 }, +] + +[[package]] +name = "pyyaml-env-tag" +version = "1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/2e/79c822141bfd05a853236b504869ebc6b70159afc570e1d5a20641782eaa/pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff", size = 5737 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/11/432f32f8097b03e3cd5fe57e88efb685d964e2e5178a48ed61e841f7fdce/pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04", size = 4722 }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738 }, +] + [[package]] name = "ruff" version = "0.15.0" @@ -310,6 +827,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f6/b0/2d823f6e77ebe560f4e397d078487e8d52c1516b331e3521bc75db4272ca/ruff-0.15.0-py3-none-win_arm64.whl", hash = "sha256:c480d632cc0ca3f0727acac8b7d053542d9e114a462a145d0b00e7cd658c515a", size = 10865753 }, ] +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, +] + [[package]] name = "typing-extensions" version = "4.15.0" @@ -330,3 +856,39 @@ sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac wheels = [ { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611 }, ] + +[[package]] +name = "urllib3" +version = "2.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584 }, +] + +[[package]] +name = "watchdog" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393 }, + { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392 }, + { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019 }, + { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471 }, + { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449 }, + { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054 }, + { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480 }, + { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451 }, + { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057 }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079 }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076 }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077 }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077 }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065 }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070 }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067 }, +] From 365238798ab7873b2db77819e4c4410a840a2f83 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Wed, 18 Feb 2026 21:42:21 +0530 Subject: [PATCH 3/6] feat: add examples --- .gitignore | 3 + docs/examples/auto-resolve-stale.md | 98 +++++++++++++++++++++++++ docs/examples/handle-support-request.md | 90 +++++++++++++++++++++++ docs/examples/pagination.md | 76 +++++++++++++++++++ docs/examples/sync-contacts.md | 91 +++++++++++++++++++++++ mkdocs.yml | 5 ++ 6 files changed, 363 insertions(+) create mode 100644 docs/examples/auto-resolve-stale.md create mode 100644 docs/examples/handle-support-request.md create mode 100644 docs/examples/pagination.md create mode 100644 docs/examples/sync-contacts.md diff --git a/.gitignore b/.gitignore index 8027415..93336b3 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,9 @@ build/ .coverage htmlcov/ +# Docs +site/ + # IDE .vscode/ .idea/ diff --git a/docs/examples/auto-resolve-stale.md b/docs/examples/auto-resolve-stale.md new file mode 100644 index 0000000..9c6a8f9 --- /dev/null +++ b/docs/examples/auto-resolve-stale.md @@ -0,0 +1,98 @@ +# Auto-Resolve Stale Conversations + +Pages through all open conversations, skips urgent/high-priority ones, and resolves anything idle past a configurable threshold — posting a closing message first. + +```python +"""Auto-resolve stale conversations. + +Lists open conversations, skips any with urgent or high priority, +resolves the rest if they've been idle past a threshold, and posts +a closing message. +""" + +import time + +from chatwoot import ChatwootClient +from chatwoot.types.common import ConversationPriority +from chatwoot.types.conversation import Conversation + +BASE_URL = "http://localhost:3000" +API_TOKEN = "your-api-token" +ACCOUNT_ID = 1 + +STALE_THRESHOLD_HOURS = 48 +CLOSING_MESSAGE = ( + "This conversation has been automatically resolved due to inactivity. " + "Feel free to reopen it if you need further assistance!" +) + + +def is_stale(conversation: Conversation) -> bool: + """Check if a conversation has been idle past the threshold.""" + last_activity = conversation.timestamp or conversation.created_at + if last_activity is None: + return False + age_hours = (time.time() - last_activity) / 3600 + return age_hours > STALE_THRESHOLD_HOURS + + +def main() -> None: + with ChatwootClient(base_url=BASE_URL, api_token=API_TOKEN) as client: + page = 1 + resolved_count = 0 + skipped_priority = 0 + + while True: + conversations = client.conversations.list( + ACCOUNT_ID, status="open", page=page + ) + if not conversations: + break + + for convo in conversations: + # Skip high-priority conversations + if convo.priority in ( + ConversationPriority.URGENT, + ConversationPriority.HIGH, + ): + skipped_priority += 1 + print( + f" Skipping conversation {convo.id} " + f"(priority={convo.priority})" + ) + continue + + if not is_stale(convo): + continue + + # Send a closing message before resolving + client.messages.create( + ACCOUNT_ID, + conversation_id=convo.id, + content=CLOSING_MESSAGE, + message_type="outgoing", + ) + client.conversations.toggle_status( + ACCOUNT_ID, convo.id, status="resolved" + ) + resolved_count += 1 + print(f" Resolved conversation {convo.id}") + + page += 1 + + print( + f"\nDone. Resolved {resolved_count} conversations, " + f"skipped {skipped_priority} high-priority." + ) + + +if __name__ == "__main__": + main() +``` + +## What it covers + +- `client.conversations.list` with `page` — paginating through all open conversations +- `ConversationPriority` enum — filtering by priority level +- `client.messages.create` — posting a closing message before resolving +- `client.conversations.toggle_status` — resolving a conversation diff --git a/docs/examples/handle-support-request.md b/docs/examples/handle-support-request.md new file mode 100644 index 0000000..7079fe5 --- /dev/null +++ b/docs/examples/handle-support-request.md @@ -0,0 +1,90 @@ +# Handle a Support Request + +Creates a contact, opens a conversation, sends a welcome message, assigns it to an agent, and applies a label — end-to-end in one script. + +```python +"""Handle an inbound support request end-to-end. + +Creates a contact, starts a conversation, sends a welcome message, +and assigns it to an agent. +""" + +import sys + +from chatwoot import ChatwootClient + +BASE_URL = "http://localhost:3000" +API_TOKEN = "your-api-token" +ACCOUNT_ID = 1 + + +def main() -> None: + with ChatwootClient(base_url=BASE_URL, api_token=API_TOKEN) as client: + # 1. Pick an inbox (use the first API-type inbox, or any available one) + inboxes = client.inboxes.list(ACCOUNT_ID) + if not inboxes: + print("No inboxes found. Create one in the Chatwoot dashboard first.") + sys.exit(1) + inbox = inboxes[0] + print(f"Using inbox: {inbox.name} (id={inbox.id})") + + # 2. Create a contact + result = client.contacts.create( + ACCOUNT_ID, + inbox_id=inbox.id, + name="Jane Doe", + email="jane.doe@example.com", + phone_number="+1234567890", + ) + contact = result.contact + source_id = result.contact_inbox.source_id + print(f"Created contact: {contact.name} (id={contact.id})") + + # 3. Start a conversation + conversation = client.conversations.create( + ACCOUNT_ID, + source_id=source_id, + inbox_id=inbox.id, + contact_id=contact.id, + ) + print(f"Created conversation: id={conversation.id}") + + # 4. Send a welcome message + message = client.messages.create( + ACCOUNT_ID, + conversation_id=conversation.id, + content="Hi Jane! Thanks for reaching out. How can we help you today?", + message_type="outgoing", + ) + print(f"Sent message: id={message.id}") + + # 5. Assign to an agent + agents = client.agents.list(ACCOUNT_ID) + if agents: + agent = agents[0] + client.conversations.assign( + ACCOUNT_ID, + conversation_id=conversation.id, + assignee_id=agent.id, + ) + print(f"Assigned to agent: {agent.name}") + + # 6. Add a label + client.conversations.labels.add( + ACCOUNT_ID, conversation.id, labels=["new-request"] + ) + print("Added label: new-request") + + +if __name__ == "__main__": + main() +``` + +## What it covers + +- `client.inboxes.list` — pick a target inbox +- `client.contacts.create` — create a contact and capture the `source_id` from the response +- `client.conversations.create` — open a conversation linked to the contact +- `client.messages.create` — send an outbound message +- `client.conversations.assign` — assign to the first available agent +- `client.conversations.labels.add` — tag the conversation diff --git a/docs/examples/pagination.md b/docs/examples/pagination.md new file mode 100644 index 0000000..9854c9e --- /dev/null +++ b/docs/examples/pagination.md @@ -0,0 +1,76 @@ +# Pagination + +Two resources support pagination via a `page` parameter — `conversations.list` and `contacts.list`. Both return an empty list when the page is beyond the last one, which is the natural loop terminator. + +## Fetch all open conversations + +```python +from chatwoot import ChatwootClient + +client = ChatwootClient(base_url="...", api_token="...") + +all_conversations = [] +page = 1 + +while True: + batch = client.conversations.list(account_id=1, status="open", page=page) + if not batch: + break + all_conversations.extend(batch) + page += 1 + +print(f"Total: {len(all_conversations)} conversations") +``` + +## Fetch all contacts + +```python +all_contacts = [] +page = 1 + +while True: + batch = client.contacts.list(account_id=1, page=page) + if not batch: + break + all_contacts.extend(batch) + page += 1 +``` + +## Async variant + +```python +import asyncio +from chatwoot import AsyncChatwootClient + +async def fetch_all_conversations(account_id: int) -> list: + async with AsyncChatwootClient(base_url="...", api_token="...") as client: + results = [] + page = 1 + while True: + batch = await client.conversations.list( + account_id=account_id, status="open", page=page + ) + if not batch: + break + results.extend(batch) + page += 1 + return results + +conversations = asyncio.run(fetch_all_conversations(account_id=1)) +``` + +## Process page-by-page without loading everything + +If the full dataset is large, process each page immediately rather than collecting all results first: + +```python +page = 1 + +while True: + batch = client.conversations.list(account_id=1, status="open", page=page) + if not batch: + break + for conversation in batch: + process(conversation) # handle one at a time + page += 1 +``` diff --git a/docs/examples/sync-contacts.md b/docs/examples/sync-contacts.md new file mode 100644 index 0000000..46b1d32 --- /dev/null +++ b/docs/examples/sync-contacts.md @@ -0,0 +1,91 @@ +# Sync Contacts + +Mirrors users from an external data source into Chatwoot — creates missing contacts, updates existing ones, and applies plan-based labels. + +```python +"""Sync contacts from your application database into Chatwoot. + +Looks up each user by email — creates the contact if missing, updates +custom_attributes and labels if it already exists. +""" + +from chatwoot import ChatwootClient + +BASE_URL = "http://localhost:3000" +API_TOKEN = "your-api-token" +ACCOUNT_ID = 1 +INBOX_ID = 1 # Inbox to associate new contacts with + +# Simulated application users — in practice, query your own database. +APP_USERS = [ + {"name": "Alice Park", "email": "alice@example.com", "plan": "enterprise"}, + {"name": "Bob Chen", "email": "bob@example.com", "plan": "pro"}, + {"name": "Carol Singh", "email": "carol@example.com", "plan": "free"}, +] + +PLAN_LABELS = { + "enterprise": ["enterprise", "priority-support"], + "pro": ["pro"], + "free": ["free-tier"], +} + + +def sync_contact(client: ChatwootClient, user: dict) -> None: + """Create or update a single contact from application data.""" + email = user["email"] + plan = user["plan"] + custom_attrs = {"plan": plan, "synced_from": "app-db"} + + # Search for existing contact + matches = client.contacts.search(ACCOUNT_ID, query=email) + existing = next((c for c in matches if c.email == email), None) + + if existing: + # Update existing contact + client.contacts.update( + ACCOUNT_ID, + existing.id, + name=user["name"], + custom_attributes=custom_attrs, + ) + client.contacts.labels.add( + ACCOUNT_ID, existing.id, labels=PLAN_LABELS.get(plan, []) + ) + print(f" Updated: {email} (id={existing.id})") + else: + # Create new contact + result = client.contacts.create( + ACCOUNT_ID, + inbox_id=INBOX_ID, + name=user["name"], + email=email, + custom_attributes=custom_attrs, + ) + client.contacts.labels.add( + ACCOUNT_ID, result.contact.id, labels=PLAN_LABELS.get(plan, []) + ) + print(f" Created: {email} (id={result.contact.id})") + + +def main() -> None: + with ChatwootClient(base_url=BASE_URL, api_token=API_TOKEN) as client: + print(f"Syncing {len(APP_USERS)} contacts") + for user in APP_USERS: + try: + sync_contact(client, user) + except Exception as e: + print(f" Failed: {user['email']} — {e}") + + print("Done.") + + +if __name__ == "__main__": + main() +``` + +## What it covers + +- `client.contacts.search` — look up a contact by email before creating +- `client.contacts.update` — update name and `custom_attributes` on an existing contact +- `client.contacts.create` — create a new contact with inbox association +- `client.contacts.labels.add` — apply plan-tier labels after create or update diff --git a/mkdocs.yml b/mkdocs.yml index 9c80412..14de854 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -52,6 +52,11 @@ plugins: nav: - Home: index.md + - Examples: + - Handle Support Request: examples/handle-support-request.md + - Auto-Resolve Stale: examples/auto-resolve-stale.md + - Sync Contacts: examples/sync-contacts.md + - Pagination: examples/pagination.md - API Reference: - Client: api/client.md - Resources: From cd8bf5f284d2d758820a7fa97990f15707b1ba9f Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Wed, 18 Feb 2026 21:44:14 +0530 Subject: [PATCH 4/6] fix: hide nav on index --- docs/index.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/index.md b/docs/index.md index 5bfda7a..806c77c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,3 +1,8 @@ +--- +hide: + - navigation +--- + # Chatwoot Python SDK A modern, type-safe Python SDK for the [Chatwoot](https://www.chatwoot.com/) API. Provides both synchronous and asynchronous clients with full type hints and Pydantic models. From 7b2a873baf0d1c10a07716f1f53c1f9a076e7a03 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Wed, 18 Feb 2026 22:01:30 +0530 Subject: [PATCH 5/6] feat: add docs ci --- .github/workflows/docs.yml | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/docs.yml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..d132322 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,37 @@ +name: Deploy Docs + +on: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: astral-sh/setup-uv@v4 + + - name: Build docs + run: uv run --group docs mkdocs build + + - uses: actions/upload-pages-artifact@v3 + with: + path: site/ + + - uses: actions/deploy-pages@v4 + id: deployment From 338cbe90fb9fc83e5080431acfb28d0f4f4e7e1c Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Wed, 18 Feb 2026 22:02:50 +0530 Subject: [PATCH 6/6] fix: client --- chatwoot/__init__.py | 10 +++++----- chatwoot/client.py | 18 +++++++++--------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/chatwoot/__init__.py b/chatwoot/__init__.py index b8fd36a..bc19198 100644 --- a/chatwoot/__init__.py +++ b/chatwoot/__init__.py @@ -4,30 +4,30 @@ Examples: from chatwoot import ChatwootClient - + client = ChatwootClient( base_url="https://app.chatwoot.com", api_token="your_api_token_here" ) - + # Fetch your profile profile = client.profile.get() print(f"Logged in as: {profile.name}") - + # List open conversations conversations = client.conversations.list( account_id=1, status="open" ) print(f"Open conversations: {len(conversations)}") - + # Send a message message = client.messages.create( account_id=1, conversation_id=42, content="Hello from the Python SDK!" ) - + client.close() """ diff --git a/chatwoot/client.py b/chatwoot/client.py index d676252..5533a2b 100644 --- a/chatwoot/client.py +++ b/chatwoot/client.py @@ -24,21 +24,21 @@ class ChatwootClient: base_url="https://app.chatwoot.com", api_token="your_api_token_here" ) - + # Fetch user profile profile = client.profile.get() print(profile.name) - + # List conversations conversations = client.conversations.list(account_id=1, status="open") - + # Send a message message = client.messages.create( account_id=1, conversation_id=42, content="Hello from SDK!" ) - + # Use as context manager for automatic cleanup with ChatwootClient(base_url="", api_token="") as client: profile = client.profile.get() @@ -92,25 +92,25 @@ class AsyncChatwootClient: Examples: import asyncio - + async def main(): client = AsyncChatwootClient( base_url="https://app.chatwoot.com", api_token="your_api_token_here" ) - + # Fetch user profile profile = await client.profile.get() print(profile.name) - + # List conversations conversations = await client.conversations.list( account_id=1, status="open" ) - + await client.aclose() - + # Or use as async context manager async def main(): async with AsyncChatwootClient(base_url="", api_token="") as client: