This is second stage question of problem. I originaly asked here
, I forked pyrebase to implement onDisconnect feature, can you tell me how can I implement that on this module?
I know, it should be very easy change on this file but I stucked coz I am newbie at python. Should I put a new method in to Database class? or new class needed?
import requests
from requests import Session
from requests.exceptions import HTTPError
try:
from urllib.parse import urlencode, quote
except:
from urllib import urlencode, quote
import json
import math
from random import uniform
import time
from collections import OrderedDict
from sseclient import SSEClient
import threading
import socket
from oauth2client.service_account import ServiceAccountCredentials
from gcloud import storage
from requests.packages.urllib3.contrib.appengine import is_appengine_sandbox
from requests_toolbelt.adapters import appengine
import python_jwt as jwt
from Crypto.PublicKey import RSA
import datetime
def initialize_app(config):
return Firebase(config)
class Firebase:
""" Firebase Interface """
def __init__(self, config):
self.api_key = config["apiKey"]
self.auth_domain = config["authDomain"]
self.database_url = config["databaseURL"]
self.storage_bucket = config["storageBucket"]
self.credentials = None
self.requests = requests.Session()
if config.get("serviceAccount"):
scopes = [
'https://www.googleapis.com/auth/firebase.database',
'https://www.googleapis.com/auth/userinfo.email',
"https://www.googleapis.com/auth/cloud-platform"
]
service_account_type = type(config["serviceAccount"])
if service_account_type is str:
self.credentials = ServiceAccountCredentials.from_json_keyfile_name(config["serviceAccount"], scopes)
if service_account_type is dict:
self.credentials = ServiceAccountCredentials.from_json_keyfile_dict(config["serviceAccount"], scopes)
if is_appengine_sandbox():
# Fix error in standard GAE environment
# is releated to https://github.com/kennethreitz/requests/issues/3187
# ProtocolError('Connection aborted.', error(13, 'Permission denied'))
adapter = appengine.AppEngineAdapter(max_retries=3)
else:
adapter = requests.adapters.HTTPAdapter(max_retries=3)
for scheme in ('http://', 'https://'):
self.requests.mount(scheme, adapter)
def auth(self):
return Auth(self.api_key, self.requests, self.credentials)
def database(self):
return Database(self.credentials, self.api_key, self.database_url, self.requests)
def storage(self):
return Storage(self.credentials, self.storage_bucket, self.requests)
class Auth:
""" Authentication Service """
def __init__(self, api_key, requests, credentials):
self.api_key = api_key
self.current_user = None
self.requests = requests
self.credentials = credentials
def sign_in_with_email_and_password(self, email, password):
request_ref = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key={0}".format(self.api_key)
headers = {"content-type": "application/json; charset=UTF-8"}
data = json.dumps({"email": email, "password": password, "returnSecureToken": True})
request_object = requests.post(request_ref, headers=headers, data=data)
raise_detailed_error(request_object)
self.current_user = request_object.json()
return request_object.json()
def create_custom_token(self, uid, additional_claims=None):
service_account_email = self.credentials.service_account_email
private_key = RSA.importKey(self.credentials._private_key_pkcs8_pem)
payload = {
"iss": service_account_email,
"sub": service_account_email,
"aud": "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
"uid": uid
}
if additional_claims:
payload["claims"] = additional_claims
exp = datetime.timedelta(minutes=60)
return jwt.generate_jwt(payload, private_key, "RS256", exp)
def sign_in_with_custom_token(self, token):
request_ref = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken?key={0}".format(self.api_key)
headers = {"content-type": "application/json; charset=UTF-8"}
data = json.dumps({"returnSecureToken": True, "token": token})
request_object = requests.post(request_ref, headers=headers, data=data)
raise_detailed_error(request_object)
return request_object.json()
def refresh(self, refresh_token):
request_ref = "https://securetoken.googleapis.com/v1/token?key={0}".format(self.api_key)
headers = {"content-type": "application/json; charset=UTF-8"}
data = json.dumps({"grantType": "refresh_token", "refreshToken": refresh_token})
request_object = requests.post(request_ref, headers=headers, data=data)
raise_detailed_error(request_object)
request_object_json = request_object.json()
# handle weirdly formatted response
user = {
"userId": request_object_json["user_id"],
"idToken": request_object_json["id_token"],
"refreshToken": request_object_json["refresh_token"]
}
return user
def get_account_info(self, id_token):
request_ref = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/getAccountInfo?key={0}".format(self.api_key)
headers = {"content-type": "application/json; charset=UTF-8"}
data = json.dumps({"idToken": id_token})
request_object = requests.post(request_ref, headers=headers, data=data)
raise_detailed_error(request_object)
return request_object.json()
def send_email_verification(self, id_token):
request_ref = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/getOobConfirmationCode?key={0}".format(self.api_key)
headers = {"content-type": "application/json; charset=UTF-8"}
data = json.dumps({"requestType": "VERIFY_EMAIL", "idToken": id_token})
request_object = requests.post(request_ref, headers=headers, data=data)
raise_detailed_error(request_object)
return request_object.json()
def send_password_reset_email(self, email):
request_ref = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/getOobConfirmationCode?key={0}".format(self.api_key)
headers = {"content-type": "application/json; charset=UTF-8"}
data = json.dumps({"requestType": "PASSWORD_RESET", "email": email})
request_object = requests.post(request_ref, headers=headers, data=data)
raise_detailed_error(request_object)
return request_object.json()
def verify_password_reset_code(self, reset_code, new_password):
request_ref = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/resetPassword?key={0}".format(self.api_key)
headers = {"content-type": "application/json; charset=UTF-8"}
data = json.dumps({"oobCode": reset_code, "newPassword": new_password})
request_object = requests.post(request_ref, headers=headers, data=data)
raise_detailed_error(request_object)
return request_object.json()
def create_user_with_email_and_password(self, email, password):
request_ref = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key={0}".format(self.api_key)
headers = {"content-type": "application/json; charset=UTF-8" }
data = json.dumps({"email": email, "password": password, "returnSecureToken": True})
request_object = requests.post(request_ref, headers=headers, data=data)
raise_detailed_error(request_object)
return request_object.json()
class Database:
""" Database Service """
def __init__(self, credentials, api_key, database_url, requests):
if not database_url.endswith('/'):
url = ''.join([database_url, '/'])
else:
url = database_url
self.credentials = credentials
self.api_key = api_key
self.database_url = url
self.requests = requests
self.path = ""
self.build_query = {}
self.last_push_time = 0
self.last_rand_chars = []
def order_by_key(self):
self.build_query["orderBy"] = "$key"
return self
def order_by_value(self):
self.build_query["orderBy"] = "$value"
return self
def order_by_child(self, order):
self.build_query["orderBy"] = order
return self
def start_at(self, start):
self.build_query["startAt"] = start
return self
def end_at(self, end):
self.build_query["endAt"] = end
return self
def equal_to(self, equal):
self.build_query["equalTo"] = equal
return self
def limit_to_first(self, limit_first):
self.build_query["limitToFirst"] = limit_first
return self
def limit_to_last(self, limit_last):
self.build_query["limitToLast"] = limit_last
return self
def shallow(self):
self.build_query["shallow"] = True
return self
def child(self, *args):
new_path = "/".join([str(arg) for arg in args])
if self.path:
self.path += "/{}".format(new_path)
else:
if new_path.startswith("/"):
new_path = new_path[1:]
self.path = new_path
return self
def build_request_url(self, token):
parameters = {}
if token:
parameters['auth'] = token
for param in list(self.build_query):
if type(self.build_query[param]) is str:
parameters[param] = quote('"' + self.build_query[param] + '"')
elif type(self.build_query[param]) is bool:
parameters[param] = "true" if self.build_query[param] else "false"
else:
parameters[param] = self.build_query[param]
# reset path and build_query for next query
request_ref = '{0}{1}.json?{2}'.format(self.database_url, self.path, urlencode(parameters))
self.path = ""
self.build_query = {}
return request_ref
def build_headers(self, token=None):
headers = {"content-type": "application/json; charset=UTF-8"}
if not token and self.credentials:
access_token = self.credentials.get_access_token().access_token
headers['Authorization'] = 'Bearer ' + access_token
return headers
def get(self, token=None, json_kwargs={}):
build_query = self.build_query
query_key = self.path.split("/")[-1]
request_ref = self.build_request_url(token)
# headers
headers = self.build_headers(token)
# do request
request_object = self.requests.get(request_ref, headers=headers)
raise_detailed_error(request_object)
request_dict = request_object.json(**json_kwargs)
# if primitive or simple query return
if isinstance(request_dict, list):
return PyreResponse(convert_list_to_pyre(request_dict), query_key)
if not isinstance(request_dict, dict):
return PyreResponse(request_dict, query_key)
if not build_query:
return PyreResponse(convert_to_pyre(request_dict.items()), query_key)
# return keys if shallow
if build_query.get("shallow"):
return PyreResponse(request_dict.keys(), query_key)
# otherwise sort
sorted_response = None
if build_query.get("orderBy"):
if build_query["orderBy"] == "$key":
sorted_response = sorted(request_dict.items(), key=lambda item: item[0])
elif build_query["orderBy"] == "$value":
sorted_response = sorted(request_dict.items(), key=lambda item: item[1])
else:
sorted_response = sorted(request_dict.items(), key=lambda item: item[1][build_query["orderBy"]])
return PyreResponse(convert_to_pyre(sorted_response), query_key)
def push(self, data, token=None, json_kwargs={}):
request_ref = self.check_token(self.database_url, self.path, token)
self.path = ""
headers = self.build_headers(token)
request_object = self.requests.post(request_ref, headers=headers, data=json.dumps(data, **json_kwargs).encode("utf-8"))
raise_detailed_error(request_object)
return request_object.json()
def set(self, data, token=None, json_kwargs={}):
request_ref = self.check_token(self.database_url, self.path, token)
self.path = ""
headers = self.build_headers(token)
request_object = self.requests.put(request_ref, headers=headers, data=json.dumps(data, **json_kwargs).encode("utf-8"))
raise_detailed_error(request_object)
return request_object.json()
def update(self, data, token=None, json_kwargs={}):
request_ref = self.check_token(self.database_url, self.path, token)
self.path = ""
headers = self.build_headers(token)
request_object = self.requests.patch(request_ref, headers=headers, data=json.dumps(data, **json_kwargs).encode("utf-8"))
raise_detailed_error(request_object)
return request_object.json()
def remove(self, token=None):
request_ref = self.check_token(self.database_url, self.path, token)
self.path = ""
headers = self.build_headers(token)
request_object = self.requests.delete(request_ref, headers=headers)
raise_detailed_error(request_object)
return request_object.json()
def stream(self, stream_handler, token=None, stream_id=None):
request_ref = self.build_request_url(token)
return Stream(request_ref, stream_handler, self.build_headers, stream_id)
def check_token(self, database_url, path, token):
if token:
return '{0}{1}.json?auth={2}'.format(database_url, path, token)
else:
return '{0}{1}.json'.format(database_url, path)
def generate_key(self):
push_chars = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz'
now = int(time.time() * 1000)
duplicate_time = now == self.last_push_time
self.last_push_time = now
time_stamp_chars = [0] * 8
for i in reversed(range(0, 8)):
time_stamp_chars[i] = push_chars[now % 64]
now = int(math.floor(now / 64))
new_id = "".join(time_stamp_chars)
if not duplicate_time:
for i in range(0, 12):
self.last_rand_chars.append(int(math.floor(uniform(0, 1) * 64)))
else:
for i in range(0, 11):
if self.last_rand_chars[i] == 63:
self.last_rand_chars[i] = 0
self.last_rand_chars[i] += 1
for i in range(0, 12):
new_id += push_chars[self.last_rand_chars[i]]
return new_id
def sort(self, origin, by_key):
# unpack pyre objects
pyres = origin.each()
new_list = []
for pyre in pyres:
new_list.append(pyre.item)
# sort
data = sorted(dict(new_list).items(), key=lambda item: item[1][by_key])
return PyreResponse(convert_to_pyre(data), origin.key())
class Storage:
""" Storage Service """
def __init__(self, credentials, storage_bucket, requests):
self.storage_bucket = "https://firebasestorage.googleapis.com/v0/b/" + storage_bucket
self.credentials = credentials
self.requests = requests
self.path = ""
if credentials:
client = storage.Client(credentials=credentials, project=storage_bucket)
self.bucket = client.get_bucket(storage_bucket)
def child(self, *args):
new_path = "/".join(args)
if self.path:
self.path += "/{}".format(new_path)
else:
if new_path.startswith("/"):
new_path = new_path[1:]
self.path = new_path
return self
def put(self, file, token=None):
# reset path
path = self.path
self.path = None
if isinstance(file, str):
file_object = open(file, 'rb')
else:
file_object = file
request_ref = self.storage_bucket + "/o?name={0}".format(path)
if token:
headers = {"Authorization": "Firebase " + token}
request_object = self.requests.post(request_ref, headers=headers, data=file_object)
raise_detailed_error(request_object)
return request_object.json()
elif self.credentials:
blob = self.bucket.blob(path)
if isinstance(file, str):
return blob.upload_from_filename(filename=file)
else:
return blob.upload_from_file(file_obj=file)
else:
request_object = self.requests.post(request_ref, data=file_object)
raise_detailed_error(request_object)
return request_object.json()
def delete(self, name):
self.bucket.delete_blob(name)
def download(self, filename, token=None):
# remove leading backlash
path = self.path
url = self.get_url(token)
self.path = None
if path.startswith('/'):
path = path[1:]
if self.credentials:
blob = self.bucket.get_blob(path)
blob.download_to_filename(filename)
else:
r = requests.get(url, stream=True)
if r.status_code == 200:
with open(filename, 'wb') as f:
for chunk in r:
f.write(chunk)
def get_url(self, token):
path = self.path
self.path = None
if path.startswith('/'):
path = path[1:]
if token:
return "{0}/o/{1}?alt=media&token={2}".format(self.storage_bucket, quote(path, safe=''), token)
return "{0}/o/{1}?alt=media".format(self.storage_bucket, quote(path, safe=''))
def list_files(self):
return self.bucket.list_blobs()
def raise_detailed_error(request_object):
try:
request_object.raise_for_status()
except HTTPError as e:
# raise detailed error message
# TODO: Check if we get a { "error" : "Permission denied." } and handle automatically
raise HTTPError(e, request_object.text)
def convert_to_pyre(items):
pyre_list = []
for item in items:
pyre_list.append(Pyre(item))
return pyre_list
def convert_list_to_pyre(items):
pyre_list = []
for item in items:
pyre_list.append(Pyre([items.index(item), item]))
return pyre_list
class PyreResponse:
def __init__(self, pyres, query_key):
self.pyres = pyres
self.query_key = query_key
def val(self):
if isinstance(self.pyres, list):
# unpack pyres into OrderedDict
pyre_list = []
# if firebase response was a list
if isinstance(self.pyres[0].key(), int):
for pyre in self.pyres:
pyre_list.append(pyre.val())
return pyre_list
# if firebase response was a dict with keys
for pyre in self.pyres:
pyre_list.append((pyre.key(), pyre.val()))
return OrderedDict(pyre_list)
else:
# return primitive or simple query results
return self.pyres
def key(self):
return self.query_key
def each(self):
if isinstance(self.pyres, list):
return self.pyres
class Pyre:
def __init__(self, item):
self.item = item
def val(self):
return self.item[1]
def key(self):
return self.item[0]
class KeepAuthSession(Session):
"""
A session that doesn't drop Authentication on redirects between domains.
"""
def rebuild_auth(self, prepared_request, response):
pass
class ClosableSSEClient(SSEClient):
def __init__(self, *args, **kwargs):
self.should_connect = True
super(ClosableSSEClient, self).__init__(*args, **kwargs)
def _connect(self):
if self.should_connect:
super(ClosableSSEClient, self)._connect()
else:
raise StopIteration()
def close(self):
self.should_connect = False
self.retry = 0
self.resp.raw._fp.fp.raw._sock.shutdown(socket.SHUT_RDWR)
self.resp.raw._fp.fp.raw._sock.close()
class Stream:
def __init__(self, url, stream_handler, build_headers, stream_id):
self.build_headers = build_headers
self.url = url
self.stream_handler = stream_handler
self.stream_id = stream_id
self.sse = None
self.thread = None
self.start()
def make_session(self):
"""
Return a custom session object to be passed to the ClosableSSEClient.
"""
session = KeepAuthSession()
return session
def start(self):
self.thread = threading.Thread(target=self.start_stream)
self.thread.start()
return self
def start_stream(self):
self.sse = ClosableSSEClient(self.url, session=self.make_session(), build_headers=self.build_headers)
for msg in self.sse:
if msg:
msg_data = json.loads(msg.data)
msg_data["event"] = msg.event
if self.stream_id:
msg_data["stream_id"] = self.stream_id
self.stream_handler(msg_data)
def close(self):
while not self.sse and not hasattr(self.sse, 'resp'):
time.sleep(0.001)
self.sse.running = False
self.sse.close()
self.thread.join()
return self
Thanks.
Related
I would like to be able to pass a call of either get, post, delete, etc, into my requests function. So instead of having all these different functions for each RESTFULness, I'd like to have a func like:
I have:
class BitbucketAPIHoss(object):
API_URL_1 = 'https://api.bitbucket.org/1.0/'
API_URL_2 = 'https://api.bitbucket.org/2.0/'
HEADERS = {'Content-Type': 'application/json'}
def __init__(self, username='codyc54321', password='trump_4_dictator_of_milky_way'):
self.username = username
self.password = password
def get_bitbucket_project_names(self):
repo_dicts = self.get_bitbucket_response_as_dict('user/repositories', "1")
repo_names = extract_values(key='name', dictionaries=repo_dicts)
return repo_names
def create_repository(self, name=None):
payload = {'scm': 'git',
'name': name,
'is_private': 'true',
}
json_payload = json.dumps(payload)
url_ending = os.path.join('repositories', self.username, name)
print(url_ending)
response = self.post_to_bitbucket(url_ending=url_ending, payload=json_payload)
print(response)
def delete_repository(self, name=None):
url_ending = os.path.join('repositories', self.username, name)
print(url_ending)
(url_ending=url_ending)
def get_bitbucket_response_as_dict(self, url_ending, api_version="2"):
if api_version == "2":
api_url = self.API_URL_2
elif api_version == "1":
api_url = self.API_URL_1
url = os.path.join(api_url, url_ending)
r = requests.get(url, auth=(self.username, self.password), headers=self.HEADERS)
content = r.text
payload = demjson.decode(content)
return payload
def post_to_bitbucket(self, url_ending, payload=None, api_version="2"):
if api_version == "2":
api_url = self.API_URL_2
elif api_version == "1":
api_url = self.API_URL_1
url = os.path.join(api_url, url_ending)
if payload:
r = requests.post(url, auth=(self.username, self.password), data=payload, headers=self.HEADERS)
else:
r = requests.post(url, auth=(self.username, self.password), headers=self.HEADERS)
try
def call_request(style):
r = requests.style(url, auth=(username, pw), headers=headers)
call_request('get')
but no:
In [6]: def call(style):
r = requests.style('https://api.bitbucket.org/1.0/', auth=('codyc54321', 'pw'), headers={'Content-Type': 'application/json'})
...:
In [7]: call(get)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-7-72b682ad376c> in <module>()
----> 1 call(get)
NameError: name 'get' is not defined
In [8]: call('get')
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-8-6a61a82da77f> in <module>()
----> 1 call('get')
<ipython-input-6-6ef72c4981c2> in call(style)
1 def call(style):
----> 2 r = requests.style('https://api.bitbucket.org/1.0/', auth=('codyc54321', 'pw'), headers={'Content-Type': 'application/json'})
3
AttributeError: 'module' object has no attribute 'style'
Can I call any func I want w a string? I can't see how to use getattr here. Thank you
ANSWER:
class BitbucketAPIHoss(object):
API_URL_1 = 'https://api.bitbucket.org/1.0/'
API_URL_2 = 'https://api.bitbucket.org/2.0/'
HEADERS = {'Content-Type': 'application/json'}
def __init__(self, username='codyc54321', password='why_so_broke_kanye?'):
self.username = username
self.password = password
self.d = {'auth': (self.username, self.password), 'headers': self.HEADERS}
def get_bitbucket_project_names(self):
repo_dicts = self.call_api('get', 'user/repositories', api_version="1")
repo_names = extract_values(key='name', dictionaries=repo_dicts)
return repo_names
def call_api(self, method, url_ending, api_version="2", **kwargs):
if api_version == "2":
api_url = self.API_URL_2
elif api_version == "1":
api_url = self.API_URL_1
url = os.path.join(api_url, url_ending) # 'user/repositories'
request_call_function = getattr(requests, method)
kwargs.update(self.d)
r = request_call_function(url, **kwargs)
payload = demjson.decode(r.content)
return payload
In [1]: from my_scripting_library import *
In [2]: hoss = BitbucketAPIHoss()
In [3]: names = hoss.get
hoss.get_bitbucket_project_names hoss.get_bitbucket_response_as_dict
In [3]: names = hoss.get_bitbucket_project_names()
In [4]: names
Out[4]:
[u'autohelper',
u'bookwormbuddy',
u'bytesized_python',
u'fakething',
u'foodpro',
...]
I think you probably want getattr:
def call(method):
f = getattr(requests, method)
return f('https://api....', ...);
I have a function that gets the profile data of an user:
API.py
def getProfileData(self):
data = json.dumps({
'_uuid' : self.uuid,
'_uid' : self.username_id,
'_csrftoken' : self.token
})
return self.SendRequest('accounts/current_user/?edit=true', self.generateSignature(data))
I want to print the returned request in the terminal, so I did this:
test.py
from API import API
API = API("username", "password")
API.login() # login
print(API.getProfileData())
But nothing is logged in the console.
Maybe I'm doing it the JavaScript way, since that's my background.
What's the correct way to do it?
EDIT:
This is what's inside SendRequest:
def SendRequest(self, endpoint, post = None, login = False):
if (not self.isLoggedIn and not login):
raise Exception("Not logged in!\n")
return;
self.s.headers.update ({'Connection' : 'close',
'Accept' : '*/*',
'Content-type' : 'application/x-www-form-urlencoded; charset=UTF-8',
'Cookie2' : '$Version=1',
'Accept-Language' : 'en-US',
'User-Agent' : self.USER_AGENT})
if (post != None): # POST
response = self.s.post(self.API_URL + endpoint, data=post) # , verify=False
else: # GET
response = self.s.get(self.API_URL + endpoint) # , verify=False
if response.status_code == 200:
self.LastResponse = response
self.LastJson = json.loads(response.text)
return True
else:
print ("Request return " + str(response.status_code) + " error!")
# for debugging
try:
self.LastResponse = response
self.LastJson = json.loads(response.text)
except:
pass
return False
def getTotalFollowers(self,usernameId):
followers = []
next_max_id = ''
while 1:
self.getUserFollowers(usernameId,next_max_id)
temp = self.LastJson
for item in temp["users"]:
followers.append(item)
if temp["big_list"] == False:
return followers
next_max_id = temp["next_max_id"]
def getTotalFollowings(self,usernameId):
followers = []
next_max_id = ''
while 1:
self.getUserFollowings(usernameId,next_max_id)
temp = self.LastJson
for item in temp["users"]:
followers.append(item)
if temp["big_list"] == False:
return followers
next_max_id = temp["next_max_id"]
def getTotalUserFeed(self, usernameId, minTimestamp = None):
user_feed = []
next_max_id = ''
while 1:
self.getUserFeed(usernameId, next_max_id, minTimestamp)
temp = self.LastJson
for item in temp["items"]:
user_feed.append(item)
if temp["more_available"] == False:
return user_feed
next_max_id = temp["next_max_id"]
If all you want to do is print the response that you get back, you can do that in SendRequest, but I suspect tha tyour real problem is that you are self-serializing your post data when requests does that for you. In any case, since your question is about printing:
if response.status_code == 200:
print('Yay, my response was: %s' % response.content)
self.LastResponse = response
self.LastJson = json.loads(response.text)
return True
else:
print ("Request return " + str(response.status_code) + " error!")
# for debugging
try:
self.LastResponse = response
self.LastJson = json.loads(response.text)
except:
pass
return False
I'm using the pyvona package (from July 3rd 2016). I have all dependencies installed. It works correctly when I call it to speak for the first time. But if I run the command again, it gives me the local unbound error:
>>> import pyvona
>>> v = pyvona.create_voice('<key>', '<secret>')
>>> v.speak('hello')
>>> v.speak('hello')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python34\lib\site-packages\pyvona.py", line 159, in speak
channel.play(sound)
UnboundLocalError: local variable 'channel' referenced before assignment
>>>
Here's the pyvona.py script:
#!/usr/bin/env python
# encoding: utf-8
"""Pyvona : an IVONA python library
Author: Zachary Bears
Contact Email: bears.zachary#gmail.com
Note: Full operation of this library requires the requests and pygame libraries
"""
import datetime
import hashlib
import hmac
import json
import tempfile
import contextlib
import os
class PyvonaException(Exception):
pass
try:
import pygame
except ImportError:
pygame_available = False
else:
pygame_available = True
try:
import requests
requests.packages.urllib3.disable_warnings()
except ImportError:
msg = 'The requests library is essential for Pyvona operation. '
msg += 'Without it, Pyvona will not function correctly.'
raise PyvonaException(msg)
_amazon_date_format = '%Y%m%dT%H%M%SZ'
_date_format = '%Y%m%d'
def create_voice(access_key, secret_key):
"""Creates and returns a voice object to interact with
"""
return Voice(access_key, secret_key)
class Voice(object):
"""An object that contains all the required methods for interacting
with the IVONA text-to-speech system
"""
voice_name = None
language = None
gender = None
speech_rate = None
sentence_break = None
paragraph_break = None
_codec = "ogg"
region_options = {
'us-east': 'us-east-1',
'us-west': 'us-west-2',
'eu-west': 'eu-west-1',
}
access_key = None
secret_key = None
algorithm = 'AWS4-HMAC-SHA256'
signed_headers = 'content-type;host;x-amz-content-sha256;x-amz-date'
_region = None
_host = None
#property
def region(self):
return self._region
#region.setter
def region(self, region_name):
self._region = self.region_options.get(region_name, 'us-east-1')
self._host = 'tts.{}.ivonacloud.com'.format(self._region)
#property
def codec(self):
return self._codec
#codec.setter
def codec(self, codec):
if codec not in ["mp3", "ogg"]:
raise PyvonaException(
"Invalid codec specified. Please choose 'mp3' or 'ogg'")
self._codec = codec
#contextlib.contextmanager
def use_ogg_codec(self):
current_codec = self.codec
self.codec = "ogg"
try:
yield
finally:
self.codec = current_codec
def fetch_voice_ogg(self, text_to_speak, filename):
"""Fetch an ogg file for given text and save it to the given file name
"""
with self.use_ogg_codec():
self.fetch_voice(text_to_speak, filename)
def fetch_voice(self, text_to_speak, filename):
"""Fetch a voice file for given text and save it to the given file name
"""
file_extension = ".{codec}".format(codec=self.codec)
filename += file_extension if not filename.endswith(
file_extension) else ""
with open(filename, 'wb') as f:
self.fetch_voice_fp(text_to_speak, f)
def fetch_voice_fp(self, text_to_speak, fp):
"""Fetch a voice file for given text and save it to the given file pointer
"""
r = self._send_amazon_auth_packet_v4(
'POST', 'tts', 'application/json', '/CreateSpeech', '',
self._generate_payload(text_to_speak), self._region, self._host)
if r.content.startswith(b'{'):
raise PyvonaException('Error fetching voice: {}'.format(r.content))
else:
fp.write(r.content)
def speak(self, text_to_speak, use_cache=False):
"""Speak a given text
"""
if not pygame_available:
raise PyvonaException(
"Pygame not installed. Please install to use speech.")
if not pygame.mixer.get_init():
pygame.mixer.init()
channel = pygame.mixer.Channel(5)
if use_cache is False:
with tempfile.SpooledTemporaryFile() as f:
with self.use_ogg_codec():
self.fetch_voice_fp(text_to_speak, f)
f.seek(0)
sound = pygame.mixer.Sound(f)
else:
cache_f = hashlib.md5(text_to_speak).hexdigest() + '.ogg'
speech_cache_dir = os.getcwd() + '/speech_cache/'
if not os.path.isdir(speech_cache_dir):
os.makedirs(speech_cache_dir)
if not os.path.isfile(speech_cache_dir + cache_f):
with self.use_ogg_codec():
self.fetch_voice(text_to_speak, 'speech_cache/' + cache_f)
f = speech_cache_dir + cache_f
sound = pygame.mixer.Sound(f)
channel.play(sound)
while channel.get_busy():
pass
def list_voices(self):
"""Returns all the possible voices
"""
r = self._send_amazon_auth_packet_v4(
'POST', 'tts', 'application/json', '/ListVoices', '', '',
self._region, self._host)
return r.json()
def _generate_payload(self, text_to_speak):
return json.dumps({
'Input': {
"Type":"application/ssml+xml",
'Data': text_to_speak
},
'OutputFormat': {
'Codec': self.codec.upper()
},
'Parameters': {
'Rate': self.speech_rate,
'SentenceBreak': self.sentence_break,
'ParagraphBreak': self.paragraph_break
},
'Voice': {
'Name': self.voice_name,
'Language': self.language,
'Gender': self.gender
}
})
def _send_amazon_auth_packet_v4(self, method, service, content_type,
canonical_uri, canonical_querystring,
request_parameters, region, host):
"""Send a packet to a given amazon server using Amazon's signature Version 4,
Returns the resulting response object
"""
# Create date for headers and the credential string
t = datetime.datetime.utcnow()
amazon_date = t.strftime(_amazon_date_format)
date_stamp = t.strftime(_date_format)
# Step 1: Create canonical request
payload_hash = self._sha_hash(request_parameters)
canonical_headers = 'content-type:{}\n'.format(content_type)
canonical_headers += 'host:{}\n'.format(host)
canonical_headers += 'x-amz-content-sha256:{}\n'.format(payload_hash)
canonical_headers += 'x-amz-date:{}\n'.format(amazon_date)
canonical_request = '\n'.join([
method, canonical_uri, canonical_querystring, canonical_headers,
self.signed_headers, payload_hash])
# Step 2: Create the string to sign
credential_scope = '{}/{}/{}/aws4_request'.format(
date_stamp, region, service)
string_to_sign = '\n'.join([
self.algorithm, amazon_date, credential_scope,
self._sha_hash(canonical_request)])
# Step 3: Calculate the signature
signing_key = self._get_signature_key(
self.secret_key, date_stamp, region, service)
signature = hmac.new(
signing_key, string_to_sign.encode('utf-8'),
hashlib.sha256).hexdigest()
# Step 4: Create the signed packet
endpoint = 'https://{}{}'.format(host, canonical_uri)
authorization_header = '{} Credential={}/{}, ' +\
'SignedHeaders={}, Signature={}'
authorization_header = authorization_header.format(
self.algorithm, self.access_key, credential_scope,
self.signed_headers, signature)
headers = {
'Host': host,
'Content-type': content_type,
'X-Amz-Date': amazon_date,
'Authorization': authorization_header,
'x-amz-content-sha256': payload_hash,
'Content-Length': len(request_parameters)
}
# Send the packet and return the response
return requests.post(endpoint, data=request_parameters,
headers=headers)
def _sha_hash(self, to_hash):
return hashlib.sha256(to_hash.encode('utf-8')).hexdigest()
def _sign(self, key, msg):
return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()
def _get_signature_key(self, key, date_stamp, region_name, service_name):
k_date = self._sign(('AWS4{}'.format(key)).encode('utf-8'), date_stamp)
k_region = self._sign(k_date, region_name)
k_service = self._sign(k_region, service_name)
k_signing = self._sign(k_service, 'aws4_request')
return k_signing
def __init__(self, access_key, secret_key):
"""Set initial voice object parameters
"""
self.region = 'us-east'
self.voice_name = 'Brian'
self.access_key = access_key
self.secret_key = secret_key
self.speech_rate = 'medium'
self.sentence_break = 400
self.paragraph_break = 650
Any help is highly appreciated.
Was able to find a workaround by adding:
pygame.mixer.init()
channel = pygame.mixer.Channel(5)
immediately after defining the speak function:
def speak(self, text_to_speak, use_cache=False):
def speak(self, text_to_speak, use_cache=False):
"""Speak a given text
"""
pygame.mixer.init()
channel = pygame.mixer.Channel(5)
Usually UnboundLocalError relates to Scopes and Namespaces in Python Scopes and NameSpaces ,
but in Your case:
In function speak() You create channel in code
if not pygame.mixer.get_init():
pygame.mixer.init()
channel = pygame.mixer.Channel(5)
In case this code does not execute channel does not bound to any object.
For example, You can check this situation by this code sample:
def test_if():
if True:
# Bound
channel_1 = "Channel_1"
if False:
# Not bound
channel_2 = "Channel_2"
print(channel_1)
print(channel_2)
test_if()
I would like to be able to pass a call of either get, post, delete, etc, into my requests function. So instead of having all these different functions for each RESTFULness, I'd like to have a func like:
I have:
class BitbucketAPIHoss(object):
API_URL_1 = 'https://api.bitbucket.org/1.0/'
API_URL_2 = 'https://api.bitbucket.org/2.0/'
HEADERS = {'Content-Type': 'application/json'}
def __init__(self, username='codyc54321', password='trump_4_dictator_of_milky_way'):
self.username = username
self.password = password
def get_bitbucket_project_names(self):
repo_dicts = self.get_bitbucket_response_as_dict('user/repositories', "1")
repo_names = extract_values(key='name', dictionaries=repo_dicts)
return repo_names
def create_repository(self, name=None):
payload = {'scm': 'git',
'name': name,
'is_private': 'true',
}
json_payload = json.dumps(payload)
url_ending = os.path.join('repositories', self.username, name)
print(url_ending)
response = self.post_to_bitbucket(url_ending=url_ending, payload=json_payload)
print(response)
def delete_repository(self, name=None):
url_ending = os.path.join('repositories', self.username, name)
print(url_ending)
(url_ending=url_ending)
def get_bitbucket_response_as_dict(self, url_ending, api_version="2"):
if api_version == "2":
api_url = self.API_URL_2
elif api_version == "1":
api_url = self.API_URL_1
url = os.path.join(api_url, url_ending)
r = requests.get(url, auth=(self.username, self.password), headers=self.HEADERS)
content = r.text
payload = demjson.decode(content)
return payload
def post_to_bitbucket(self, url_ending, payload=None, api_version="2"):
if api_version == "2":
api_url = self.API_URL_2
elif api_version == "1":
api_url = self.API_URL_1
url = os.path.join(api_url, url_ending)
if payload:
r = requests.post(url, auth=(self.username, self.password), data=payload, headers=self.HEADERS)
else:
r = requests.post(url, auth=(self.username, self.password), headers=self.HEADERS)
try
def call_request(style):
r = requests.style(url, auth=(username, pw), headers=headers)
call_request('get')
but no:
In [6]: def call(style):
r = requests.style('https://api.bitbucket.org/1.0/', auth=('codyc54321', 'pw'), headers={'Content-Type': 'application/json'})
...:
In [7]: call(get)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-7-72b682ad376c> in <module>()
----> 1 call(get)
NameError: name 'get' is not defined
In [8]: call('get')
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-8-6a61a82da77f> in <module>()
----> 1 call('get')
<ipython-input-6-6ef72c4981c2> in call(style)
1 def call(style):
----> 2 r = requests.style('https://api.bitbucket.org/1.0/', auth=('codyc54321', 'pw'), headers={'Content-Type': 'application/json'})
3
AttributeError: 'module' object has no attribute 'style'
Can I call any func I want w a string? I can't see how to use getattr here. Thank you
ANSWER:
class BitbucketAPIHoss(object):
API_URL_1 = 'https://api.bitbucket.org/1.0/'
API_URL_2 = 'https://api.bitbucket.org/2.0/'
HEADERS = {'Content-Type': 'application/json'}
def __init__(self, username='codyc54321', password='why_so_broke_kanye?'):
self.username = username
self.password = password
self.d = {'auth': (self.username, self.password), 'headers': self.HEADERS}
def get_bitbucket_project_names(self):
repo_dicts = self.call_api('get', 'user/repositories', api_version="1")
repo_names = extract_values(key='name', dictionaries=repo_dicts)
return repo_names
def call_api(self, method, url_ending, api_version="2", **kwargs):
if api_version == "2":
api_url = self.API_URL_2
elif api_version == "1":
api_url = self.API_URL_1
url = os.path.join(api_url, url_ending) # 'user/repositories'
request_call_function = getattr(requests, method)
kwargs.update(self.d)
r = request_call_function(url, **kwargs)
payload = demjson.decode(r.content)
return payload
In [1]: from my_scripting_library import *
In [2]: hoss = BitbucketAPIHoss()
In [3]: names = hoss.get
hoss.get_bitbucket_project_names hoss.get_bitbucket_response_as_dict
In [3]: names = hoss.get_bitbucket_project_names()
In [4]: names
Out[4]:
[u'autohelper',
u'bookwormbuddy',
u'bytesized_python',
u'fakething',
u'foodpro',
...]
I think you probably want getattr:
def call(method):
f = getattr(requests, method)
return f('https://api....', ...);
I write script, which uploads large file to third party website. I use poster module
Here code
class upload_in_chunks(object):
def __init__(self, filename, chunksize):
self.filename = filename
self.chunksize = chunksize
self.totalsize = os.path.getsize(filename)
self.readsofar = 0
def __iter__(self):
with open(self.filename, 'rb') as file:
while True:
data = file.read(self.chunksize)
if not data:
sys.stderr.write("\n")
break
self.readsofar += len(data)
percent = self.readsofar * 1e2 / self.totalsize
sys.stderr.write("\r{percent:3.0f}%".format(percent=percent))
yield data
def __len__(self):
return self.totalsize
class IterableToFileAdapter(object):
def __init__(self, iterable):
self.iterator = iter(iterable)
self.length = len(iterable)
def read(self, size=-1): # TBD: add buffer for `len(data) > size` case
return next(self.iterator, b'')
def __len__(self):
return self.length
def upload_file(s, data, files, url):
class FuncThread(threading.Thread):
def __init__(self, s, data, files, url):
threading.Thread.__init__(self)
self.result = False
self.error = None
self.s = s
self.data = data
self.files = files
self.url = url
def run(self):
try:
register_openers()
items = []
for name, value in self.data.items():
items.append(MultipartParam(name, value))
#add file
for name, value in self.files.items():
items.append(MultipartParam.from_file(name, value))
datagen, h = multipart_encode(items)
#h.update(headers)
# Create the Request object
#self.result = self.s.post(self.url, data = datagen.read(), headers = h)
for item, value in headers.iteritems():
h[item] = value
#for item, value in headers.iteritems():
#h[item] = value
h["Cookie"] = ""
for item, value in requests.utils.dict_from_cookiejar(self.s.cookies).iteritems():
h["Cookie"] += item + "=" + value + "; "
print h["Cookie"]
#h[item] = value
print h
request = urllib2.Request(self.url, datagen, h)
#Actually do the request, and get the response
self.result = urllib2.urlopen(request).read()
except Exception as error:
self.error = error
self.result = False
def _stop(self):
if self.isAlive():
threading.Thread._Thread__stop(self)
try:
it = FuncThread(s, data, files, url)
it.start()
it.join(upload_timeout)
if it.isAlive():
it._stop()
return (False, "[-] Time expired.")
else:
return (it.result, it.error)
except Exception as error:
return (False, error)
And in my upload.py I use
try:
payload = {'Filename': f_path,
'tags': 'tag1',
'keywords': 'keyword1',
'cookie': cookie,
'title': 'Large file',
'categories': '["35","13","37"]',
'privacy': 'community',
'source': 5,
'production': "professional"}
(r, error) = upload_file(self.s, payload, {'Filedata': f_path}, url)
I have dedicated server with 100m\bit internet channel.
But my script upload files using only 1-2 m\bit
The website recipient has not any limitations and it doesn't throttle me.
How can I force my code to use full 100 m\bit?