Package: zbpy
zbpy: official Zetabase client for PythonThezbpypackage provides a pure-Python Zetabase client and reference implementation of the Zetabase protocol, along with integrations for commonly used Python tools like Numpy/Pandas.For more complete documentation, please refer to the main documentation section on the Zetabase website:Python quick startPython library referenceZetabase main documentationPrerequisites and external dependenciesPython 3.6 or highergccor equivalent compiler (except Windows)gmplibrary and headers (except Windows)Note: a C compiler is not required when runningzbpyon Windows. However, all requests made with ECDSA on Windows will be
slightly slower when compared to other operating systems due to limitations of the platform. We recommend that heavy workloads
on Windows use JWT authentication when possible.Installing gmp (if needed)OSX:brew install gmpUbuntu:apt-get install libgmp3-devCentos:yum install gmp gmp-devel gmp-statusNot required for Windows OS.InstallationRun the following to install:pip3installzbpyYou may get an error indicating you need to installcython. In this case, simply run the following:pip3installcythonAnd then re-runpip3 install zbpy.Creating an accountIf you do not have an account already you can easily create one through the Python client module. If you are using Juptyer notebooks, simply use the Jupyter account creation magic:fromzbpyimportclient%createaccountThe%createaccountmagic will run you through an interactive wizard to create a new Zetabase user identity.Otherwise, run the following code within the Python interactive shell to go through the same wizard
on the console:fromzbpyimportutilutil.new_account_interactive()Answer the prompts that will appear, and if the account is created successfully, three files will be created in your current directory. These are:your private key;your public key; andan identity file containing both keys along with your user ID.Test your installationTo test that everything has installed correctly run thetest_zbpymethod fromzbpy.utilin Jupyter or the Python interactive shell:fromzbpyimportutilutil.test_zbpy()Library usageCreating a Zetabase clientWhen you created your identity, you were assigned a user id (a uuid, or random-looking string of letters and numbers). use this to instantiate your client.fromzbpyimportclientzb_client=client.ZetabaseClient('YOUR USER ID')Connecting your client to ZetabaseTo use JWT authentication for all requestsWhen you created your identity, you created a "name" (handle) and administrator password. You can use these instead of your public and private keys if your tables are configured to allow it.zb.login_jwt('YOUR USERNAME','YOUR PASSWORD')To use ECDSA authentication for all requestszb_client.setup_ecdsa('FILEPATH TO PRIVATE KEY','FILEPATH TO PUBLIC KEY')Creating TablesWith PandasNote: There are two methods to create tables using zbpy. There are two optional parameters with both of the methods:perms: used to specify the permissions of the table (can also be added to an existing table using theadd_perm()method)allow_jwt: if true, allows data to be put into the table using JWT authentication.If you are creating a table to hold a Pandas dataframe, the easiest way is to use the following function. This will create a table with indexed fields that match the names and types of the columns of your dataframe, and then it inserts your dataframe into the given table using some given "dataframe key" to identify it.zb_client.put_dataframe_new_table('TABLE ID',YOURDATAFRAME,'YOUR DF KEY')If you would like a subset of the DataFrame's columns to be turned into indexed fields in the table use the 'specify_fields' parameter.zb_client.put_dataframe_new_table('Table ID',YOURDATAFRAME,'YOUR DF KEY',specify_fields=['age','height'])This field can be[]to not index any fields (i.e. if you have no intention of querying the table based on field values).Custom tables (no Pandas)In this case, we create a new table by passing in a set of zero or more fields to index and some given list of permissions, e.g.:fromzbpy.indexedfieldentityimportIndexedFieldfromzbpyimportzb_protocol_pb2aszbindex_age=IndexedField('age',zb.QueryOrdering.INTEGRAL_NUMBERS)index_height=IndexedField('height',zb.QueryOrdering.REAL_NUMBERS)zb_client.create_table('TABLE ID',zb.TableDataFormat.JSON,[index_age,index_height],[OPTIONALPERMS],allow_jwt=True)Creating permissions and adding them to existing tablesfromzbpy.permissionentityimportPermEntryfromzbpyimportzb_protocol_pb2aszbperm=PermEntry(zb.PermissionLevel.READ,zb.PermissionAudienceType.PUBLIC,'')zb_client.add_permission('TABLE ID',perm)Retrieving data and PaginationWhen using the functionslist_keys(),get(), andquery(), the data is returned as aGetPagesobject. AGetPagesobjects can be iterated over or turned into a Pandas dataframes using theto_dataframe()method (both demonstrated below).Retrieving keys from tablelist_keys=zb_client.list_keys('TABLE ID')keys=[keyforkeyinlist_keys]Retrieving data by keyresult=zb_client.get('TABLE ID',['KEY 1','KEY 2','KEY 3','etc.'])dataframe=result.to_dataframe()Retrieving data as objectsThereturn_prettymethod will pre-parse JSON objects for you.result=zb_client.get('TABLE ID',['KEY 1','KEY 2','KEY 3','etc.'])result.return_pretty()foriinresult:print(i)Retrieving data by queryTo query data from Zetabase, we have a Python-based DSL ("domain-specific language") that allows you to express queries. The idea is to useFieldobjects to represent indexed fields and to build queries based on them. We can then use comparison operators on each field to create a subquery, and we can combine subquery with logical operators. Seethe documentation for more information.The example below assumes that a table exists with indexed fields 'age' and 'name'. Queries use '&' and '|' for 'and' and 'or' operators -- for that reason, use parentheses to avoid operator precedence issues.fromzbpyimportqueriesage=Field('age')name=Field('name')query=((age==19)|((age>25)&(age<=27)))&(name=='Austin')result=zb_client.query('TABLE ID',query)foriinresult:print(i)Inserting dataTo insert a Pandas dataframe into an existing table, use theput_dataframe()method. Each row of the dataframe will be inserted as its own object, the collection of which is identified by a key: thedf_keyparameter. Dataframes can be appended to one another by simply storing a new dataframe using the samedf_keyon the same table as an existing dataframe.zb_client.put_dataframe('TABLE ID',YOURDATAFRAME,'YOUR DF KEY')To insert data without Pandas, we can useput_datafor a single object, orput_multifor a list of objects:zb_client.put_data('TABLE ID','DATA KEY',DATAASBYTES)zb_client.put_multi('TABLE ID',['KEY 1','KEY 2','KEY 3','etc.'],[DATA1ASBYTES,DATA2ASBYTES,etc.])NotesFor performance reasons, to insert multiple pieces of data, it is suggested to use theput_multi()method.When possible, if storing large quantities of data, it is faster to use JWT over ECDSA if possible.