A basic REST Firestore api.
Project description
Firestore4Kivy
A very basic, lightweight, machine independent Firestore API
2023-11-13 This repository is archived.
Introduction
The package contains methods to authorize and perform CRUD operations on a Firestore database. The data saved and retrieved is a constrained Python dict, constrained by the datatypes and resources available on Firestore. The implementation uses REST APIs.
Data is saved in a 'document' in a 'collection'. Firestore security rules that enable authorized public access to a document, and authorized private access to a document are compatible.
Nothing in this package is Kivy specific, however the motivation for the package is mobile devices and for Python that likely means Kivy.
Example Usage
Assuming a Firebase account has been created, a Firestore project has been configured, and the Firebase all authenticated users rule is specified.
In a real usage each access would be in its own thread.
Obtain the APIKEY and PROJECT_ID of a Firebase project.
from firestore4kivy import Authorize, Firestore
from math import pi
auth = Authorize(APIKEY)
success, response = auth.sign_in_with_email('email', 'password')
if success:
db = Firestore(PROJECT_ID)
db.enable_database(response)
data = {'name' : 'Random Hacker', 'favorite number' : pi }
success, result, update_time = db.create('collection', 'document', data)
if success:
success, result, update_time = db.read('collection', 'document')
if success:
field_to_update = {'favorite number' : 0 }
success, result, update_time = db.update('collection', 'document', field_to_update)
print(result) #{'name' : 'Random Hacker', 'favorite number' : 0 }
See also the example.
Install
Desktop
pip3 install firestore4kivy
Buildozer
requirements = python3, kivy, firestore4kivy, requests, urllib3, charset-normalizer==2.1.1, idna, certifi
android.permissions = INTERNET
kivy-ios
toolchain pip install firestore4kivy
Firestore
Checklist
This checklist is not a substitute for reading the Firebase documentation. See the Firebase quick start, and Firebase documentation.
-
Create a Firebase account and project.
- This generates the Project ID you will need for client apps.
-
Create API Key
Build->Authentication->Get started->sign-in method->Email/Password->Enable->Save
-
Firestore Database->Create Database
- Select security rules.
- Edit and publish new security rules.
- Select a geographic location for the server.
- Allow a few minutes for changes to propagate.
Security Rules
Successful implementation requires that the security rules are correctly implemented. The default rules deny access and must be changed. For development only, you can use the all authenticated users rule. As the name suggests this requires that the user is signed in.
Private documents will require the content-owner only access rule..
In practice the rules may be some hybrid, see the rules for the example.
Constraints
This section is not a substitute for reading Firestore usage and limits.
Some highlights:
-
The data dict values may contain
None
or values with Python data types:bool, int, float, str, bytes
. The dict may also contain three classes provided to access data types available in Firestore but not in Python, there areGeoPoint, TimeStamp, Reference
. -
The data dict may not contain values with Python data types:
bytearray, memoryview, tuple, complex, range, frozenset, set
, or any class other than the three that enable Firestore data types. -
A dict key is always cast to a string. There is potential for a conflict if you use integers and strings as dict keys.
-
A list may not contain a list as an element.
-
A document may have a maximum of slightly less than 20k indices (sum of all keys and all list lengths).
-
A document may have a maximum size of slightly less than 1MB.
If you are uncertain about violating Firestore constraints, as a test you can manually create your data structure in the Firebase console.
API
The methods must be called from a thread. If this is not done the Kivy UI will freeze for an undetermined time. A general example of using threads is documented.
The package contains an Authorize class, a Firestore class, and three classes to access custom Firestore data types.
Authorize
All methods return a tuple of two values, success and response. If success is True, response is a dict. If success is False, response is an error message string.
A user initially signs in and the app saves a refresh token. On restart, resume, or after a timeout the app re-signs in using the token. Firestore will time out 3600 seconds after the last sign in. A sign in response contains the refresh token (save it), and data to enable Firestore (re-enable with each new response).
Authorize Basic Usage
from firestore4kivy import Authorize
# Instantiate with an APIKEY
auth = Authorize(APIKEY)
# sign in
success, response = auth.sign_in_with_email('user', 'password')
Authorize API
def create_user_with_email(self, email, password):
return success, response
def sign_in_with_email(self, email, password):
return success, response
def sign_in_with_token(self, refresh_token):
return success, response
def delete_user(self, response):
return success, response
Firestore
All methods except enable_database return a tuple of three values, success, response, and update time. If success is True, response is a dict. If success is False, response is an error message string.
Firestore Basic Usage
from firestore4kivy import Firestore
# Instantiate with an PROJECT_ID
db = Firestore(PROJECT_ID)
# Enable the database with the response from sign in
db.enable_database(response)
# Create Document
data = {'name' : 'Joe', 'age' : 99}
success, response, update_time = db.create('collection', 'document', data)
Firestore API
Enable_database
The auth argument is the response from Authorize api calls.
def enable_database(self, auth):
Create, Read, Delete
The collection
and document
arguments are strings. The data
argument is a dict.
def create(self, collection, document, data):
return success, response, update_time
def read(self, collection, document):
return success, response, update_time
def delete(self, collection, document):
return success, response, update_time
To create a private document the collection or document is set to None
, the UserId will be substituted. This enables use of the Firestore the private document rule.
Update
The collection
and document
arguments are strings. The replace
, delete
, and callback method arguments are dicts. Examples below.
def update(self, collection, document, replace = {}, delete ={}, callback=None):
return success, response, update_time
The update()
method specifies changes to a created dict. It has three arguments used to update the document contents: replace, delete, and callback. One or all may be specified, they are applied in the above order.
Update is a secure read-modify-write operation. It ensures that another user will not corrupt the operation, the cost will be increased latency with heavily used shared documents. Single updates take fractions of a second, an update taking several seconds is a sign there are an excessive number of concurrent users and a failed update is possible. Do not implement update()
on a shared document if you expect heavy concurrent usage.
In a Python dict, a list is atomic. To access list elements we use a list of tuples [(index, new_value), (index, new_value),.... ]
, and specify the semantics as accessing list elements in a dict. Out of range indices are ignored.
Modification dicts are hierarchical. Check that root and intermediate dict keys are only specified once, otherwise one key will overwrite the other.
- replace: a dict of key value pairs to replace. Pairs that do not exist in the original document are created. An empty dict specifies no modification. Special case: a tuple representing a list index equal to list length implements append(). An example replace dict (taken from the example where you can find the dict to be modified):
# Equivalent statements
replace_these = {'b' : False, # ['b'] = False
'd' : {'c' : -43 , # ['d']['c'] = -43
'e' : [-10,-20,-30]},# ['d']['e'] =[-10,-20,-30]
'new' : True, # ['new'] = True
'a' : [(1,'negative'), # ['a'][1] = 'negative'
(4,'new')],} # ['a'].append('new')
# Note that for example ['d']['c'] and ['d']['e'] are hierarchical in the dict.
- delete: a dict of keys to remove, the values should be empty except when specifying hierarchy. Keys that do not exist are ignored. An empty dict removes no keys. A delete of multiple list elements in the same list does not depend on lexical order (unlike the equivalent statements). An example delete dict:
# Equivalent statements
delete_these = {'f':'', # pop('f')
'd': {'d' : {'aa': ''}}, # ['d']['d'].pop('aa')
'a': [(0,''), # d['a'].pop(0)
(3, {'yes': ''})] } # d['a'][2].pop('yes')
- callback: a user supplied method that has the dict of modified data as an argument. It can be used to implment a state machine, or for debugging use a print statement to see the modified dict. An example of a state machine:
def counter(self, data):
if 'counter' in data:
data['counter'] += 1
else:
data['counter'] = 0
Implement as:
success, response, update_time =\
db.update('secrets', None, replace_these, delete_these, self.couner)
GeoPoint, TimeStamp, and Reference
The package provides three classes to access data types that exist in Firestore but not in Python.
All are written with initialize parameters, and read by a get() method.
from firestore4kivy import GeoPoint, Timestamp, Reference
# Latitude and longitude take there usual range
GeoPoint(latitude, longitude).get() == { 'latitude' : latitude, 'longitude' :longitude}
# TimeStamp is a Firestore compatible ISO 8601 string
TimeStamp('2000-01-01T00:00:00Z').get() == '2000-01-01T00:00:00Z'
# Reference to a Firestore document that must exist
Reference('projects/{project}/databases/(default)/documents/{collection}/{document}).get() == 'projects/{project}/databases/(default)/documents/{collection}/{document}
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file firestore4kivy-0.0.1.tar.gz
.
File metadata
- Download URL: firestore4kivy-0.0.1.tar.gz
- Upload date:
- Size: 14.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.11.1
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 4cacf9a8c3f1a57fcfbcf402a1f1df961c868d323b9566fe016a366e3c21f587 |
|
MD5 | 365c78c802bef07da8f9cbd97e21fc93 |
|
BLAKE2b-256 | a1fdb406f2937ab9393bc9a5dca929036b020caefc472d4d44769e3db57a36ff |
File details
Details for the file firestore4kivy-0.0.1-py3-none-any.whl
.
File metadata
- Download URL: firestore4kivy-0.0.1-py3-none-any.whl
- Upload date:
- Size: 11.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.11.1
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | f93e6d82d475579fc850a50a3ec635d5118b80f93f74614349250680039cad2d |
|
MD5 | a8f57d2a51e9ca16bd7ea6073393d230 |
|
BLAKE2b-256 | e09ffd411785f0a5be72f1121e347d2eba7e1efabc9656b4f94f43b140737679 |