Package: etiket-client
etiket-clientA client library for accessing etiket  $e|i>$Logging in to etiketFirst, create a client:frometiket_clientimportClientclient=Client(base_url="https://etiket.example.com")#of course change base_urlYou can only use the unauthenticated client to call the login endpoint with your credentials to obtain a valid token:frometiket_clientimportClientfrometiket_client.api.accessimportlogin_for_access_tokenasget_tokenfrometiket_client.modelsimportBodyLoginForAccessTokenclient=Client(base_url="https://etiket.example.com")form_data=BodyLoginForAccessToken(username=username,password=password)token=get_token.sync(client=client,form_data=form_data)access_token=token.access_tokenrefresh_token=token.refresh_tokenOther endpoints require authentication, useAuthenticatedClientwith obtained access token as above:frometiket_clientimportAuthenticatedClientclient=AuthenticatedClient(base_url="https://etiket.example.com",#of course change base_urltoken="SuperSecretToken")Creating datasetsA minimal example of creating a dataset is shown below. Note that a scope should already be created and available to you.importshortuuidfromdatetimeimportdatetimefrometiket_client.modelsimportDatasetIn,DatasetOutfrometiket_client.api.datasetsimportcreate_datasetfrometiket_client.typesimportResponse<...youhaveobtainedtokensandcreatedclient:AuthenticatedClient...>dataset_new=DatasetIn(name='awesomedataset',uid=shortuuid.ShortUUID().random(length=10),scope='somescope',collected=datetime.now(),)response:DatasetOut=create_dataset.sync(client=client,json_body=dataset_new)# or if you need more info (e.g. status_code)response:Response[DatasetOut]=create_dataset.sync(client=client,json_body=dataset_new,)When a dataset is created, it requires a unique identifer string, uid. Above we created a random string of length 10 which would be unique enough for a lifetime, but you can choose your own way to create a unique identifier. This also allows already created datasets with a different type of uid (e.g. UUID, TUID) to be added easily to $e|i>$.  A single dataset can then be uniquely identified through 'scope/uid'. Although, a dataset is uniquely defined by the combination of a scope and uid, it is typically recognized by name, description, ranking and additional user defined metadata.Additionally, a list of files can also be defined upon creation of the dataset. Note that the files willnotbe uploaded upon creation of datasets. Upload is done explicitly via/uploadsendpoint or withetiket_client.api.tusmethods.frometiket_client.modelsimportDatasetIn,DatasetOutfrometiket_client.api.datasetsimportcreate_datasetfrometiket_client.typesimportResponsefile1=FileDatasetIn(name='filename1',uid=shortuuid.ShortUUID().random(length=10))file2=FileDatasetIn(name='filename2',uid=shortuuid.ShortUUID().random(length=10))dataset_new=DatasetIn(name='awesomedataset',scope='somescope',uid=shortuuid.ShortUUID().random(length=10),collected=datetime.now(),files=[file1,file2])dataset:DatasetOut=create_dataset.sync(client=client,json_body=dataset_new)Files can of course also be added after dataset creation by callingetiket_client.api.file.add_file.Collections and metadataDatasets can be grouped into collections. First a collection needs to be created, and subsequently datasets can be added to the collection:frometiket_client.modelsimportCollectionInfrometiket_client.api.collectionsimportcreate_collection,add_dataset_to_collectioncollection=create_collection.sync(client=client,json_body=CollectionIn(name='somecollection',scope='somescope',))response=add_dataset_to_collection.sync(client=client,scope='somescope',name=collection.name,dataset_uuid=dataset.uuid,)Datasets can also be removed from collections.Additional user defined metadata can be provided to datasets in JSON format, either upon creation of the dataset by adding a meta field or explicitly via metadata functions:dataset_new=DatasetIn(name='awesomedataset',scope='somescope',collected=datetime.now(),uid=shortuuid.ShortUUID().random(length=10),files=[file1,file2],meta={'key1':'value1','key2':['value2a','value2b']},)Note that the JSON document that can be added is limited in format. Only key-value pairs or key-list(values) pairs are allowed, where all keys and values are strings ( more than 2 and less than  20 characters). Arbitrary keys can be added, but not all keys can be used in dataset query. Only a predefined list of keys can be used when  querying datasets: sample, fridge, setup, measurement_type, variablesMeasured, keywords.Exploring datasetsA dataset is identified by a scope and UUID, but you can query or list datasets given a scope filtering on additional metadata to be able to browse through datasets:frometiket_client.api.datasetsimportget_datasetsdatasets=get_datasets.sync(client=client,scope='somescope',collection='somecollection',name='prefixofdataset',since=datetime.utcnow()-timedelta(days=100),until=datetime.utcnow()+timedelta(days=1),ranking=0,sample='samplename',fridge='bluefors',)Datasets are ordered by date of creation and use pagination to limit the number of datasets per request. Use offset and limit to move through pages.Via the ranking attribute of a dataset you can specify which datasets are filtered out of the query. Only datasets larger than the requested ranking will be returned. In this way, you can favour datasets over others.Uploading filesFile uploads are done using the tus.io protocol.tuspypackage which is included in this client can be used:tuspy docs.An etiket upload client can be initalized:frometiket_clientimportAuthenticatedClient,UploadClientclient=AuthenticatedClient(base_url="https://etiket.example.com",#of course change base_urltoken="SuperSecretToken")#initialize tus client with autenticated clienttus=UploadClient(client)#or optinally specify scopetus=UploadClient(client,scope=scope)#create uploader by specifying scope and file_uiduploader=tus.uploader('path/to/file',scope=scope,file_uid=file_uid)#or only file_uid if scope is already specified in UploadClientuploader=tus.uploader('path/to/file',file_uid=file_uid)#chunk size is sys.maxsize by default (probably quite large)#you can specify chunksizeuploader=tus.uploader('path/to/file',scope=scope,file_uid=file_uid,chunk_size=1024)#instead of path provide filestreamfs=open('path/to/file.ext',mode=)uploader=tus.uploader(file_stream=fs,scope=scope,file_uid=file_uid,chunk_size=200)# Upload a chunk i.e 200 bytes.uploader.upload_chunk()# Uploads the entire file.# This uploads chunk by chunk.uploader.upload()# you could increase the chunk size to reduce the# number of upload_chunk cycles.uploader.chunk_size=800uploader.upload()# Continue uploading chunks till total chunks uploaded reaches 1000 bytes.uploader.upload(stop_at=1000)Downloading filesFile downloads are done by using theget_filemethod. Optionally a range_ header can be added to do a partial download and perform downloads in parallel.