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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ 3.9, "3.10", "3.11", "3.12", "3.13" ]
python-version: [ 3.9, "3.10", "3.11", "3.12", "3.13", "3.14" ]

steps:
- uses: actions/checkout@v4
Expand All @@ -104,7 +104,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ 3.9, "3.10", "3.11", "3.12", "3.13" ]
python-version: [ 3.9, "3.10", "3.11", "3.12", "3.13", "3.14" ]

steps:
- uses: actions/checkout@v4
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ classifiers = [
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3 :: Only",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
Expand Down
2 changes: 1 addition & 1 deletion src/pytito/__about__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@

Variables that describes the Package
"""
__version__ = "0.0.6"
__version__ = "0.0.8"
2 changes: 2 additions & 0 deletions src/pytito/admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,7 @@
from .event import Event
from .ticket import Ticket
from .account import Account
from .release import Release
from .activity import Activity

from ._base_client import UnauthorizedException
41 changes: 41 additions & 0 deletions src/pytito/admin/_base_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import os
from abc import ABC
from typing import Any, Optional
from datetime import datetime

import requests

Expand Down Expand Up @@ -98,3 +99,43 @@ def _get_response(self, endpoint: str) -> dict[str, Any]:
raise RuntimeError(f'Hello failed with status code: {response.status_code}')

return response.json()

class EventChildAPIBase(AdminAPIBase, ABC):
"""
Base Class for the children of an event e.g. Tickets, Releases, Actvities
"""
# pylint: disable=too-few-public-methods

def __init__(self, *, account_slug:str, event_slug:str,
json_content:Optional[dict[str, Any]]=None,
allow_automatic_json_retrieval: bool=False) -> None:
if json_content is None and allow_automatic_json_retrieval is False:
raise RuntimeError('If the JSON content is not provided at initialisation, '
'runtime retrival is needed')
super().__init__(json_content=json_content,
allow_automatic_json_retrieval=allow_automatic_json_retrieval)
self.__account_slug = account_slug
self.__event_slug = event_slug

@property
def _account_slug(self) -> str:
return self.__account_slug

@property
def _event_slug(self) -> str:
return self.__event_slug

def datetime_from_json(json_value: str) -> datetime:
"""
convert the isoformat datetime from the json content to a python object
"""
return datetime.fromisoformat(json_value)

def optional_datetime_from_json(json_value: str) -> Optional[datetime]:
"""
convert the isoformat datetime from the json content to a python object, with support for
a null (unpopulated value)
"""
if json_value is None:
return None
return datetime.fromisoformat(json_value)
17 changes: 8 additions & 9 deletions src/pytito/admin/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,15 @@ def _populate_json(self) -> None:
raise ValueError('slug in json content does not match expected value')

def __event_getter(self, end_point: str) -> dict[str, Event]:
response = self._get_response(end_point)
return_dict:dict[str, Event] = {}
for event in response['events']:
if event['account_slug'] != self._account_slug:
raise RuntimeError('Account Slug inconsistency')
slug = event['slug']
return_dict[slug] = Event(event_slug=slug, account_slug=self._account_slug,

def event_factory(json_content:dict[str, Any]) -> tuple[str, Event]:
event_slug = json_content['slug']
return event_slug, Event(event_slug=event_slug, account_slug=self._account_slug,
api_key=self.__api_key_internal,
json_content=event)
return return_dict
json_content=json_content)

response = self._get_response(end_point)
return dict(event_factory(event) for event in response['events'])

@property
def events(self) -> dict[str, Event]:
Expand Down
86 changes: 86 additions & 0 deletions src/pytito/admin/activity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"""
pytito is a python wrapper for the tito.io API
Copyright (C) 2024

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.

This file provides the activity class
"""
from typing import Optional, Any
from datetime import datetime

from ._base_client import EventChildAPIBase, optional_datetime_from_json

class Activity(EventChildAPIBase):
"""
One of the activities for an event available through the Tito IO AdminAPI
"""

def __init__(self, *, account_slug:str, event_slug:str, activity_id:str,
json_content:Optional[dict[str, Any]]=None,
allow_automatic_json_retrieval: bool=False) -> None:
super().__init__(json_content=json_content,
account_slug=account_slug,
event_slug=event_slug,
allow_automatic_json_retrieval=allow_automatic_json_retrieval)
self.__activity_id = activity_id
if json_content is not None:
if self._json_content['_type'] != "activity":
raise ValueError('JSON content type was expected to be activity')

@property
def _activity_id(self) -> str:
return self.__activity_id

@property
def _end_point(self) -> str:
return super()._end_point +\
f'/{self._account_slug}/{self._event_slug}/activities/{self._activity_id}'

def _populate_json(self) -> None:
self._json_content = self._get_response(endpoint='')['id']
if self._activity_id != self._json_content['id']:
raise ValueError('slug in json content does not match expected value')
if self._json_content['view'] != 'extended':
raise ValueError('expected the extended view of the ticket')

@property
def name(self) -> str:
"""
Name of the Activity
"""
return self._json_content['name']

@property
def capacity(self) -> Optional[int]:
"""
The number of people who can attend. A value of `None` means there is no limit
"""
return self._json_content['capacity']

@property
def start_at(self) -> Optional[datetime]:
"""
Start date and time for the activity
"""
json_value = self._json_content['start_at']
return optional_datetime_from_json(json_value=json_value)

@property
def end_at(self) -> Optional[datetime]:
"""
End date and time for the activity
"""
json_value = self._json_content['end_at']
return optional_datetime_from_json(json_value=json_value)
55 changes: 52 additions & 3 deletions src/pytito/admin/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@

from datetime import datetime

from ._base_client import AdminAPIBase
from ._base_client import AdminAPIBase, datetime_from_json
from .ticket import Ticket
from .release import Release
from .activity import Activity


class Event(AdminAPIBase):
Expand All @@ -36,6 +38,9 @@ def __init__(self, account_slug:str, event_slug:str,
super().__init__(json_content=json_content, api_key=api_key)
self.__account_slug = account_slug
self.__event_slug = event_slug
if json_content is not None:
if self._json_content['_type'] != "event":
raise ValueError('JSON content type was expected to be ticket')

@property
def _account_slug(self) -> str:
Expand All @@ -45,7 +50,6 @@ def _account_slug(self) -> str:
def _event_slug(self) -> str:
return self.__event_slug


@property
def _end_point(self) -> str:
return super()._end_point + f'/{self._account_slug}/{self._event_slug}'
Expand Down Expand Up @@ -79,4 +83,49 @@ def start_at(self) -> datetime:
"""
Start date and time for the event
"""
return datetime.fromisoformat(self._json_content['start_at'])
json_content = self._json_content['start_at']
return datetime_from_json(json_value=json_content)

@property
def end_at(self) -> datetime:
"""
End date and time for the event
"""
json_content = self._json_content['end_at']
return datetime_from_json(json_value=json_content)

def __release_getter(self) -> dict[str, Release]:

def release_factory(json_content:dict[str, Any]) -> tuple[str, Release]:
release_slug = json_content['slug']
return release_slug, Release(event_slug=self.__event_slug,
account_slug=self._account_slug,
release_slug=release_slug,
json_content=json_content)

response = self._get_response('releases')
return dict(release_factory(release) for release in response['releases'])

@property
def releases(self) -> dict[str, Release]:
"""
retrieve all the releases for the event
"""
return self.__release_getter()

def __activity_getter(self) -> list[Activity]:

def activity_factory(json_content:dict[str, Any]) -> Activity:
activity_id = json_content['id']
return Activity(event_slug=self.__event_slug, account_slug=self._account_slug,
activity_id=activity_id, json_content=json_content)

response = self._get_response('activities')
return [activity_factory(activity) for activity in response['activities']]

@property
def activities(self) -> list[Activity]:
"""
retrieve all the activities for the event
"""
return self.__activity_getter()
95 changes: 95 additions & 0 deletions src/pytito/admin/release.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"""
pytito is a python wrapper for the tito.io API
Copyright (C) 2024

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.

This file provides the release class
"""
from typing import Optional, Any
from datetime import datetime

from ._base_client import EventChildAPIBase, optional_datetime_from_json

class Release(EventChildAPIBase):
"""
One of the release for an event available through the Tito IO AdminAPI
"""

def __init__(self, *, account_slug:str, event_slug:str, release_slug:str,
json_content:Optional[dict[str, Any]]=None,
allow_automatic_json_retrieval: bool=False) -> None:
super().__init__(json_content=json_content,
account_slug=account_slug,
event_slug=event_slug,
allow_automatic_json_retrieval=allow_automatic_json_retrieval)
self.__release_slug = release_slug
if json_content is not None:
if self._json_content['_type'] != "release":
raise ValueError('JSON content type was expected to be release')

@property
def _release_slug(self) -> str:
return self.__release_slug

@property
def _end_point(self) -> str:
return super()._end_point +\
f'/{self._account_slug}/{self._event_slug}/releases/{self._release_slug}'

def _populate_json(self) -> None:
self._json_content = self._get_response(endpoint='')['release']
if self._release_slug != self._json_content['slug']:
raise ValueError('slug in json content does not match expected value')
if self._json_content['view'] != 'extended':
raise ValueError('expected the extended view of the ticket')
if self._json_content['_type'] != "release":
raise ValueError('JSON content type was expected to be release')

@property
def title(self) -> str:
"""
Title of the release
"""
return self._json_content['title']

@property
def secret(self) -> bool:
"""
Title of the release
"""
return self._json_content['secret']

@property
def start_at(self) -> Optional[datetime]:
"""
Start date and time for the release being available (i.e. when is it on sale)
"""
json_value = self._json_content['start_at']
return optional_datetime_from_json(json_value=json_value)

@property
def end_at(self) -> Optional[datetime]:
"""
End date and time for the release being available (i.e. when is it on sale)
"""
json_value = self._json_content['end_at']
return optional_datetime_from_json(json_value=json_value)

@property
def quantity(self) -> Optional[int]:
"""
The number of tickets who can attend. A value of `None` means there is no limit
"""
return self._json_content['quantity']
Loading