apitable 1.4.0__tar.gz → 1.4.2__tar.gz
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.
- {apitable-1.4.0 → apitable-1.4.2}/PKG-INFO +18 -11
- {apitable-1.4.0 → apitable-1.4.2}/apitable/datasheet/datasheet.py +12 -1
- {apitable-1.4.0 → apitable-1.4.2}/apitable/types/node.py +1 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/types/response.py +2 -0
- {apitable-1.4.0 → apitable-1.4.2}/pyproject.toml +2 -2
- apitable-1.4.0/apitable.egg-info/PKG-INFO +0 -310
- apitable-1.4.0/apitable.egg-info/SOURCES.txt +0 -58
- apitable-1.4.0/apitable.egg-info/dependency_links.txt +0 -1
- apitable-1.4.0/apitable.egg-info/requires.txt +0 -3
- apitable-1.4.0/apitable.egg-info/top_level.txt +0 -1
- apitable-1.4.0/setup.cfg +0 -4
- apitable-1.4.0/setup.py +0 -28
- apitable-1.4.0/test/test_apitable.py +0 -18
- apitable-1.4.0/test/test_create_datasheet.py +0 -30
- apitable-1.4.0/test/test_create_embed_link.py +0 -58
- apitable-1.4.0/test/test_create_field.py +0 -43
- apitable-1.4.0/test/test_create_records.py +0 -38
- apitable-1.4.0/test/test_delete_field.py +0 -37
- apitable-1.4.0/test/test_delete_records.py +0 -37
- apitable-1.4.0/test/test_get_fields.py +0 -31
- apitable-1.4.0/test/test_get_nodes.py +0 -32
- apitable-1.4.0/test/test_get_records.py +0 -45
- apitable-1.4.0/test/test_get_spaces.py +0 -25
- apitable-1.4.0/test/test_get_views.py +0 -24
- apitable-1.4.0/test/test_unit.py +0 -91
- apitable-1.4.0/test/test_update_records.py +0 -73
- apitable-1.4.0/test/test_upload_file.py +0 -32
- apitable-1.4.0/test/test_utils.py +0 -26
- {apitable-1.4.0 → apitable-1.4.2}/LICENSE +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/README.md +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/__init__.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/apitable.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/const.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/datasheet/__init__.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/datasheet/datasheet_manager.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/datasheet/field_manager.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/datasheet/query_set.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/datasheet/record.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/datasheet/record_manager.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/datasheet/view_manager.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/exceptions.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/node/__init__.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/node/node_manager.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/request.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/space/__init__.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/space/space.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/space/space_manager.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/types/__init__.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/types/embedlink.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/types/field.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/types/record.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/types/space.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/types/unit_model.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/types/view.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/unit/__init__.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/unit/member.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/unit/role.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/unit/team.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/unit/unit.py +0 -0
- {apitable-1.4.0 → apitable-1.4.2}/apitable/utils.py +0 -0
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: apitable
|
|
3
|
-
Version: 1.4.
|
|
4
|
-
Summary:
|
|
5
|
-
|
|
6
|
-
Author: apitable
|
|
3
|
+
Version: 1.4.2
|
|
4
|
+
Summary: APITable OpenAPI Python SDK
|
|
5
|
+
Author: APITable Ltd.
|
|
7
6
|
Author-email: dev@apitable.com
|
|
7
|
+
Requires-Python: >=3.8,<4.0
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
|
-
Classifier:
|
|
10
|
-
Classifier:
|
|
11
|
-
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Requires-Dist: certifi (>=2023.7.22,<2024.0.0)
|
|
14
|
+
Requires-Dist: charset-normalizer (>=3.2.0,<4.0.0)
|
|
15
|
+
Requires-Dist: environs (>=9.5.0,<10.0.0)
|
|
16
|
+
Requires-Dist: idna (>=3.4,<4.0)
|
|
17
|
+
Requires-Dist: marshmallow (>=3.20.1,<4.0.0)
|
|
18
|
+
Requires-Dist: pydantic (==2.5.3)
|
|
19
|
+
Requires-Dist: python-dotenv (>=1.0.0,<2.0.0)
|
|
20
|
+
Requires-Dist: requests (>=2.31.0,<3.0.0)
|
|
21
|
+
Requires-Dist: urllib3 (>=2.0.4,<3.0.0)
|
|
12
22
|
Description-Content-Type: text/markdown
|
|
13
|
-
License-File: LICENSE
|
|
14
|
-
Requires-Dist: requests<=2.31.0
|
|
15
|
-
Requires-Dist: pydantic==1.7
|
|
16
|
-
Requires-Dist: environs<=9.5.0
|
|
17
23
|
|
|
18
24
|
# APITable.py
|
|
19
25
|
|
|
@@ -308,3 +314,4 @@ pipenv install --pre
|
|
|
308
314
|
pipenv shell
|
|
309
315
|
python -m unittest test
|
|
310
316
|
```
|
|
317
|
+
|
|
@@ -57,6 +57,11 @@ class Datasheet:
|
|
|
57
57
|
return urljoin(self.apitable.api_base,
|
|
58
58
|
f"/fusion/v1/datasheets/{self.id}/records")
|
|
59
59
|
|
|
60
|
+
@property
|
|
61
|
+
def _record_api_endpoint_v3(self):
|
|
62
|
+
return urljoin(self.apitable.api_base,
|
|
63
|
+
f"/fusion/v3/datasheets/{self.id}/records")
|
|
64
|
+
|
|
60
65
|
@property
|
|
61
66
|
@timed_lru_cache(seconds=300)
|
|
62
67
|
def fields(self):
|
|
@@ -137,6 +142,12 @@ class Datasheet:
|
|
|
137
142
|
"""
|
|
138
143
|
Paginate to get data
|
|
139
144
|
"""
|
|
145
|
+
|
|
146
|
+
is_v3 = bool(kwargs.get("isV3", False))
|
|
147
|
+
endpoint = self._record_api_endpoint
|
|
148
|
+
if is_v3:
|
|
149
|
+
endpoint = self._record_api_endpoint_v3
|
|
150
|
+
|
|
140
151
|
params = {}
|
|
141
152
|
for key in kwargs:
|
|
142
153
|
if key in API_GET_DATASHEET_QS_SET:
|
|
@@ -147,7 +158,7 @@ class Datasheet:
|
|
|
147
158
|
else:
|
|
148
159
|
raise ErrorSortParams('The format of the sort parameter is incorrect')
|
|
149
160
|
params.update({key: params_value})
|
|
150
|
-
resp = self.apitable.request.get(
|
|
161
|
+
resp = self.apitable.request.get(endpoint, params=params)
|
|
151
162
|
return handle_response(resp, GETRecordResponse)
|
|
152
163
|
|
|
153
164
|
def get_records_all(self, **kwargs) -> List[RawRecord]:
|
|
@@ -104,9 +104,11 @@ class GETNodeListResponseData(BaseModel):
|
|
|
104
104
|
class GETNodeListResponse(ResponseBase):
|
|
105
105
|
data: GETNodeListResponseData
|
|
106
106
|
|
|
107
|
+
|
|
107
108
|
class GETSearchNodeListResponseData(BaseModel):
|
|
108
109
|
nodes: List[NodeSearchInfo]
|
|
109
110
|
|
|
111
|
+
|
|
110
112
|
class GETSearchNodeListResponse(ResponseBase):
|
|
111
113
|
data: GETSearchNodeListResponseData
|
|
112
114
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "apitable"
|
|
3
|
-
version = "1.4.
|
|
3
|
+
version = "1.4.2"
|
|
4
4
|
description = "APITable OpenAPI Python SDK"
|
|
5
5
|
authors = ["APITable Ltd. <dev@apitable.com>"]
|
|
6
6
|
readme = "README.md"
|
|
@@ -12,7 +12,7 @@ charset-normalizer = "^3.2.0"
|
|
|
12
12
|
environs = "^9.5.0"
|
|
13
13
|
idna = "^3.4"
|
|
14
14
|
marshmallow = "^3.20.1"
|
|
15
|
-
pydantic = "2.
|
|
15
|
+
pydantic = "2.5.3"
|
|
16
16
|
python-dotenv = "^1.0.0"
|
|
17
17
|
requests = "^2.31.0"
|
|
18
18
|
urllib3 = "^2.0.4"
|
|
@@ -1,310 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: apitable
|
|
3
|
-
Version: 1.4.0
|
|
4
|
-
Summary: Apitable Python SDK
|
|
5
|
-
Home-page: https://github.com/apitable/apitable-sdks
|
|
6
|
-
Author: apitable
|
|
7
|
-
Author-email: dev@apitable.com
|
|
8
|
-
Classifier: Programming Language :: Python :: 3
|
|
9
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
-
Classifier: Operating System :: OS Independent
|
|
11
|
-
Requires-Python: >=3.6
|
|
12
|
-
Description-Content-Type: text/markdown
|
|
13
|
-
License-File: LICENSE
|
|
14
|
-
Requires-Dist: requests<=2.31.0
|
|
15
|
-
Requires-Dist: pydantic==1.7
|
|
16
|
-
Requires-Dist: environs<=9.5.0
|
|
17
|
-
|
|
18
|
-
# APITable.py
|
|
19
|
-
|
|
20
|
-
[](https://pypi.python.org/pypi/apitable)
|
|
21
|
-
|
|
22
|
-
It is the official package for the Fusion API of APITable, and provides an API similar to the Django ORM style.
|
|
23
|
-
|
|
24
|
-
# Requirements
|
|
25
|
-
|
|
26
|
-
python3.6 +
|
|
27
|
-
|
|
28
|
-
If you want to call apitable rest api, you need get the API Token first: visit the workbench of APITable, click the avatar in the lower left corner, and go to User Center > Developer Configuration. Click to generate Token (you need to bind your email for the first time).
|
|
29
|
-
|
|
30
|
-
# Installation
|
|
31
|
-
|
|
32
|
-
```shell
|
|
33
|
-
pip install --upgrade apitable
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
# Getting started
|
|
37
|
-
|
|
38
|
-
## Example
|
|
39
|
-
|
|
40
|
-
```python
|
|
41
|
-
from apitable import Apitable
|
|
42
|
-
|
|
43
|
-
apitable = Apitable("your api_token")
|
|
44
|
-
|
|
45
|
-
dst = apitable.datasheet("your datasheet id")
|
|
46
|
-
# When the URL is used as a parameter, the datasheet id is automatically resolved, ignoring the view id.
|
|
47
|
-
# dst = apitable.datasheet("https://apitable.com/workbench/dstxxxxxxxx/viwxxxxxxxx")
|
|
48
|
-
|
|
49
|
-
# Create a record
|
|
50
|
-
record = dst.records.create({"title": "new record from Python SDK"})
|
|
51
|
-
print(record.title)
|
|
52
|
-
|
|
53
|
-
# Create records in bulk
|
|
54
|
-
records = dst.records.bulk_create([
|
|
55
|
-
{"title": "new record from Python SDK"},
|
|
56
|
-
{"title": "new record from Python SDK2"}
|
|
57
|
-
])
|
|
58
|
-
|
|
59
|
-
# Update a single field
|
|
60
|
-
record.title = "new title"
|
|
61
|
-
print(record.title)
|
|
62
|
-
# "new title"
|
|
63
|
-
|
|
64
|
-
# Update multiple fields
|
|
65
|
-
record.update({
|
|
66
|
-
"title": "new title",
|
|
67
|
-
"other_field": "new value",
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
# Batch update multiple records
|
|
71
|
-
records = dst.records.bulk_update([
|
|
72
|
-
{"recordId": "recxxxxx1", "fields":{"title": "new record.title from Python SDK"}},
|
|
73
|
-
{"recordId": "recxxxxx2", "fields":{"title": "new record.title from Python SDK2"}},
|
|
74
|
-
])
|
|
75
|
-
|
|
76
|
-
# Attachment field update
|
|
77
|
-
my_file = dst.upload_file( <local or network file path>)
|
|
78
|
-
record.files = [my_file]
|
|
79
|
-
|
|
80
|
-
# Filter record
|
|
81
|
-
songs = dst_songs.records.filter(artist="faye wong")
|
|
82
|
-
for song in songs:
|
|
83
|
-
print(song.title)
|
|
84
|
-
|
|
85
|
-
# Batch update a batch of records
|
|
86
|
-
dst_tasks.records.filter(title=None).update(status="Pending")
|
|
87
|
-
|
|
88
|
-
# Get a single record
|
|
89
|
-
book = dst_book.records.get(ISBN="9787506341271")
|
|
90
|
-
print(book.title)
|
|
91
|
-
|
|
92
|
-
# Convert the record object to json
|
|
93
|
-
record.json()
|
|
94
|
-
|
|
95
|
-
# Delete a batch of records that match the filter criteria
|
|
96
|
-
dst.records.filter(title=None).delete()
|
|
97
|
-
|
|
98
|
-
# Get fields
|
|
99
|
-
for field in apitable.datasheet("dstId").fields.all():
|
|
100
|
-
print(field.name)
|
|
101
|
-
|
|
102
|
-
# Get the fields of the specified view, hidden fields will not be returned
|
|
103
|
-
for field in apitable.datasheet("dstId").fields.all(viewId="viewId"):
|
|
104
|
-
print(field.name)
|
|
105
|
-
|
|
106
|
-
# Get views
|
|
107
|
-
for view in apitable.datasheet("dstId").views.all():
|
|
108
|
-
print(view.name)
|
|
109
|
-
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
## Field mapping
|
|
113
|
-
|
|
114
|
-
Using the field name of the datasheet directly as a variable may not conform to the variable specification. So you have to fall back to using fieldId as the key, making the code less readable.
|
|
115
|
-
|
|
116
|
-
In order to solve this problem, the Python SDK provides the function of field mapping.
|
|
117
|
-
|
|
118
|
-
| Bug title\! | Bug status |
|
|
119
|
-
| --------------------------------- | ---------- |
|
|
120
|
-
| The page crashes after logging in | Waiting |
|
|
121
|
-
|
|
122
|
-
```python
|
|
123
|
-
dst = apitable.datasheet("dstt3KGCKtp11fgK0t",field_key_map={
|
|
124
|
-
"title": "Bug title!",
|
|
125
|
-
"state": "Bug status",
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
record = dst.records.get()
|
|
129
|
-
print(record.title)
|
|
130
|
-
# "The page crashes after logging in"
|
|
131
|
-
print(record.state)
|
|
132
|
-
# "Waiting"
|
|
133
|
-
record.state="Done"
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
Keep the use of field id as the key
|
|
137
|
-
|
|
138
|
-
```python
|
|
139
|
-
bug = apitable.datasheet("dstn2lEFltyGHe2j86", field_key="id")
|
|
140
|
-
row = bug.records.get(flddpSLHEzDPQ="The page crashes after logging in")
|
|
141
|
-
row.flddpSLHEzDPQ = "The page crashes after logging in"
|
|
142
|
-
row.update({
|
|
143
|
-
"flddpSLHEzDPQ": "The page crashes after logging in",
|
|
144
|
-
"fldwvNDf9teD2": "Done"
|
|
145
|
-
})
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
When specifying `field_key="id"`, specify the corresponding key value of `field_key_map` should be `fieldId`
|
|
149
|
-
|
|
150
|
-
```python
|
|
151
|
-
bug = apitable.datasheet("dstn2lEFltyGHe2j86", field_key="id", field_key_map={
|
|
152
|
-
"title": "flddpSLHEzDPQ",
|
|
153
|
-
"state": "fldwvNDf9teD2",
|
|
154
|
-
})
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
# Documentation
|
|
158
|
-
|
|
159
|
-
## records
|
|
160
|
-
|
|
161
|
-
`dst.records` manage records in datasheets.
|
|
162
|
-
|
|
163
|
-
| Method | Parameter | Type | Description | Example |
|
|
164
|
-
| ---------------- | --------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- |
|
|
165
|
-
| create | dict | Record | Create a single record | `dst.records.create({"title":"new title"})` |
|
|
166
|
-
| bulk_create | dict[] | Record[] | Create multiple records in batches | `dst.records.bulk_create([{"title":"new record1"},{"title":"new record2"}])` |
|
|
167
|
-
| bulk_update | dict[] | Record[] | Batch update multiple records | `dst.records.bulk_update([{"recordId": "recxxxxx1", "fields":{"title": "new record.title from Python SDK"}}])` |
|
|
168
|
-
| all | \*\*kwargs | QuerySet | Return the record collection, you can pass parameters to customize the return content | `dst.records.all()` |
|
|
169
|
-
| get | \*\*kwargs | Record | single record | `dst.records.get(title="new title")` |
|
|
170
|
-
| get_or_create | (defaults,\*\*kwargs) | Record,bool | Query the corresponding record through kwargs. If it does not exist, create a new record in combination with defaults. The returned bool indicates whether it is a new record. | `dst.records.get_or_create(title="new title",defaults={"status":"pending"})` |
|
|
171
|
-
| update_or_create | (defaults,\*\*kwargs) | Record,bool | Query the corresponding record through kwargs, and update the record with defaults. Create if it does not exist (same as get_or_create) | `dst.records.update_or_create(title="new title",defaults={"status":"done"})` |
|
|
172
|
-
| filter | \*\*kwargs | QuerySet | Filter a batch of records | `dst.records.filter(title="new title")` |
|
|
173
|
-
|
|
174
|
-
## QuerySet
|
|
175
|
-
|
|
176
|
-
Chained calls are possible. For example, `qs = dst.records.all()` returns a batch of queried datasets.
|
|
177
|
-
|
|
178
|
-
| Method | Parameter | Type | Description | Example |
|
|
179
|
-
| ------ | --------- | -------- | ---------------------------------------- | -------------------------------------------------------- |
|
|
180
|
-
| filter | \*\*dict | QuerySet | Filter out a batch of records | `qs.filter(title="new title")` |
|
|
181
|
-
| all | / | QuerySet | Returns a copy of the current record set | `qs.filter(title="new title").all()` |
|
|
182
|
-
| get | \*\*dict | Record | Single record | `qs.get(title="new title")` |
|
|
183
|
-
| count | / | int | Total number of records | `qs.filter(title="new title").count()` |
|
|
184
|
-
| last | / | Record | Last record | `qs.filter(title="new title").last()` |
|
|
185
|
-
| first | / | Record | First record | `qs.filter(title="new title").first()` |
|
|
186
|
-
| update | \*\*dict | Record | Number of records successfully updated | `qs.filter(title="new title").update(title="new title")` |
|
|
187
|
-
| delete | / | bool | Whether the deletion is successful | `qs.filter(title="new title").delete()` |
|
|
188
|
-
|
|
189
|
-
## Record
|
|
190
|
-
|
|
191
|
-
The QuerySet queried out is a collection of Records. A single Record can obtain the value of the specified field through `record.fieldname`.
|
|
192
|
-
|
|
193
|
-
**Please try to avoid the same name of the field name and the method property reserved by Record, the field with the same name in the table will be obscured. If it does exist, use the field mapping configuration**
|
|
194
|
-
|
|
195
|
-
| Method/Attribute | Parameter | Type | Description | Example |
|
|
196
|
-
| ---------------- | --------- | ---- | ------------------------------------------------------------------------ | --------------- |
|
|
197
|
-
| json | / | dict | Returns all field values of the current record | `record.json()` |
|
|
198
|
-
| \_id | / | str | \_id is a reserved attribute, returns the recordId of the current record | `record._id` |
|
|
199
|
-
|
|
200
|
-
## Field
|
|
201
|
-
|
|
202
|
-
The mapping relationship between Field and Python data structure. The data with empty cells in the datasheet is always null, and the records returned by the API will not contain fields with null values.
|
|
203
|
-
|
|
204
|
-
| Field Type | Data type |
|
|
205
|
-
| ---------------- | ------------------- |
|
|
206
|
-
| SingleText | str |
|
|
207
|
-
| Text | str |
|
|
208
|
-
| SingleSelect | str |
|
|
209
|
-
| MultiSelect | str[] |
|
|
210
|
-
| URL | str |
|
|
211
|
-
| Phone | str |
|
|
212
|
-
| Email | str |
|
|
213
|
-
| Number | number |
|
|
214
|
-
| Currency | number |
|
|
215
|
-
| Percent | number |
|
|
216
|
-
| AutoNumber | number |
|
|
217
|
-
| DateTime | number |
|
|
218
|
-
| CreatedTime | number |
|
|
219
|
-
| LastModifiedTime | number |
|
|
220
|
-
| Attachment | attachment object[] |
|
|
221
|
-
| Member | unit object[] |
|
|
222
|
-
| Checkbox | bool |
|
|
223
|
-
| Rating | int |
|
|
224
|
-
| CreatedBy | unit object |
|
|
225
|
-
| LastModifiedBy | unit object |
|
|
226
|
-
| MagicLink | str[] |
|
|
227
|
-
| MagicLookUp | any[] |
|
|
228
|
-
| Formula | str / bool |
|
|
229
|
-
|
|
230
|
-
## all
|
|
231
|
-
|
|
232
|
-
all method will automatically handle paging loading all resources
|
|
233
|
-
|
|
234
|
-
_When the paging-related parameters (pageNum, pageSize) are passed in, the SDK will no longer automatically load all records, and only return the specified page data_。
|
|
235
|
-
|
|
236
|
-
> Try to avoid using the dst.records.all method without parameters to get all the data.
|
|
237
|
-
> The API can obtain a maximum of 1000 pieces of data per request. If your data volume is too large, it is close to the limit of 50000. In the case of no parameters, calling all will serially request the API 50 times. Not only is it very slow, but it consumes API request credit.
|
|
238
|
-
|
|
239
|
-
_Return the records of the specified pagination_
|
|
240
|
-
|
|
241
|
-
```python
|
|
242
|
-
dst.records.all(pageNum=3)
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
_Use with views_
|
|
246
|
-
|
|
247
|
-
Specifying the view id returns the same data as in the view.
|
|
248
|
-
|
|
249
|
-
```python
|
|
250
|
-
dst.records.all(viewId="viwxxxxxx")
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
_Filter data using formulas_
|
|
254
|
-
|
|
255
|
-
```python
|
|
256
|
-
dst.records.all(filterByFormula='{title}="hello"')
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
| Parameter | Type | Description | Example |
|
|
260
|
-
| --------------- | ------------------ | ----------------------------------------------------------------------------------------------------------- | ------------------------------------- |
|
|
261
|
-
| viewId | str | View ID. The request will return the filtered/sorted results in the view | |
|
|
262
|
-
| pageNum | int | Default 1 | |
|
|
263
|
-
| pageSize | int | Default 100, maximum 1000 | |
|
|
264
|
-
| sort | dict[] | Specify the sorting field, which overrides the view sorting conditions | `[{ field: 'field1', order: 'asc' }]` |
|
|
265
|
-
| recordIds | str[] | Returns the recordset with the specified recordId | `['recordId1', 'recordId2']` |
|
|
266
|
-
| fields | str[] | Only the specified fields will be returned | |
|
|
267
|
-
| filterByFormula | str | Returns matching records using formulas as filter criteria | |
|
|
268
|
-
| maxRecords | int | Limit the number of records returned, the default is 5000 | |
|
|
269
|
-
| cellFormat | 'json' or 'string' | Defaults to 'json', when specified as 'string' all values will be automatically converted to string format. | |
|
|
270
|
-
| fieldKey | 'name' or 'id' | Specifies the field query and returned key. The column name 'name' is used by default. | |
|
|
271
|
-
|
|
272
|
-
See: [Tutorial getting started with formulas](https://help.apitable.com/docs/guide/tutorial-getting-started-with-formulas)
|
|
273
|
-
|
|
274
|
-
## FAQ
|
|
275
|
-
|
|
276
|
-
### Can I get the field type (meta) information of the datasheet?
|
|
277
|
-
|
|
278
|
-
Can be get through the fields/views API.
|
|
279
|
-
|
|
280
|
-
### Can option be created automatically?
|
|
281
|
-
|
|
282
|
-
If you write to a non-existent option, the option will be created automatically
|
|
283
|
-
|
|
284
|
-
### How many records can a single datasheet?
|
|
285
|
-
|
|
286
|
-
5w records.
|
|
287
|
-
|
|
288
|
-
### Can more records be processed per request?
|
|
289
|
-
|
|
290
|
-
10 records. In the future, we will adjust the size of this limit according to the actual situation.
|
|
291
|
-
|
|
292
|
-
### Can more records be fetched per request?
|
|
293
|
-
|
|
294
|
-
The current maximum is 1000 records. In the future, we will adjust the size of this limit according to the actual situation.
|
|
295
|
-
|
|
296
|
-
# Development and test
|
|
297
|
-
|
|
298
|
-
Create a new `.env`, the content can refer to `.env.example`.
|
|
299
|
-
|
|
300
|
-
```shell
|
|
301
|
-
cp .env .env.example
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
Then modify the test code in the `test/` folder for testing.
|
|
305
|
-
|
|
306
|
-
```shell
|
|
307
|
-
pipenv install --pre
|
|
308
|
-
pipenv shell
|
|
309
|
-
python -m unittest test
|
|
310
|
-
```
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
LICENSE
|
|
2
|
-
README.md
|
|
3
|
-
pyproject.toml
|
|
4
|
-
setup.py
|
|
5
|
-
apitable/__init__.py
|
|
6
|
-
apitable/apitable.py
|
|
7
|
-
apitable/const.py
|
|
8
|
-
apitable/exceptions.py
|
|
9
|
-
apitable/request.py
|
|
10
|
-
apitable/utils.py
|
|
11
|
-
apitable.egg-info/PKG-INFO
|
|
12
|
-
apitable.egg-info/SOURCES.txt
|
|
13
|
-
apitable.egg-info/dependency_links.txt
|
|
14
|
-
apitable.egg-info/requires.txt
|
|
15
|
-
apitable.egg-info/top_level.txt
|
|
16
|
-
apitable/datasheet/__init__.py
|
|
17
|
-
apitable/datasheet/datasheet.py
|
|
18
|
-
apitable/datasheet/datasheet_manager.py
|
|
19
|
-
apitable/datasheet/field_manager.py
|
|
20
|
-
apitable/datasheet/query_set.py
|
|
21
|
-
apitable/datasheet/record.py
|
|
22
|
-
apitable/datasheet/record_manager.py
|
|
23
|
-
apitable/datasheet/view_manager.py
|
|
24
|
-
apitable/node/__init__.py
|
|
25
|
-
apitable/node/node_manager.py
|
|
26
|
-
apitable/space/__init__.py
|
|
27
|
-
apitable/space/space.py
|
|
28
|
-
apitable/space/space_manager.py
|
|
29
|
-
apitable/types/__init__.py
|
|
30
|
-
apitable/types/embedlink.py
|
|
31
|
-
apitable/types/field.py
|
|
32
|
-
apitable/types/node.py
|
|
33
|
-
apitable/types/record.py
|
|
34
|
-
apitable/types/response.py
|
|
35
|
-
apitable/types/space.py
|
|
36
|
-
apitable/types/unit_model.py
|
|
37
|
-
apitable/types/view.py
|
|
38
|
-
apitable/unit/__init__.py
|
|
39
|
-
apitable/unit/member.py
|
|
40
|
-
apitable/unit/role.py
|
|
41
|
-
apitable/unit/team.py
|
|
42
|
-
apitable/unit/unit.py
|
|
43
|
-
test/test_apitable.py
|
|
44
|
-
test/test_create_datasheet.py
|
|
45
|
-
test/test_create_embed_link.py
|
|
46
|
-
test/test_create_field.py
|
|
47
|
-
test/test_create_records.py
|
|
48
|
-
test/test_delete_field.py
|
|
49
|
-
test/test_delete_records.py
|
|
50
|
-
test/test_get_fields.py
|
|
51
|
-
test/test_get_nodes.py
|
|
52
|
-
test/test_get_records.py
|
|
53
|
-
test/test_get_spaces.py
|
|
54
|
-
test/test_get_views.py
|
|
55
|
-
test/test_unit.py
|
|
56
|
-
test/test_update_records.py
|
|
57
|
-
test/test_upload_file.py
|
|
58
|
-
test/test_utils.py
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
apitable
|
apitable-1.4.0/setup.cfg
DELETED
apitable-1.4.0/setup.py
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import setuptools
|
|
2
|
-
|
|
3
|
-
with open("README.md", "r") as fh:
|
|
4
|
-
long_description = fh.read()
|
|
5
|
-
|
|
6
|
-
with open(".version", "r") as fh:
|
|
7
|
-
version_number = fh.read()
|
|
8
|
-
|
|
9
|
-
setuptools.setup(
|
|
10
|
-
name="apitable",
|
|
11
|
-
version=version_number,
|
|
12
|
-
author="apitable",
|
|
13
|
-
author_email="dev@apitable.com",
|
|
14
|
-
description="Apitable Python SDK",
|
|
15
|
-
long_description=long_description,
|
|
16
|
-
long_description_content_type="text/markdown",
|
|
17
|
-
url="https://github.com/apitable/apitable-sdks",
|
|
18
|
-
packages=[
|
|
19
|
-
"apitable", "apitable.datasheet", "apitable.types", "apitable.node", "apitable.space", "apitable.unit"
|
|
20
|
-
],
|
|
21
|
-
classifiers=[
|
|
22
|
-
"Programming Language :: Python :: 3",
|
|
23
|
-
"License :: OSI Approved :: MIT License",
|
|
24
|
-
"Operating System :: OS Independent",
|
|
25
|
-
],
|
|
26
|
-
python_requires=">=3.6",
|
|
27
|
-
install_requires=["requests<=2.31.0", "pydantic==1.7", "environs<=9.5.0"],
|
|
28
|
-
)
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
from unittest.mock import patch
|
|
3
|
-
|
|
4
|
-
from apitable.space import Space
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class TestApitable(unittest.TestCase):
|
|
8
|
-
"""
|
|
9
|
-
base test class.
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
def setUp(self):
|
|
13
|
-
"""
|
|
14
|
-
set up.
|
|
15
|
-
"""
|
|
16
|
-
with patch('apitable.apitable') as mock_apitable:
|
|
17
|
-
self._apitable = mock_apitable
|
|
18
|
-
self._space = Space(self._apitable, 'test_space_id')
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
import warnings
|
|
3
|
-
from apitable import Apitable
|
|
4
|
-
from . import DOMAIN, TOKEN, SPACE_ID, FOLDER_ID
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class TestCreateDatasheet(unittest.TestCase):
|
|
8
|
-
"""Apitable Python SDK create datasheet test class
|
|
9
|
-
- Datasheet Creation SDK Test
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
def setUp(self):
|
|
13
|
-
"""Create a datasheet test class object initial hook:"""
|
|
14
|
-
warnings.simplefilter("ignore", ResourceWarning)
|
|
15
|
-
apitable = Apitable(TOKEN)
|
|
16
|
-
apitable.set_api_base(DOMAIN)
|
|
17
|
-
self.spc = apitable.space(SPACE_ID)
|
|
18
|
-
|
|
19
|
-
def test_datasheet_create(self):
|
|
20
|
-
"""Datasheet Creation SDK Test"""
|
|
21
|
-
req_data = {"name": "python_test_datasheet_create", "folderId": FOLDER_ID}
|
|
22
|
-
self.datasheet = self.spc.datasheets.create(req_data)
|
|
23
|
-
self.assertIsNotNone(self.datasheet.id)
|
|
24
|
-
|
|
25
|
-
def tearDown(self):
|
|
26
|
-
"""Create a Datasheet test class object destroy hook:"""
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if __name__ == "__main__":
|
|
30
|
-
unittest.main()
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import time
|
|
2
|
-
import unittest
|
|
3
|
-
import warnings
|
|
4
|
-
from apitable import Apitable
|
|
5
|
-
from apitable.types import EmbedLinkThemeEnum,EmbedLinkPermissionType
|
|
6
|
-
from . import DOMAIN, TOKEN, SPACE_ID, DATASHEET_ID
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class TestEmbedLinkCRD(unittest.TestCase):
|
|
10
|
-
def setUp(self):
|
|
11
|
-
warnings.simplefilter("ignore", ResourceWarning)
|
|
12
|
-
apitable = Apitable(TOKEN)
|
|
13
|
-
apitable.set_api_base(DOMAIN)
|
|
14
|
-
self.spc = apitable.space(SPACE_ID)
|
|
15
|
-
|
|
16
|
-
def test_embed_link_crd(self):
|
|
17
|
-
datasheet = self.spc.datasheet(DATASHEET_ID)
|
|
18
|
-
newEmbedLink = datasheet.create_embed_link(
|
|
19
|
-
{
|
|
20
|
-
"paylod": {
|
|
21
|
-
"primarySideBar": {"collapsed": False},
|
|
22
|
-
"viewControl": {
|
|
23
|
-
"viewId": "viwBBc0PMN3WB",
|
|
24
|
-
"tabBar": False,
|
|
25
|
-
"toolBar": {
|
|
26
|
-
"basicTools": False,
|
|
27
|
-
"shareBtn": False,
|
|
28
|
-
"widgetBtn": False,
|
|
29
|
-
"apiBtn": False,
|
|
30
|
-
"formBtn": False,
|
|
31
|
-
"historyBtn": False,
|
|
32
|
-
"robotBtn": False,
|
|
33
|
-
},
|
|
34
|
-
"collapsed": False,
|
|
35
|
-
},
|
|
36
|
-
"bannerLogo": True,
|
|
37
|
-
"permissionType": EmbedLinkPermissionType.READ_ONLY,
|
|
38
|
-
},
|
|
39
|
-
"theme": EmbedLinkThemeEnum.Light,
|
|
40
|
-
}
|
|
41
|
-
)
|
|
42
|
-
self.assertIsNotNone(newEmbedLink.linkId)
|
|
43
|
-
time.sleep(0.5)
|
|
44
|
-
embedLinks = datasheet.get_embed_links()
|
|
45
|
-
self.assertEqual(len(embedLinks), 1)
|
|
46
|
-
time.sleep(0.5)
|
|
47
|
-
isDeleted = datasheet.delete_embed_link(newEmbedLink.linkId)
|
|
48
|
-
self.assertTrue(isDeleted)
|
|
49
|
-
time.sleep(0.5)
|
|
50
|
-
embedLinks = datasheet.get_embed_links()
|
|
51
|
-
self.assertEqual(len(embedLinks), 0)
|
|
52
|
-
|
|
53
|
-
def tearDown(self):
|
|
54
|
-
"""Create an embed link test class object destroy hook:"""
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if __name__ == "__main__":
|
|
58
|
-
unittest.main()
|