Giter VIP home page Giter VIP logo

pyrebase's Introduction

Pyrebase

A simple python wrapper for the Firebase API.

Support

Does your business or project depend on Pyrebase? Reach out to [email protected]

Installation

pip install pyrebase

Getting Started

Python Version

Pyrebase was written for python 3 and will not work correctly with python 2.

Add Pyrebase to your application

For use with only user based authentication we can create the following configuration:

import pyrebase

config = {
  "apiKey": "apiKey",
  "authDomain": "projectId.firebaseapp.com",
  "databaseURL": "https://databaseName.firebaseio.com",
  "storageBucket": "projectId.appspot.com"
}

firebase = pyrebase.initialize_app(config)

We can optionally add a service account credential to our configuration that will allow our server to authenticate with Firebase as an admin and disregard any security rules.

import pyrebase

config = {
  "apiKey": "apiKey",
  "authDomain": "projectId.firebaseapp.com",
  "databaseURL": "https://databaseName.firebaseio.com",
  "storageBucket": "projectId.appspot.com",
  "serviceAccount": "path/to/serviceAccountCredentials.json"
}

firebase = pyrebase.initialize_app(config)

Adding a service account will authenticate as an admin by default for all database queries, check out the Authentication documentation for how to authenticate users.

Use Services

A Pyrebase app can use multiple Firebase services.

firebase.auth() - Authentication

firebase.database() - Database

firebase.storage() - Storage

Check out the documentation for each service for further details.

Authentication

The sign_in_with_email_and_password() method will return user data including a token you can use to adhere to security rules.

Each of the following methods accepts a user token: get(), push(), set(), update(), remove() and stream().

# Get a reference to the auth service
auth = firebase.auth()

# Log the user in
user = auth.sign_in_with_email_and_password(email, password)

# Get a reference to the database service
db = firebase.database()

# data to save
data = {
    "name": "Mortimer 'Morty' Smith"
}

# Pass the user's idToken to the push method
results = db.child("users").push(data, user['idToken'])

Token expiry

A user's idToken expires after 1 hour, so be sure to use the user's refreshToken to avoid stale tokens.

user = auth.sign_in_with_email_and_password(email, password)
# before the 1 hour expiry:
user = auth.refresh(user['refreshToken'])
# now we have a fresh token
user['idToken']

Custom tokens

You can also create users using custom tokens, for example:

token = auth.create_custom_token("your_custom_id")

You can also pass in additional claims.

token_with_additional_claims = auth.create_custom_token("your_custom_id", {"premium_account": True})

You can then send these tokens to the client to sign in, or sign in as the user on the server.

user = auth.sign_in_with_custom_token(token)

Manage Users

Creating users

auth.create_user_with_email_and_password(email, password)

Note: Make sure you have the Email/password provider enabled in your Firebase dashboard under Auth -> Sign In Method.

Verifying emails

auth.send_email_verification(user['idToken'])

Sending password reset emails

auth.send_password_reset_email("email")

Get account information

auth.get_account_info(user['idToken'])

Refreshing tokens

user = auth.refresh(user['refreshToken'])

Database

You can build paths to your data by using the child() method.

db = firebase.database()
db.child("users").child("Morty")

Save Data

push

To save data with a unique, auto-generated, timestamp-based key, use the push() method.

data = {"name": "Mortimer 'Morty' Smith"}
db.child("users").push(data)

set

To create your own keys use the set() method. The key in the example below is "Morty".

data = {"name": "Mortimer 'Morty' Smith"}
db.child("users").child("Morty").set(data)

update

To update data for an existing entry use the update() method.

db.child("users").child("Morty").update({"name": "Mortiest Morty"})

remove

To delete data for an existing entry use the remove() method.

db.child("users").child("Morty").remove()

multi-location updates

You can also perform multi-location updates with the update() method.

data = {
    "users/Morty/": {
        "name": "Mortimer 'Morty' Smith"
    },
    "users/Rick/": {
        "name": "Rick Sanchez"
    }
}

db.update(data)

To perform multi-location writes to new locations we can use the generate_key() method.

data = {
    "users/"+ref.generate_key(): {
        "name": "Mortimer 'Morty' Smith"
    },
    "users/"+ref.generate_key(): {
        "name": "Rick Sanchez"
    }
}

db.update(data)

Retrieve Data

val

Queries return a PyreResponse object. Calling val() on these objects returns the query data.

users = db.child("users").get()
print(users.val()) # {"Morty": {"name": "Mortimer 'Morty' Smith"}, "Rick": {"name": "Rick Sanchez"}}

key

Calling key() returns the key for the query data.

user = db.child("users").get()
print(user.key()) # users

each

Returns a list of objects on each of which you can call val() and key().

all_users = db.child("users").get()
for user in all_users.each():
    print(user.key()) # Morty
    print(user.val()) # {name": "Mortimer 'Morty' Smith"}

get

To return data from a path simply call the get() method.

all_users = db.child("users").get()

shallow

To return just the keys at a particular path use the shallow() method.

all_user_ids = db.child("users").shallow().get()

Note: shallow() can not be used in conjunction with any complex queries.

streaming

You can listen to live changes to your data with the stream() method.

def stream_handler(message):
    print(message["event"]) # put
    print(message["path"]) # /-K7yGTTEp7O549EzTYtI
    print(message["data"]) # {'title': 'Pyrebase', "body": "etc..."}

my_stream = db.child("posts").stream(stream_handler)

You should at least handle put and patch events. Refer to "Streaming from the REST API" for details.

You can also add a stream_id to help you identify a stream if you have multiple running:

my_stream = db.child("posts").stream(stream_handler, stream_id="new_posts")

close the stream

my_stream.close()

Complex Queries

Queries can be built by chaining multiple query parameters together.

users_by_name = db.child("users").order_by_child("name").limit_to_first(3).get()

This query will return the first three users ordered by name.

order_by_child

We begin any complex query with order_by_child().

users_by_name = db.child("users").order_by_child("name").get()

This query will return users ordered by name.

equal_to

Return data with a specific value.

users_by_score = db.child("users").order_by_child("score").equal_to(10).get()

This query will return users with a score of 10.

start_at and end_at

Specify a range in your data.

users_by_score = db.child("users").order_by_child("score").start_at(3).end_at(10).get()

This query returns users ordered by score and with a score between 3 and 10.

limit_to_first and limit_to_last

Limits data returned.

users_by_score = db.child("users").order_by_child("score").limit_to_first(5).get()

This query returns the first five users ordered by score.

order_by_key

When using order_by_key() to sort your data, data is returned in ascending order by key.

users_by_key = db.child("users").order_by_key().get()

order_by_value

When using order_by_value(), children are ordered by their value.

users_by_value = db.child("users").order_by_value().get()

Storage

The storage service allows you to upload images to Firebase.

child

Just like with the Database service, you can build paths to your data with the Storage service.

storage.child("images/example.jpg")

put

The put method takes the path to the local file and an optional user token.

storage = firebase.storage()
# as admin
storage.child("images/example.jpg").put("example2.jpg")
# as user
storage.child("images/example.jpg").put("example2.jpg", user['idToken'])

download

The download method takes the path to the saved database file and the name you want the downloaded file to have.

storage.child("images/example.jpg").download("downloaded.jpg")

get_url

The get_url method takes the path to the saved database file and returns the storage url.

storage.child("images/example.jpg").get_url()
# https://firebasestorage.googleapis.com/v0/b/storage-url.appspot.com/o/images%2Fexample.jpg?alt=media

Helper Methods

generate_key

db.generate_key() is an implementation of Firebase's key generation algorithm.

See multi-location updates for a potential use case.

sort

Sometimes we might want to sort our data multiple times. For example, we might want to retrieve all articles written between a certain date then sort those articles based on the number of likes.

Currently the REST API only allows us to sort our data once, so the sort() method bridges this gap.

articles = db.child("articles").order_by_child("date").start_at(startDate).end_at(endDate).get()
articles_by_likes = db.sort(articles, "likes")

Common Errors

Index not defined

Indexing is not enabled for the database reference.

pyrebase's People

Contributors

aleksanb avatar craigloftus avatar jonathanbaby avatar laurentsenta avatar mar664 avatar rasgo-cc avatar shamrin avatar sherifzain avatar tenzer avatar thisbejim avatar zoek1 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pyrebase's Issues

query chaining

Right now queries are confusing and each method is a bit restrictive. Users should be able to build their own queries more explicitly, chaining a query together much like complex queries in the javascript library.
Example:

results = admin.query("path/to/data").orderBy("votes").startAt(5).get()

get() on simple structures fails

If you only want to get a single item/key in Firebase, which contains one of the primitives Firebase supports (string, number or boolean), get() will fail with something like this:

  File "path/to/virtualenv/lib/python3.4/site-packages/pyrebase/pyrebase.py", line 94, in get
    if not isinstance(list(request_dict.values())[0], dict):
AttributeError: 'str' object has no attribute 'values'

This is with Pyrebase 0.3.1 and with the key I am trying to get being a string. In my original pull request for the previous one() method, I added a check for if we got a dictionary or something else back, before the id attribute was attempted to be set on the data:

if isinstance(request_json, dict):
    request_json["id"] = item_id

In the current version we have a check which is supposed to check the same, as far as I can see, in the interest of returning the raw primitive, if it's not a dictionary, which looks like this:

if not isinstance(list(request_dict.values())[0], dict):
    return request_dict

As is evident in the stacktrace, the values() method fails on a string, and would in fact fail on anything but a dictionary. I wonder what the reason was behind structuring the check like that. Wouldn't it be better with the simpler method shown on top here?

performing multiple queries returns none

Currently with the way paths are being built you can't query the correct path when doing two separate queries.

result = admin.child("users").get()
# will correctly be: users
result = admin.child("test").get()
# will be: users/test rather than test

Streaming Issues

Hey,
I am on python 3.5 and have been trying to stream a database, however on executing the stream_handler nothing is printed. I am authenticated using a service account, but it doesn't even throw an unauthorized access error. What could be the problem.

`def stream_handler(post):
print(post["event"])
print(post["path"])
print(post["data"])'

my_stream=test_db.child("resources").stream(stream_handler)
`

Prints Nothing

I understand that the handler is only supposed to act when there is a change made, but every time the streamer starts shouldn't it return the entire data under the child?
Also I tried putting random print statements in the handler function and even they weren't executed.

Thanks.

Error handling

Looking through the recent commits you made on the error handling of .get() (c393f84, 5b8a304 and d4a83b8), I can't help but think if it wouldn't be more Pythonic to raise an exception in that case?

Having to check the returned output to see if it matches the data you expected to get back or if it's an error message, makes it a bit too much of a hassle in my mind.

From what I can tell, error statuses on the .get() method will either have to be due to not having enough access, or Firebase not being able to handle the request due to some unforeseen circumstances. Requesting a path that doesn't exist just returns status 200 and null, in which case Pyrebase will return None which matches what I would expect.

Bad request when creating a new user

Hello,
I try to create a new user using the auth.create_user_with_email_and_password method. However, I ran into this error: 400 Client Error: Bad Request for url: https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key=....

Can you offer some hints about how to solve this? Thanks

No naked child?

First of all, that is a good title (I think :3)

It seems like the child method should not be used alone, for example:

db.child('any_path')
db.child('some_good_path').get().val()

The first one will interfere with the second one.
I took a quick look i think it is because child function append path instead of set path

if self.path:
    self.path += "/{}".format(new_path)

Correct me if i am wrong.
First, This issue does not allow store a reference to one location in db, because it will interfere with other queries. For example:

ref = db.child('some_good_path_for_later')
print db.child('some_other_good_path').get().val()

Second, if it is the design intention to not use child alone, should this function hide from users? e.g instead of doing

db.child('path').get()

The child logic should be moved to the append functions, and use like this:

db.get('path')

Thanks! Keep up the good work!

Empty dictionaries are not stored in realtime database

First of all I'd like to thank for this lib, it's a blast!

When adding/updating data through the update method, dictionaries without any keys won't be stored in firebase. Example:

data = {'a': 'Hello', 'b': {}}
result = db.update(data, my_token)

The dictionary b in data would never be stored in the database.

The absence of this dictionary compared to this dictionary without any keys and values, represent two very different things in my opinion. Any idea?

stream path is always '/'

running into a issue where my path is always '/' in my stream messages.

{"path":"/","data":{"columns":32,"rows":16,"stateHash":"6452d55e7149c2847e685b69aec3685c3745208d6109befaa5e81131"}}
{"path":"/","data":{"stateHash":"00bcb09ce2a5fcd318952fe5448b09b0a966bade7f667c61ff6d437d"}}
{"path":"/","data":{"stateHash":"4e0eabd07832ca93aacb256778d84188bfabb0bd18ec03d5949e9eef"}}

my stream call looks like this:

db.child("displays").child('-KJYAuwg3nvgTdSaGUU9').stream(stream_handler, None)

because it is '/', my stream callback is not getting called.

Support for GeoFire

Is it possible to support saving and retrieving GeoLocation like GeoFire?

Streaming problem

Hello! I am trying to do Django/Python app and i want to use your library with Firebase database.
I try to stream some directory (my_stream = db.child("users").stream(stream_handler, user['idToken']))
and then i try to close stream (my_stream.close()) but i have an error:

self.sse.close()
AttributeError: 'NoneType' object has no attribute 'close'

I have a 3.4 python version, so can you help me with that?

How do we determine if Streaming stops?

Hi, thanks for a great library. I would like to know how can we determine if there is a failure in Streaming service.

my_stream = ref.child("posts").stream(stream_handler)

Since we initiate my_stream object & pass the data to the stream_handler method. But assume if my_stream stops calling this method (maybe if exception occurs on the thread). Then how can we determine that?

403 Permission denied

First off, I would like to say this is a great project!

Now onto the problem .. I have a Python application running on Google App Engine.

Python: 2.7.9.
Pyrebase: 3.0.7

I'm using a service account to authenticate to Firebase. I have anonymous and email and password authentication enabled. The database rules are the default ones. I have cron jobs setup that run once each day and insert data into Firebase's database. Currently I get lots of 403 (Permission denied) exceptions, when the cron jobs run. When I set the corn jobs to run more often, everything is fine (I had them running 2 hours apart before).

So what would be causing this issue?

TypeError

Trying to do the following:

db = firebase.database()
db.child("cricket-tables").child("division-one")
data = [{"Bat": 17.0, "Deduct": 0.0, "D": 1.0, "Bowl": 18.0, "L": 2.0, "P": 6.0, "Points": 88.0, "T": 0.0, "W": 3.0, "Team": "Lancashire"}, {"Bat": 22.0, "Deduct": 0.0, "D": 4.0, "Bowl": 14.0, "L": 0.0, "P": 6.0, "Points": 88.0, "T": 0.0, "W": 2.0, "Team": "Yorkshire"}]
db.set(data)

and get the following error:

TypeError: set() takes exactly 3 arguments (2 given)

I get the same error with push(data) as i do when I specify the children just before the set arg e.g. db.child("cricket-tables").child("division-one").set(data)

If I save the JSON as a file and upload manually to my firebase there is no problem so don't think it is the JSON structure.

Any ideas?

Thanks

Stream troubles

Hey there, I can't seem to get streaming to work.. My stream handler is never called. (I don't see logging in the handler)

def stream_handler(post):
    print(post)

my_stream = db.child("displays").stream(stream_handler, user['idToken'])
print(my_stream)

if I swap out the stream creation line with something more standard, it seems to work fine.

print(db.child("displays").get(user['idToken']).val())

I'm using this on a raspberry pi 2

Error in child("path/path").get() with two level path

In this code:
data = db.child("test").get()
data.each() return a list of Pyre objects

In this code:
data = db.child("test/people").get()
data.each() return a list of dicts, so I can't get the keys.

with another level returns Pyre objects again:
data = db.child("test/people/0").get()
data.each() return a list of Pyre objects

[X] Check that your version of Python is 3.4+ --> python 3.5
[X] Check that you are on the newest version of Pyrebase --> Donwloaded today
[X] Check that Email/password provider is enabled in your Firebase dashboard under Auth -> Sign In Method. --> Works for read and writes

Cannot create a new user

I am getting the following error on using the create_user_with_email_and_password()function

400 Client Error: Bad Request for url: https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key=secret

note: I am new to firebase

get() on dictionaries with sub-dictionaries fail

During a bit of testing, I found out with a Firebase structure such as:

{
    "test": {
        "bool": true,
        "number": 123,
        "string": "test"
    }
}

then Firebase.query("test").get() correctly returns {'bool': True, 'number': 123, 'string': 'test'}. But if the data in Firebase instead looks like this:

{
    "test": {
        "bool": true,
        "number": 123,
        "string": "test",
        "sub": {
            "string": "test"
        }
    }
}

and you do the same query, then it will fail with this error message:

Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "path/to/virtualenv/lib/python3.4/site-packages/pyrebase/pyrebase.py", line 99, in get
    request_dict[i]["key"] = i
TypeError: 'bool' object does not support item assignment

I'm not too much a fan of all the reformatting of the output going on in the current get() method. It is of course needed if you want a sorted output, due to dictionaries in Python not being ordered (unless you use a OrderedDict), but it should at least be able to handle the simpler cases before the more advanced cases, in my opinion.

Refresh Service Account Auth

Hello, thanks for making pyrebase!

I am using service account authentication and get 400s after an hour. I see the refresh method, but am not sure how to use that with a service account. Is there any way to do this?

Stream not notified if data updated from script

Hi,
Thank you for the great library, I'm currently using it for a personal garden project.
But I got a little bit of problem on the streaming part.

So in firebase, here's my database structure

image

And I start a stream to listening to changes from "light" key

firebase = pyrebase.initialize_app(config)
db = firebase.database()

def stream_handler(post):
    print "New post coming"
    print(post["event"])
    print(post["path"])    
    print(post["data"])

print "Listening to stream"
my_stream = db.child("fungi_automation").stream(stream_handler, None)

and I updated it from my other script to change the value

firebase = pyrebase.initialize_app(config)
db = firebase.database()

data = {
    "fungi_automation/light/": {
        "value": 1,
        "last_update": time.time()
    },
    "fungi_automation/water/": {
        "value": 1,
        "last_update": time.time()
    }
}

db.update(data)

But the stream doesn't notice the change. I already wait several seconds before submiting the update.

I tried to change the value directly from Firebase and my stream recognized it, I can see the changes on my console print. And push also works fine, I can also see the changes.

db.child("fungi_automation").push({"name": "morty"}, None)

but if I push with my own key, its not working

data = {"Morty": {"name": "Mortimer 'Morty' Smith"}}
db.child("fungi_automation").set(data) 

Did I do something wrong?

I also tried to update the value from my HTML front end using Firebase js, the value in the database was updated but the stream also didn't catch it.

Thank you for your time.

admin and user auth

Currently to auth as a user you must type out the firebase url, the secret, the email, and the password for each connection you want. Would be cool if you could auth once as admin then auth as users on the fly.

Fetch data from the list created with .each()

Hi, first of all thanks for the Pyrebase i love it !

btw i have a small issues you may can help me.
I m new in firebase, and i would like to store data in firebase but before the push i would like if the data are already in firebase , if they exist then i dont want to push them.

I was trying to fetch all the val using the:

db = firebase.database().child('xtrmp')
matches = db.get(user['idToken'])
for i in matches.each():
xtrmData = i.val()
print xtrmData

this gives me the list i would like ->
{u'date': u'2016-06-01T12:00:00', u'drawOdds': u'7.50', u'homeOdds': u'1.17', u'awayOdds': u'8.85', u'match': u'FC BULLEEN LIONS vs. SOUTH MELBOURNE'}

My question is how can i get the match val so i can check if there is in db before push ?

Or there is another way to achieve that ?

Thanks for your time and your help :)

closing streams

    self.resp.raw._fp.fp.raw._sock.shutdown(socket.SHUT_RDWR)
    self.resp.raw._fp.fp.raw._sock.close()

in the ssec.close function, resp.raw doesn't exist. I call my_stream.sse.resp.close() instead of my_stream.close() so that my application terminates correctly

AttributeError: module 'pyrebase' has no attribute 'initialize_app'

Hi,

I have this issue:

bash-3.2$ ./pyrebase.py
Traceback (most recent call last):
  File "./pyrebase.py", line 3, in <module>
    import pyrebase
  File "/Users/arsenyosipov/Documents/COBI/python-search/pyrebase.py", line 13, in <module>
    fire = pyrebase.initialize_app(config)
AttributeError: module 'pyrebase' has no attribute 'initialize_app'

bash-3.2$ python3 --version
Python 3.5.2

The script:

#!/usr/local/bin/python3

import pyrebase

config = {
  "apiKey": "key",
  "authDomain": "project.firebaseapp.com",
  "databaseURL": "https://project.firebaseio.com",
  "storageBucket": "project.appspot.com",
  "serviceAccount": "python.json"
}

fire = pyrebase.initialize_app(config)

Service Account and Stream

Thenk you for this beatiful library. It's very easy to use and smooth.

But I got a problem with stream.
My service account working smoothly if I get data with .get() method. But when I try to stream data with .stream() method, it gives me "permission denied" error.

My service account get owner permission on firebase,
I'm working on Python 3.5.X
And I get the last version of Pyrebase.

Every time stream handler is called, it includes all items since start

Hi there,

When I'm streaming on a particular child I receive not only what was just added, but also the ones that were added before (all that were added while the stream was active). This happens when I use either push or set to add data.

Is this the expected behavior? Is it possible to listen to only new items?

Any help would be appreciated, thanks.

Security API does not throw proper error messages

The API does not seem to report error codes on security operations. I believe closed issue #44 may be an example of this.

There are certain validations that occur on the firebase end, for example, createUserWithEmailAndPassword can fail for weak password (less than 6 characters) or invalid email (missing an '@' for example).

For these cases, the API seems to just throw a generic 400 error, like:

requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=AIzaS...

It is not clear whether these errors are even getting sent back from firebase, in that case it might be helpful to do a couple validations on the client side, or simply document the issue.

Can't generate firebase key

When I try to run the following code:
` config = {
...
}

firebase = pyrebase.initialize_app(config)
db = firebase.database()
print db.generate_key()`

I get the following error:

Traceback (most recent call last):
File "myFilenName", line 14, in
print db.generate_key()
File "/Users/dev/anaconda2/lib/python2.7/site-packages/pyrebase/pyrebase.py", line 245, in generate_key
time_stamp_chars[i] = push_chars[now % 64]
TypeError: string indices must be integers, not float

webapp2 not defined

Google App Engine default project does not work after install Pyrebase
webapp2 not defined

Provide output in an OrderedDict to keep sorting

Carrying on from #12, I think it would make sense to always use an OrderedDict everywhere in Pyrebase. Firebase use the ordering of the elements in the JSON response as a response to the sorting requested in the request, but the standard Python dictionary does not keep the ordering, which means we currently implement our own sorting on top of what Firebase does.

If we instead decode the JSON ourselves, using the object_pairs_hook kwarg, we can supply that with an OrderedDict as shown here, which will keep the ordering, and thus require less work on our end since we don't need to sort the elements again.

I think the only handling we need of the response from Firebase then would be the following:

  1. Is the JSON decoded response something else than a dict/OrderedDict? If yes, then simply return it.
  2. Are we doing a shallow request? If yes, then only return the keys of the dictionary.

What are your thoughts on this?

generating firebase keys

As the updated README in bcf0915 mentions, to perform multi-location writes using a new unique, auto-generated key you must first push some data to firebase and wait for a new key to return. The wait, especially if you want multiple keys, kind of hinders the benefits of the multi-location write. In the javascript library these keys are generated locally first, it would be cool if we could do the same.

Good resources:
Firebase's code for generating keys https://gist.github.com/mikelehen/3596a30bd69384624c11 and a python port https://gist.github.com/risent/4cab3878d995bec7d1c2

Install fails via pip

I get the following error trying to pip install pyrebase.

I'm running OSX and Python 3.5.1. New to python so I'm pretty stumped!

Collecting grpcio
  Using cached grpcio-0.14.0.tar.gz
Requirement already satisfied (use --upgrade to upgrade): six>=1.10 in /Users/matt/.virtualenvs/cv3/lib/python3.5/site-packages (from grpcio)
Requirement already satisfied (use --upgrade to upgrade): enum34>=1.0.4 in /Users/matt/.virtualenvs/cv3/lib/python3.5/site-packages (from grpcio)
Requirement already satisfied (use --upgrade to upgrade): futures>=2.2.0 in /Users/matt/.virtualenvs/cv3/lib/python3.5/site-packages (from grpcio)
Requirement already satisfied (use --upgrade to upgrade): protobuf>=3.0.0a3 in /Users/matt/.virtualenvs/cv3/lib/python3.5/site-packages (from grpcio)
Requirement already satisfied (use --upgrade to upgrade): setuptools in /Users/matt/.virtualenvs/cv3/lib/python3.5/site-packages (from protobuf>=3.0.0a3->grpcio)
Building wheels for collected packages: grpcio
  Running setup.py bdist_wheel for grpcio ... error
  Complete output from command /Users/matt/.virtualenvs/cv3/bin/python3.5 -u -c "import setuptools, tokenize;__file__='/private/var/folders/cm/jhy671nj51bf80148gr7grwr0000gn/T/pip-build-v2v0619p/grpcio/setup.py';exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" bdist_wheel -d /var/folders/cm/jhy671nj51bf80148gr7grwr0000gn/T/tmpw80x2gappip-wheel- --python-tag cp35:
  /Users/matt/.virtualenvs/cv3/lib/python3.5/site-packages/setuptools/command/easy_install.py:333: UserWarning: Unbuilt egg for grpcio [unknown version] (/private/var/folders/cm/jhy671nj51bf80148gr7grwr0000gn/T/pip-build-v2v0619p/grpcio/src/python/grpcio)
    self.local_index = Environment(self.shadow_path + sys.path)
  running bdist_wheel
  running build
  running build_py
  running build_proto_modules
  Traceback (most recent call last):
    File "/private/var/folders/cm/jhy671nj51bf80148gr7grwr0000gn/T/pip-build-v2v0619p/grpcio/src/python/grpcio/commands.py", line 227, in run
      self.run_command('build_proto_modules')
    File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/distutils/cmd.py", line 313, in run_command
      self.distribution.run_command(command)
    File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/distutils/dist.py", line 974, in run_command
      cmd_obj.run()
    File "/private/var/folders/cm/jhy671nj51bf80148gr7grwr0000gn/T/pip-build-v2v0619p/grpcio/src/python/grpcio/commands.py", line 159, in run
      raise CommandError('could not find protoc')
  commands.CommandError: could not find protoc

  During handling of the above exception, another exception occurred:

  Traceback (most recent call last):
    File "<string>", line 1, in <module>
    File "/private/var/folders/cm/jhy671nj51bf80148gr7grwr0000gn/T/pip-build-v2v0619p/grpcio/setup.py", line 246, in <module>
      test_runner=TEST_RUNNER,
    File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/distutils/core.py", line 148, in setup
      dist.run_commands()
    File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/distutils/dist.py", line 955, in run_commands
      self.run_command(cmd)
    File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/distutils/dist.py", line 974, in run_command
      cmd_obj.run()
    File "/Users/matt/.virtualenvs/cv3/lib/python3.5/site-packages/wheel/bdist_wheel.py", line 179, in run
      self.run_command('build')
    File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/distutils/cmd.py", line 313, in run_command
      self.distribution.run_command(command)
    File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/distutils/dist.py", line 974, in run_command
      cmd_obj.run()
    File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/distutils/command/build.py", line 135, in run
      self.run_command(cmd_name)
    File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/distutils/cmd.py", line 313, in run_command
      self.distribution.run_command(command)
    File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/distutils/dist.py", line 974, in run_command
      cmd_obj.run()
    File "/private/var/folders/cm/jhy671nj51bf80148gr7grwr0000gn/T/pip-build-v2v0619p/grpcio/src/python/grpcio/commands.py", line 229, in run
      sys.stderr.write('warning: %s\n' % error.message)
  AttributeError: 'CommandError' object has no attribute 'message'

  ----------------------------------------
  Failed building wheel for grpcio
  Running setup.py clean for grpcio
Failed to build grpcio
Installing collected packages: grpcio
  Running setup.py install for grpcio ... error
    Complete output from command /Users/matt/.virtualenvs/cv3/bin/python3.5 -u -c "import setuptools, tokenize;__file__='/private/var/folders/cm/jhy671nj51bf80148gr7grwr0000gn/T/pip-build-v2v0619p/grpcio/setup.py';exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record /var/folders/cm/jhy671nj51bf80148gr7grwr0000gn/T/pip-0zyt3z6f-record/install-record.txt --single-version-externally-managed --compile --install-headers /Users/matt/.virtualenvs/cv3/bin/../include/site/python3.5/grpcio:
    /Users/matt/.virtualenvs/cv3/lib/python3.5/site-packages/setuptools/command/easy_install.py:333: UserWarning: Unbuilt egg for grpcio [unknown version] (/private/var/folders/cm/jhy671nj51bf80148gr7grwr0000gn/T/pip-build-v2v0619p/grpcio/src/python/grpcio)
      self.local_index = Environment(self.shadow_path + sys.path)
    running install
    running build
    running build_py
    running build_proto_modules
    Traceback (most recent call last):
      File "/private/var/folders/cm/jhy671nj51bf80148gr7grwr0000gn/T/pip-build-v2v0619p/grpcio/src/python/grpcio/commands.py", line 227, in run
        self.run_command('build_proto_modules')
      File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/distutils/cmd.py", line 313, in run_command
        self.distribution.run_command(command)
      File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/distutils/dist.py", line 974, in run_command
        cmd_obj.run()
      File "/private/var/folders/cm/jhy671nj51bf80148gr7grwr0000gn/T/pip-build-v2v0619p/grpcio/src/python/grpcio/commands.py", line 159, in run
        raise CommandError('could not find protoc')
    commands.CommandError: could not find protoc

    During handling of the above exception, another exception occurred:

    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/private/var/folders/cm/jhy671nj51bf80148gr7grwr0000gn/T/pip-build-v2v0619p/grpcio/setup.py", line 246, in <module>
        test_runner=TEST_RUNNER,
      File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/distutils/core.py", line 148, in setup
        dist.run_commands()
      File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/distutils/dist.py", line 955, in run_commands
        self.run_command(cmd)
      File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/distutils/dist.py", line 974, in run_command
        cmd_obj.run()
      File "/Users/matt/.virtualenvs/cv3/lib/python3.5/site-packages/setuptools/command/install.py", line 61, in run
        return orig.install.run(self)
      File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/distutils/command/install.py", line 539, in run
        self.run_command('build')
      File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/distutils/cmd.py", line 313, in run_command
        self.distribution.run_command(command)
      File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/distutils/dist.py", line 974, in run_command
        cmd_obj.run()
      File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/distutils/command/build.py", line 135, in run
        self.run_command(cmd_name)
      File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/distutils/cmd.py", line 313, in run_command
        self.distribution.run_command(command)
      File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/distutils/dist.py", line 974, in run_command
        cmd_obj.run()
      File "/private/var/folders/cm/jhy671nj51bf80148gr7grwr0000gn/T/pip-build-v2v0619p/grpcio/src/python/grpcio/commands.py", line 229, in run
        sys.stderr.write('warning: %s\n' % error.message)
    AttributeError: 'CommandError' object has no attribute 'message'

    ----------------------------------------
Command "/Users/matt/.virtualenvs/cv3/bin/python3.5 -u -c "import setuptools, tokenize;__file__='/private/var/folders/cm/jhy671nj51bf80148gr7grwr0000gn/T/pip-build-v2v0619p/grpcio/setup.py';exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record /var/folders/cm/jhy671nj51bf80148gr7grwr0000gn/T/pip-0zyt3z6f-record/install-record.txt --single-version-externally-managed --compile --install-headers /Users/matt/.virtualenvs/cv3/bin/../include/site/python3.5/grpcio" failed with error code 1 in /private/var/folders/cm/jhy671nj51bf80148gr7grwr0000gn/T/pip-build-v2v0619p/grpcio/

Dependencies of project

I can see from the commit history that the setup.py file was part of this repository earlier, but was removed. What was the reason behind that?

Having neither setup.py or a requirements.txt in the project will make it more difficult for contributors to figure out which dependencies the project relies on, and which versions you may have pinned of those packages.

Would you consider adding at least one of the two files back in?

Cannot pass a file object to the storage API (only a filename)

The Storage.put() operation currently only handles file names, and then calls open() on the name.
It would be nice to pass a file object directly, to be able to handle something like werkzeug.datastructures.Filestorage.

My solution is to simply monkey-patch Storage by adding a new method almost the same as the put() method, but there may be a better way.


def monkeypatch_method(cls):
    def decorator(func):
        setattr(cls, func.__name__, func)
        return func
    return decorator

# INFO monkey patch to the pyrebase.Storage class
@monkeypatch_method(Storage)
def pyrebase_storage_put(self, file_object: FileStorage, token=None):
    # reset path
    path = self.path
    self.path = None
    if token:
        # file_object = open("requirements.txt", 'rb')
        request_ref = self.storage_bucket + "/o?name={0}".format(path)
        headers = {"Authorization": "Firebase " + token}
        print("file object: " + repr(file_object))
        request_object = self.requests.put(request_ref, headers=headers, data=file_object)
        print("JSON:" + repr(request_object.json()))
        return request_object.json()
    elif self.credentials:
        blob = self.bucket.blob(path)
    return blob.upload_from_filename(filename=file_object.filename)

def upload_file_to_firebase(image, resource_path):
    storage = get_firebase_app().storage()
    filepath = resource_path + image.filename
    storage.child(filepath).pyrebase_storage_put(image, token='Omye0DJUYHz...')

Firebase 3 auth with service account

Hello there, great job with the wrapper.. I'm sorry if that's not the proper place to ask. I'm trying to authenticate with a service account credentials .json file. I believe i should be authenticated right after
firebase = pyrebase.initialize_app(config)
however it seems that's not the case:

auth: None
account info: {'error': {'message': None, 'code': 500}}
current_user: None

I'm not sure if i miss something or this kind of auth is not yet implemented? If not yet, i guess i would have to create an ordinary user and adjust the security rules to allow him to edit the database.
Thanks for any hints..

to child() or not

With #9 we can more easily pass in variables for paths and let pyrebase build that path. Given that queries are now more aligned with the javascript library, would it also make sense to chain child paths in a similar way? e.g. python admin.query("users").child("Marty").get()

The benefit is that it is again more explicit. Additionally, if a user tries out pyrebase and are familiar with the javascript way of handling firebase then it might be easier for them to get started.

So in the end you could build paths three way:
python admin.query("users/Marty").get()
python admin.query("users", "Marty").get()
python admin.query("users").child("Marty").get()

Is this flexible or confusing? Not sure yet.

Stream ignores messages with path '/'

I've observed some strange behaviour with the Stream listener. Looking at the following code I noticed that Pyrebase stream only triggers if msg_data['path'] != '/'. What's the reason for this?

def start_stream(self, url, stream_handler):
        self.sse = ClosableSSEClient(url)
        for msg in self.sse:
            msg_data = json.loads(msg.data)
            # don't return initial data
            if msg_data and msg_data['path'] != '/':
                msg_data["event"] = msg.event
                stream_handler(msg_data)

The way I understand it, this constraint will ignore updates on a resource we're watching. For example, the following stream will not see updates happening in 'resource1', but will see the ones in its children.
my_stream = db.child("resource1").stream(stream_handler)

using service account json file with heroku

Hola! Just wondering what the best practices are for using this library and the service account json file with a PaaS like Heroku.

I figure it'd be a bad idea to commit the json file to git, so should I set all the json key pairs as env variables?

Atomic Write and/or Check

Hello!
Correct me if i am wrong. I can not use this lib to atomic write and/or check data.
For example, if I want to check if user/colin exists, and if not write to this location.

For firebase offical js library, it can be done by transaction function: https://www.firebase.com/docs/web/api/firebase/transaction.html

But here i have no way of lock the data when i check, and unlock it after i write.

Thanks! Keep up the good work ๐Ÿ‘

Error with get() - database

So far Pyrebase has been great for the firebase/auth however, in the database, it is running into some issues.

Just as a test, I have tried
users = db.child("usernames").get()
Which stores the usernames and user Id's and is structured as follows:

usernames {
"username1":"userID1",
"username2":"userID2",
. . .
}

Except the code above (.get()) is coming into an error. It is displaying an error message:
[Errno 401 Client Error: Unauthorized for url: https://myapp.firebaseio.com/usernames.json] { "error" : "Permission denied" }

As far as I can tell, this URL is invalid (when viewed in a browser or in the firebase console) but https://myapp.firebaseio.com/usernames is a valid URL. I'm not sure how to get it to get to the correct URL.

[X] Check that your version of Python is 3.4+ (have python 3.5)
[X] Check that you are on the newest version of Pyrebase (reinstalled pyrebase today)
[X] Check that Email/password provider is enabled in your Firebase dashboard under Auth -> Sign In Method.

Thanks!

Occasional Permission Denied

I occasionally get this permission denied error and resolve it by restarting my local server... until it happens again. What could be causing this?

Traceback (most recent call last):
  File "/Users/.../lib/python3.5/site-packages/pyrebase/pyrebase.py", line 353, in raise_detailed_error
    request_object.raise_for_status()
  File "/Users/.../lib/python3.5/site-packages/requests/models.py", line 844, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 403 Client Error: Forbidden for url: https://....firebaseio.com/....json

During handling of the above exception, another exception occurred:

  File "/Users/.../lib/python3.5/site-packages/pyrebase/pyrebase.py", line 232, in set
    raise_detailed_error(request_object)
  File "/Users/.../lib/python3.5/site-packages/pyrebase/pyrebase.py", line 356, in raise_detailed_error
    raise HTTPError(e, request_object.text)
requests.exceptions.HTTPError: [Errno 403 Client Error: Forbidden for url: https://....firebaseio.com/....json] {
  "error" : "Permission denied."
}

I'm on the latest version of Pyrebase and on Python 3.5, using a Firebase service account.

Retrieve Data AttributeError

I get the following error whenever I try and retrieve data via .val() or .each()

AttributeError: 'dict' object has no attribute 'key'

Unable to understand streaming

def stream_handler(post): print(post["event"]) # put print(post["path"]) # /-K7yGTTEp7O549EzTYtI print(post["data"]) # {'title': 'Pyrebase', "body": "etc..."}
my_stream = dsdb.child("some_child").stream(stream_handler)

The stream_handler prints the changes made since streaming has begun?

No module named winrandom

Have python 3.5, the latest version of pyrebase and email/password provider is enabled

On Windows 10, have no issue installing Pyrebase, with:
python -m pip install pyrebase

However, when trying to import pyrebase, in the cmd console (using the python interpreter), it says
ImportError: No module named winrandom

I can't seem to figure out how to correct this as all installation of pyrebase is ok, using pip but it appears to keep happening with this. I have seen something online about editing the code to:
from Crypto.Random.OSRNG import winrandom
However, I cannot seem to find the correct place to enter this and also, I am not able to do this import even when typed alone.

UTF-8 support

Currently json.dumps() is used without additional arguments other than the data itself. Passing "ensure_ascii=False" ensures data is decoded with UTF-8, so no weird characters anymore.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.