chris.client.base

 1import abc
 2from typing import AsyncContextManager, Generic, Optional, Callable, TypeVar
 3
 4import aiohttp
 5from serde import from_dict
 6
 7from chris.link.collection_client import L, CollectionJsonApiClient
 8from chris.util.errors import raise_for_status
 9
10CSelf = TypeVar(
11    "CSelf", bound="BaseChrisClient"
12)  # can't wait for `Self` in Python 3.11!
13
14
15class BaseChrisClient(
16    Generic[L, CSelf],
17    CollectionJsonApiClient[L],
18    AsyncContextManager[CSelf],
19    abc.ABC,
20):
21    """
22    Provides the implementation for most of the read-only GET resources of ChRIS
23    and functions related to the client object's own usage.
24    """
25
26    @classmethod
27    async def new(
28        cls,
29        url: str,
30        max_search_requests: int = 100,
31        connector: Optional[aiohttp.BaseConnector] = None,
32        connector_owner: bool = True,
33        session_modifier: Optional[Callable[[aiohttp.ClientSession], None]] = None,
34    ) -> CSelf:
35        """
36        A constructor which creates the session for the `BaseChrisClient`
37        and makes an initial request to populate `collection_links`.
38
39        Parameters
40        ----------
41        url
42            ChRIS backend url, e.g. "https://cube.chrisproject.org/api/v1/"
43        max_search_requests
44            Maximum number of HTTP requests to make while retrieving items from a
45            paginated endpoint before raising `chris.util.search.TooMuchPaginationError`.
46            Use `max_search_requests=-1` to allow for "infinite" pagination
47            (well, you're still limited by Python's stack).
48        connector
49            [`aiohttp.BaseConnector`](https://docs.aiohttp.org/en/v3.8.3/client_advanced.html#connectors) to use.
50            If creating multiple client objects in the same program,
51            reusing connectors between them is more efficient.
52        connector_owner
53            If `True`, this client will close its `aiohttp.BaseConnector`
54        session_modifier
55            Called to mutate the created `aiohttp.ClientSession` for the object.
56            If the client requires authentication, define `session_modifier`
57            to add authentication headers to the session.
58        """
59        if not url.endswith("/api/v1/"):
60            raise ValueError("url must end with /api/v1/")
61        accept_json = {
62            "Accept": "application/json",
63            # 'Content-Type': 'application/vnd.collection+json',
64        }
65        # TODO maybe we want to wrap the session:
66        # - status == 4XX --> print response text
67        # - content-type: application/vnd.collection+json
68        session = aiohttp.ClientSession(
69            headers=accept_json,
70            raise_for_status=False,
71            connector=connector,
72            connector_owner=connector_owner,
73        )
74        if session_modifier is not None:
75            session_modifier(session)
76
77        async with session.get(url) as res:
78            await raise_for_status(res)
79            body = await res.json()
80        links = from_dict(cls._collection_type(), body["collection_links"])
81        return cls(
82            url=url,
83            s=session,
84            collection_links=links,
85            max_search_requests=max_search_requests,
86        )
87
88    async def __aenter__(self) -> CSelf:
89        return self
90
91    async def __aexit__(self, exc_type, exc_val, exc_tb):
92        await self.close()
93
94    async def close(self):
95        """
96        Close the HTTP session used by this client.
97        """
98        await self.s.close()
class BaseChrisClient(typing.Generic[~L, ~CSelf], chris.link.collection_client.CollectionJsonApiClient[~L], typing.AsyncContextManager[~CSelf], abc.ABC):
16class BaseChrisClient(
17    Generic[L, CSelf],
18    CollectionJsonApiClient[L],
19    AsyncContextManager[CSelf],
20    abc.ABC,
21):
22    """
23    Provides the implementation for most of the read-only GET resources of ChRIS
24    and functions related to the client object's own usage.
25    """
26
27    @classmethod
28    async def new(
29        cls,
30        url: str,
31        max_search_requests: int = 100,
32        connector: Optional[aiohttp.BaseConnector] = None,
33        connector_owner: bool = True,
34        session_modifier: Optional[Callable[[aiohttp.ClientSession], None]] = None,
35    ) -> CSelf:
36        """
37        A constructor which creates the session for the `BaseChrisClient`
38        and makes an initial request to populate `collection_links`.
39
40        Parameters
41        ----------
42        url
43            ChRIS backend url, e.g. "https://cube.chrisproject.org/api/v1/"
44        max_search_requests
45            Maximum number of HTTP requests to make while retrieving items from a
46            paginated endpoint before raising `chris.util.search.TooMuchPaginationError`.
47            Use `max_search_requests=-1` to allow for "infinite" pagination
48            (well, you're still limited by Python's stack).
49        connector
50            [`aiohttp.BaseConnector`](https://docs.aiohttp.org/en/v3.8.3/client_advanced.html#connectors) to use.
51            If creating multiple client objects in the same program,
52            reusing connectors between them is more efficient.
53        connector_owner
54            If `True`, this client will close its `aiohttp.BaseConnector`
55        session_modifier
56            Called to mutate the created `aiohttp.ClientSession` for the object.
57            If the client requires authentication, define `session_modifier`
58            to add authentication headers to the session.
59        """
60        if not url.endswith("/api/v1/"):
61            raise ValueError("url must end with /api/v1/")
62        accept_json = {
63            "Accept": "application/json",
64            # 'Content-Type': 'application/vnd.collection+json',
65        }
66        # TODO maybe we want to wrap the session:
67        # - status == 4XX --> print response text
68        # - content-type: application/vnd.collection+json
69        session = aiohttp.ClientSession(
70            headers=accept_json,
71            raise_for_status=False,
72            connector=connector,
73            connector_owner=connector_owner,
74        )
75        if session_modifier is not None:
76            session_modifier(session)
77
78        async with session.get(url) as res:
79            await raise_for_status(res)
80            body = await res.json()
81        links = from_dict(cls._collection_type(), body["collection_links"])
82        return cls(
83            url=url,
84            s=session,
85            collection_links=links,
86            max_search_requests=max_search_requests,
87        )
88
89    async def __aenter__(self) -> CSelf:
90        return self
91
92    async def __aexit__(self, exc_type, exc_val, exc_tb):
93        await self.close()
94
95    async def close(self):
96        """
97        Close the HTTP session used by this client.
98        """
99        await self.s.close()

Provides the implementation for most of the read-only GET resources of ChRIS and functions related to the client object's own usage.

@classmethod
async def new( cls, url: str, max_search_requests: int = 100, connector: Optional[aiohttp.connector.BaseConnector] = None, connector_owner: bool = True, session_modifier: Optional[Callable[[aiohttp.client.ClientSession], NoneType]] = None) -> ~CSelf:
27    @classmethod
28    async def new(
29        cls,
30        url: str,
31        max_search_requests: int = 100,
32        connector: Optional[aiohttp.BaseConnector] = None,
33        connector_owner: bool = True,
34        session_modifier: Optional[Callable[[aiohttp.ClientSession], None]] = None,
35    ) -> CSelf:
36        """
37        A constructor which creates the session for the `BaseChrisClient`
38        and makes an initial request to populate `collection_links`.
39
40        Parameters
41        ----------
42        url
43            ChRIS backend url, e.g. "https://cube.chrisproject.org/api/v1/"
44        max_search_requests
45            Maximum number of HTTP requests to make while retrieving items from a
46            paginated endpoint before raising `chris.util.search.TooMuchPaginationError`.
47            Use `max_search_requests=-1` to allow for "infinite" pagination
48            (well, you're still limited by Python's stack).
49        connector
50            [`aiohttp.BaseConnector`](https://docs.aiohttp.org/en/v3.8.3/client_advanced.html#connectors) to use.
51            If creating multiple client objects in the same program,
52            reusing connectors between them is more efficient.
53        connector_owner
54            If `True`, this client will close its `aiohttp.BaseConnector`
55        session_modifier
56            Called to mutate the created `aiohttp.ClientSession` for the object.
57            If the client requires authentication, define `session_modifier`
58            to add authentication headers to the session.
59        """
60        if not url.endswith("/api/v1/"):
61            raise ValueError("url must end with /api/v1/")
62        accept_json = {
63            "Accept": "application/json",
64            # 'Content-Type': 'application/vnd.collection+json',
65        }
66        # TODO maybe we want to wrap the session:
67        # - status == 4XX --> print response text
68        # - content-type: application/vnd.collection+json
69        session = aiohttp.ClientSession(
70            headers=accept_json,
71            raise_for_status=False,
72            connector=connector,
73            connector_owner=connector_owner,
74        )
75        if session_modifier is not None:
76            session_modifier(session)
77
78        async with session.get(url) as res:
79            await raise_for_status(res)
80            body = await res.json()
81        links = from_dict(cls._collection_type(), body["collection_links"])
82        return cls(
83            url=url,
84            s=session,
85            collection_links=links,
86            max_search_requests=max_search_requests,
87        )

A constructor which creates the session for the BaseChrisClient and makes an initial request to populate collection_links.

Parameters
  • url: ChRIS backend url, e.g. "https://cube.chrisproject.org/api/v1/"
  • max_search_requests: Maximum number of HTTP requests to make while retrieving items from a paginated endpoint before raising chris.util.search.TooMuchPaginationError. Use max_search_requests=-1 to allow for "infinite" pagination (well, you're still limited by Python's stack).
  • connector: aiohttp.BaseConnector to use. If creating multiple client objects in the same program, reusing connectors between them is more efficient.
  • connector_owner: If True, this client will close its aiohttp.BaseConnector
  • session_modifier: Called to mutate the created aiohttp.ClientSession for the object. If the client requires authentication, define session_modifier to add authentication headers to the session.
async def close(self):
95    async def close(self):
96        """
97        Close the HTTP session used by this client.
98        """
99        await self.s.close()

Close the HTTP session used by this client.

Inherited Members
chris.link.collection_client.CollectionJsonApiClient
CollectionJsonApiClient
url
chris.link.linked.Linked
max_search_requests