Skip to content

Endpoints adapters (Domains)

Endpoints are grouped under tags which represent a domain exposed by the API.

Calendar API exposes 2 domains:

  • Holidays: Holidays related operations
  • Bdays: Business Days related operations

Conceptually if we merge the results of both of them we will have the whole calendar

In the client side, the domains are represented as Resource adapters

BaseMixin

BaseMixin(client: Client, endpoints: dict = None, **kwargs)

Mixin Base class for resource-interaction with Calendar API.

Attributes:

  • resource_name (str) –

    Resource canonical name

  • model_type (ModelT) –

    Default model class of an endpoint

  • endpoints (dict) –

    A mapping of operation keys and endpoint URLS. Each operation has a unique key in the dict

Methods:

  • endpoint_by_operation

    Retrieve the endpoint URL from the deined method key in URLS (self.endpoints)

  • host_url

    Returns the host url from the client. self.client.base_url contains the /api/v1 path to ease the definition of operation keys.

  • json_from_response_or_raise

    Extract the json payload from the Response.

Source code in pycalendar_api/domains/base.py
26
27
28
29
30
31
32
33
def __init__(self, client: Client, endpoints: dict = None, **kwargs):
    self.client: Client = client
    if endpoints:
        self.endpoints = endpoints

    if self.endpoints is _UNSET:
        msg = f"endpoint not defined for the resource {self.resource_name}. {self.endpoints=}"
        raise CalendarAPIClientError(msg)

endpoint_by_operation

endpoint_by_operation(method: str) -> str

Retrieve the endpoint URL from the deined method key in URLS (self.endpoints) the key is in the form of {self.resource_name}:{method}.

Parameters:

  • method

    (str) –

    Operation key

Returns:

  • str ( str ) –

    Endpoint URL

Raises:

Source code in pycalendar_api/domains/base.py
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
def endpoint_by_operation(self, method: str) -> str:
    """Retrieve the endpoint URL from the deined method key in URLS (self.endpoints)
    the key is in the form of {self.resource_name}:{method}.

    Args:
        method (str): Operation key

    Returns:
        str: Endpoint URL

    Raises:
        CalendarAPIParamError: Method not defined
    """
    try:
        return self.endpoints[self._endpoint_key(method)]
    except KeyError as err:
        msg = f"{method} not defined in self.endpoints de key={err}.\n{self.endpoints=}"
        raise CalendarAPIParamError(msg)

host_url

host_url() -> str

Returns the host url from the client. self.client.base_url contains the /api/v1 path to ease the definition of operation keys.

Source code in pycalendar_api/domains/base.py
54
55
56
57
58
def host_url(self) -> str:
    """Returns the host url from the client. `self.client.base_url` contains the `/api/v1` path to ease the definition of operation keys.
    """
    from pycalendar_api.config import Settings
    return Settings().api.host

json_from_response_or_raise staticmethod

json_from_response_or_raise(
    response: Response, *, error_key: str = "detail"
) -> dict

Extract the json payload from the Response.

Parameters:

  • response

    (Response) –

    httpx Response

  • error_key

    ((str, detail), default: 'detail' ) –

    Error key name in the Json body

Returns:

  • dict ( dict ) –

    Json extracted from the response

Raises:

Source code in pycalendar_api/domains/base.py
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
@staticmethod
def json_from_response_or_raise(response: Response, *, error_key: str = "detail") -> dict:
    """Extract the json payload from the Response.

    Args:
        response (Response): httpx Response
        error_key (str, 'detail'): Error key name in the Json body

    Returns:
        dict: Json extracted from the response

    Raises:
        CalendarAPIClientError: If the HTTP response status is >= 400
    """
    if response.status_code >= 400:
        raise CalendarAPIClientError(response.json().get(error_key, default_message(response, error_key)))

    return response.json()

HolidaysResource

HolidaysResource(client: Session)

Methods:

  • endpoint_by_operation

    Retrieve the endpoint URL from the deined method key in URLS (self.endpoints)

  • host_url

    Returns the host url from the client. self.client.base_url contains the /api/v1 path to ease the definition of operation keys.

  • is_holiday

    Verify if the provided date is a Holiday. If True, also returns the description of that Holiday and its type.

  • json_from_response_or_raise

    Extract the json payload from the Response.

  • year

    Get the holidays of a year

  • years

    Get the holidays of many years

Source code in pycalendar_api/domains/holidays.py
17
18
def __init__(self, client: niquests.Session):
    super().__init__(client, endpoints=ENDPOINTS)

endpoint_by_operation

endpoint_by_operation(method: str) -> str

Retrieve the endpoint URL from the deined method key in URLS (self.endpoints) the key is in the form of {self.resource_name}:{method}.

Parameters:

  • method

    (str) –

    Operation key

Returns:

  • str ( str ) –

    Endpoint URL

Raises:

Source code in pycalendar_api/domains/base.py
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
def endpoint_by_operation(self, method: str) -> str:
    """Retrieve the endpoint URL from the deined method key in URLS (self.endpoints)
    the key is in the form of {self.resource_name}:{method}.

    Args:
        method (str): Operation key

    Returns:
        str: Endpoint URL

    Raises:
        CalendarAPIParamError: Method not defined
    """
    try:
        return self.endpoints[self._endpoint_key(method)]
    except KeyError as err:
        msg = f"{method} not defined in self.endpoints de key={err}.\n{self.endpoints=}"
        raise CalendarAPIParamError(msg)

host_url

host_url() -> str

Returns the host url from the client. self.client.base_url contains the /api/v1 path to ease the definition of operation keys.

Source code in pycalendar_api/domains/base.py
54
55
56
57
58
def host_url(self) -> str:
    """Returns the host url from the client. `self.client.base_url` contains the `/api/v1` path to ease the definition of operation keys.
    """
    from pycalendar_api.config import Settings
    return Settings().api.host

is_holiday

is_holiday(date: date) -> HolidayCheckResult

Verify if the provided date is a Holiday. If True, also returns the description of that Holiday and its type.

Parameters:

Returns:

Source code in pycalendar_api/domains/holidays.py
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
def is_holiday(self, date: datetime.date) -> HolidayCheckResult:
    """Verify if the provided date is a Holiday. If True, also returns the description of that Holiday and its type.

    Args:
        date (datetime.date): A date

    Returns:
        HolidayCheckResult: Result of the verification
    """
    key = 'is-holiday'
    pms = {'date': date}
    url = self.endpoint_by_operation(key)
    resp = self.client.get(url, params=pms)
    data = self.json_from_response_or_raise(resp)
    return self._struct_model(data, model_type=HolidayCheckResult)

json_from_response_or_raise staticmethod

json_from_response_or_raise(
    response: Response, *, error_key: str = "detail"
) -> dict

Extract the json payload from the Response.

Parameters:

  • response

    (Response) –

    httpx Response

  • error_key

    ((str, detail), default: 'detail' ) –

    Error key name in the Json body

Returns:

  • dict ( dict ) –

    Json extracted from the response

Raises:

Source code in pycalendar_api/domains/base.py
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
@staticmethod
def json_from_response_or_raise(response: Response, *, error_key: str = "detail") -> dict:
    """Extract the json payload from the Response.

    Args:
        response (Response): httpx Response
        error_key (str, 'detail'): Error key name in the Json body

    Returns:
        dict: Json extracted from the response

    Raises:
        CalendarAPIClientError: If the HTTP response status is >= 400
    """
    if response.status_code >= 400:
        raise CalendarAPIClientError(response.json().get(error_key, default_message(response, error_key)))

    return response.json()

year

year(
    year: int, *, holiday_type: CalHolidayType = None
) -> list[Holiday]

Get the holidays of a year

Parameters:

  • year

    (int) –

    the Year

  • holiday_type

    (`CalHolidayType`, default: None ) –

    Optional filter on holiday type. See CalHolidayType

Returns:

  • list[Holiday]

    list[Holiday]: Ordered list of holidays of one year

Source code in pycalendar_api/domains/holidays.py
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
def year(self, year: int, *, holiday_type: CalHolidayType=None) -> list[Holiday]:
    """Get the holidays of a year

    Args:
        year (int): the Year
        holiday_type (`CalHolidayType`): Optional filter on holiday type. See `CalHolidayType`

    Returns:
        list[Holiday]: Ordered list of holidays of one year
    """
    key = 'year'
    qp = {}
    pms = {'year': year}
    if holiday_type:
        qp = {'holiday_type': holiday_type}

    endpoint = self.endpoint_by_operation(key)
    url = endpoint.format(**pms)
    resp = self.client.get(url, params=qp)
    data = self.json_from_response_or_raise(resp)
    rv = [self._struct_model(d, model_type=Holiday) for d in data]
    return rv

years

Get the holidays of many years

Parameters:

  • years

    (Iterable[int]) –

    Iterable of years as int

  • holiday_type

    (`CalHolidayType`, default: None ) –

    Optional filter on holiday type. See CalHolidayType

Returns:

  • list[Holiday]

    list[Holiday]: Ordered list of holidays spanning many years

Source code in pycalendar_api/domains/holidays.py
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
def years(self, years: Iterable[int], *, holiday_type: CalHolidayType=None) -> list[Holiday]:
    """Get the holidays of many years

    Args:
        years (Iterable[int]): Iterable of years as int
        holiday_type (`CalHolidayType`): Optional filter on holiday type. See `CalHolidayType`

    Returns:
        list[Holiday]: Ordered list of holidays spanning many years
    """
    key = 'years'
    years = years if isinstance(years, Iterable) else [years]
    pms = {'years': years}
    if holiday_type:
        pms['holiday_type'] = holiday_type

    url = self.endpoint_by_operation(key)
    resp = self.client.get(url, params=pms)
    data = self.json_from_response_or_raise(resp)
    rv = [self._struct_model(d, model_type=Holiday) for d in data]
    return rv

BDaysResource

BDaysResource(client: Session)

Methods:

  • bdays_of

    Get the Business days of a year.

  • between

    Get the Business days between 2 dates

  • count

    Count the business days (inclusive) between 2 dates

  • endpoint_by_operation

    Retrieve the endpoint URL from the deined method key in URLS (self.endpoints)

  • host_url

    Returns the host url from the client. self.client.base_url contains the /api/v1 path to ease the definition of operation keys.

  • json_from_response_or_raise

    Extract the json payload from the Response.

  • next_date

    Returns the next Business day following the provided date

  • previous_date

    Returns the previous Business day before the provided date

  • span

    Get the Start/End dates of periods (Quarters, Semesters, Months) in the form of ]Start, End] (Open-Close Interval).

Source code in pycalendar_api/domains/bdays.py
17
18
def __init__(self, client: niquests.Session):
    super().__init__(client, endpoints=ENDPOINTS)

bdays_of

bdays_of(year: int, month: int = None) -> DateSeries

Get the Business days of a year.

Parameters:

  • year

    (int) –

    the year

  • month

    (int, default: None ) –

    If provided returns the business days of that month

Returns:

  • DateSeries ( DateSeries ) –

    Ordered Set of dates. The collection is under DateSeries.serie

Source code in pycalendar_api/domains/bdays.py
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
def bdays_of(self, year: int, month: int=None) -> DateSeries:
    """Get the Business days of a year.

    Args:
        year (int): the year
        month (int, optional): If provided returns the business days of that month

    Returns:
        DateSeries: Ordered Set of dates. The collection is under `DateSeries.serie`
    """
    key = 'year'
    pms = {'year': year}
    if month:
        key = 'month'
        pms['month'] = to_int(month)

    url = self.endpoint_by_operation(key)
    url = url.format(**pms)
    resp = self.client.get(url)
    data = self.json_from_response_or_raise(resp)
    return self._struct_model(data, model_type=DateSeries)

between

between(start: date, end: date) -> DateSeries

Get the Business days between 2 dates

Parameters:

Returns:

  • DateSeries ( DateSeries ) –

    Ordered Set of dates. The collection is under DateSeries.serie

Source code in pycalendar_api/domains/bdays.py
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
def between(self, start: datetime.date, end: datetime.date) -> DateSeries:
    """Get the Business days between 2 dates

    Args:
        start (datetime.date): Start date
        end (datetime.date): End date

    Returns:
        DateSeries: Ordered Set of dates. The collection is under `DateSeries.serie`
    """
    key = 'between'
    pms = {'start': start, 'end': end}
    url = self.endpoint_by_operation(key)
    resp = self.client.get(url, params=pms)
    data = self.json_from_response_or_raise(resp)
    return self._struct_model(data, model_type=DateSeries)

count

count(start: date, end: date) -> DaysCount

Count the business days (inclusive) between 2 dates

Parameters:

Returns:

  • DaysCount ( DaysCount ) –

    Days count datastruct

Source code in pycalendar_api/domains/bdays.py
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
def count(self, start: datetime.date, end: datetime.date) -> DaysCount:
    """Count the business days (inclusive) between 2 dates

    Args:
        start (datetime.date): Start date
        end (datetime.date): End date

    Returns:
        DaysCount: Days count datastruct
    """
    key = 'count'
    pms = {'start': start, 'end': end}
    url = self.endpoint_by_operation(key)
    resp = self.client.get(url, params=pms)
    data = self.json_from_response_or_raise(resp)
    return self._struct_model(data, model_type=DaysCount)

endpoint_by_operation

endpoint_by_operation(method: str) -> str

Retrieve the endpoint URL from the deined method key in URLS (self.endpoints) the key is in the form of {self.resource_name}:{method}.

Parameters:

  • method

    (str) –

    Operation key

Returns:

  • str ( str ) –

    Endpoint URL

Raises:

Source code in pycalendar_api/domains/base.py
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
def endpoint_by_operation(self, method: str) -> str:
    """Retrieve the endpoint URL from the deined method key in URLS (self.endpoints)
    the key is in the form of {self.resource_name}:{method}.

    Args:
        method (str): Operation key

    Returns:
        str: Endpoint URL

    Raises:
        CalendarAPIParamError: Method not defined
    """
    try:
        return self.endpoints[self._endpoint_key(method)]
    except KeyError as err:
        msg = f"{method} not defined in self.endpoints de key={err}.\n{self.endpoints=}"
        raise CalendarAPIParamError(msg)

host_url

host_url() -> str

Returns the host url from the client. self.client.base_url contains the /api/v1 path to ease the definition of operation keys.

Source code in pycalendar_api/domains/base.py
54
55
56
57
58
def host_url(self) -> str:
    """Returns the host url from the client. `self.client.base_url` contains the `/api/v1` path to ease the definition of operation keys.
    """
    from pycalendar_api.config import Settings
    return Settings().api.host

json_from_response_or_raise staticmethod

json_from_response_or_raise(
    response: Response, *, error_key: str = "detail"
) -> dict

Extract the json payload from the Response.

Parameters:

  • response

    (Response) –

    httpx Response

  • error_key

    ((str, detail), default: 'detail' ) –

    Error key name in the Json body

Returns:

  • dict ( dict ) –

    Json extracted from the response

Raises:

Source code in pycalendar_api/domains/base.py
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
@staticmethod
def json_from_response_or_raise(response: Response, *, error_key: str = "detail") -> dict:
    """Extract the json payload from the Response.

    Args:
        response (Response): httpx Response
        error_key (str, 'detail'): Error key name in the Json body

    Returns:
        dict: Json extracted from the response

    Raises:
        CalendarAPIClientError: If the HTTP response status is >= 400
    """
    if response.status_code >= 400:
        raise CalendarAPIClientError(response.json().get(error_key, default_message(response, error_key)))

    return response.json()

next_date

next_date(date: date) -> NextDate

Returns the next Business day following the provided date

Parameters:

Returns:

  • NextDate ( NextDate ) –

    Contains the requested date and the next open date

Source code in pycalendar_api/domains/bdays.py
76
77
78
79
80
81
82
83
84
85
86
87
88
def next_date(self, date: datetime.date) -> NextDate:
    """Returns the `next` Business day following the provided date

    Args:
        date (datetime.date): A date

    Returns:
        NextDate: Contains the requested date and the next open date
    """
    url = self.endpoint_by_operation('next')
    params = {'date': date}
    data = self.json_from_response_or_raise(self.client.get(url, params=params))
    return self._struct_model(data, model_type=NextDate)

previous_date

previous_date(date: date) -> PreviousDate

Returns the previous Business day before the provided date

Parameters:

Returns:

  • PreviousDate ( PreviousDate ) –

    Contains the requested date and the previous open date

Source code in pycalendar_api/domains/bdays.py
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
def previous_date(self, date: datetime.date) -> PreviousDate:
    """Returns the `previous` Business day before the provided date

    Args:
        date (datetime.date): A date

    Returns:
        PreviousDate: Contains the requested date and the previous open date
    """
    url = self.endpoint_by_operation('previous')
    params = {'date': date}
    data = self.json_from_response_or_raise(self.client.get(url, params=params))
    return self._struct_model(data, model_type=PreviousDate)

span

span(
    year: int,
    *,
    month: int = None,
    quarter: int = None,
    semester: int = None
) -> CalSpan

Get the Start/End dates of periods (Quarters, Semesters, Months) in the form of ]Start, End] (Open-Close Interval).

  • Start: The last Open Business day of the previous period

  • End: The last Open Business day of the period

Parameters:

  • year

    (int) –

    Span of a year

  • month

    (int, default: None ) –

    Span of a month, 1 <= month <= 12

  • quarter

    (int, default: None ) –

    Span of a quarter, 1 <= quarter <= 4

  • semester

    (int, default: None ) –

    Span of a semester, 1 <= semester <= 2

Returns:

  • CalSpan ( CalSpan ) –

    Span interval of the requested period

Raises:

Source code in pycalendar_api/domains/bdays.py
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
def span(self, year: int, *, month: int=None, quarter: int=None, semester: int=None) -> CalSpan:
    """Get the Start/End dates of periods (Quarters, Semesters, Months) in the form of ]`Start`, `End`] (Open-Close Interval).

    - `Start`: The last Open Business day of the previous period

    - `End`: The last Open Business day of the period

    Args:
        year (int): Span of a year
        month (int, optional): Span of a month, 1 <= month <= 12
        quarter (int, optional): Span of a quarter, 1 <= quarter <= 4
        semester (int, optional): Span of a semester, 1 <= semester <= 2

    Returns:
        CalSpan: Span interval of the requested period

    Raises:
        CalendarAPIParamError: Only one of the periods must be provided.
    """
    args = (month, quarter, semester)
    t_args = sum([x is None for x in args])
    # Au max un seul argument doit être renseigné.
    # On compte les arguments nuls, Si 2 ou tous renseignés t_args = (0, 1)
    if t_args < 2:
        raise CalendarAPIParamError(f"Pass ONLY one of the args: `month` or `quarter` or `semester`, received: {month=}, {quarter=}, {semester=}")

    key = None
    params = {'year': year}

    if t_args == 3:  # Span Year => All args are None
        key = 'span:year'
    elif month:  # Span Month
        params['month'] = month
        key = 'span:month'
    elif quarter:  # Span quarter
        params['quarter'] = quarter
        key = 'span:quarter'
    elif semester:  # Span semester
        params['semester'] = semester
        key = 'span:semester'

    url = self.endpoint_by_operation(key)
    resp = self.client.get(url, params=params)
    data = self.json_from_response_or_raise(resp)
    return self._struct_model(data, model_type=CalSpan)