App¶
An App lists an app's details and gives you its tables. Get one from Quickbase.app(). Getting one doesn't contact Quickbase, so an ID that doesn't exist only fails on first use.
The examples below use app, made as shown here, in an app that has a table named Job Tasks with three records. A live test runs every example with both clients and checks its output. AsyncApp has the same methods, which you await, but table(), url(), and settings_url() are called without it.
from pyquickbase import Quickbase
with Quickbase(
realm="acme", token="your_user_token"
) as qb:
app = qb.app("bq1234567")
from pyquickbase import AsyncQuickbase
async with AsyncQuickbase(
realm="acme", token="your_user_token"
) as qb:
app = qb.app("bq1234567")
Look up the app's details¶
For the full picture, see Reading records.
The app's ID¶
The app's ID, as passed to qb.app().
id: str
Example
print(app.id)
print(app.id)
Output
bq1234567
Get the app's details¶
Get the app's metadata, from the client's cache if it's there.
Returns AppInfo
An AppInfo, with the app's id, name, description, time_zone, and date_format.
Raises
AuthenticationError: Quickbase doesn't recognize the app ID. It answers with a 401 here, rather than a 404.PermissionDeniedError: The token's role can't edit the app's structure.
info() -> AppInfo
Example
info = app.info()
print(info.id)
info = await app.info()
print(info.id)
Output
bq1234567
List tables¶
List the app's tables, from the cache unless refresh is set.
Parameters
refreshbool, defaultFalse
Ask Quickbase instead of using the client's cache, which keeps metadata for five minutes by default. A change made through this client updates the cache, so this is for changes made elsewhere, such as in the Quickbase interface.
Returns list[ TableInfo ]
A TableInfo for each table the token can see.
Raises
AuthenticationError: Quickbase doesn't recognize the app ID. It answers with a 401 here, rather than a 404.
tables(*, refresh: bool = False) -> list[TableInfo]
Example
tables = app.tables()
print(sorted(t.name for t in tables if "Job" in t.name))
tables = await app.tables()
print(sorted(t.name for t in tables if "Job" in t.name))
Output
['Job Projects', 'Job Tasks']
List roles¶
List the app's roles, from the cache unless refresh is set.
Quickbase has no API for reading or changing what a role can do.
Parameters
refreshbool, defaultFalse
Ask Quickbase instead of using the client's cache, which keeps metadata for five minutes by default. A change made through this client updates the cache, so this is for changes made elsewhere, such as in the Quickbase interface.
Returns list[ Role ]
A Role for each role in the app.
Raises
PermissionDeniedError: The token isn't an administrator's.
roles(*, refresh: bool = False) -> list[Role]
Example
roles = app.roles()
print(any(role.name == "Administrator" for role in roles))
roles = await app.roles()
print(any(role.name == "Administrator" for role in roles))
Output
True
List webhooks and automations¶
List the app's webhooks, Quickbase actions, notifications, subscriptions, reminders, and the automations that records trigger.
Quickbase leaves out scheduled automations, and doesn't say which changes set each one off. With a policy, only events on tables it shows are listed, without their owners.
Returns list[ AppEvent ]
An AppEvent for each, active or not.
Raises
PermissionDeniedError: The token isn't an administrator's.
events() -> list[AppEvent]
Example
events = app.events()
print([event.type for event in events if event.active])
events = await app.events()
print([event.type for event in events if event.active])
Output
[]
Get a table¶
For the full picture, see Reading records.
Get a table¶
Get a table in this app by name or ID. It's checked when first used.
This doesn't contact Quickbase, so a table that doesn't exist raises UnknownTableError on first use.
Parameters
name_or_idstr, required
The table's name, or its ID.
Returns Table
A Table.
table(name_or_id: str) -> Table
Example
tasks = app.table("Job Tasks")
print(tasks.count())
tasks = app.table("Job Tasks")
print(await tasks.count())
Output
3
Link to the Quickbase interface¶
For the full picture, see Using pyquickbase from an AI agent.
Link to the app¶
Link to the app's home page in Quickbase. This makes no network calls.
Returns str
The URL, on the client's realm.
url() -> str
Example
print(app.url())
print(app.url())
Output
https://acme.quickbase.com/nav/app/bq1234567/action/appoverview
Link to the app's settings¶
Link to the app's settings in Quickbase. This makes no network calls.
Returns str
The URL, on the client's realm.
settings_url() -> str
Example
print(app.settings_url())
print(app.settings_url())
Output
https://acme.quickbase.com/nav/app/bq1234567/action/appsettingshome
Create tables¶
For the full picture, see Changing the schema.
Get or create a table¶
Return the table with this name, creating it if it doesn't exist.
This makes a setup script safe to run again. An existing table isn't changed.
Parameters
namestr, required
The table's name, ignoring case when looking for an existing table.descriptionstr | None, optional
The new table's description.single_record_namestr | None, optional
What the new table calls one record, such asProject.plural_record_namestr | None, optional
What the new table calls several records, such asProjects.
Returns Table
A Table for the existing or new table.
Raises
AuthenticationError: Quickbase doesn't recognize the app ID, or the token can't reach it.BadRequestError: Quickbase refused to create the table.PolicyRefusedError: The client's policy doesn't allow creating a table. Nothing was created.
ensure_table(
name: str,
*,
description: str | None = None,
single_record_name: str | None = None,
plural_record_name: str | None = None,
) -> Table
Example
sites = app.ensure_table("Job Sites")
again = app.ensure_table("Job Sites")
first_info = sites.info()
again_info = again.info()
print(first_info.id == again_info.id)
sites = await app.ensure_table("Job Sites")
again = await app.ensure_table("Job Sites")
first_info = await sites.info()
again_info = await again.info()
print(first_info.id == again_info.id)
Output
True
Create a table¶
Create a table and return it.
Parameters
namestr, required
The table's name.descriptionstr | None, optional
The table's description.single_record_namestr | None, optional
What the table calls one record, such asProject.plural_record_namestr | None, optional
What the table calls several records, such asProjects.
Returns Table
A Table for the new table.
Raises
BadRequestError: The app already has a table with this name.
create_table(
name: str,
*,
description: str | None = None,
single_record_name: str | None = None,
plural_record_name: str | None = None,
) -> Table
Example
sites = app.create_table(
"Job Sites",
description="Where each job takes place.",
single_record_name="Site",
plural_record_name="Sites",
)
info = sites.info()
print(info.name)
sites = await app.create_table(
"Job Sites",
description="Where each job takes place.",
single_record_name="Site",
plural_record_name="Sites",
)
info = await sites.info()
print(info.name)
Output
Job Sites
Change the schema with a plan¶
For the full picture, see Changing the schema.
Preview schema changes¶
Work out what schema changes would do, without making them.
Each change is compared with the app as it is now, in order, so a later one can use a table or field an earlier one makes. The plan says what each would set, what else it would do or affect, such as records that lose a deleted field's values, and anything that stops it, including the client's own limits. A change the app already has counts as done, so planning again after a failed apply shows only what's left.
This only reads. It may count records, and look for duplicates before making a field unique, reading up to 10,000 records.
Parameters
changesSequence[SchemaChange], required
The changes, such asCreateField(table="Tasks", label="Due", type="date").
Returns SchemaPlan
A SchemaPlan, for apply_schema_changes().
Raises
InvalidValueError:changesis empty. Nothing was read.
preview_schema_changes(
changes: Sequence[SchemaChange],
) -> SchemaPlan
Example
from pyquickbase import CreateField
change = CreateField(
table="Job Tasks", label="Crew", type="text"
)
plan = app.preview_schema_changes([change])
for planned in plan.changes:
print(planned.status, planned.summary)
from pyquickbase import CreateField
change = CreateField(
table="Job Tasks", label="Crew", type="text"
)
plan = await app.preview_schema_changes([change])
for planned in plan.changes:
print(planned.status, planned.summary)
Output
ready Add field "Crew" (text) to Job Tasks.
Apply schema changes¶
Make the changes in a plan, in order, if the app hasn't changed since it was made.
The changes are planned again first, and nothing is sent unless that finds the same schema and nothing stopping them. Quickbase has no way to undo a change, so if one fails, the ones before it stay made, and the ones after it aren't attempted.
Parameters
planSchemaPlan, required
Frompreview_schema_changes().
Returns SchemaChangeResult
A SchemaChangeResult, with what was made and what was already there.
Raises
SchemaMismatchError: The schema has changed since the plan was made. Nothing was sent.InvalidValueError: The plan has blockers, or is for another app. Nothing was sent.SchemaChangeError: A change failed. Itsresultsays which were made.
apply_schema_changes(
plan: SchemaPlan,
) -> SchemaChangeResult
Example
from pyquickbase import CreateField
change = CreateField(
table="Job Tasks", label="Crew", type="text"
)
plan = app.preview_schema_changes([change])
result = app.apply_schema_changes(plan)
print(len(result.applied))
again = app.preview_schema_changes([change])
print(again.changes[0].status)
from pyquickbase import CreateField
change = CreateField(
table="Job Tasks", label="Crew", type="text"
)
plan = await app.preview_schema_changes([change])
result = await app.apply_schema_changes(plan)
print(len(result.applied))
again = await app.preview_schema_changes([change])
print(again.changes[0].status)
Output
1
already_done
Give a model the schema¶
For the full picture, see Using pyquickbase from an AI agent.
Make a schema tool for a model¶
Make a schema operation into a tool for a model, with its JSON Schema.
describe_schema lists the tables and fields the client can read. preview_schema_changes says what a list of changes would do, without making them, and apply_schema_changes makes them, but only with the confirmation that preview_schema_changes returned for exactly those changes, within 15 minutes, while the schema is as it was then. Show the person each plan before they approve it.
The schema offers only the kinds of change, tables, and field types the client's policy allows, and a plan reports anything it would refuse. Give the model a client with a policy, so that what it can change and see is limited, and a formula, lookup, or summary it adds can only show what it could already read.
plan = app.operation(
"preview_schema_changes"
)
tool = {
"name": "plan_changes",
"input_schema": plan.schema,
}
result = plan.run(arguments)
Parameters
nameSchemaOperationName, required
describe_schema,preview_schema_changes, orapply_schema_changes.max_changesint, default20
The most changes one plan may hold.
Returns SchemaOperation
A SchemaOperation, with its schema and run().
Raises
ConfigurationError:nameisn't a schema operation,max_changesisn't a positive whole number, or the client's policy allows no schema change forpreview_schema_changesorapply_schema_changes.
operation(
name: SchemaOperationName, *, max_changes: int = 20
) -> SchemaOperation
Example
plan = app.operation(
"preview_schema_changes", max_changes=5
)
print(plan.schema["properties"]["changes"]["maxItems"])
plan = await app.operation(
"preview_schema_changes", max_changes=5
)
print(plan.schema["properties"]["changes"]["maxItems"])
Output
5
Copy or delete the app¶
For the full picture, see Working with apps.
Copy the app¶
Copy this app, with the same tables, fields, reports, and forms, and return the copy.
Parameters
namestr, required
The copy's name. Quickbase allows several apps with the same name.descriptionstr | None, optional
The copy's description.keep_databool, defaultFalse
Copy the records too.
3 more: keep_files, keep_users, assign_token
keep_filesbool, defaultFalse
Withkeep_data, copy file attachments too.keep_usersbool, defaultFalse
Give the copy's users the roles they have here. Otherwise the roles are copied without anyone in them.assign_tokenbool, defaultTrue
Let this client's token reach the copy, which a token limited to some apps can't otherwise do.
Returns App
An App for the copy.
Raises
InvalidValueError:nameis empty. Nothing was sent.PermissionDeniedError: The token's user can't copy this app.PolicyRefusedError: The client has a policy, which covers one app. Nothing was sent.
copy(
name: str,
*,
description: str | None = None,
keep_data: bool = False,
keep_files: bool = False,
keep_users: bool = False,
assign_token: bool = True,
) -> App
Example
staging = app.copy("Jobs (staging)")
print(staging.id != app.id)
staging = await app.copy("Jobs (staging)")
print(staging.id != app.id)
Output
True
Delete the app¶
Delete this app, with all its tables and records. Quickbase can't undo this.
Parameters
confirmstr, required
The app's exact name, so a wrong variable can't delete the wrong app.
Raises
InvalidValueError:confirmisn't the app's exact name. Nothing was sent.PermissionDeniedError: The token's user can't delete this app.PolicyRefusedError: The client has a policy, which covers one app. Nothing was sent.
drop(*, confirm: str) -> None
Example
staging = app.copy("Jobs (staging)")
staging.drop(confirm="Jobs (staging)")
staging = await app.copy("Jobs (staging)")
await staging.drop(confirm="Jobs (staging)")