pyquickbase 0.1.0a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,73 @@
1
+ """pyquickbase: an unofficial, typed Python SDK for the Quickbase API."""
2
+
3
+ from ._async._client import AsyncQuickbase
4
+ from ._async._resources import AsyncApp, AsyncRecordIterator, AsyncTable
5
+ from ._models import AppInfo, Field, Page, Record, Relationship, TableInfo
6
+ from ._query import F, WhereCondition, parse_where
7
+ from ._retry import RetryPolicy
8
+ from ._sync._client import Quickbase
9
+ from ._sync._resources import App, RecordIterator, Table
10
+ from ._version import __version__
11
+ from ._writes import RowError, WriteResult
12
+ from .errors import (
13
+ APIError,
14
+ AuthenticationError,
15
+ BadRequestError,
16
+ ConfigurationError,
17
+ InvalidResponseError,
18
+ InvalidValueError,
19
+ NetworkError,
20
+ NotFoundError,
21
+ PermissionDeniedError,
22
+ QueryError,
23
+ QuickbaseError,
24
+ RateLimitError,
25
+ ReadOnlyError,
26
+ RequestTimeoutError,
27
+ ServerError,
28
+ UnknownFieldError,
29
+ UnknownTableError,
30
+ WriteError,
31
+ )
32
+
33
+ __all__ = [
34
+ "APIError",
35
+ "App",
36
+ "AppInfo",
37
+ "AsyncApp",
38
+ "AsyncQuickbase",
39
+ "AsyncRecordIterator",
40
+ "AsyncTable",
41
+ "AuthenticationError",
42
+ "BadRequestError",
43
+ "ConfigurationError",
44
+ "F",
45
+ "Field",
46
+ "InvalidResponseError",
47
+ "InvalidValueError",
48
+ "NetworkError",
49
+ "NotFoundError",
50
+ "Page",
51
+ "PermissionDeniedError",
52
+ "QueryError",
53
+ "Quickbase",
54
+ "QuickbaseError",
55
+ "RateLimitError",
56
+ "ReadOnlyError",
57
+ "Record",
58
+ "RecordIterator",
59
+ "Relationship",
60
+ "RequestTimeoutError",
61
+ "RetryPolicy",
62
+ "RowError",
63
+ "ServerError",
64
+ "Table",
65
+ "TableInfo",
66
+ "UnknownFieldError",
67
+ "UnknownTableError",
68
+ "WhereCondition",
69
+ "WriteError",
70
+ "WriteResult",
71
+ "__version__",
72
+ "parse_where",
73
+ ]
File without changes
@@ -0,0 +1,151 @@
1
+ """The async Quickbase client."""
2
+
3
+ import re
4
+ from collections.abc import Collection, Mapping
5
+ from types import TracebackType
6
+ from typing import Any, Self
7
+
8
+ import httpx
9
+
10
+ from .._auth import UserTokenAuth
11
+ from .._config import (
12
+ DEFAULT_BASE_URL,
13
+ DEFAULT_TIMEOUT,
14
+ build_user_agent,
15
+ normalize_allowed_writes,
16
+ normalize_realm,
17
+ read_env,
18
+ validate_base_url,
19
+ validate_token,
20
+ )
21
+ from .._retry import RetryPolicy
22
+ from .._schema import SchemaCache
23
+ from ..errors import ConfigurationError
24
+ from ._resources import AsyncApp
25
+ from ._transport import AsyncTransport
26
+
27
+ DEFAULT_SCHEMA_TTL = 300.0
28
+ _APP_ID = re.compile(r"[A-Za-z0-9]+")
29
+
30
+
31
+ class AsyncQuickbase:
32
+ """A Quickbase API client. Use it as a context manager so connections get closed.
33
+
34
+ Args:
35
+ realm: Your realm, as `acme`, `acme.quickbase.com`, or a realm URL.
36
+ token: A Quickbase user token.
37
+ base_url: The API root. Must use HTTPS, except for loopback addresses.
38
+ retry: How to retry rate limits and connection failures.
39
+ timeout: Request timeout in seconds. Ignored if you pass `http_client`.
40
+ user_agent: Identifies your application, placed before the SDK's own User-Agent.
41
+ http_client: Your own configured httpx client, for proxies, custom TLS, event hooks,
42
+ or custom transports. You remain responsible for closing it.
43
+ schema_ttl: Seconds to cache app, table, and field metadata. Use 0 to disable caching.
44
+ read_only: Refuse any request that could change data, raising `ReadOnlyError`. Only GET
45
+ requests and record queries are sent, including through `request()`.
46
+ allowed_writes: Like `read_only`, but also allow these `(method, path)` pairs, such as
47
+ `{("POST", "/records")}`. Paths must match exactly.
48
+ """
49
+
50
+ def __init__(
51
+ self,
52
+ *,
53
+ realm: str,
54
+ token: str,
55
+ base_url: str = DEFAULT_BASE_URL,
56
+ retry: RetryPolicy | None = None,
57
+ timeout: float = DEFAULT_TIMEOUT,
58
+ user_agent: str | None = None,
59
+ http_client: httpx.AsyncClient | None = None,
60
+ schema_ttl: float = DEFAULT_SCHEMA_TTL,
61
+ read_only: bool = False,
62
+ allowed_writes: Collection[tuple[str, str]] | None = None,
63
+ ) -> None:
64
+ self._realm = normalize_realm(realm)
65
+ self._transport = AsyncTransport(
66
+ realm=self._realm,
67
+ auth=UserTokenAuth(validate_token(token)),
68
+ base_url=validate_base_url(base_url),
69
+ retry=RetryPolicy() if retry is None else retry,
70
+ timeout=timeout,
71
+ user_agent=build_user_agent(user_agent),
72
+ http_client=http_client,
73
+ allowed_writes=normalize_allowed_writes(read_only, allowed_writes),
74
+ )
75
+ self._schema = SchemaCache(schema_ttl)
76
+
77
+ @classmethod
78
+ def from_env(
79
+ cls,
80
+ *,
81
+ base_url: str = DEFAULT_BASE_URL,
82
+ retry: RetryPolicy | None = None,
83
+ timeout: float = DEFAULT_TIMEOUT,
84
+ user_agent: str | None = None,
85
+ http_client: httpx.AsyncClient | None = None,
86
+ schema_ttl: float = DEFAULT_SCHEMA_TTL,
87
+ read_only: bool = False,
88
+ allowed_writes: Collection[tuple[str, str]] | None = None,
89
+ ) -> Self:
90
+ """Create a client from the `QB_REALM` and `QB_USER_TOKEN` environment variables."""
91
+ realm, token = read_env()
92
+ return cls(
93
+ realm=realm,
94
+ token=token,
95
+ base_url=base_url,
96
+ retry=retry,
97
+ timeout=timeout,
98
+ user_agent=user_agent,
99
+ http_client=http_client,
100
+ schema_ttl=schema_ttl,
101
+ read_only=read_only,
102
+ allowed_writes=allowed_writes,
103
+ )
104
+
105
+ @property
106
+ def realm(self) -> str:
107
+ """The full realm hostname, such as `acme.quickbase.com`."""
108
+ return self._realm
109
+
110
+ def app(self, app_id: str) -> AsyncApp:
111
+ """Get an app by ID, the `bq...` part of its URL. This makes no network calls."""
112
+ if not _APP_ID.fullmatch(app_id):
113
+ raise ConfigurationError("An app ID contains only letters and numbers.")
114
+ return AsyncApp(self._transport, self._schema, app_id)
115
+
116
+ def clear_schema_cache(self) -> None:
117
+ """Forget cached metadata, for example after changing a table's fields."""
118
+ self._schema.clear()
119
+
120
+ async def request(
121
+ self,
122
+ method: str,
123
+ path: str,
124
+ *,
125
+ params: Mapping[str, Any] | None = None,
126
+ json: Any = None,
127
+ ) -> Any:
128
+ """Call any Quickbase endpoint directly and return its decoded JSON body.
129
+
130
+ This is the escape hatch for endpoints without a dedicated method. `path` is relative
131
+ to the API root, such as `/tables/abc123`, and the body is None if the response is empty.
132
+ """
133
+ return await self._transport.request(method, path, params=params, json=json)
134
+
135
+ async def aclose(self) -> None:
136
+ """Close connections. Safe to call more than once."""
137
+ await self._transport.aclose()
138
+
139
+ async def __aenter__(self) -> Self:
140
+ return self
141
+
142
+ async def __aexit__(
143
+ self,
144
+ exc_type: type[BaseException] | None,
145
+ exc: BaseException | None,
146
+ traceback: TracebackType | None,
147
+ ) -> None:
148
+ await self.aclose()
149
+
150
+ def __repr__(self) -> str:
151
+ return f"{type(self).__name__}(realm={self._realm!r})"