Best regards,
Nicolas
Thanks,
Nicolas
1) replace
if head == '\xef\xbb\xbf' : # BOM for utf-8
with
if head == b'\xef\xbb\xbf' : # BOM for utf-8
bytes compare to bytes.
2) During my tests I have generated a script with illegal characters. As
a consequence, the BOM detection code block was skipped because of the
try/except. I suggest to decode with the "replace" option. In this case,
� are displayed by the browser. I think this is better than an exception
raised at the end of the source() function saying asccii decoding have
failed. I also suggest to use "replace" option in other instances of
decode() function in source().
Regards,
Nicolas
Traceback (most recent call last):
File "C:\Python32\lib\site-packages\Karrigell\Karrigell.py", line 156, in handle_data
self.run(func)
File "C:\Python32\lib\site-packages\Karrigell\Karrigell.py", line 296, in run
src = self.source(self.script_path)
File "C:\Python32\lib\site-packages\Karrigell\Karrigell.py", line 265, in source
src = bfo.read().decode(src_enc)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xef in position 0: ordinal not in range(128)
I searched a long time why the UTF-8 decoding did not took place.
I tried to replace the if head == b'\xef\xbb\xbf' : statement by another
working statement. Of course, the problem was that my script file was
wrong. But the "except :" catch all statement lead me to the wrong way.
I finaly found the problem and rolled back all my test code.
Unfortunately, I guess the undo stack was not deep enought and I thought
the b was l missing. I should have checked the original file. Sorry for
that.
>
>> 2) During my tests I have generated a script with illegal characters. As
>> a consequence, the BOM detection code block was skipped because of the
>> try/except. I suggest to decode with the "replace" option. In this case,
>> are displayed by the browser. I think this is better than an exception
>> raised at the end of the source() function saying asccii decoding have
>> failed. I also suggest to use "replace" option in other instances of
>> decode() function in source().
> The try/except clause is here mainly in case the source file is empty
> or only has one line, so that an exception on readline() doesn't crash
> the server. If the BOM header is found and decode() raises an
> exception, it is ignored, but raised again in line 265 and caught in
> the try/except clause starting at line 155
>
> Not sure about decoding with errors='replace'. Why do you think it
> better than raising an exception ?
Imagine you write a script, and for any reason (code copied from another
editor or byte string coming from a database with wrong encoding), there
is an encoding error.
Imagine this script is imported by another one.
How much time do you think you will need to find the problem. You will
have an exception like the one above.
- ASCII encoding error -> script is UTF-8 encoded, not ASCII encoded.
- Error at line 265 in Karrigell.py -> The actual error is at line 245.
- You don't know which script is faulty.
- You don't know where is the error in the script.
I propose another solution : Do not use "replace" in the decode()
function but enumerate the script line, catch the DecodeError exception
and raise an exception giving the script name and line number in the
message. This way, the problem is clearly identified.
Here is the code :
class ScriptError(Exception):
pass
...
def source(self,script_path):
# manages encoding of Python source code (PEP 0263 and PEP3120)
src_enc = "utf-8" # Default encoding
bfo = open(script_path,'rb')
try:
head = bfo.read(3)
if head == b'\xef\xbb\xbf': # BOM for utf-8
lines = []
for n,l in enumerate(bfo.readlines()) :
lines.append(l.decode('utf-8'))
src = ''.join(lines)
bfo.close()
return src.replace('\r\n','\n')
except UnicodeDecodeError as exc :
raise ScriptError("Error in file %s at line %d" %
(script_path, n+1)) from exc
except:
pass
bfo.seek(0)
try:
mo = re.search(b"coding[:=]\s*([-\w.]+)",bfo.readline())
if mo:
src_enc = mo.groups()[0].decode('ascii')
else:
try:
mo =
re.search(b"coding[:=]\s*([-\w.]+)",bfo.readline())
if mo:
src_enc = mo.groups()[0].decode('ascii')
except:
pass
bfo.seek(0)
except:
pass
try :
lines = []
for n,l in enumerate(bfo.readlines()) :
lines.append(l.decode(src_enc))
except UnicodeDecodeError as exc :
raise ScriptError("Error in file %s at line %d" %
(script_path, n+1)) from exc
src = ''.join(lines)
bfo.close()
return src.replace('\r\n','\n')
...
Best regards,
Nicolas
>> Regards,
>> Nicolas
> A+
> Pierre
>
> Salut Nicolas,
All my tests where successful !
I have one remark : I just discovered that enumerate() accepts a second
argument, a start value for the index count. This way, we can replace
n+1 by n when printing.
I have one question : Why enumerating a file open in binary mode returns
lines of bytes and not bytes ?
Best regards,
Nicolas