empyrebase 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- empyrebase-1.0.0/PKG-INFO +19 -0
- empyrebase-1.0.0/README.md +566 -0
- empyrebase-1.0.0/empyrebase/__init__.py +1 -0
- empyrebase-1.0.0/empyrebase/empyrebase.py +51 -0
- empyrebase-1.0.0/empyrebase/services/__init__.py +4 -0
- empyrebase-1.0.0/empyrebase/services/auth.py +131 -0
- empyrebase-1.0.0/empyrebase/services/database.py +254 -0
- empyrebase-1.0.0/empyrebase/services/firestore.py +174 -0
- empyrebase-1.0.0/empyrebase/services/storage.py +106 -0
- empyrebase-1.0.0/empyrebase/types/__init__.py +5 -0
- empyrebase-1.0.0/empyrebase/types/closable_sseclient.py +20 -0
- empyrebase-1.0.0/empyrebase/types/keep_auth_session.py +9 -0
- empyrebase-1.0.0/empyrebase/types/pyre.py +9 -0
- empyrebase-1.0.0/empyrebase/types/pyre_response.py +33 -0
- empyrebase-1.0.0/empyrebase/types/sseclient.py +167 -0
- empyrebase-1.0.0/empyrebase/types/stream.py +50 -0
- empyrebase-1.0.0/empyrebase/utils/__init__.py +32 -0
- empyrebase-1.0.0/empyrebase.egg-info/PKG-INFO +19 -0
- empyrebase-1.0.0/empyrebase.egg-info/SOURCES.txt +24 -0
- empyrebase-1.0.0/empyrebase.egg-info/dependency_links.txt +1 -0
- empyrebase-1.0.0/empyrebase.egg-info/requires.txt +7 -0
- empyrebase-1.0.0/empyrebase.egg-info/top_level.txt +1 -0
- empyrebase-1.0.0/setup.cfg +4 -0
- empyrebase-1.0.0/setup.py +27 -0
- empyrebase-1.0.0/tests/test_database.py +171 -0
- empyrebase-1.0.0/tests/test_setup.py +6 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: empyrebase
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A simple python wrapper for the Firebase API with current deps
|
|
5
|
+
Home-page: https://github.com/emrothenberg/empyrebase
|
|
6
|
+
Author: emrothenberg
|
|
7
|
+
License: MIT
|
|
8
|
+
Keywords: Firebase,Pyrebase,Google,Empyrebase
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.4
|
|
13
|
+
Requires-Dist: requests-toolbelt>=1.0.0
|
|
14
|
+
Requires-Dist: requests>=2.31
|
|
15
|
+
Requires-Dist: urllib3<2,>=1.21.1
|
|
16
|
+
Requires-Dist: google-cloud-storage>=2.18.2
|
|
17
|
+
Requires-Dist: oauth2client>=4.1.2
|
|
18
|
+
Requires-Dist: pyjwt>=2.8.0
|
|
19
|
+
Requires-Dist: pycryptodome>=3.6.4
|
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
# Empyrebase
|
|
2
|
+
|
|
3
|
+
A simple python wrapper for the [Firebase API](https://firebase.google.com).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```shell
|
|
8
|
+
pip install empyrebase
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Getting Started
|
|
12
|
+
|
|
13
|
+
### Python Version
|
|
14
|
+
|
|
15
|
+
Empyrebase was written for python 3 and will not work correctly with python 2.
|
|
16
|
+
|
|
17
|
+
### Add empyrebase to your application
|
|
18
|
+
|
|
19
|
+
For use with only user based authentication we can create the following configuration:
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
import empyrebase
|
|
23
|
+
|
|
24
|
+
config = {
|
|
25
|
+
"apiKey": "apiKey",
|
|
26
|
+
"authDomain": "projectId.firebaseapp.com",
|
|
27
|
+
"databaseURL": "https://databaseName.firebaseio.com",
|
|
28
|
+
"storageBucket": "projectId.appspot.com"
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
firebase = empyrebase.initialize_app(config)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
We can optionally add a [service account credential](https://firebase.google.com/docs/server/setup#prerequisites) to our
|
|
35
|
+
configuration that will allow our server to authenticate with Firebase as an admin and disregard any security rules.
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
import empyrebase
|
|
39
|
+
|
|
40
|
+
config = {
|
|
41
|
+
"apiKey": "apiKey",
|
|
42
|
+
"authDomain": "projectId.firebaseapp.com",
|
|
43
|
+
"databaseURL": "https://databaseName.firebaseio.com",
|
|
44
|
+
"storageBucket": "projectId.appspot.com",
|
|
45
|
+
"serviceAccount": "path/to/serviceAccountCredentials.json"
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
firebase = empyrebase.initialize_app(config)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Adding a service account will authenticate as an admin by default for all database queries, check out the
|
|
52
|
+
[Authentication documentation](#authentication) for how to authenticate users.
|
|
53
|
+
|
|
54
|
+
### Use Services
|
|
55
|
+
|
|
56
|
+
An empyrebase app can use multiple Firebase services.
|
|
57
|
+
|
|
58
|
+
```firebase.auth()``` - [Authentication](#authentication)
|
|
59
|
+
|
|
60
|
+
```firebase.database()``` - [Database](#database)
|
|
61
|
+
|
|
62
|
+
```firebase.storage()``` - [Storage](#storage)
|
|
63
|
+
|
|
64
|
+
```firebase.firestore()``` - [Firestore](#firestore)
|
|
65
|
+
|
|
66
|
+
Check out the documentation for each service for further details.
|
|
67
|
+
|
|
68
|
+
## Authentication
|
|
69
|
+
|
|
70
|
+
The ```sign_in_with_email_and_password()``` method will return user data including a token you can use to adhere to security rules.
|
|
71
|
+
|
|
72
|
+
Each of the following methods accepts a user token: ```get()```, ```push()```, ```set()```, ```update()```, ```remove()``` and ```stream()```.
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
# Get a reference to the auth service
|
|
76
|
+
auth = firebase.auth()
|
|
77
|
+
|
|
78
|
+
# Log the user in
|
|
79
|
+
user = auth.sign_in_with_email_and_password(email, password)
|
|
80
|
+
|
|
81
|
+
# Log the user in anonymously
|
|
82
|
+
user = auth.sign_in_anonymous()
|
|
83
|
+
|
|
84
|
+
# Add user info
|
|
85
|
+
user = auth.update_profile(display_name, photo_url, delete_attribute)
|
|
86
|
+
|
|
87
|
+
# Get user info
|
|
88
|
+
user = auth.get_account_info()
|
|
89
|
+
|
|
90
|
+
# Get a reference to the database service
|
|
91
|
+
db = firebase.database()
|
|
92
|
+
|
|
93
|
+
# data to save
|
|
94
|
+
data = {
|
|
95
|
+
"name": "Mortimer 'Morty' Smith"
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
# Pass the user's idToken to the push method
|
|
99
|
+
results = db.child("users").push(data, user['idToken'])
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Token expiry
|
|
103
|
+
|
|
104
|
+
A user's idToken expires after 1 hour, so be sure to use the user's refreshToken to avoid stale tokens.
|
|
105
|
+
```
|
|
106
|
+
user = auth.sign_in_with_email_and_password(email, password)
|
|
107
|
+
# before the 1 hour expiry:
|
|
108
|
+
user = auth.refresh(user['refreshToken'])
|
|
109
|
+
# now we have a fresh token
|
|
110
|
+
user['idToken']
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Custom tokens
|
|
114
|
+
|
|
115
|
+
You can also create users using [custom tokens](https://firebase.google.com/docs/auth/server/create-custom-tokens), for example:
|
|
116
|
+
```
|
|
117
|
+
token = auth.create_custom_token("your_custom_id")
|
|
118
|
+
```
|
|
119
|
+
You can also pass in additional claims.
|
|
120
|
+
```
|
|
121
|
+
token_with_additional_claims = auth.create_custom_token("your_custom_id", {"premium_account": True})
|
|
122
|
+
```
|
|
123
|
+
You can then send these tokens to the client to sign in, or sign in as the user on the server.
|
|
124
|
+
```
|
|
125
|
+
user = auth.sign_in_with_custom_token(token)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Manage Users
|
|
129
|
+
|
|
130
|
+
#### Creating users
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
auth.create_user_with_email_and_password(email, password)
|
|
134
|
+
```
|
|
135
|
+
Note: Make sure you have the Email/password provider enabled in your Firebase dashboard under Auth -> Sign In Method.
|
|
136
|
+
|
|
137
|
+
#### Verifying emails
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
auth.send_email_verification(user['idToken'])
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
#### Sending password reset emails
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
auth.send_password_reset_email("email")
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
#### Get account information
|
|
150
|
+
```python
|
|
151
|
+
auth.get_account_info(user['idToken'])
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
#### Refreshing tokens
|
|
155
|
+
```python
|
|
156
|
+
user = auth.refresh(user['refreshToken'])
|
|
157
|
+
```
|
|
158
|
+
#### Delete account
|
|
159
|
+
```python
|
|
160
|
+
auth.delete_user_account(user['idToken'])
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Database
|
|
164
|
+
|
|
165
|
+
You can build paths to your data by using the ```child()``` method.
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
db = firebase.database()
|
|
169
|
+
db.child("users").child("Morty")
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Save Data
|
|
173
|
+
|
|
174
|
+
#### push
|
|
175
|
+
|
|
176
|
+
To save data with a unique, auto-generated, timestamp-based key, use the ```push()``` method.
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
data = {"name": "Mortimer 'Morty' Smith"}
|
|
180
|
+
db.child("users").push(data)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
#### set
|
|
184
|
+
|
|
185
|
+
To create your own keys use the ```set()``` method. The key in the example below is "Morty".
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
data = {"name": "Mortimer 'Morty' Smith"}
|
|
189
|
+
db.child("users").child("Morty").set(data)
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
#### update
|
|
193
|
+
|
|
194
|
+
To update data for an existing entry use the ```update()``` method.
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
db.child("users").child("Morty").update({"name": "Mortiest Morty"})
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
#### remove
|
|
201
|
+
|
|
202
|
+
To delete data for an existing entry use the ```remove()``` method.
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
db.child("users").child("Morty").remove()
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
#### multi-location updates
|
|
209
|
+
|
|
210
|
+
You can also perform [multi-location updates](https://www.firebase.com/blog/2015-09-24-atomic-writes-and-more.html) with the ```update()``` method.
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
data = {
|
|
214
|
+
"users/Morty/": {
|
|
215
|
+
"name": "Mortimer 'Morty' Smith"
|
|
216
|
+
},
|
|
217
|
+
"users/Rick/": {
|
|
218
|
+
"name": "Rick Sanchez"
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
db.update(data)
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
To perform multi-location writes to new locations we can use the ```generate_key()``` method.
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
data = {
|
|
229
|
+
"users/"+ref.generate_key(): {
|
|
230
|
+
"name": "Mortimer 'Morty' Smith"
|
|
231
|
+
},
|
|
232
|
+
"users/"+ref.generate_key(): {
|
|
233
|
+
"name": "Rick Sanchez"
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
db.update(data)
|
|
238
|
+
```
|
|
239
|
+
#### Conditional Requests
|
|
240
|
+
|
|
241
|
+
It's possible to do conditional sets and removes by using the `conditional_set()` and `conitional_remove()` methods respectively. You can read more about conditional requests in Firebase [here](https://firebase.google.com/docs/reference/rest/database/#section-conditional-requests).
|
|
242
|
+
|
|
243
|
+
To use these methods, you first get the ETag of a particular path by using the `get_etag()` method. You can then use that tag in your conditional request.
|
|
244
|
+
|
|
245
|
+
```python
|
|
246
|
+
etag = db.child("users").child("Morty").get_etag()
|
|
247
|
+
data = {"name": "Mortimer 'Morty' Smith"}
|
|
248
|
+
db.child("users").child("Morty").conditional_set(data, etag["ETag"])
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
If the passed ETag does not match the ETag of the path in the database, the data will not be written, and both conditional request methods will return a single key-value pair with the new ETag to use of the following form:
|
|
252
|
+
|
|
253
|
+
```json
|
|
254
|
+
{ "ETag": "8KnE63B6HiKp67Wf3HQrXanujSM=", "value": "<current value>" }
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Here's an example of checking whether or not a conditional removal was successful:
|
|
258
|
+
|
|
259
|
+
```python
|
|
260
|
+
etag = db.child("users").child("Morty").get_etag()
|
|
261
|
+
response = db.child("users").child("Morty").conditional_remove(etag["ETag"])
|
|
262
|
+
if type(response) is dict and "ETag" in response:
|
|
263
|
+
etag = response["ETag"] # our ETag was out-of-date
|
|
264
|
+
else:
|
|
265
|
+
print("We removed the data successfully!")
|
|
266
|
+
```
|
|
267
|
+
Here's an example of looping to increase age by 1:
|
|
268
|
+
|
|
269
|
+
```python
|
|
270
|
+
etag = db.child("users").child("Morty").child("age").get_etag()
|
|
271
|
+
while type(etag) is dict and "ETag" in etag:
|
|
272
|
+
new_age = etag["value"] + 1
|
|
273
|
+
etag = db.child("users").child("Morty").child("age").conditional_set(new_age, etag["ETag"])
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Retrieve Data
|
|
277
|
+
|
|
278
|
+
#### val
|
|
279
|
+
Queries return a PyreResponse object. Calling ```val()``` on these objects returns the query data.
|
|
280
|
+
|
|
281
|
+
```
|
|
282
|
+
users = db.child("users").get()
|
|
283
|
+
print(users.val()) # {"Morty": {"name": "Mortimer 'Morty' Smith"}, "Rick": {"name": "Rick Sanchez"}}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
#### key
|
|
287
|
+
Calling ```key()``` returns the key for the query data.
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
user = db.child("users").get()
|
|
291
|
+
print(user.key()) # users
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
#### each
|
|
295
|
+
Returns a list of objects on each of which you can call ```val()``` and ```key()```.
|
|
296
|
+
|
|
297
|
+
```
|
|
298
|
+
all_users = db.child("users").get()
|
|
299
|
+
for user in all_users.each():
|
|
300
|
+
print(user.key()) # Morty
|
|
301
|
+
print(user.val()) # {"name": "Mortimer 'Morty' Smith"}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
#### get
|
|
305
|
+
|
|
306
|
+
To return data from a path simply call the ```get()``` method.
|
|
307
|
+
|
|
308
|
+
```python
|
|
309
|
+
all_users = db.child("users").get()
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
#### shallow
|
|
313
|
+
|
|
314
|
+
To return just the keys at a particular path use the ```shallow()``` method.
|
|
315
|
+
|
|
316
|
+
```python
|
|
317
|
+
all_user_ids = db.child("users").shallow().get()
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Note: ```shallow()``` can not be used in conjunction with any complex queries.
|
|
321
|
+
|
|
322
|
+
#### streaming
|
|
323
|
+
|
|
324
|
+
You can listen to live changes to your data with the ```stream()``` method.
|
|
325
|
+
|
|
326
|
+
```python
|
|
327
|
+
def stream_handler(message):
|
|
328
|
+
print(message["event"]) # put
|
|
329
|
+
print(message["path"]) # /-K7yGTTEp7O549EzTYtI
|
|
330
|
+
print(message["data"]) # {'title': 'empyrebase', "body": "etc..."}
|
|
331
|
+
|
|
332
|
+
my_stream = db.child("posts").stream(stream_handler)
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
You should at least handle `put` and `patch` events. Refer to ["Streaming from the REST API"][streaming] for details.
|
|
336
|
+
|
|
337
|
+
[streaming]: https://firebase.google.com/docs/reference/rest/database/#section-streaming
|
|
338
|
+
|
|
339
|
+
You can also add a ```stream_id``` to help you identify a stream if you have multiple running:
|
|
340
|
+
|
|
341
|
+
```
|
|
342
|
+
my_stream = db.child("posts").stream(stream_handler, stream_id="new_posts")
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
#### close the stream
|
|
346
|
+
|
|
347
|
+
```python
|
|
348
|
+
my_stream.close()
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### Complex Queries
|
|
352
|
+
|
|
353
|
+
Queries can be built by chaining multiple query parameters together.
|
|
354
|
+
|
|
355
|
+
```python
|
|
356
|
+
users_by_name = db.child("users").order_by_child("name").limit_to_first(3).get()
|
|
357
|
+
```
|
|
358
|
+
This query will return the first three users ordered by name.
|
|
359
|
+
|
|
360
|
+
#### order_by_child
|
|
361
|
+
|
|
362
|
+
We begin any complex query with ```order_by_child()```.
|
|
363
|
+
|
|
364
|
+
```python
|
|
365
|
+
users_by_name = db.child("users").order_by_child("name").get()
|
|
366
|
+
```
|
|
367
|
+
This query will return users ordered by name.
|
|
368
|
+
|
|
369
|
+
#### equal_to
|
|
370
|
+
|
|
371
|
+
Return data with a specific value.
|
|
372
|
+
|
|
373
|
+
```python
|
|
374
|
+
users_by_score = db.child("users").order_by_child("score").equal_to(10).get()
|
|
375
|
+
```
|
|
376
|
+
This query will return users with a score of 10.
|
|
377
|
+
|
|
378
|
+
#### start_at and end_at
|
|
379
|
+
|
|
380
|
+
Specify a range in your data.
|
|
381
|
+
|
|
382
|
+
```python
|
|
383
|
+
users_by_score = db.child("users").order_by_child("score").start_at(3).end_at(10).get()
|
|
384
|
+
```
|
|
385
|
+
This query returns users ordered by score and with a score between 3 and 10.
|
|
386
|
+
|
|
387
|
+
#### limit_to_first and limit_to_last
|
|
388
|
+
|
|
389
|
+
Limits data returned.
|
|
390
|
+
|
|
391
|
+
```python
|
|
392
|
+
users_by_score = db.child("users").order_by_child("score").limit_to_first(5).get()
|
|
393
|
+
```
|
|
394
|
+
This query returns the first five users ordered by score.
|
|
395
|
+
|
|
396
|
+
#### order_by_key
|
|
397
|
+
|
|
398
|
+
When using ```order_by_key()``` to sort your data, data is returned in ascending order by key.
|
|
399
|
+
|
|
400
|
+
```python
|
|
401
|
+
users_by_key = db.child("users").order_by_key().get()
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
#### order_by_value
|
|
405
|
+
|
|
406
|
+
When using ```order_by_value()```, children are ordered by their value.
|
|
407
|
+
|
|
408
|
+
```python
|
|
409
|
+
users_by_value = db.child("users").order_by_value().get()
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
## Storage
|
|
414
|
+
|
|
415
|
+
The storage service allows you to upload images to Firebase.
|
|
416
|
+
|
|
417
|
+
### child
|
|
418
|
+
|
|
419
|
+
Just like with the Database service, you can build paths to your data with the Storage service.
|
|
420
|
+
|
|
421
|
+
```python
|
|
422
|
+
storage.child("images/example.jpg")
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### put
|
|
426
|
+
|
|
427
|
+
The put method takes the path to the local file and an optional user token.
|
|
428
|
+
|
|
429
|
+
```python
|
|
430
|
+
storage = firebase.storage()
|
|
431
|
+
# as admin
|
|
432
|
+
storage.child("images/example.jpg").put("example2.jpg")
|
|
433
|
+
# as user
|
|
434
|
+
storage.child("images/example.jpg").put("example2.jpg", user['idToken'])
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### download
|
|
438
|
+
|
|
439
|
+
The download method takes the path to the saved database file and the name you want the downloaded file to have.
|
|
440
|
+
|
|
441
|
+
```
|
|
442
|
+
storage.child("images/example.jpg").download("downloaded.jpg")
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
### get_url
|
|
446
|
+
|
|
447
|
+
The get_url method takes the path to the saved database file and user token which returns the storage url.
|
|
448
|
+
|
|
449
|
+
```
|
|
450
|
+
storage.child("images/example.jpg").get_url(user["idToken"])
|
|
451
|
+
# https://firebasestorage.googleapis.com/v0/b/storage-url.appspot.com/o/images%2Fexample.jpg?alt=media
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
### delete
|
|
455
|
+
|
|
456
|
+
The delete method takes the path to the saved database file and user token.
|
|
457
|
+
```
|
|
458
|
+
storage.delete("images/example.jpg",user["idToken"])
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
### Helper Methods
|
|
462
|
+
|
|
463
|
+
#### generate_key
|
|
464
|
+
|
|
465
|
+
```db.generate_key()``` is an implementation of Firebase's [key generation algorithm](https://www.firebase.com/blog/2015-02-11-firebase-unique-identifiers.html).
|
|
466
|
+
|
|
467
|
+
See multi-location updates for a potential use case.
|
|
468
|
+
|
|
469
|
+
#### sort
|
|
470
|
+
|
|
471
|
+
Sometimes we might want to sort our data multiple times. For example, we might want to retrieve all articles written between a
|
|
472
|
+
certain date then sort those articles based on the number of likes.
|
|
473
|
+
|
|
474
|
+
Currently the REST API only allows us to sort our data once, so the ```sort()``` method bridges this gap.
|
|
475
|
+
|
|
476
|
+
```python
|
|
477
|
+
articles = db.child("articles").order_by_child("date").start_at(startDate).end_at(endDate).get()
|
|
478
|
+
articles_by_likes = db.sort(articles, "likes")
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### Common Errors
|
|
482
|
+
|
|
483
|
+
#### Index not defined
|
|
484
|
+
|
|
485
|
+
+Indexing is [not enabled](https://firebase.google.com/docs/database/security/indexing-data) for the database reference.
|
|
486
|
+
|
|
487
|
+
## Firestore
|
|
488
|
+
|
|
489
|
+
The `firestore` method in empyrebase allows interaction with Firebase Firestore.
|
|
490
|
+
|
|
491
|
+
### Initialize Firestore
|
|
492
|
+
|
|
493
|
+
Initialize Firestore with required project and authentication parameters.
|
|
494
|
+
|
|
495
|
+
```python
|
|
496
|
+
from empyrebase import Firestore
|
|
497
|
+
|
|
498
|
+
firebase_path = "your_firestore_path" # Optional. Base path for all Firestore operations. Defaults to "/"
|
|
499
|
+
auth_id = "your_auth_id_token" # Optional. Enables authorized transactions.
|
|
500
|
+
database_name = "your_database_name" # Optional. defaults to "(default)"
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
firestore = firebase.firestore(firebase_path=firebase_path, database_name=database_name, auth_id=auth_id)
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
### Authorization
|
|
507
|
+
Authorize Firestore using an authentication token. Firestore can be authorized at any time.
|
|
508
|
+
```python
|
|
509
|
+
firestore.authorize("auth_id_token")
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
### CRUD Operations
|
|
513
|
+
#### Create a Document
|
|
514
|
+
Creates a new document.
|
|
515
|
+
Alias to: [`firestore.update_document("collection/document", {})`](#update-a-document)
|
|
516
|
+
```python
|
|
517
|
+
data = {"name": "John Doe", "age": 30} # Optional
|
|
518
|
+
firestore.create_document("users/user_id", data)
|
|
519
|
+
# Alternatively, updating a non-existing document will create a new one.
|
|
520
|
+
firestore.create_document("users/user_id", data) # Data is required, but can be an empty dictionary
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
#### Retrieve a Document
|
|
524
|
+
Fetches a document.
|
|
525
|
+
|
|
526
|
+
```python
|
|
527
|
+
document = firestore.get_document("users/user_id")
|
|
528
|
+
print(document)
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
#### Batch Get Documents
|
|
532
|
+
Fetch multiple documents in one batch.
|
|
533
|
+
```python
|
|
534
|
+
documents = firestore.batch_get_documents(["users/user_id1", "users/user_id2"])
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
#### Run Query
|
|
538
|
+
Run a structured query against a collection.
|
|
539
|
+
```python
|
|
540
|
+
query = {"field": "name", "value": "John Doe"}
|
|
541
|
+
results = firestore.run_query("users", query)
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
#### Update a Document
|
|
545
|
+
|
|
546
|
+
Update data in an existing document. If the document does not exist, it will be created with the new data.
|
|
547
|
+
|
|
548
|
+
```python
|
|
549
|
+
firestore.update_document("users/user_id", {"age": 31})
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
#### Delete a Document
|
|
553
|
+
|
|
554
|
+
Deletes a document.
|
|
555
|
+
|
|
556
|
+
```python
|
|
557
|
+
firestore.delete_document("users/user_id")
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
#### List Documents
|
|
561
|
+
|
|
562
|
+
Lists all documents in a collection.
|
|
563
|
+
|
|
564
|
+
```python
|
|
565
|
+
documents = firestore.list_documents("users")
|
|
566
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .pyrebase import initialize_app
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from requests.adapters import HTTPAdapter
|
|
3
|
+
|
|
4
|
+
from oauth2client.service_account import ServiceAccountCredentials
|
|
5
|
+
|
|
6
|
+
from .services import Auth, Database, Firestore, Storage
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def initialize_app(config):
|
|
10
|
+
return Firebase(config)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Firebase:
|
|
14
|
+
""" Firebase Interface """
|
|
15
|
+
def __init__(self, config):
|
|
16
|
+
self.api_key = config["apiKey"]
|
|
17
|
+
self.auth_domain = config["authDomain"]
|
|
18
|
+
self.database_url = config["databaseURL"]
|
|
19
|
+
self.storage_bucket = config["storageBucket"]
|
|
20
|
+
self.project_id = config["projectId"]
|
|
21
|
+
self.credentials = None
|
|
22
|
+
self.requests = requests.Session()
|
|
23
|
+
if config.get("serviceAccount"):
|
|
24
|
+
scopes = [
|
|
25
|
+
'https://www.googleapis.com/auth/firebase.database',
|
|
26
|
+
'https://www.googleapis.com/auth/userinfo.email',
|
|
27
|
+
"https://www.googleapis.com/auth/cloud-platform",
|
|
28
|
+
"https://firebasestorage.googleapis.com/",
|
|
29
|
+
]
|
|
30
|
+
service_account_type = type(config["serviceAccount"])
|
|
31
|
+
if service_account_type is str:
|
|
32
|
+
self.credentials = ServiceAccountCredentials.from_json_keyfile_name(config["serviceAccount"], scopes)
|
|
33
|
+
if service_account_type is dict:
|
|
34
|
+
self.credentials = ServiceAccountCredentials.from_json_keyfile_dict(config["serviceAccount"], scopes)
|
|
35
|
+
|
|
36
|
+
adapter = HTTPAdapter()
|
|
37
|
+
|
|
38
|
+
for scheme in ('http://', 'https://'):
|
|
39
|
+
self.requests.mount(scheme, adapter)
|
|
40
|
+
|
|
41
|
+
def auth(self):
|
|
42
|
+
return Auth(self.api_key, self.requests, self.credentials)
|
|
43
|
+
|
|
44
|
+
def database(self):
|
|
45
|
+
return Database(self.credentials, self.api_key, self.database_url, self.requests)
|
|
46
|
+
|
|
47
|
+
def firestore(self, firebase_path: str="/", database_name="(default)", auth_id: str | None=None):
|
|
48
|
+
return Firestore(self.requests, self.project_id, firebase_path, database_name, auth_id)
|
|
49
|
+
|
|
50
|
+
def storage(self):
|
|
51
|
+
return Storage(self.credentials, self.storage_bucket, self.requests)
|