diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..c022e41 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "restructuredtext.confPath": "" +} \ No newline at end of file diff --git a/README.md b/README.md index 63ddb75..1c779a4 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Python interface to the Firebase's REST API -[![Firebase](https://www.firebase.com/images/logo.png)](http://www.firebase.com) +[![Firebase](https://szimek.github.io/presentation-firebase-intro/images/firebase_logo.png)](http://www.firebase.com) ## Installation @@ -24,8 +24,8 @@ To fetch all the users in your storage simply do the following: ```python from firebase import firebase -firebase = firebase.FirebaseApplication('https://your_storage.firebaseio.com', None) -result = firebase.get('/users', None) +fb_app = firebase.FirebaseApplication('https://your_storage.firebaseio.com', None) +result = fb_app.get('/users', None) print result {'1': 'John Doe', '2': 'Jane Doe'} ``` @@ -35,8 +35,8 @@ The second argument of **get** method is the name of the snapshot. Thus, if you ```python from firebase import firebase -firebase = firebase.FirebaseApplication('https://your_storage.firebaseio.com', None) -result = firebase.get('/users', '1') +fb_app = firebase.FirebaseApplication('https://your_storage.firebaseio.com', None) +result = fb_app.get('/users', '1') print result {'1': 'John Doe'} ``` @@ -45,8 +45,8 @@ You can also provide extra query parameters that will be appended to the url or ```python from firebase import firebase -firebase = firebase.FirebaseApplication('https://your_storage.firebaseio.com', None) -result = firebase.get('/users/2', None, {'print': 'pretty'}, {'X_FANCY_HEADER': 'VERY FANCY'}) +fb_app = firebase.FirebaseApplication('https://your_storage.firebaseio.com', None) +result = fb_app.get('/users/2', None, {'print': 'pretty'}, {'X_FANCY_HEADER': 'VERY FANCY'}) print result {'2': 'Jane Doe'} ``` @@ -55,14 +55,14 @@ Creating new data requires a POST or PUT request. Assuming you don't append **pr ```python from firebase import firebase -firebase = firebase.FirebaseApplication('https://your_storage.firebaseio.com', None) +fb_app = firebase.FirebaseApplication('https://your_storage.firebaseio.com', None) new_user = 'Ozgur Vatansever' -result = firebase.post('/users', new_user, {'print': 'pretty'}, {'X_FANCY_HEADER': 'VERY FANCY'}) +result = fb_app.post('/users', new_user, {'print': 'pretty'}, {'X_FANCY_HEADER': 'VERY FANCY'}) print result {u'name': u'-Io26123nDHkfybDIGl7'} -result = firebase.post('/users', new_user, {'print': 'silent'}, {'X_FANCY_HEADER': 'VERY FANCY'}) +result = fb_app.post('/users', new_user, {'print': 'silent'}, {'X_FANCY_HEADER': 'VERY FANCY'}) print result == None True ``` @@ -71,8 +71,8 @@ Deleting data is relatively easy compared to other actions. You just set the url ```python from firebase import firebase -firebase = firebase.FirebaseApplication('https://your_storage.firebaseio.com', None) -firebase.delete('/users', '1') +fb_app = firebase.FirebaseApplication('https://your_storage.firebaseio.com', None) +fb_app.delete('/users', '1') # John Doe goes away. ``` @@ -82,13 +82,13 @@ Authentication in Firebase is nothing but to simply creating a token that confor ```python from firebase import firebase -firebase = firebase.FirebaseApplication('https://your_storage.firebaseio.com', authentication=None) -result = firebase.get('/users', None, {'print': 'pretty'}) +fb_app = firebase.FirebaseApplication('https://your_storage.firebaseio.com', authentication=None) +result = fb_app.get('/users', None, {'print': 'pretty'}) print result {'error': 'Permission denied.'} authentication = firebase.FirebaseAuthentication('THIS_IS_MY_SECRET', 'ozgurvt@gmail.com', extra={'id': 123}) -firebase.authentication = authentication +fb_app.authentication = authentication print authentication.extra {'admin': False, 'debug': False, 'email': 'ozgurvt@gmail.com', 'id': 123, 'provider': 'password'} @@ -99,7 +99,7 @@ hdCI6IDEzNjE5NTAxNzQsICJkIjogeyJkZWJ1ZyI6IGZhbHNlLCAiYWRtaW4iOiBmYWxzZSwgInByb3Z InBhc3N3b3JkIiwgImlkIjogNSwgImVtYWlsIjogIm96Z3VydnRAZ21haWwuY29tIn0sICJ2IjogMH0.lq4IRVfvE GQklslOlS4uIBLSSJj88YNrloWXvisRgfQ" -result = firebase.get('/users', None, {'print': 'pretty'}) +result = fb_app.get('/users', None, {'print': 'pretty'}) print result {'1': 'John Doe', '2': 'Jane Doe'} ``` @@ -114,17 +114,17 @@ import json from firebase import firebase from firebase import jsonutil -firebase = firebase.FirebaseApplication('https://your_storage.firebaseio.com', authentication=None) +fb_app = firebase.FirebaseApplication('https://your_storage.firebaseio.com', authentication=None) def log_user(response): with open('/tmp/users/%s.json' % response.keys()[0], 'w') as users_file: users_file.write(json.dumps(response, cls=jsonutil.JSONEncoder)) -firebase.get_async('/users', None, {'print': 'pretty'}, callback=log_user) +fb_app.get_async('/users', None, {'print': 'pretty'}, callback=log_user) ``` # TODO - * Async calls must deliver exceptions raised back to the main process. - * More regression/stress tests on asynchronous calls. - * Docs must be generated. +- [ ] Async calls must deliver exceptions raised back to the main process. +- [ ] More regression/stress tests on asynchronous calls. +- [ ] Docs must be generated. diff --git a/README.rst b/README.rst index ebb8651..c093561 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,7 @@ Python Firebase ================= -Python interface to the Firebase's REST API +Python interface to Firebase's REST API .. image:: https://travis-ci.org/ozgur/python-firebase.png?branch=master :target: https://travis-ci.org/ozgur/python-firebase @@ -9,7 +9,7 @@ Python interface to the Firebase's REST API Installation ----------------- -python-firebase highly makes use of the **requests** library so before you begin, you need to have that package installed. +python-firebase depends heavily on the **requests** library. .. code-block:: bash @@ -19,12 +19,11 @@ python-firebase highly makes use of the **requests** library so before you begin Getting Started ------------------ -You can fetch any of your data in JSON format by appending '.json' to the end of the URL in which your data resides and, then send an HTTPS request through your browser. Like all other REST specific APIs, Firebase offers a client to update(PATCH, PUT), create(POST), or remove(DELETE) his stored data along with just to fetch it. +You can read or write any of your data in JSON format. Append '.json' to the end of the URL in which your data resides. Send an HTTPS request from the browser. You can read (GET), replace (PUT), selectively update (PATCH), append (POST), or remove (DELETE) data From firebase. -The library provides all the correspoding methods for those actions in both synchoronous and asynchronous manner. You can just start an asynchronous GET request with your callback function, and the method +The library provides all the correspoding methods for those actions in both synchoronous and asynchronous manner. - -To fetch all the users in your storage simply do the following: +To read some data, start an asynchronous GET request with your callback function. For example, to fetch the entire content of "/users" in your Firebase database called "your_storage", do the following: .. code-block:: python @@ -34,7 +33,7 @@ To fetch all the users in your storage simply do the following: print result {'1': 'John Doe', '2': 'Jane Doe'} -The second argument of **get** method is the name of the snapshot. Thus, if you leave it NULL, you get the data in the URL **/users.json**. Besides, if you set it to **1**, you get the data in the url **/users/1.json**. In other words, you get the user whose ID equals to 1. +The second argument of **get** method is the branch of the database you wish to read. If you leave it None, you get all the data in the URL **/users.json**. If, instead, you set it to **1**, you get the data in the url **/users/1.json**. In other words, you get the user whose ID equals to 1. .. code-block:: python @@ -54,7 +53,9 @@ You can also provide extra query parameters that will be appended to the url or print result {'2': 'Jane Doe'} -Creating new data requires a POST or PUT request. Assuming you don't append **print=silent** to the url, if you use POST the returning value becomes the name of the snapshot, if PUT you get the data you just sent. If print=silent is provided, you get just NULL because the backend never sends an output. +Creating new data requires a PUT or POST request. If you know exactly where you want to put the data, use PUT. If you just want to append some data under a new key, but don't want to tell Firebase what key to use, use POST and Firebase will create a unique time-ordered key. + +By default, in POST the function returns the a dictionary containing in "name", the key it has created for the data you have written, and in PUT the function returns the data you have just sent. If, instead, you set print=silent, the function returns None because the backend never sends an output. .. code-block:: python @@ -70,7 +71,7 @@ Creating new data requires a POST or PUT request. Assuming you don't append **pr print result == None True -Deleting data is relatively easy compared to other actions. You just set the url and that's all. Backend sends no output as a result of a delete operation. +Deleting data is relatively easy compared to other actions. You just specify the url. The backend sends no output. .. code-block:: python @@ -82,7 +83,7 @@ Deleting data is relatively easy compared to other actions. You just set the url Authentication ------------------ -Authentication in Firebase is nothing but to simply creating a token that conforms to the JWT standarts and, putting it into the querystring with the name **auth**. The library creates that token for you so you never end up struggling with constructing a valid token on your own. If the data has been protected against write/read operations with some security rules, the backend sends an appropriate error message back to the client with the status code **403 Forbidden**. +Authentication in Firebase involves simply creating a token that conforms to the JWT standarts and putting it into the querystring with the name **auth**. The library creates that token for you so you never end up struggling with constructing a valid token on your own. If the data has been protected against write/read operations with some security rules, the backend sends an appropriate error message back to the client with the status code **403 Forbidden**. .. code-block:: python @@ -116,9 +117,9 @@ The interface heavily depends on the standart **multiprocessing** library when c .. code-block:: python - import json - from firebase import firebase - from firebase import jsonutil + import json + from firebase import firebase + from firebase import jsonutil firebase = firebase.FirebaseApplication('https://your_storage.firebaseio.com', authentication=None) diff --git a/firebase/__init__.py b/firebase/__init__.py index 8c84e53..b6e9db2 100644 --- a/firebase/__init__.py +++ b/firebase/__init__.py @@ -1,6 +1,6 @@ import atexit -from .async import process_pool +from .multiprocess_pool import process_pool from firebase import * diff --git a/firebase/decorators.py b/firebase/decorators.py index 66d0a11..1db2079 100644 --- a/firebase/decorators.py +++ b/firebase/decorators.py @@ -14,7 +14,9 @@ def wrapped(*args, **kwargs): kwargs['connection'] = connection else: connection = kwargs['connection'] - connection.timeout = timeout + + if not getattr(connection, 'timeout', False): + connection.timeout = timeout connection.headers.update({'Content-type': 'application/json'}) return f(*args, **kwargs) return wraps(f)(wrapped) diff --git a/firebase/firebase.py b/firebase/firebase.py index 2e55865..aac5980 100644 --- a/firebase/firebase.py +++ b/firebase/firebase.py @@ -9,7 +9,7 @@ from .firebase_token_generator import FirebaseTokenGenerator from .decorators import http_connection -from .async import process_pool +from .multiprocess_pool import process_pool from .jsonutil import JSONEncoder __all__ = ['FirebaseAuthentication', 'FirebaseApplication'] @@ -243,8 +243,7 @@ def _build_endpoint_url(self, url, name=None): url = url + self.URL_SEPERATOR if name is None: name = '' - return '%s%s%s' % (urlparse.urljoin(self.dsn, url), name, - self.NAME_EXTENSION) + return f'{urlparse.urljoin(self.dsn, url)}{name}{self.NAME_EXTENSION}' def _authenticate(self, params, headers): """ @@ -258,7 +257,7 @@ def _authenticate(self, params, headers): """ if self.authentication: user = self.authentication.get_user() - params.update({'auth': user.firebase_auth_token}) + params.update({'auth_token': user.firebase_auth_token}) headers.update(self.authentication.authenticator.HEADERS) @http_connection(60) diff --git a/firebase/async.py b/firebase/multiprocess_pool.py similarity index 100% rename from firebase/async.py rename to firebase/multiprocess_pool.py diff --git a/setup.py b/setup.py index 995f3e5..8f08a9c 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ setup(name='python-firebase', - version='1.2', + version='1.2.1', description="Python interface to the Firebase's REST API.", long_description=long_description, classifiers=[ diff --git a/tests/jsonutil_test.py b/tests/jsonutil_test.py index 29a3a81..5971596 100644 --- a/tests/jsonutil_test.py +++ b/tests/jsonutil_test.py @@ -11,7 +11,7 @@ def setUp(self): self.data = {'now': datetime.datetime.now(), 'oneday': datetime.timedelta(days=1), 'five': decimal.Decimal(5), - 'date': datetime.date(2014, 03, 11)} + 'date': datetime.date(2014, 3, 11)} def test_conversion(self): serialized = json.dumps(self.data, cls=JSONEncoder)