I've come across a bug in Python (at least in 2.6.1) for the bytearray.fromhex function. This is what happens if you try the example from the docstring:
>>> bytearray.fromhex('B9 01EF')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: fromhex() argument 1 must be unicode, not str
This example works fine in Python 2.7, and I want to know the best way of coding around the problem. I don't want to always convert to unicode as it's a performance hit, and testing which Python version is being used feels wrong.
So is there a better way to code around this sort of problem so that it will work for all versions, preferably without slowing it down for the working Pythons?
For cases like this it's good to remember that a try block is very cheap if no exception is thrown. So I'd use:
try:
x = bytearray.fromhex(some_str)
except TypeError:
# Work-around for Python 2.6 bug
x = bytearray.fromhex(unicode(some_str))
This lets Python 2.6 work with a small performance hit, but 2.7 shouldn't suffer at all. It's certainly preferable to checking Python version explicitly!
The bug itself (and it certainly does seem to be one) is still present in Python 2.6.5, but I couldn't find any mention of it at bugs.python.org, so maybe it was fixed by accident in 2.7! It looks like a back-ported Python 3 feature that wasn't tested properly in 2.6.
You can also create your own function to do the work, conditionalized on what you need:
def my_fromhex(s):
return bytearray.fromhex(s)
try:
my_fromhex('hello')
except TypeError:
def my_fromhex(s):
return bytearray.fromhex(unicode(s))
and then use my_fromhex in your code. This way, the exception only happens once, and during your runtime, the correct function is used without excess unicode casting or exception machinery.
Related
I'm backporting a modern python script to 2.4 to make it compatible with stock RHEL 5.X. While most of the work has been fairly straight-forward, I can't figure out how to handle this case where I am appending to a file:
print("Foo",file=file("/tmp/bar",'ab'))
This is a very common construct in the code I'm porting. I am using the print function from future, which works fine, but here it chokes on the "file=file("filename", 'ab')" part. Apparently this kind of redirection is not supported in 2.4. Likewise, I haven't found a way for the print function to support the >> operator from the old print. It would be an enormous task to re-write this script without the print function, so I'd like a solution based on the print function.
I've found plenty of docs showing how to use >> in the old print, or file=file() in the new print function, but nothing that actually works in 2.4.
What is the equivalent Python 2.4 compatible code for this?
The syntax is pretty awful:
print >> file('/tmp/bar', 'ab'), 'Foo'
Though of course you should rather write:
f = open('/tmp/bar', 'ab')
try:
print >> f, 'Foo'
finally:
f.close()
to make sure that the output is actually closed and flushed. (Python 2.4 doesn't have with statement!).
As an alternative to converting everything to print statement, you could also try the print_ function from the Six: Python 2 and 3 Compatibility Library. I am not sure whether the whole library supports 2.4 any longer, but that one function should be OK in 2.4.
I was trying to use the os.mknod function in Python 3.5.0 in Windows 7, however I find the error:
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
os.mknod
AttributeError: module 'os' has no attribute 'mknod'
I guess it's supposed to be there, since https://docs.python.org/3/library/os.html doesn't say anything about limited availability. Is there another option to use for a similar function in Windows? I'm just looking to create an empty file in a specific path, and I was thinking calling open(path, 'w') is kinda ugly for this.
I don't know if this might be a version specific problem since I've never used Python in Windows before.
Since commit in 2016, this is now documented:
Availability: Unix.
I'm new here and on Python World (although learning kind of quickly...), and just stumbled uppon the same issue.
My suggestion: for now, I would just go with the following and turn a blind eye on it...
with open('name_your_file.extention', 'w') as an_alias_for_it:
pass
In the end, it's not neat, but will be naturally "portable" among POSIX and NT systems.
According to this: http://code.activestate.com/lists/python-list/413540/, tokenize.generate_tokens should be used and not tokenize.tokenize.
This works perfectly fine in Python 2.6. But it does not work anymore in Python 3:
>>> a = list(tokenize.generate_tokens(io.BytesIO("1\n".encode()).readline))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.2/tokenize.py", line 439, in _tokenize
if line[pos] in '#\r\n': # skip comments or blank lines
However, also in Python 3, this works (and returns also the desired output):
a = list(tokenize.tokenize(io.BytesIO("1\n".encode()).readline))
According to the documentation, it seems like tokenize.tokenize is the new way to use this module: http://docs.python.org/py3k/library/tokenize.html. tokenize.generate_tokens isn't even documented anymore.
But, why is there still a generate_tokens function in this module, if it's not documented? I haven't found any PEP regarding this.
I'm trying to maintain a code base for Python 2.5-3.2, should I call generate_tokens for Python 2 and tokenize for Python 3? Aren't there any better ways?
generate_tokens seems to be really a strange thing in Python 3. It doesn't work like in Python 2. However, tokenize.tokenize behaves like the old Python 2 tokenize.generate_tokens. Therefore I wrote a little workaround:
import tokenize
if sys.hexversion >= 0x03000000d:
tokenize_func = tokenize.tokenize
else:
tokenize_func = tokenize.generate_tokens
Now I just use tokenize_func, which works without problems.
generate_tokens in python3 is undocumented but not uncommented. it's there for backward compatibility, so you can use it, but it's probably better to use the changed tokenize instead...
This is a 2-part question and the first part is simple. I'm trying to get the current time as a high resolution number, something easily done with the Time::HiRes module in perl. I did find answers this questions elsewhere to use using time.time() in python. The only thing is when I do this all I get as 2 significant digits and am wondering if I need to import something else or set something in my environment or what. Look at this:
>>> import time
>>> print time.time()
1326459121.68
My second question has to do with setitimer, which according to the docs says it will deliver alarms and the time can be specified as a floating point number. Sounds exactly what I want. In fact, according to this - python timer mystery it looks pretty easy to use. But when I make an exact copy of that example, I get this:
[root#poker python]# ./signal.py
Traceback (most recent call last):
File "./signal.py", line 10, in ?
signal.setitimer(signal.ITIMER_REAL, 2, 2)
AttributeError: 'module' object has no attribute 'setitimer'
Perhaps part my the problem is that as a new python user I'm still not 'one with python' and perhaps am not understanding what the error message it trying to tell me. Is it complaining that it can't find signal.setitimer OR is there something wrong with the attributes I'm passing? I was wondering if it couldn't resolve signal.ITIMER_REAL and so tried calling it with a 0 just to see what would happen and now it's telling me:
[root#poker python]# ./signal.py
Traceback (most recent call last):
File "./signal.py", line 10, in ?
signal.setitimer(0, 2, 2)
AttributeError: 'module' object has no attribute 'setitimer'
so I have to believe it is signal.setitmer itself that is having issues.
Aha! I just figured out the problem by trying this on a VM with a newer version of python and it works just fine. Looks like setitimer is not available with my version of python but how can I tell from the error message? Shouldn't it be saying the module has no method? Calling the missing method an attribute is pretty confusing.
Maybe that's just part of the learning curve. Anyhow I thought I'd keep this second question in here so other might benefit, but I still am still stumped by what I can't get high resultion time from time.time() which still only reports in hundredths of a second even on this newer version of python.
time.time() returns more digits but the repr truncates to 2.
>>> import time
>>> time.time()
1326460396.626451
>>> print time.time()
1326460422.68
The problem with not being able to find setitimer is quite simply because you've named your python script 'signal.py', when you 'import signal' in your script, you're actually importing your script -- not the signal module. Just rename it to something else and it'll work.
I just noticed that my old codes written in python 2.5 does not work now. I am in python 2.6 btw.
>>> os.spawnl(os.P_NOWAIT,"setup.exe")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "c:\python26\lib\os.py", line 612, in spawnl
return spawnv(mode, file, args)
OSError: [Errno 22] Invalid argument
>>>
Any clue? or do you have any working sample of os.spawn* with NOWAIT option.
Update:
Even I put full path in os.spawnl(), Its still error.
thrope is right about subprocess being preferred. But the spawn* stuff is still there in 2.6. In fact, you can see that in your error message. Your first arg seems to be valid. I'd check the second arg, which is the path.
I got it work by adding DUMMY parameter finally, a bit funky though
This is not working
os.spawnl(os.P_NOWAIT,"Setup.exe")
This is also not working
os.spawnl(os.P_NOWAIT,"Setup.exe","")
But this is working
os.spawnl(os.P_NOWAIT,"Setup.exe","DUMMY")
Thanks all anyway.
I think its recommended to use the subprocess module these days rather than the os.spawn* functions. (I can't reproduce your problem, but I'm not on windows).
A Google search brings up this page about the same problem happening when there is a space in the Python installation path. I couldn't reproduce it here, but maybe it's the problem?
In any case, according to MS documentation this error value (EINVAL) should only be returned if the mode argument is invalid, which isn't the case here.
os.spawnl() requires full path to executable, while os.spawnlp() uses PATH environment variable to find it.
Update: Also it's common error to use unescaped backslashes in the path literal (try printing it to see whether it's interpreted right).