local variable 'verify_payment' referenced before assignment - python

I'm having the local variable referenced before assignment error and I have tried a lot of ways that I can use to fix this. Any help would be greatly appreciated
This is my Views.py (the error after the top of the second if statement)
def call_back_url(request):
reference = request.GET.get('reference')
# We need to fetch the reference from PAYMENT
check_pay = PayHistory.objects.filter(paystack_charge_id=reference).exists()
if check_pay == False:
# This means payment was not made error should be thrown here...
print("Error")
else:
payment = PayHistory.objects.get(paystack_charge_id=reference)
# We need to fetch this to verify if the payment was successful.
def verify_payment(request):
url = 'https://api.paystack.co/transaction/verify/'+reference
headers = {
'Authorization': 'Bearer '+settings.PAYSTACK_SECRET_KEY,
'Content-Type' : 'application/json',
'Accept': 'application/json',
}
datum = {
"reference": payment.paystack_charge_id
}
x = requests.get(url, data=json.dumps(datum), headers=headers)
if x.status_code != 200:
return str(x.status_code)
results = x.json()
return results
initialized = verify_payment(request)
if initialized['data']['status'] == 'success':
PayHistory.objects.filter(paystack_charge_id=initialized['data']['reference']).update(paid=True)
new_payment = PayHistory.objects.get(paystack_charge_id=initialized['data']['reference'])
instance = Membership.objects.get(id=new_payment.payment_for.id)
sub = UserMembership.objects.filter(reference_code=initialized['data']['reference']).update(membership=instance)
user_membership = UserMembership.objects.get(reference_code=initialized['data']['reference'])
Subscription.objects.create(user_membership=user_membership, expires_in=dt.now().date() + timedelta(days=user_membership.membership.duration))
return redirect('subscribed')
return render(request, 'payment.html')
def subscribed(request):
return render(request, 'subscribed.html')

try:
def verify_payment(request):
url = 'https://api.paystack.co/transaction/verify/'+reference
headers = {
'Authorization': 'Bearer '+settings.PAYSTACK_SECRET_KEY,
'Content-Type' : 'application/json',
'Accept': 'application/json',
}
datum = {
"reference": payment.paystack_charge_id
}
x = requests.get(url, data=json.dumps(datum), headers=headers)
if x.status_code != 200:
return str(x.status_code)
results = x.json()
return results
def call_back_url(request):
reference = request.GET.get('reference')
# We need to fetch the reference from PAYMENT
check_pay = PayHistory.objects.filter(paystack_charge_id=reference).exists()
if check_pay == False:
# This means payment was not made error should be thrown here...
print("Error")
else:
payment = PayHistory.objects.get(paystack_charge_id=reference)
# We need to fetch this to verify if the payment was successful.
initialized = verify_payment(request)
if initialized['data']['status'] == 'success':
PayHistory.objects.filter(paystack_charge_id=initialized['data']['reference']).update(paid=True)
new_payment = PayHistory.objects.get(paystack_charge_id=initialized['data']['reference'])
instance = Membership.objects.get(id=new_payment.payment_for.id)
sub = UserMembership.objects.filter(reference_code=initialized['data']['reference']).update(membership=instance)
user_membership = UserMembership.objects.get(reference_code=initialized['data']['reference'])
Subscription.objects.create(user_membership=user_membership, expires_in=dt.now().date() + timedelta(days=user_membership.membership.duration))
return redirect('subscribed')
return render(request, 'payment.html')
def subscribed(request):
return render(request, 'subscribed.html')

Related

Time format incorrect error when posting buy order Bitget API

Hello and thanks in advance for any help
I used this post (How to fix <Response [400]> error when making a request to the Bitget Futures Rest API in Python?) to get me well on my way to creating a post buy limit order for the Bitget API.
I keep getting this error though: {'code': '40409', 'msg': 'wrong format', 'requestTime': 1673551362880, 'data': None}
Looking up that error code suggests it's the time - I presume that used for the nonce - which is incorrect somehow?
For my post order I've tried using exactly the same format as the very useful answer provided by Tariq - https://stackoverflow.com/users/12907359/tarique in the above post - (Thanks Tariq!) ...therefore, effectively the only things that change from his code (which works for me), is the fact that mine a POST rather than a GET, and the 'query' content is different.
I'm posting below Tariq's code which works and my own as well where I'm getting the error. Any ideas very welcome, thanks!
I have commented where appropriate to highlight Tariq's original code and where I have created similar functions of my own.
import hashlib
import hmac
import base64
import requests
import time
import json
api_passphrase = "your secret"
api_key = "api key"
api_sec = "api secret"
api_url = "https://api.bitget.com"
#symbol = "BTCUSDT_UMCBL" # this is futures
symbol = 'BTC/USDT' # this is spot - I've added this here
def parse_params_to_str(params):
url = '?'
for key, value in params.items():
url = url + str(key) + '=' + str(value) + '&'
return url[0:-1]
def get_signature(message):
mac = hmac.new(bytes(api_sec, encoding='utf8'), bytes(message, encoding='utf-8'), digestmod='sha256')
d = mac.digest()
return base64.b64encode(d)
def bitget_request_info(request_path, body, query, method): # this is Tariq's
std_time = time.time() * 1000
new_time = int(std_time)
if str(body) == '{}' or str(body) == 'None':
converted_body = ''
else:
converted_body = json.dumps(body)
message = str(new_time) + method + request_path + parse_params_to_str(query) + converted_body
headers = {"ACCESS-KEY": api_key,
"ACCESS-SIGN": get_signature(message),
"ACCESS-TIMESTAMP": str(new_time),
"ACCESS-PASSPHRASE": api_passphrase,
"Content-Type": "application/json",
"Locale": "en-US"
}
if method == "GET":
request_resp = requests.get((api_url + request_path), headers=headers, params=query)
return request_resp
def bitget_post_buy_order(request_path, body, query, method): # This is my version for the post buy order
std_time = time.time() * 1000
new_time = int(std_time)
if str(body) == '{}' or str(body) == 'None':
converted_body = ''
else:
converted_body = json.dumps(body)
message = str(new_time) + method + request_path + parse_params_to_str(query) + converted_body
headers = {"ACCESS-KEY": api_key,
"ACCESS-SIGN": get_signature(message),
"ACCESS-TIMESTAMP": str(new_time),
"ACCESS-PASSPHRASE": api_passphrase
"Content-Type": "application/json",
"Locale": "en-US"
}
if method == "POST":
request_resp = requests.post((api_url + request_path), headers=headers, params=query)
return request_resp
def get_info(): # this was Tariq's (I put it in a def)
order_resp = bitget_request_info("/api/mix/v1/account/account", None, query, "GET")
print(order_resp.json())
def place_buy_order(): # this is my version
place_order = bitget_post_buy_order("/api/spot/v1/trade/orders", None, query, "POST")
print(place_order.json())
def get_query_deets(): # this was Tariq's original
global query
query = {
"symbol": symbol,
"marginCoin": "USDT"
}
return(query)
def buy_order_deets(): # this is mine for the post buy order query
global query
query = {
'symbol': symbol,
'side': 'buy',
'orderType': 'limit',
'price': 9999,
'quantity': 0.01
}
return(query)
def main():
buy_order_deets()
place_buy_order()
#get_query_deets()
#get_info()
main()

How to pass multiple values to a API call in get method?

This is my list:
unique_IMO = [94229,95986,96967,94731,95731,96612]
I need to pass these numbers to the following request:
url = 'https://api.lloydslistintelligence.com/v1/aispositionhistory?output=json&vesselImo={0}&pageNumber={1}'.format(unique_IMO,1)
I was able to call the endpoint for each number using a for loop but I don't know how to pass all the numbers at once.
I tried the below code but it still gave an error.
test1 = format(','.join(map(str,unique_IMO)))
Can someone please help me with this?
I have a list of numbers which I am trying to pass all at once to an API call. I did check using Postman to see if the endpoint accepts multiple values and it does.
API documentation snippet
So below is what I'm doing right now and it works. I am trying to make the api calls faster/efficient.
df_list = []
for ind,row in vessels.iterrows():
vesselImo = int(row['Imo'])
#Retrieve data from aispositionhistory endpoint
vessel_hist = pd.DataFrame()
total_recs = 0
for date_string in date_list:
url = 'https://api.lloydslistintelligence.com/v1/aispositionhistory?output=json&vesselImo={0}&dateRange={1}&pageNumber={2}'.format(vesselImo,date_string,1)
head = {'Authorization': '{}'.format(api_token)}
response = requests.get(url, headers=head)
#****DEBUGGING****
#print("status code: ", response.status_code )
if(response.json()['Data']['totalRecords'] != 0):
tmp = response.json()['Data']['items']
df = json_normalize(tmp)
vessel_hist = vessel_hist.append(df,ignore_index=True)
#Get reported number of records for validation
total_recs = total_recs + response.json()['Data']['totalRecords']
#Identify if API response is multiple pages
if(response.json()['Data']['totalPages'] > 1):
num_pages = response.json()['Data']['totalPages']
#print('API pull had more than one page: ' + date_string)
for page_no in range(2,num_pages+1):
url = 'https://api.lloydslistintelligence.com/v1/aispositionhistory?output=json&vesselImo={0}&dateRange={1}&pageNumber={2}'.format(vesselImo,date_string,1)
response = requests.get(url, headers=head)
tmp = response.json()['Data']['items']
df = json_normalize(tmp)
vessel_hist = vessel_hist.append(df,ignore_index=True)
# Validation based on record count
if(total_recs != vessel_hist.shape[0]):
print('Validation Error: reported records do not match dataframe')
if(vessel_hist.shape[0]>0):
#Format Dataframe
new_columns = ['vesselId','MMSI','PositionTimestamp','Latitude','Longitude','Speed','Course','Rot','Heading',
'nearestPlace','nearestPlaceId','nearestCountry','Distance','Destination','Eta','Draught',
'Dimensions','Status','Ship_type','Source']
vessel_hist.columns = new_columns
vessel_hist = vessel_hist[['MMSI','PositionTimestamp','Status','Latitude','Longitude','Speed','Course','Rot',
'Heading','Draught','Destination','Eta','Source','Ship_type','Dimensions',
'Distance','nearestCountry','nearestPlace','nearestPlaceId','vesselId']]
vessel_hist['PositionTimestamp'] = pd.to_datetime(vessel_hist['PositionTimestamp'],dayfirst=False)
vessel_hist.sort_values('PositionTimestamp', inplace=True)
vessel_hist.reset_index(drop=True, inplace=True)
df_list.append(vessel_hist)
print('Input vessel Id: ' + str(vesselImo))
print('Input Date Range: ' + start_input + ' - ' + end_input)
print('No. of AIS records: ' + str(vessel_hist.shape[0]))
df_list
vessels is a dataframe which contains the IMO numbers
vessels = pd.DataFrame((94229,95986,96967,94731,95731,96612),columns=['Imo'])
date_list is a list created based on the desired time range.
Hope this example will help
import requests
def main():
unique_IMO = [94229, 95986, 96967, 94731, 95731, 96612]
base_url = "http://httpbin.org"
query_params = {
"output": "json",
"vesselImo": unique_IMO,
"pagerNumber": 1
}
response = requests.get(url=base_url + "/get", params=query_params)
print(response.json())
if __name__ == '__main__':
main()
GET query parameters will be:
{'args': {'output': 'json', 'pagerNumber': '1', 'vesselImo': ['94229', '95986', '96967', '94731', '95731', '96612']}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.27.1', 'X-Amzn-Trace-Id': 'Root=1-633bc95b-2771014e17fa5dc6580e4e3e'}, 'origin': 'x.x.x.x', 'url': 'http://httpbin.org/get?output=json&vesselImo=94229&vesselImo=95986&vesselImo=96967&vesselImo=94731&vesselImo=95731&vesselImo=96612&pagerNumber=1'}```

Python: cannot access class attribute from different modules/functions

I have a class called Org, and I'm trying to access its method from multiple functions (that are defined outside of the class). I'm calling main() first, followed by discover_buildings(). The main() executes without error, however, I get AttributeError: 'Org' has no attribute 'headers' error after I call discover_buildings(). What is it that I'm doing wrong? (I was expecting the headers attribute to be shared across the different methods)
class Org(object):
def __init__(self, client_id, client_secret, grant_type='client_credentials'):
self.grant_type = grant_type
self.client_id = client_id
self.client_secret = client_secret
self.url = CI_A_URL
def auth(self):
""" authenticate with bos """
params = {
'client_id': self.client_id,
'client_secret': self.client_secret,
'grant_type': self.grant_type
}
r = requests.post(self.url + 'o/token/', data=params)
if r.status_code == 200:
self.access_token = r.json()['access_token']
self.headers = {
'Authorization': 'Bearer %s' %self.access_token,
'Content-Type': 'application/json',
}
else:
logging.error(r.content)
r.raise_for_status()
def get_buildings(self, perPage=1000):
params = {
'perPage': perPage
}
r = requests.get(self.url + 'buildings/', params=params, headers=self.headers)
result = r.json().get('data')
if r.status_code == 200:
buildings_dict = {i['name']: i['id'] for i in result}
sheet_buildings['A1'].value = buildings_dict
else:
logging.error(r.content)
r.raise_for_status()
client_id = 'xxx'
client_secret = 'yyy'
gateway_id = 123
o = Org(client_id, client_secret)
def discover_buildings():
return o.get_buildings()
def main():
return o.auth()
Thanks, in advance, for your help!
Try using a property to calculate headers whenever you need it and then cache it.
def auth(self):
""" authenticate with bos """
# 👇you might want to isolate `token` into a nested #property token
params = {
'client_id': self.client_id,
'client_secret': self.client_secret,
'grant_type': self.grant_type
}
# note assignment to `_headers`, not `headers`
r = requests.post(self.url + 'o/token/', data=params)
if r.status_code == 200:
self._access_token = r.json()['access_token']
# 👆
self._headers = { # 👈
'Authorization': 'Bearer %s' %self._access_token,
'Content-Type': 'application/json',
}
else:
logging.error(r.content)
r.raise_for_status()
#cache after the first time.
_headers = None
#property
def headers(self):
""" call auth when needed
you might want to isolate `token`
into its own property, allowing different
headers to use the same token lookup
"""
if self._headers is None:
self.auth()
return self._headers
the problem is the way you define "discover_buildings"
you define it first with "o" just initialised not after the authentication.
to handle this:
rewrite discover to take 'o' as a parameter
or
check first to see 'o' has 'headers' if not authenticate 'o' and do the rest
def discover_buildings():
if not getattr(o, 'headers'):
o.auth()
return o.get_buildings()
You didn't define self.headers. You need to run o.auth() (or define self.headers) before you run o.get_buildings().

Python Dynamics 365 package to read write data

We managed to connect to our dynamics 365 cloud instance with token auth. However, we were hoping to find package like "pydynamics".
The package "https://libraries.io/pypi/dynamics365crm-python" seems newer, but it seems only to be able to handle standard objects, not custom objects.
Our current solution works with REST only.
import requests
import json
#set these values to retrieve the oauth token
crmorg = 'https://org.crm4.dynamics.com' #base url for crm org
clientid = '<id>' #application client id
client_secret = '<secret>'
username = 'dynamics-api#org.com' #username
userpassword = 'pw' #password
tokenendpoint = 'https://login.microsoftonline.com/bb23defa-be1d-4137-969b-324f8468f15a/oauth2/token' #oauth token endpoint
authorizationendpoint = 'https://login.microsoftonline.com/bb23defa-be1d-4137-969b-324f8468f15a/oauth2/authorize'
#build the authorization token request
tokenpost = {
'client_id':clientid,
'resource':crmorg,
'client_secret':client_secret,
'username':username,
'password':userpassword,
'grant_type':'password',
'oauthUrl':authorizationendpoint
}
#make the token request
tokenres = requests.post(tokenendpoint, data=tokenpost)
#set accesstoken variable to empty string
accesstoken = ''
#extract the access token
try:
accesstoken = tokenres.json()['access_token']
except(KeyError):
#handle any missing key errors
print('Could not get access token')
#set these values to query your crm data
crmwebapi = 'https://<org>.crm4.dynamics.com/api/data/v9.1' #full path to web api endpoint
crmwebapiquery = '/new_households' #web api query (include leading /)
#prepare the crm request headers
crmrequestheaders = {
'Authorization': 'Bearer ' + accesstoken,
'OData-MaxVersion': '4.0',
'OData-Version': '4.0',
'Accept': 'application/json',
'Content-Type': 'application/json; charset=utf-8',
'Prefer': 'odata.maxpagesize=500',
'Prefer': 'odata.include-annotations=OData.Community.Display.V1.FormattedValue'
}
#make the crm request
crmres = requests.get(crmwebapi+crmwebapiquery, headers=crmrequestheaders)
try:
#get the response json
crmresults = crmres.json()['value'][0]
#loop through it
for key,value in crmresults.items():
print (key, value)
except KeyError:
#handle any missing key errors
print('Could not parse CRM results')
Anyone know a package?
REST API is the way to go.
We use them every time with JavaScript and parase the response as Json.
Below is sample call which I perform within crm, you will see the response been transformed into Json
Don't worry much about details, for you important is this line var results = JSON.parse(this.response);
var req = new XMLHttpRequest();
req.open("GET", Xrm.Page.context.getClientUrl() + "/api/data/v9.1/accounts?$select=accountcategorycode,accountclassificationcode,accountid,accountnumber,accountratingcode", false);
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.setRequestHeader("Prefer", "odata.include-annotations=\"*\",odata.maxpagesize=10");
req.onreadystatechange = function() {
if (this.readyState === 4) {
req.onreadystatechange = null;
if (this.status === 200) {
var results = JSON.parse(this.response);
for (var i = 0; i < results.value.length; i++) {
var accountcategorycode = results.value[i]["accountcategorycode"];
var accountcategorycode_formatted = results.value[i]["accountcategorycode#OData.Community.Display.V1.FormattedValue"];
var accountclassificationcode = results.value[i]["accountclassificationcode"];
var accountclassificationcode_formatted = results.value[i]["accountclassificationcode#OData.Community.Display.V1.FormattedValue"];
var accountid = results.value[i]["accountid"];
var accountnumber = results.value[i]["accountnumber"];
var accountratingcode = results.value[i]["accountratingcode"];
var accountratingcode_formatted = results.value[i]["accountratingcode#OData.Community.Display.V1.FormattedValue"];
}
} else {
Xrm.Utility.alertDialog(this.statusText);
}
}
};
req.send();

Why raise_for_status() did not catch the error?

Trying to check for none 200 Response in the current_track() function. What could be a problem? It throwing JSONDecodeError error. But if I understood raise_for_ status correctly it should have prevented the function from trying to load a JSON from a faulty web-page? If I run the script without this check and with uncommenting lines check_playback() it successfully catches JSONDecodeError.
The script is fetching data from Spotify and putting it to the status on vk.com.
import config
import webbrowser
import requests
import furl
import secrets
import string
import time
import os
import simplejson as json
URL_CODE_BASE_VK = 'https://oauth.vk.com/authorize'
URL_CODE_BASE_SP = 'https://accounts.spotify.com/authorize'
URL_TOKEN_VK = 'https://oauth.vk.com/access_token'
URL_TOKEN_SP = 'https://accounts.spotify.com/api/token'
URL_TRACK = 'https://api.spotify.com/v1/me/player/currently-playing'
URL_STATUS = 'https://api.vk.com/method/status.set'
EXP_IN_TOKEN_SP = 3400
EXP_IN_TOKEN_VK = 86400
FILE_TOKEN_VK = 'vk_token.json'
FILE_TOKEN_SP = 'sp_token.json'
def get_auth_code_vk():
url_code_params = {
'client_id': config.CLIENT_ID_VK,
'response_type': 'code',
'redirect_uri': 'https://oauth.vk.com/blank.html',
'v': 5.92,
'scope': 'status',
'state': gen_state(),
'display': 'page'
}
code = url_open(URL_CODE_BASE_VK, url_code_params)
return parse_code(code)
def get_auth_code_sp():
url_code_params = {
'client_id': config.CLIENT_ID_SP,
'response_type': 'code',
'redirect_uri': 'https://www.spotify.com/',
'scope': 'user-read-currently-playing',
'state': gen_state()
}
code = url_open(URL_CODE_BASE_SP, url_code_params)
return parse_code(code)
def gen_state():
symbols = string.ascii_lowercase + string.digits
return ''.join(secrets.choice(symbols) for _ in range(12))
def url_open(url_base, url_params):
url_code_full = furl.furl(url_base).add(url_params).url
webbrowser.open_new_tab(url_code_full)
input_url = input('Enter the whole URL, that you have been redirected on: ')
return input_url
def parse_code(url):
return (url.split("code=")[1]).split("&state=")[0]
def get_token_vk():
data = {
'grant_type': 'authorization_code',
'code': get_auth_code_vk(),
'redirect_uri': 'https://oauth.vk.com/blank.html',
'client_id': 6782333,
'client_secret': config.CLIENT_SECRET_VK
}
response = requests.post(url=URL_TOKEN_VK, data=data).json()
write_file(FILE_TOKEN_VK, response)
def get_token_sp():
data = {
'grant_type': 'authorization_code',
'code': get_auth_code_sp(),
'redirect_uri': 'https://www.spotify.com/',
'client_id': config.CLIENT_ID_SP,
'client_secret': config.CLIENT_SECRET_SP
}
response = requests.post(url=URL_TOKEN_SP, data=data).json()
write_file(FILE_TOKEN_SP, response)
def write_file(tkn_file, response):
dict = {}
dict['token'] = response["access_token"]
dict['time'] = time.time()
with open(tkn_file, 'w') as file:
file.write(json.dumps(dict))
def load_file(tkn_file):
with open(tkn_file) as file:
data = json.load(file)
return data
def set_status():
params = {
'v': 5.92,
'access_token': load_file(FILE_TOKEN_VK)['token'],
'text': current_track()
}
set_status = requests.get(url=URL_STATUS, params=params)
def track_data():
tkn_file = load_file(FILE_TOKEN_SP)['token']
headers = {
'Accept': 'application/json',
'Authorization': f'Bearer {tkn_file}'
}
return requests.get(url=URL_TRACK, headers=headers)
def current_track():
response = track_data()
print(response)
try:
response.raise_for_status()
except requests.exceptions.HTTPError as e:
return "Error: " + str(e)
# data = track_data().json()
data = response.json()
artist = data['item']['artists'][0]['name']
track = data['item']['name']
return(f'{artist} - {track}')
def check_playback():
set_status()
print(current_track())
# try:
# set_status()
# print(current_track())
# except json.decoder.JSONDecodeError:
# print('Not playing')
def token_missing(file):
return not os.path.isfile(file)
def token_expired(file, exp_in):
return time.time() - load_file(file)['time'] > exp_in
def token_not_valid(file, exp_in):
return token_missing(file) or token_expired(file, exp_in)
def run_script():
if token_not_valid(FILE_TOKEN_VK, EXP_IN_TOKEN_VK):
get_token_vk()
if token_not_valid(FILE_TOKEN_SP, EXP_IN_TOKEN_SP):
get_token_sp()
check_playback()
if __name__ == "__main__":
run_script()
Error screen
raise_for_status() will only raise an exception if the server reported an error to you (and even then, only if it actually followed the HTTP spec and returned a HTTP error code).
There is no way for the library to know that the response is incorrect. Even if it was correctly formatted JSON, it can't know what schema you expect it to follow (what fields should be present, and what types those fields should have). Even if it knew the schema and had verified it, there is no way for it to know that the data is actually correct and not made up on the spot.

Categories