Package: pyqbclient
$~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~$pyqbclientSimple Quickbase Table client moduleReport BugÂ·Request FeatureTable of ContentsAbout The ProjectBuilt WithGetting StartedRequirementsInstallationUsageRoadmapContributingLicenseContactAcknowledgmentsVersion 1.2.0Added download_files function to clientAdded future deprecation warning for get_filesImproved docstringsRefactored multiple functionsFixed bug in post_data where fields were created when subset was specified and field  was not in subsetVersion 1.1.1Added a function to download filesChanged a docstringAdded an error message for bad filter criteriaVersion 1.1.0Added return values for post_data, upload_files, create_fields, delete_fields, update_field, delete_recordsAdded a ten second sleep before retrying JSON requestscreate_fields now allows for manual multiple field creation by accepting a list of field dicts to the argument field_dict, previously multiple fields were only created if called within post_data using a DataFramePrefixed Client methods for internal use  with underscoresVersion 1.0.2Fixed an issue with columns in get_data where specifying a column with only sub columns would cause an ExceptionAdded Type HintingAdded some docstringsAdded a datatypeVersion 1.0.1Fixed a bug with columns in get_dataAdded support for UInt32Set a default sort option on queries as paginated queries were returning duplicates without itAbout The ProjectA  module for interacting with the Quickbase tables  via the API with an emphasis on
being easy to use. Everywhere the API calls for record or field IDs I have
changed it to work with values  or labels. Evolved from simple functions I wrote while getting started with python, has been useful for me, maybe you will find it useful as well.(back to top)Getting StartedRequirementsOlder versions of below untested, below known to work.Python (3.8+)numpy (1.21.4+)pandas (1.3.4+)requests (2.26.0+)lxml (4.6.4+)Installation1: Can be installed using pippip install pyqbclientUsageset_defaultBelow we supply our realm and token as defaults for all subsequent Client
instantiation. Note that both realm_hostname and user_token can be supplied
as arguments for the Client directly and that doing so will over-ride
any defaults set.  I have implemented some logging as well, so we will also configure thatimport pyqbclient as pyqbc
import logging
logging.basicConfig(level = logging.INFO)


my_realm = 'example-realm.quickbase.com'
my_token = 'example_token_string'


pyqbc.set_default(realm_hostname=my_realm,user_token=my_token)ClientClass pyqbclient.Client(table_id,realm_hostname=None,user_token=None,retries=3,dataframe=pd.DataFrame())Parameters:table_id:strThe Table ID you want to create a client forrealm_hostname:strYour quickbase realm hostnameuser_token:strYour quickbase API user tokenretries:intThe amount of retries desired for any given requestdataframe:pandas.DataFrame()The DataFrame associated with the Client, empty DataFrame passed so the editor knows it is a DataFrame.Below we will instantiate our Client, relying on the defaults we set abovemy_table_id = 'example_table_id'
my_table_client = pyqbc.Client(my_table_id)get_datapyqbclient.Client.get_data(report=None,columns=None,all_columns=False,overwrite_df=True,return_copy=True,filter_list_dict=None,where=None,**kwargs)Parameters:report:str, (optional)The name of a report you wish to download, e.g "List All"columns:list, (optional)A list of field labels corresponding to fields you wish to return, e.g ["Field1","Field2"]all_columns:bool, (optional)When True returns all fields as well as any properties of attachment/built in fields (versions, userName etc.)overwrite_df:bool, (optional)Overwrites the Client's DataFramereturn_copy:bool, (optional)Returns a copy of the Client's DataFramefilter_list_dict:dict, (optional)Query records based on a list of values. Takes a dictionary set up as below:{
'Field Label': ['Field_value_1','Field_value_2']
}where:str, (optional)Filter for queries using modified quickbase query language. Use the field label instead of the field ID, e.g. '{Record_ID#.EX.3}'**kwargs: * (optional)Valid kwargs are  sortBy and groupBy,  consult documentation for utilizationReturns: DataFrameBelow we will get a DataFrame based on the fields and records available in the "List All" reportdf = my_table_client.get_data(report='List All')Note: When called without any arguments returns default fields for all recordsFor more information on the quickbase query language, please refer to theDocumentationFor more information on the query parameters, please refer to theDocumentationdownload_filespyqbclient.Client.download_files(file_field: str, where: str= None,filter_list_dict: dict = None )Parameters:file_field:str,The label of the field with the file you wish to download"where:str, (optional)Filter for queries using modified quickbase query language. Use the field label instead of the field ID, e.g. '{Record_ID#.EX.3}'filter_list_dict:dict, (optional)Query records based on a list of values. Takes a dictionary set up as below:{
'Field Label': ['Field_value_1','Field_value_2']
}Returns: ListFunction will return a list of dictionaries with Field ID 3 values, file names and base64 encoded file strings as values .file_list = my_table_client.download_files(filter_list_dict={'Record ID#': ['6225', '6224']})For more information on the quickbase query language, please refer to theDocumentationFor more information on the query parameters, please refer to theDocumentationget_filespyqbclient.Client.get_files(file_field: str, where: str= None,filter_list_dict: dict = None )Warning:Will be deprecated in version 1.3.0. Please use download_files.Parameters:file_field:str,The label of the field with the file you wish to download"where:str, (optional)Filter for queries using modified quickbase query language. Use the field label instead of the field ID, e.g. '{Record_ID#.EX.3}'filter_list_dict:dict, (optional)Query records based on a list of values. Takes a dictionary set up as below:{
'Field Label': ['Field_value_1','Field_value_2']
}Returns: DictFunction will return a dictionary with Field id 3 values as keys and base64 encoded files as valuesfile_dict = my_table_client.get_files(filter_list_dict={'Record ID#': ['6225', '6224']})For more information on the quickbase query language, please refer to theDocumentationFor more information on the query parameters, please refer to theDocumentationpost_datapyqbclient.Client.post_data(external_df=None,step=5000, merge=None,create_if_missing=False, exclude_columns=None, subset=None)Parameters:external_df:DataFrame, (optional)The DataFrame you wish to upload. Omitting uses the client's internal DataFramestep:intThe amount of records to upload at a time. Quickbase has an upper limit of 10 MB per call, 5k has been pretty safe so far for my use.merge:str, (optional)The label of the field you wish to merge on, must be a unique field. Updates where possible, creates where not.create_if_missing:boolCreate fields in table for any columns in the DataFrame that are not present in the table.exclude_columns:listA list of columns in your DataFrame you do not wish to be uploadedsubset:listA list of columns in your DataFrame you wish to be uploaded while excluding all others (except merge if specified)Returns: dictReturns a dict with lists of created, updated and unchanged record ids as well as a count of processed recordsWill upload records to the table based on the DataFrame provided.my_table_client.post_data(external_df=df)create_fieldspyqbclient.Client.create_fields(field_dict=None,external_df=None,ignore_errors=False, appearsByDefault=True)Parameters:field_dict:list or dict, (optional)A dict or list of dicts for field creationexternal_df:dict, (optional)Create columns based on a DataFrameignore_errors:boolIgnore errors in creation and continueappearsByDefault:boolWhether or not this will be a default fieldReturns: listReturns a list with a dict for each field createdWill create fields with the given arguments.field_dict = {
  "label": "Field1",
  "fieldType": "text"
  }

my_table_client.create_fields(field_dict=field_dict)For more examples, please refer to theDocumentation(back to top)update_fieldpyqbclient.Client.update_field(field_label,field_dict = None,**kwargs)Parameters:field_label:strThe label of the field to updatefield_dict:dict, (optional)A dictionary for updating the field**kwargs:  (optional)Accepts label, noWrap, bold, required, appearsByDefault, findEnabled, unique, fieldHelp, addToForms, propertiesReturns: dictReturns a dict with updated field characteristicsWill update fields with the given argumentsmy_table_client.update_field("Field1",unique=True)For more examples, please refer to theDocumentationdelete_fieldspyqbclient.Client.delete_fields(field_labels)Parameters:field_labels:list**A list of field labels corresponding to fields **Returns: listReturns a list of deleted field idsWill delete the list of supplied fieldsmy_table_client.delete_fields(["Field1","Field2"])delete_recordspyqbclient.Client.delete_records(where=None,all_records=False)Parameters:where:str, (optional)Filter for deletion using modified quickbase query language. Use the field label instead of the field ID, e.g. '{Record_ID#.EX.3}'all_records:bool, (optional)Delete all records from the tableReturns: dictReturns a dict indicating the number of records deletedWill delete indicated records from the tableNOTE: One of where or all_records must be passed as an argument. Former default behaviour was to delete all records without an argument, thought it better to be explicitmy_table_client.delete_records(
  where='{Field1.EX."Some Value"}OR{Field1.EX."Some Other Value"}'
)upload_filespyqbclient.Client.upload_files(field_label, file_dict,
merge_field,try_internal=True)Parameters:field_label:strThe label of the field we are uploading the file tofile_dict:dictA dictionary  setup as below:{'Filename with extension':
{
'merge_value': 'The value you are merging on',
'file_str': 'Base64 encoded string of your file'
}
}merge_field:strThe label of the field we are merging ontry_internal:boolWhether or not we consult the Client's DataFrame for merge values.Returns: listReturns a list with a dict of record id and update id for each file uploadedUploads files to the given file field based on a value in a unique field.
When called, will create a dictionary using the supplied unique field
and built in Record ID# to facilitate the upload. try_internal will attempt
to use the Client's DataFrame before resorting to downloading from the table.Example usage belowpicture_hash = base64.b64encode(picture_IObytes.read()).decode()


file_dict = {
    'pic.png': {
    'file_str': picture_hash,
    'merge_value': 49
    }
}

my_table_client.upload_files('Attachment',file_dict,merge_field='Field1')ContributingContributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make aregreatly appreciated.If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement".
Don't forget to give the project a star! Thanks again!Fork the ProjectCreate your Feature Branch (git checkout -b feature/AmazingFeature)Commit your Changes (git commit -m 'Add some AmazingFeature')Push to the Branch (git push origin feature/AmazingFeature)Open a Pull Request(back to top)LicenseDistributed under the MIT License. SeeLICENSE.txtfor more information.(back to top)ContactJeff MacDonald -jeffmacd@protonmail.comProject Link:https://github.com/jeffmacd/pyqbclient(back to top)AcknowledgmentsSome XML functionality derived fromhttps://github.com/pyQuickBase/pyQuickBase(back to top)