How to iterate over a bytes object in Python? - python

I am doing a POST request in Django and I am receiving a bytes object. I need to count the number of times a particular user appears on this object but I am receiving the following error TypeError: 'int' object is not subscriptable. This is what I have so far:
def filter_url(user):
''' do the POST request, this code works '''
filters = {"filter": {
"filters": [{
"field": "Issue_Status",
"operator": "neq",
"value": "Queued"
}],
"logic": "and"}}
url = "http://10.61.202.98:8081/Dev/api/rows/cat/tickets?"
response = requests.post(url, json=filters)
return response
def request_count():
'''This code requests a POST method and then it stores the result of all the data
for user001 as a bytes object in the response variable. Afterwards, a call to the
perform_count function is made to count the number of times that user user001 appeared.'''
user = "user001"
response = filter_url(user).text.encode('utf-8')
weeks_of_data = []
weeks_of_data.append(perform_count(response))
def perform_count(response):
''' This code does not work, int object is not subscriptable '''
return Counter([k['user_id'] for k in response)
#structure of the bytes object
b'[{"id":1018002,"user_id":"user001","registered_first_time":"Yes", ...}]'
# This is the result that indicates that response is a bytes object.
print(type(response))
<class 'bytes'>
How can I count the number of times that user001 appears by using the the peform_count() function? Which modification does this function require to work?

You do receive bytes, yes, but you then have the requests library decode it (via the response.text attribute, which automatically decodes the data), which you then re-encode yourself:
response = filter_url(user).text.encode('utf-8')
Apart from just using the response.content attribute instead to avoid the decode -> encode round-trip, you should really just decode the data as JSON:
data = filter_url(user).json()
Now data is a list of dictionaries, and your perform_count() function can operate on that directly.

Related

Django Rest framework - I am trying to convert a property received in Response object to JSON object and iterate through it. But response is string

In views.py VENDOR_MAPPER is list of dictionary each dictionary has id, name, placeholder and autocommit key. I also tried sending json instead of Response object.
resp_object = {}
resp_object['supported_vendors'] = VENDOR_MAPPER
resp_object['vendor_name'] = ""
resp_object['create_vo_entry'] = False
resp_object['generate_signature_flag'] = False
resp_object['branch_flag'] = False
resp_object['trunk_flag'] = False
resp_object['branch_name'] = ""
resp_object['advisory'] = ""
data = {'data': resp_object}
return Response(data)
On home.html I am accessing the vendors_supported which is list and iterate through it, however instead of object i am getting string as type of variable.
var supported_vendors = "{{data.supported_vendors|safe}}";
console.log(supported_vendors);
console.log("Supported_vendors ", supported_vendors);
console.log("Supported_vendors_type:", typeof(supported_vendors));
data.supported_vendors|safe (django template tagging) is used to remove the unwanted characters in the response i have also tried without safe, but still the type was string
also tried converted as well as parse the response but type is shown as string
var supported_vendors = "{{data.supported_vendors}}";
console.log(JSON.parse(supported_vendors));
console.log(JSON.stringify(supported_vendors));
Output generated, i have printed the response type and values i get, also converting using JSON.parse and JSON.stringify did not work and output every time was string
[1]: https://i.stack.imgur.com/DuSMb.png
I want to convert the property into javascript object and perform some computations
You can try this instead ,
return HttpResponse(json.dumps(data),
content_type="application/json")
I got the answer:
var supported_vendors = "{{data.supported_vendors}}";
Converted the above line to
var supported_vendors = {{data.supported_vendors}};
removed quotes from the variable

Python Base64 decode failed error in a function

I have the error as "Base64 decode failed" using the following function. The following function is used to call the model that is saved in Google AI Platform. However, the data input has to be base64 serialized, hence, I include the get_serialized_example(raw) function within the tfx_test(request). Any help and advice are appreciated. Thanks in advance!
def tfx_test(request):
#User Inputs
project = request.project
model = request.model
signature = request.signature
version = request.version
#Data inputs Base64 encoder
def get_serialized_example(raw):
return tf.train.Example(
features=tf.train.Features(
feature={"value":
tf.train.Feature(bytes_list=tf.train.BytesList(value=[raw]))
}
)
).SerializeToString()
b64_country_code = base64.b64encode(get_serialized_example(request.country_code)).decode('utf-8')
b64_project_type = base64.b64encode(get_serialized_example(request.project_type)).decode('utf-8')
# ml.googleapis.com
service = googleapiclient.discovery.build('ml', 'v1')
name = 'projects/{}/models/{}'.format(project, model)
if version is not None:
name += '/versions/{}'.format(version)
response = service.projects().predict(
name=name,
body={
'signature_name': signature,
'instances': [
{
"examples":{"b64": b64_country_code[0],
"b64": b64_project_type[0]}
}]
}
).execute()
if 'error' in response:
raise RuntimeError(response['error'])
return response['predictions']
It seems that you're not senfing a valid base64 string. Instead, you're just sending the first character:
"examples":{"b64": b64_country_code[0],
"b64": b64_project_type[0]}
The first character of a base-64 string is not a valid base 64 string, as base64 encoding takes every three characters and encodes them as four.

Flask returning some response objects as string-like JSON not JSON

I have five variables I am trying to return from a flask route. Seemingly no matter how I format them, two of them will NOT return as anything but JSON-looking strings.
My Flask route looks like this
#app.route('/mapcreator/<lat>/<lng>', methods=['GET', 'POST'])
def receive_coords(lat, lng):
lat = float(lat)
lng = float(lng)
point = (lat,lng)
map1 = somefunction(point)
number = ((somefunction(point))[0])
featureCount = ((somefunction(point))[1])
map2 = ((amb.somefunction(point))[2])
response = make_response(jsonify(map1=map1, number=number, featureCount=featureCount, map2=map2, point=point))
response.headers['content-type'] = 'application/json'
return response
number, point, map1 are returning correctly as json objects.
Each variable's Type in Python:
number: int
point: array
map1: dict
map2: str
featureCount: str
This is how each of the variables is processed in the backend:
map1: map1back = mplleaflet.fig_to_geojson(fig=ax.figure) prints as a geojson, looks like a dict
map2: map2back = df_to_geojson(poi_df, col); map2back = json.dumps(poiGJ)
looks like a standard geojson
featureCount:
featureCount = all_features['feature'].value_counts(); featureCount = featureCount.to_json()
looks like a standard json
If I change the type of these to dict, I get
500 internal server error.
As everything stands they log in the browser console like this:
featureCount:"{"parking":67,"bicycle_parking":32,"bench":20,"p.....
map2:"{"type": "FeatureCollection", "features": [{"geometry": {"type": "Point", "coo.....
They do not read as "Object > " but rather as JSON-looking strings.
I have tried everything here and I am really stumped. I can't see anything different about these two response objects and I cannot get them to be real JSON responses.
Thanks a million in advance!
I solved this issue.
response = make_response(jsonify(map1=map1, number=number,
featureCount=json.loads(featureCount),
map2=json.loads(map2), point=point))
Had to do with the jsons being json like strings rather than JSON objects. Pandas only creates json style strings.

TypeError: byte indices must be integers

I want to get the top artists from a specific country from the last fm API in JSON and save the name and url in the name and url variables. But it always appears "TypeError: byte indices must be integers". Do you know where is the issue?
Working example:
import requests
api_key = "xxx"
for i in range(2,5):
artists = requests.get('http://ws.audioscrobbler.com/2.0/?method=geo.gettopartists&country=spain&format=json&page='+str(i)+'&api_key='+api_key)
for artist in artists:
print(artist)
#name = artist['topartists']['artist']['name']
#url = artist['topartists']['artist']['url']
You want:
response = requests.get(...)
data = response.json()
for artist in data["topartists"]["artist"]:
name = artist["name"]
# etc
Explanation: requests.get() returns a response object. Iterating over the response object is actually iterating over the raw textual response content, line by line. Since this content is actually json, you want to first decode it to Python (response.json() is mainly a shortcut for json.loads(response.content)). You then get a python dict with, in this case, a single key "topartists" which points to a list of "artist" dicts.
A couple hints:
First you may want to learn to use string formatting instead of string concatenation. This :
'http://ws.audioscrobbler.com/2.0/?method=geo.gettopartists&country=spain&format=json&page='+str(i)+'&api_key='+api_key
is ugly and hardly readable. Using string formatting:
urltemplate = "http://ws.audioscrobbler.com/2.0/?method=geo.gettopartists&country=spain&format=json&page={page}&api_key={api_key}"
url = urltemplate.format(page=i, api_key=api_key)
but actually requests knows how to build a querystring from a dict, so you should really use this instead:
query = {
"method": "geo.gettopartists",
"country":"spain",
"format":"json",
"api_key": api_key
}
url = "http://ws.audioscrobbler.com/2.0/"
for pagenum in range(x, y):
query["page"] = pagenum
response = requests.get(url, params=query)
# etc
Then, you may also want to handle errors - there are quite a few things that can go wrong doing an HTTP request.

Convert a dict of bytes to json

I'm trying to convert:
response data = {'policy': b'eyJleHBpcmF0a', 'signature': b'TdXjfAp'}
to json:
jsonified = json.dumps( response_data )
but it results in error message:
TypeError: Object of type 'bytes' is not JSON serializable
What is the proper way to make the proper conversion ?
Expected result
jsonified = {"policy": "eyJleHBpcmF0a", "signature": "TdXjfAp"}
You could write your own encoder for types that can not be serialized out-of-the-box:
import json
class MyEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, (bytes, bytearray)):
return obj.decode("ASCII") # <- or any other encoding of your choice
# Let the base class default method raise the TypeError
return json.JSONEncoder.default(self, obj)
data = {'policy': b'eyJleHBpcmF0a', 'signature': b'TdXjfAp'}
jsonified = json.dumps( data, cls=MyEncoder )
print(jsonified)
# {"policy": "eyJleHBpcmF0a", "signature": "TdXjfAp"}
This approach can easily be extended to support other types, such das datetime.
Just make sure you end up with a str/int/float/... or any other serializeable type at the end of the function.
As #Tomalak pointed out, you could also use a base64 encoding instead of the ASCII encoding to make sure you support control characters.

Categories