even looking through the code, it is not obvious to me what the possible exceptions might be.
Here's my attempt at looking through it:
def json(self, **kwargs: typing.Any) -> typing.Any:
if self.charset_encoding is None and self.content and len(self.content) > 3:
encoding = guess_json_utf(self.content)
if encoding is not None:
return jsonlib.loads(self.content.decode(encoding), **kwargs)
return jsonlib.loads(self.text, **kwargs)
self.contentcan raiseResponseNotReadif (as it sounds like) the response has not been read yet. However, this is almost certainly due to a logical error in the code rather than any meaningful problem at runtime worth detecting; so there is no good reason to catch this. (It also wouldn't happen with the most straightforward use cases, such as the one shown in the documentation.) Otherwise,self.contentwill be abytes, solenwill work.self.charset_encodingwill either returnNone(if there is no corresponding data in the response header) or else eventually use the standard libraryemail.message.Message.get_content_charsetto parse a content type from the response header. The latter is not documented to raise any exceptions; so there should not be any exception from accessing this value.guess_json_utfwill necessarily be passed abytesthat is at least 4 bytes long. Nothing in its logic should be able to fail under those conditions. EitherNoneor a string will be returned.If
jsonlib.loadsis called usingself.content.decode(encoding), thenencodingwas necessarily notNone, and is a valid encoding name returned fromguess_json_utfHowever, it's possible that theself.content(bytesdata) is not valid data (i.e., convertible to text using the guessed text encoding). This would causeUnicodeDecodeError.Otherwise, it's called with
self.text. If the underlying_textwas set before, it will be a string and gets returned. If there is no content in the response, an empty string is returned. Otherwise, decoding is attempted using a default text encoder with a"replace"error-handling policy. There again shouldn't be anything that could cause the text encoding name to be invalid, so again this can only raiseUnicodeDecodeError, and even that shouldn't be possible with the"replace"error-handling policy.Finally:
jsonlib.loadsis simplyjson.loads(i.e., the standard libraryjson). if the code gets this far,json.loadswill definitely be given a string to load; all possible issues with the string contents will be reported asJSONDecodeError.
tl;dr: the possible exceptions that make sense to catch are JSONDecodeError (the response is not valid JSON - this includes e.g. an empty response) and UnicodeDecodeError (the response is corrupt in some way, for example it mixes bytes intended to encode text in two different ways, or it's supposed to be UTF-8 but contains bytes that are illegal in that encoding; or it's encoded using a non-UTF scheme, such as Latin-1, in a way that is incompatible with the corresponding guessed UTF scheme, and doesn't advertise the encoding in the header).
Custom JSON library
Randomly receiving json.decoder.JSONDecodeError error when using requests.get. Completely out of ideas
python - JSONDecodeError: Expecting value: line 1 column 1 (char 0) - Stack Overflow
python requests randomly breaks with JSONDecodeError - Stack Overflow
I really dont know what is going on...sometimes i am able to get 1-3 records, and other times i can get around 100 before the error appears. There is no consistency. This is how i have my request:
token = lms_token
url = endpoint
headers = {
"Authorization": "bearer " + str(token),
"Content-Type": "application/json;odata.metadata=minimal",
"Accept": "application/json"
}
r = requests.get(url, headers=headers).json()print(r)
Is there something i need to decode or change to prevent that error from happening? Here is the full error i receive:
File "C:\Users\name\Documents\lib\json_init_.py", line 319, in loads return _default_decoder.decode(s) File "C:\Users\name\Documents\lib\json\decoder.py", line 339, in decode obj, end = self.raw_decode(s, idx=_w(s, 0).end()) File "C:\Users\name\Documents\lib\json\decoder.py", line 357, in raw_decode raise JSONDecodeError("Expecting value", s, err.value) from None json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
Thanks!
Your code produced an empty response body; you'd want to check for that or catch the exception raised. It is possible the server responded with a 204 No Content response, or a non-200-range status code was returned (404 Not Found, etc.). Check for this.
Note:
There is no need to decode a response from UTF8 to Unicode, the
json.loads()method can handle UTF8-encoded data natively.pycurlhas a very archaic API. Unless you have a specific requirement for using it, there are better choices.
Either requests or httpx offer much friendlier APIs, including JSON support.
If you can, replace your call with the following httpx code:
import httpx
response = httpx.get(url)
response.raise_for_status() # raises exception when not a 2xx response
if response.status_code != 204:
return response.json()
Of course, this won't protect you from a URL that doesn't comply with HTTP standards; when using arbitrary URLs where this is a possibility, check if the server intended to give you JSON by checking the Content-Type header, and for good measure catch the exception:
if (
response.status_code != 204 and
response.headers["content-type"].strip().startswith("application/json")
):
try:
return response.json()
except ValueError:
# decide how to handle a server that's misbehaving to this extent
Be sure to remember to invoke json.loads() on the contents of the file, as opposed to the file path of that JSON:
json_file_path = "/path/to/example.json"
with open(json_file_path, 'r') as j:
contents = json.loads(j.read())
I think a lot of people are guilty of doing this every once in a while (myself included):
contents = json.load(json_file_path)
Looking at the documentation for this API it seems the only responses are in JSON format, so receiving HTML is strange. To increase the likelihood of receiving a JSON response, you can set the 'Accept' header to 'application/json'.
I tried querying this API many times with parameters and did not encounter a JSONDecodeError. This error is likely the result of another error on the server side. To handle it, except a json.decoder.JSONDecodeError in addition to the ConnectionError error you currently except and handle this error in the same way as the ConnectionError.
Here is an example with all that in mind:
import requests, json, time, random
def get_submission_records(client, since, try_number=1):
url = 'http://reymisterio.net/data-dump/api.php/submission?filter[]=form,cs,'+client+'&filter[]=date,cs,'+since
headers = {'Accept': 'application/json'}
try:
response = requests.get(url, headers=headers).json()
except (requests.exceptions.ConnectionError, json.decoder.JSONDecodeError):
time.sleep(2**try_number + random.random()*0.01) #exponential backoff
return get_submission_records(client, since, try_number=try_number+1)
else:
return response['submission']['records']
I've also wrapped this logic in a recursive function, rather than using while loop because I think it is semantically clearer. This function also waits before trying again using exponential backoff (waiting twice as long after each failure).
Edit: For Python 2.7, the error from trying to parse bad json is a ValueError, not a JSONDecodeError
import requests, time, random
def get_submission_records(client, since, try_number=1):
url = 'http://reymisterio.net/data-dump/api.php/submission?filter[]=form,cs,'+client+'&filter[]=date,cs,'+since
headers = {'Accept': 'application/json'}
try:
response = requests.get(url, headers=headers).json()
except (requests.exceptions.ConnectionError, ValueError):
time.sleep(2**try_number + random.random()*0.01) #exponential backoff
return get_submission_records(client, since, try_number=try_number+1)
else:
return response['submission']['records']
so just change that except line to include a ValueError instead of json.decoder.JSONDecodeError.
Catching ValueError is universal across python versions from py2 to py3
For py3 only is better to catch from already imported requests library: requests.JSONDecoderError, so you don't need to import json library.
Hello.
I'm trying to make my Alexa/Echo dot 3 powered by ChatGPT. I would like to integrate ChatGPT into my Alexa / Echo dot 3. I want to have more engaging and natural conversations with my smart speaker. To achieve the goal I found a Step-By-Step guide. The relevant steps to do are :
1. I need python 3.10.9 3. Inside the folder run the command `pip install -r requirements.txt` on cmd 4. run the server with: `python server.py`
ok. Let's assume that I'm using the jetson nano where I have installed ubuntu 20.04 and python 3.10.9,as you can see :
marietto@marietto-nano:/mnt/fisso/ChatGPT/BingChatGPT$ python --version Python 3.10.9 marietto@marietto-nano:/mnt/fisso/ChatGPT/BingChatGPT$ python3 --version Python 3.10.9
Let's also say that I have been able to satisfy all the python pip dependencies requested :
marietto@marietto-nano:/mnt/fisso/ChatGPT/BingChatGPT$ pip install -r requirements.txt Requirement already satisfied: EdgeGPT==0.0.60 in /usr/local/lib/python3.10/site-packages (from -r requirements.txt (line 1)) (0.0.60) Requirement already satisfied: Flask==2.2.3 in /usr/local/lib/python3.10/site-packages (from -r requirements.txt (line 2)) (2.2.3) Requirement already satisfied: rich in /usr/local/lib/python3.10/site-packages (from EdgeGPT==0.0.60->-r requirements.txt (line 1)) (13.3.3) Requirement already satisfied: asyncio in /usr/local/lib/python3.10/site-packages (from EdgeGPT==0.0.60->-r requirements.txt (line 1)) (3.4.3) Requirement already satisfied: certifi in /usr/local/lib/python3.10/site-packages (from EdgeGPT==0.0.60->-r requirements.txt (line 1)) (2022.12.7) Requirement already satisfied: httpx in /usr/local/lib/python3.10/site-packages (from EdgeGPT==0.0.60->-r requirements.txt (line 1)) (0.23.3) Requirement already satisfied: prompt-toolkit in /usr/local/lib/python3.10/site-packages (from EdgeGPT==0.0.60->-r requirements.txt (line 1)) (3.0.38) Requirement already satisfied: websockets in /usr/local/lib/python3.10/site-packages (from EdgeGPT==0.0.60->-r requirements.txt (line 1)) (11.0.1) Requirement already satisfied: click>=8.0 in /usr/local/lib/python3.10/site-packages (from Flask==2.2.3->-r requirements.txt (line 2)) (8.1.3) Requirement already satisfied: Jinja2>=3.0 in /usr/local/lib/python3.10/site-packages (from Flask==2.2.3->-r requirements.txt (line 2)) (3.1.2) Requirement already satisfied: itsdangerous>=2.0 in /usr/local/lib/python3.10/site-packages (from Flask==2.2.3->-r requirements.txt (line 2)) (2.1.2) Requirement already satisfied: Werkzeug>=2.2.2 in /usr/local/lib/python3.10/site-packages (from Flask==2.2.3->-r requirements.txt (line 2)) (2.2.3) Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.10/site-packages (from rich->EdgeGPT==0.0.60->-r requirements.txt (line 1)) (2.14.0) Requirement already satisfied: markdown-it-py<3.0.0,>=2.2.0 in /usr/local/lib/python3.10/site-packages (from rich->EdgeGPT==0.0.60->-r requirements.txt (line 1)) (2.2.0) Requirement already satisfied: rfc3986[idna2008]<2,>=1.3 in /usr/local/lib/python3.10/site-packages (from httpx->EdgeGPT==0.0.60->-r requirements.txt (line 1)) (1.5.0) Requirement already satisfied: sniffio in /usr/local/lib/python3.10/site-packages (from httpx->EdgeGPT==0.0.60->-r requirements.txt (line 1)) (1.3.0) Requirement already satisfied: httpcore<0.17.0,>=0.15.0 in /usr/local/lib/python3.10/site-packages (from httpx->EdgeGPT==0.0.60->-r requirements.txt (line 1)) (0.16.3) Requirement already satisfied: wcwidth in /usr/local/lib/python3.10/site-packages (from prompt-toolkit->EdgeGPT==0.0.60->-r requirements.txt (line 1)) (0.2.6) Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/site-packages (from Jinja2>=3.0->Flask==2.2.3->-r requirements.txt (line 2)) (2.1.2) Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.10/site-packages (from markdown-it-py<3.0.0,>=2.2.0->rich->EdgeGPT==0.0.60->-r requirements.txt (line 1)) (0.1.2) Requirement already satisfied: idna; extra == "idna2008" in /usr/local/lib/python3.10/site-packages (from rfc3986[idna2008]<2,>=1.3->httpx->EdgeGPT==0.0.60->-r requirements.txt (line 1)) (3.4) Requirement already satisfied: h11<0.15,>=0.13 in /usr/local/lib/python3.10/site-packages (from httpcore<0.17.0,>=0.15.0->httpx->EdgeGPT==0.0.60->-r requirements.txt (line 1)) (0.14.0) Requirement already satisfied: anyio<5.0,>=3.0 in /usr/local/lib/python3.10/site-packages (from httpcore<0.17.0,>=0.15.0->httpx->EdgeGPT==0.0.60->-r requirements.txt (line 1)) (3.6.2) WARNING: You are using pip version 20.0.2; however, version 23.0.1 is available. You should consider upgrading via the '/usr/bin/python -m pip install --upgrade pip' command. [some python package requested to install pip 20.0.2,so I did it and I kept it to this version]
This is what happens when I try to run the server.py :
marietto@marietto-nano:/mnt/fisso/ChatGPT/BingChatGPT$ python server.py
Traceback (most recent call last):
File "/mnt/fisso/ChatGPT/BingChatGPT/server.py", line 12, in <module>
cookies = json.load(f)
File "/usr/local/lib/python3.10/json/__init__.py", line 293, in load
return loads(fp.read(),
File "/usr/local/lib/python3.10/json/__init__.py", line 346, in loads
return _default_decoder.decode(s)
File "/usr/local/lib/python3.10/json/decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/usr/local/lib/python3.10/json/decoder.py", line 355, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
I suspect that there is an error inside the code. Can someone confirm this ? The full code of the server.py is the following :
from flask import Flask, request, jsonify
import json
import sys
import asyncio
import random
from EdgeGPT import Chatbot, ConversationStyle
import threading
cookies = None
import time
with open('./cookies.json', 'r') as f:
cookies = json.load(f)
app = Flask(__name__)
responses_final_list = {}
def generate_code():
code = ""
for i in range(2):
code += str(random.randint(0, 9))
return str(code)
@app.route('/res/<codes>', methods=['GET'])
def lidar_com_resposta(codes):
codes = codes.replace("%20","").replace(" ", "")
print("Password: " + str(codes))
if codes in responses_final_list:
return responses_final_list[codes]
else:
time.sleep(6)
if codes in responses_final_list:
return responses_final_list[codes]
else:
return "Invalid code, try again in 1 minute."
async def ask_stream_task(question, codes):
wrote = 0
finished = False
bot = Chatbot(cookies=cookies)
response_list = []
while not finished:
async for final, response in bot.ask_stream(prompt=question, conversation_style=ConversationStyle.creative):
if not final:
response_list.append(response[wrote:])
wrote = len(response)
sys.stdout.flush()
else:
response_list.clear()
response_list.append(response["item"]["messages"][-1]["text"])
responses_final_list[str(codes)] = response["item"]["messages"][-1]["text"]
finished = True
print("Finished: " + str(codes))
def between_callback(prompt, codes):
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(ask_stream_task(prompt, codes))
loop.close()
@app.route("/api")
async def api():
prompt = request.args.get("prompt")
timeout = 6
codes = generate_code()
asyncio.create_task(ask_stream_task(prompt, codes))
_thread = threading.Thread(target=between_callback, args=(prompt, codes))
_thread.start()
return codes
if __name__ == "__main__":
app.run(port=8080)very thanks.
There is a rule in Python programming called "it is Easier to Ask for Forgiveness than for Permission" (in short: EAFP). It means that you should catch exceptions instead of checking values for validity.
Thus, try the following:
try:
qByUser = byUsrUrlObj.read()
qUserData = json.loads(qByUser).decode('utf-8')
questionSubjs = qUserData["all"]["questions"]
except ValueError: # includes simplejson.decoder.JSONDecodeError
print('Decoding JSON has failed')
EDIT: Since simplejson.decoder.JSONDecodeError actually inherits from ValueError (proof here), I simplified the catch statement by just using ValueError.
If you don't mind importing the json module, then the best way to handle it is through json.JSONDecodeError (or json.decoder.JSONDecodeError as they are the same) as using default errors like ValueError could catch also other exceptions not necessarily connected to the json decode one.
from json.decoder import JSONDecodeError
try:
qByUser = byUsrUrlObj.read()
qUserData = json.loads(qByUser).decode('utf-8')
questionSubjs = qUserData["all"]["questions"]
except JSONDecodeError as e:
# do whatever you want
//EDIT (Oct 2020):
As @Jacob Lee noted in the comment, there could be the basic common TypeError raised when the JSON object is not a str, bytes, or bytearray. Your question is about JSONDecodeError, but still it is worth mentioning here as a note; to handle also this situation, but differentiate between different issues, the following could be used:
from json.decoder import JSONDecodeError
try:
qByUser = byUsrUrlObj.read()
qUserData = json.loads(qByUser).decode('utf-8')
questionSubjs = qUserData["all"]["questions"]
except JSONDecodeError as e:
# do whatever you want
except TypeError as e:
# do whatever you want in this case