Using urandom in windows - python

What happens when you use os.urandom(256) in python in windows ?
The code shows :
def urandom(n):
"""urandom(n) -> str
Return a string of n random bytes suitable for cryptographic use.
"""
try:
_urandomfd = open("/dev/urandom", O_RDONLY)
except (OSError, IOError):
raise NotImplementedError("/dev/urandom (or equivalent) not found")
try:
bs = b""
while n > len(bs):
bs += read(_urandomfd, n - len(bs))
finally:
close(_urandomfd)
return bs
http://docs.python.org/2/library/os.html#os.urandom says when it is run in Windows it automatically uses CryptGenRandom(). I cannot find references to this implementation anywhere.

Related

Indentation Error Python Not Working

Im trying to run my code and there is an
File "C:/trcrt/trcrt.py", line 42
def checkInternet():
^
IndentationError: unexpected unindent
The code supposed to check for the traceroute to a website... i know... its not very smart but its what i was told to do
Ive checked the code using pep8 and eveything is seems to be fine...
'''
Developer: Roei Edri
File name: trcrt.py
Date: 24.11.17
Version: 1.1.0
Description: Get an url as an input and prints the traceroute to it.
'''
import sys
import urllib2
i, o, e = sys.stdin, sys.stdout, sys.stderr
from scapy.all import *
from scapy.layers.inet import *
sys.stdin, sys.stdout, sys.stderr = i, o, e
def trcrt(dst):
"""
Check for the route for the given destination
:param dst: Final destination, in a form of a website.
:type dst: str
"""
try:
pckt = IP(dst=dst)/ICMP() # Creates the
# packet
ip = [p for p in pckt.dst] # Gets the ip
print "Tracerouting for {0} : {1}".format(dst, ip[0])
for ttl in range(1, 40):
pckt = IP(ttl=ttl, dst=dst)/ICMP()
timeBefore = time.time()
reply = sr1(pckt, verbose=0, timeout=5)
timeAfter = time.time()
timeForReply = (timeAfter - timeBefore)*1000
if reply is not None:
print "{0} : {1} ; Time for reply: {2}".format(ttl,
reply.src, timeForReply)
if reply.type == 0:
print "Tracerout Completed"
break
else:
print "{0} ... Request Time Out".format(ttl)
def checkInternet():
"""
Checks if there is an internet connection
:return: True if there is an internet connection
"""
try:
urllib2.urlopen('http://45.33.21.159', timeout=1)
return True
except urllib2.URLError as IntError:
return False
Thanks for any help...
Btw pep8 says
"module level import not at top of file"
for lines 12,13
The try block is missing its except clause.
try:
pckt = IP(dst=dst)/ICMP() # Creates the
# packet
ip = [p for p in pckt.dst] # Gets the ip
print "Tracerouting for {0} : {1}".format(dst, ip[0])
for ttl in range(1, 40):
pckt = IP(ttl=ttl, dst=dst)/ICMP()
timeBefore = time.time()
reply = sr1(pckt, verbose=0, timeout=5)
timeAfter = time.time()
timeForReply = (timeAfter - timeBefore)*1000
if reply is not None:
print "{0} : {1} ; Time for reply: {2}".format(ttl,
reply.src, timeForReply)
if reply.type == 0:
print "Tracerout Completed"
break
else:
print "{0} ... Request Time Out".format(ttl)
except: # Here : Add the exception you wish to catch
pass # handle this exception appropriately
As a general rule, do not use catch all except clauses, and do not pass on a caught exception, it lets it fail silently.
If this is your full code, there are two things to check:
1) Have you mixed tabs and spaces? Make sure that all tabs are converted to spaces (I recommend 4 spaces per tab) for indentation. A good IDE will do this for you.
2) The try: in trcrt(dst) does not hava a matching except block.
PEP8 will by the way also tell you, that function names should be lowercase:
check_internet instead of checkInternet, ...
I will give you the same recommendation, that I give to everyone working with me: Start using an IDE that marks PEP8 and other errors for you, there is multiple around. It helps spotting those errors a lot and trains you to write clean Python code that is easily readable and (if you put comments in it) also reausable and understandable a few years later.

Exception not caught in multiprocessing

I'm using multiprocessing module for files processing in parallel, which works perfectly fine almost every time.
Also I've written that in try , except block to catch any exception.
I've come across a situation where except block doesn't catch the exception.
Since the code is huge I'm just putting relevant block which is giving problem.
def reader(que, ip, start, end, filename):
""" Reader function checks each line of the file
and if the line contains any of the ip addresses which are
being scanned, then it writes to its buffer.
If the line field doesn't match date string it skips the line.
"""
logging.info("Processing : %s" % os.path.basename(filename))
ip_pat = re.compile("(\d+\.\d+\.\d+\.\d+\:\d+)")
chunk = 10000000 # taking chunk of 10MB data
buff = ""
with bz2.BZ2File(filename,"rb", chunk) as fh: # open the compressed file
for line in fh:
output = []
fields = line.split()
try:
ts = fields[1].strip() + "/" +fields[0]+"/"+fields[3].split("-")[0]+" "+fields[2]
times = da.datetime.strptime(ts,"%d/%b/%Y %H:%M:%S")
if times < start:
continue
if times > end:
break
ips = re.findall(ip_pat,line)
if len(ips) < 3:
continue
if ips[0].split(":")[0] == ip:
output.append(times.strftime("%d/%m/%Y %H:%M:%S"))
status = "SESSION_OPEN" if "SESSION_OPEN" in line or "CREATE" in line else "SESSION_CLOSE"
protocol = "TCP" if "TCP" in line else "UDP"
output.append(status)
output.append(protocol)
ips[1], ips[2] = ips[2], ips[1]
output.extend(ips)
res = "|".join(output)
buff += res + "\n"
except IndexError, ValueError:
continue
logging.info("Processed : %s of size [ %d ]" % (os.path.basename(filename), os.path.getsize(filename)))
if buff:
que.put((ip,buff))
return buff
And this is what is received as error.
File "/usr/lib64/python2.7/multiprocessing/pool.py", line 554, in get
raise self._value
ValueError: time data '2/Dec/20 10:59:59' does not match format '%d/%b/%Y %H:%M:%S'
What I don't understand is why the exception is not caught, I've mentioned ValueError in except block.
What's the best way to get through this problem.
Provide the multiple exceptions as a tuple:
except (IndexError, ValueError):
continue
The relevant doc is https://docs.python.org/2/tutorial/errors.html#handling-exceptions
Snippet from the page:
Note that the parentheses around this tuple are required, because except ValueError, e: was the syntax used for what is normally written as except ValueError as e: in modern Python (described below). The old syntax is still supported for backwards compatibility. This means except RuntimeError, TypeError is not equivalent to except (RuntimeError, TypeError): but to except RuntimeError as TypeError: which is not what you want.

Non blocking read on os.pipe on Windows

This question - How to read from an os.pipe() without getting blocked? - shows a solution how to check if os.pipe has any data for Linux, and for this you need to put the pipe into non-blocking mode:
import os, fcntl
fcntl.fcntl(thePipe, fcntl.F_SETFL, os.O_NONBLOCK)
On Windows we have this:
ImportError: No module named fcntl
But os.pipe is there:
>>> os.pipe()
(3, 4)
So, is it possible to do non-blocking read or peek the contents of os.pipe on Windows?
Answering my own question after digging for some time through StackOverflow.
UPDATE: Things changes thanks to #HarryJohnston.
At first the answer was no, it is not possible to do non-blocking read on os.pipe on Windows. From this answer I've got that:
The term for non-blocking / asynchronous I/O in Windows is 'overlapped' - that's what you should be looking at.
os.pipe on Windows is implemented through CreatePipe API (see here and ... well, I couldn't find os.pipe code in Python sources). CreatePipe makes anonymous pipes, and anonymous pipes do not support asynchronous I/O.
But then #HarryJohnston commented that SetNamedPipeHandleState doc allows to put anonymous pipe to non-blocking mode. I wrote the test and it failed with OSError: [Errno 22] Invalid argument. The error message seemed wrong, so I tried to check what should be return result on non-blocking read operation when data is not available, and after reading MSDN note on named pipe modes I found that it should be ERROR_NO_DATA that has a int value 232. Adding ctypes.WinError() call to exception handler revealed the expected [Error 232] The pipe is being closed.
So, the answer is yes, it is possible to do non-blocking read on os.pipe on Windows, and here is the proof:
import msvcrt
import os
from ctypes import windll, byref, wintypes, GetLastError, WinError
from ctypes.wintypes import HANDLE, DWORD, POINTER, BOOL
LPDWORD = POINTER(DWORD)
PIPE_NOWAIT = wintypes.DWORD(0x00000001)
ERROR_NO_DATA = 232
def pipe_no_wait(pipefd):
""" pipefd is a integer as returned by os.pipe """
SetNamedPipeHandleState = windll.kernel32.SetNamedPipeHandleState
SetNamedPipeHandleState.argtypes = [HANDLE, LPDWORD, LPDWORD, LPDWORD]
SetNamedPipeHandleState.restype = BOOL
h = msvcrt.get_osfhandle(pipefd)
res = windll.kernel32.SetNamedPipeHandleState(h, byref(PIPE_NOWAIT), None, None)
if res == 0:
print(WinError())
return False
return True
if __name__ == '__main__':
# CreatePipe
r, w = os.pipe()
pipe_no_wait(r)
print os.write(w, 'xxx')
print os.read(r, 1024)
try:
print os.write(w, 'yyy')
print os.read(r, 1024)
print os.read(r, 1024)
except OSError as e:
print dir(e), e.errno, GetLastError()
print(WinError())
if GetLastError() != ERROR_NO_DATA:
raise
Not sure but probably this answer from #jfs can also be reused and is quite elegant.
This answer is basically #anatolytechtonik's answer but with classes.
import msvcrt
import os
# No idea what is going on here but if it works, it works.
from ctypes import windll, byref, wintypes, GetLastError, WinError, POINTER
from ctypes.wintypes import HANDLE, DWORD, BOOL
# ???
LPDWORD = POINTER(DWORD)
PIPE_NOWAIT = wintypes.DWORD(0x00000001)
ERROR_NO_DATA = 232
class AdvancedFD:
"""
A wrapper for a file descriptor so that we can call:
`<AdvancedFD>.read(number_of_bytes)` and
`<AdvancedFD>.write(data_as_bytes)`
It also makes the `read_fd` non blocking. When reading from a non-blocking
pipe with no data it returns b"".
Methods:
write(data: bytes) -> None
read(number_of_bytes: int) -> bytes
rawfd() -> int
close() -> None
"""
def __init__(self, fd: int):
self.fd = fd
self.closed = False
def __del__(self) -> None:
"""
When this object is garbage collected close the fd
"""
self.close()
def close(self) -> None:
"""
Closes the file descriptor.
Note: it cannot be reopened and might raise an error if it is
being used. You don't have to call this function. It is automatically
called when this object is being garbage collected.
"""
self.closed = True
def write(self, data: bytes) -> None:
"""
Writes a string of bytes to the file descriptor.
Note: Must be bytes.
"""
os.write(self.fd, data)
def read(self, x: int) -> bytes:
"""
Reads `x` bytes from the file descriptor.
Note: `x` must be an int
Returns the bytes. Use `<bytes>.decode()` to convert it to a str
"""
try:
return os.read(self.fd, x)
except OSError as error:
err_code = GetLastError()
# If the error code is `ERROR_NO_DATA`
if err_code == ERROR_NO_DATA:
# Return an empty string of bytes
return b""
else:
# Otherwise raise the error
website = "https://learn.microsoft.com/en-us/windows/win32/" +\
"debug/system-error-codes--0-499-"
raise OSError("An exception occured. Error code: %i Look up" +\
" the error code here: %s" % (err_code, website))
def config_non_blocking(self) -> bool:
"""
Makes the file descriptor non blocking.
Returns `True` if sucessfull, otherwise returns `False`
"""
# Please note that this is kindly plagiarised from:
# https://stackoverflow.com/a/34504971/11106801
SetNamedPipeHandleState = windll.kernel32.SetNamedPipeHandleState
SetNamedPipeHandleState.argtypes = [HANDLE, LPDWORD, LPDWORD, LPDWORD]
SetNamedPipeHandleState.restype = BOOL
handle = msvcrt.get_osfhandle(self.fd)
res = windll.kernel32.SetNamedPipeHandleState(handle,
byref(PIPE_NOWAIT), None,
None)
return not (res == 0)
def rawfd(self) -> int:
"""
Returns the raw fd as an int.
"""
return self.fd
class NonBlockingPipe:
"""
Creates 2 file descriptors and wrapps them in the `AdvancedFD` class
so that we can call:
`<AdvancedFD>.read(number_of_bytes)` and
`<AdvancedFD>.write(data_as_bytes)`
It also makes the `read_fd` non blocking. When reading from a non-blocking
pipe with no data it returns b"".
Methods:
write(data: bytes) -> None
read(number_of_bytes: int) -> bytes
rawfds() -> (int, int)
close() -> None
"""
def __init__(self):
self.read_fd, self.write_fd = self.create_pipes()
self.read_fd.config_non_blocking()
def __del__(self) -> None:
"""
When this object is garbage collected close the fds
"""
self.close()
def close(self) -> None:
"""
Note: it cannot be reopened and might raise an error if it is
being used. You don't have to call this function. It is automatically
called when this object is being garbage collected.
"""
self.read_fd.close()
self.write_fd.close()
def create_pipes(self) -> (AdvancedFD, AdvancedFD):
"""
Creates 2 file descriptors and wrapps them in the `Pipe` class so
that we can call:
`<Pipe>.read(number_of_bytes)` and
`<Pipe>.write(data_as_bytes)`
"""
read_fd, write_fd = os.pipe()
return AdvancedFD(read_fd), AdvancedFD(write_fd)
def write(self, data: bytes) -> None:
"""
Writes a string of bytes to the file descriptor.
Note: Must be bytes.
"""
self.write_fd.write(data)
def read(self, number_of_bytes: int) -> bytes:
"""
Reads `x` bytes from the file descriptor.
Note: `x` must be an int
Returns the bytes. Use `<bytes>.decode()` to convert it to a str
"""
return self.read_fd.read(number_of_bytes)
def rawfds(self) -> (int, int):
"""
Returns the raw file descriptors as ints in the form:
(read_fd, write_fd)
"""
return self.read_fd.rawfd(), self.write_fd.rawfd()
if __name__ == "__main__":
# Create the nonblocking pipe
pipe = NonBlockingPipe()
pipe.write(b"xxx")
print(pipe.read(1024)) # Check if it can still read properly
pipe.write(b"yyy")
print(pipe.read(1024)) # Read all of the data in the pipe
print(pipe.read(1024)) # Check if it is non blocking

python latin-1 UnicodeDecodeError after switching to ubuntu 14 with couchdb cPickle binary data

For some strange reason my python code stopped working after I switched from ubuntu 12 to ubuntu 14. I can't unpickle my data any more. I stored the data in a couchdb database by converting to latin1 encoding.
I'm using latin1 because I read some time ago (I don't have the link any more) that it is the only encoding I can use to store and retrieve cPickled binary data from a couchdb database. It was meant to avoid encoding issues with json (couchdbkit uses json in background).
Latin1 was supposed to map 256 characters to 256 characters, which would be exactly byte by byte. Now, after system upgrade, python seems to complain as if there were only 128 valid values and throws UnicodeDecodeError (see below)
old python version was 2.7.3
old couchdb version 1.6.1
old couchdbkit was 0.5.7
new python version is 2.7.6
new couchdb version 1.6.1 (unchanged)
new couchdbkit is 0.6.5
Not sure you need all those details, but here are some declarations I use:
#deals with all the errors when saving an item
def saveitem(item):
item.set_db(self.db)
item["_id"] = key
error = True
while error:
try:
item.save()
error = False
except ResourceConflict:
try:
item = DBEntry.get_or_create(key)
except ResourceConflict:
pass
except (NoMoreData) as e:
print "CouchDB.set.saveitem: NoMoreData error, retrying...", str(e)
except (RequestError) as e:
print "CouchDB.set.saveitem: RequestError error. retrying...", str(e)
#deals with most of what could go wrong when adding an attachment
def addattachment(item, content, name = "theattachment"):
key = item["_id"]
error = True
while error:
try:
item.put_attachment(content = content, name = name) #, content_type = "application/octet-stream"
error = False
except ResourceConflict:
try:
item = DBEntry.get_or_create(key)
except ResourceConflict:
print "addattachment ResourceConflict, retrying..."
except NoMoreData:
print "addattachment NoMoreData, retrying..."
except (NoMoreData) as e:
print key, ": no more data exception, wating 1 sec and retrying... -> ", str(e)
time.sleep(1)
item = DBEntry.get_or_create(key)
except (IOError) as e:
print "addattachment IOError:", str(e), "repeating..."
item = DBEntry.get_or_create(key)
except (KeyError) as e:
print "addattachment error:", str(e), "repeating..."
try:
item = DBEntry.get_or_create(key)
except ResourceConflict:
pass
except (NoMoreData) as e:
pass
Then I save as follows:
pickled = cPickle.dumps(obj = value, protocol = 2)
pickled = pickled.decode('latin1')
item = DBEntry(content={"seeattachment": True, "ispickled" : True},
creationtm=datetime.datetime.utcnow(),lastaccesstm=datetime.datetime.utcnow())
item = saveitem(item)
addattachment(item, pickled)
And here is how I unpack. Data was written under ubuntu 12. Fails to unpack under ubuntu 14:
def unpackValue(self, value, therawkey):
if value is None: return None
originalval = value
value = value["content"]
result = None
if value.has_key("realcontent"):
result = value["realcontent"]
elif value.has_key("seeattachment"):
if originalval.has_key("_attachments"):
if originalval["_attachments"].has_key("theattachment"):
if originalval["_attachments"]["theattachment"].has_key("data"):
result = originalval["_attachments"]["theattachment"]["data"]
result = base64.b64decode(result)
else:
print "unpackvalue: no data in attachment. Here is how it looks like:"
print originalval["_attachments"]["theattachment"].iteritems()
else:
error = True
while error:
try:
result = self.db.fetch_attachment(therawkey, "theattachment")
error = False
except ResourceConflict:
print "could not get attachment for", therawkey, "retrying..."
time.sleep(1)
except ResourceNotFound:
self.delete(key = therawkey, rawkey = True)
return None
if value["ispickled"]:
result = cPickle.loads(result.encode('latin1'))
else:
result = value
if isinstance(result, unicode): result = result.encode("utf8")
return result
The line result = cPickle.loads(result.encode('latin1')) succeeds under ubuntu 12 but it fails under ubuntu 14. Following error:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position
0: ordinal not in range(128)
I did NOT get that error under ubuntu 12!
How can I read my data under ubuntu 14 while keeping the newer couchdbkit and python versions? Is that even a versioning problem? Why is that error happening?
It appears that there is some change -- possibly in couchdbkit's API -- which
makes result a UTF-8 encoded str whereas before it was unicode.
Since you want to encode the unicode in latin1, the work-around is to use
cPickle.loads(result.decode('utf8').encode('latin1'))
Note that it would be better to find where result is getting UTF-8 encoded and
either preventing that from happening (so you still have unicode as you did
under Ubuntu 12) or changing the encoding to latin1 so that result will
already be in the form you desire.

How can I fix "[Error 6] The handle is invalid." with PySerial

I'm trying to connect to my phone from my Windows 7 PC using PySerial with the following code:
import wmi
import serial
c = wmi.WMI()
modem = c.query("SELECT * FROM Win32_POTSModem").pop()
ser = serial.Serial(modem.AttachedTo, modem.MaxBaudRateToSerialPort)
try:
ser.write('at \r\n')
print ser.readline()
finally:
ser.close()
But get the following error on the write call:
Traceback (most recent call last):
File "D:\Alasdair\Documents\Python Scripts\Phone Interface\test.py", line 14, in <module>
ser.write('at \r\n')
File "C:\Python26\Lib\site-packages\serial\serialwin32.py", line 255, in write
raise SerialException("WriteFile failed (%s)" % ctypes.WinError())
SerialException: WriteFile failed ([Error 6] The handle is invalid.)
I've tried connecting with TeraTerm and that works fine, so it's not a problem with the connection to the phone itself.
I've been searching around for ages trying to find a solution but haven't come up with anything that works. Any ideas?
I have just fixed this problem on 64bit windows (XP, Vista and 7).
This problem is caused by the invalid handle casting which discard the upper 32-bit of 64-bit value due to old python-win32 functions.
If you faced this kind of problem, please use the new python-win32 functions which is included in the win32file etc. modules.
Please write the following code over site-packages\serial\serialwin32.py.
#! python
# Python Serial Port Extension for Win32, Linux, BSD, Jython
# serial driver for win32
# see __init__.py
#
# (C) 2001-2009 Chris Liechti <cliechti#gmx.net>
# this is distributed under a free software license, see license.txt
#
# Initial patch to use ctypes by Giovanni Bajo <rasky#develer.com>
import ctypes
import win32
import win32file
import win32con
import pywintypes
from serialutil import *
def device(portnum):
"""Turn a port number into a device name"""
return 'COM%d' % (portnum+1) # numbers are transformed to a string
class Win32Serial(SerialBase):
"""Serial port implementation for Win32 based on ctypes."""
BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
9600, 19200, 38400, 57600, 115200)
def __init__(self, *args, **kwargs):
self.hComPort = None
SerialBase.__init__(self, *args, **kwargs)
def open(self):
"""Open port with current settings. This may throw a SerialException
if the port cannot be opened."""
if self._port is None:
raise SerialException("Port must be configured before it can be used.")
# the "\\.\COMx" format is required for devices other than COM1-COM8
# not all versions of windows seem to support this properly
# so that the first few ports are used with the DOS device name
port = self.portstr
try:
if port.upper().startswith('COM') and int(port[3:]) > 8:
port = '\\\\.\\' + port
except ValueError:
# for like COMnotanumber
pass
self.hComPort = win32file.CreateFile(port,
win32con.GENERIC_READ | win32con.GENERIC_WRITE,
0, # exclusive access
None, # no security
win32con.OPEN_EXISTING,
win32con.FILE_ATTRIBUTE_NORMAL | win32con.FILE_FLAG_OVERLAPPED,
0)
if self.hComPort == win32.INVALID_HANDLE_VALUE:
self.hComPort = None # 'cause __del__ is called anyway
raise SerialException("could not open port %s: %s" % (self.portstr, ctypes.WinError()))
# Setup a 4k buffer
win32file.SetupComm(self.hComPort, 4096, 4096)
# Save original timeout values:
tos = win32file.GetCommTimeouts(self.hComPort)
self._orgTimeouts = win32.COMMTIMEOUTS(*tos)
self._rtsState = win32.RTS_CONTROL_ENABLE
self._dtrState = win32.DTR_CONTROL_ENABLE
self._reconfigurePort()
# Clear buffers:
# Remove anything that was there
win32file.PurgeComm(self.hComPort,
win32.PURGE_TXCLEAR | win32.PURGE_TXABORT |
win32.PURGE_RXCLEAR | win32.PURGE_RXABORT)
self._overlappedRead = pywintypes.OVERLAPPED()
self._overlappedRead.hEvent = win32.CreateEvent(None, 1, 0, None)
self._overlappedWrite = pywintypes.OVERLAPPED()
#~ self._overlappedWrite.hEvent = win32.CreateEvent(None, 1, 0, None)
self._overlappedWrite.hEvent = win32.CreateEvent(None, 0, 0, None)
self._isOpen = True
def _reconfigurePort(self):
"""Set communication parameters on opened port."""
if not self.hComPort:
raise SerialException("Can only operate on a valid port handle")
# Set Windows timeout values
# timeouts is a tuple with the following items:
# (ReadIntervalTimeout,ReadTotalTimeoutMultiplier,
# ReadTotalTimeoutConstant,WriteTotalTimeoutMultiplier,
# WriteTotalTimeoutConstant)
if self._timeout is None:
timeouts = (0, 0, 0, 0, 0)
elif self._timeout == 0:
timeouts = (win32.MAXDWORD, 0, 0, 0, 0)
else:
timeouts = (0, 0, int(self._timeout*1000), 0, 0)
if self._timeout != 0 and self._interCharTimeout is not None:
timeouts = (int(self._interCharTimeout * 1000),) + timeouts[1:]
if self._writeTimeout is None:
pass
elif self._writeTimeout == 0:
timeouts = timeouts[:-2] + (0, win32.MAXDWORD)
else:
timeouts = timeouts[:-2] + (0, int(self._writeTimeout*1000))
win32file.SetCommTimeouts(self.hComPort, timeouts)
win32file.SetCommMask(self.hComPort, win32.EV_ERR)
# Setup the connection info.
# Get state and modify it:
comDCB = win32file.GetCommState(self.hComPort)
comDCB.BaudRate = self._baudrate
if self._bytesize == FIVEBITS:
comDCB.ByteSize = 5
elif self._bytesize == SIXBITS:
comDCB.ByteSize = 6
elif self._bytesize == SEVENBITS:
comDCB.ByteSize = 7
elif self._bytesize == EIGHTBITS:
comDCB.ByteSize = 8
else:
raise ValueError("Unsupported number of data bits: %r" % self._bytesize)
if self._parity == PARITY_NONE:
comDCB.Parity = win32.NOPARITY
comDCB.fParity = 0 # Disable Parity Check
elif self._parity == PARITY_EVEN:
comDCB.Parity = win32.EVENPARITY
comDCB.fParity = 1 # Enable Parity Check
elif self._parity == PARITY_ODD:
comDCB.Parity = win32.ODDPARITY
comDCB.fParity = 1 # Enable Parity Check
elif self._parity == PARITY_MARK:
comDCB.Parity = win32.MARKPARITY
comDCB.fParity = 1 # Enable Parity Check
elif self._parity == PARITY_SPACE:
comDCB.Parity = win32.SPACEPARITY
comDCB.fParity = 1 # Enable Parity Check
else:
raise ValueError("Unsupported parity mode: %r" % self._parity)
if self._stopbits == STOPBITS_ONE:
comDCB.StopBits = win32.ONESTOPBIT
elif self._stopbits == STOPBITS_ONE_POINT_FIVE:
comDCB.StopBits = win32.ONE5STOPBITS
elif self._stopbits == STOPBITS_TWO:
comDCB.StopBits = win32.TWOSTOPBITS
else:
raise ValueError("Unsupported number of stop bits: %r" % self._stopbits)
comDCB.fBinary = 1 # Enable Binary Transmission
# Char. w/ Parity-Err are replaced with 0xff (if fErrorChar is set to TRUE)
if self._rtscts:
comDCB.fRtsControl = win32.RTS_CONTROL_HANDSHAKE
else:
comDCB.fRtsControl = self._rtsState
if self._dsrdtr:
comDCB.fDtrControl = win32.DTR_CONTROL_HANDSHAKE
else:
comDCB.fDtrControl = self._dtrState
comDCB.fOutxCtsFlow = self._rtscts
comDCB.fOutxDsrFlow = self._dsrdtr
comDCB.fOutX = self._xonxoff
comDCB.fInX = self._xonxoff
comDCB.fNull = 0
comDCB.fErrorChar = 0
comDCB.fAbortOnError = 0
comDCB.XonChar = XON
comDCB.XoffChar = XOFF
win32file.SetCommState(self.hComPort, comDCB)
#~ def __del__(self):
#~ self.close()
def close(self):
"""Close port"""
if self._isOpen:
if self.hComPort:
# Restore original timeout values:
win32file.SetCommTimeouts(self.hComPort, self._orgTimeouts)
# Close COM-Port:
win32file.CloseHandle(self.hComPort)
win32file.CloseHandle(self._overlappedRead.hEvent)
win32file.CloseHandle(self._overlappedWrite.hEvent)
self.hComPort = None
self._isOpen = False
def makeDeviceName(self, port):
return device(port)
# - - - - - - - - - - - - - - - - - - - - - - - -
def inWaiting(self):
"""Return the number of characters currently in the input buffer."""
flags = win32.DWORD()
comstat = win32.COMSTAT()
if not win32file.ClearCommError(self.hComPort, ctypes.byref(flags), ctypes.byref(comstat)):
raise SerialException('call to ClearCommError failed')
return comstat.cbInQue
def read(self, size=1):
"""Read size bytes from the serial port. If a timeout is set it may
return less characters as requested. With no timeout it will block
until the requested number of bytes is read."""
if not self.hComPort: raise portNotOpenError
if size > 0:
win32.ResetEvent(self._overlappedRead.hEvent)
if not win32file.ClearCommError(self.hComPort):
raise SerialException('call to ClearCommError failed')
if self.timeout == 0:
n = min(comstat.cbInQue, size)
if n > 0:
rc,buf = win32file.ReadFile(self.hComPort, n, self._overlappedRead)
if win32.GetLastError() != win32.ERROR_IO_PENDING:
raise SerialException("ReadFile failed (%s)" % ctypes.WinError())
err = win32.WaitForSingleObject(self._overlappedRead.hEvent, win32.INFINITE)
read = buf[:rc]
else:
read = bytes()
else:
rc,buf = win32file.ReadFile(self.hComPort, size, self._overlappedRead)
rc = win32file.GetOverlappedResult(self.hComPort, self._overlappedRead, True)
read = buf[:rc]
else:
read = bytes()
return bytes(read)
def write(self, data):
"""Output the given string over the serial port."""
if not self.hComPort: raise portNotOpenError
#~ if not isinstance(data, (bytes, bytearray)):
#~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
# convert data (needed in case of memoryview instance: Py 3.1 io lib), ctypes doesn't like memoryview
if data:
#~ win32event.ResetEvent(self._overlappedWrite.hEvent)
err,n = win32file.WriteFile(self.hComPort, data, self._overlappedWrite)
if not err and win32.GetLastError() != win32.ERROR_IO_PENDING:
raise SerialException("WriteFile failed (%s)" % ctypes.WinError())
# Wait for the write to complete.
#~ win32.WaitForSingleObject(self._overlappedWrite.hEvent, win32.INFINITE)
n = win32file.GetOverlappedResult(self.hComPort, self._overlappedWrite, True)
if n != len(data):
raise writeTimeoutError
return n
else:
return 0
def flushInput(self):
"""Clear input buffer, discarding all that is in the buffer."""
if not self.hComPort: raise portNotOpenError
win32.PurgeComm(self.hComPort, win32.PURGE_RXCLEAR | win32.PURGE_RXABORT)
def flushOutput(self):
"""Clear output buffer, aborting the current output and
discarding all that is in the buffer."""
if not self.hComPort: raise portNotOpenError
win32.PurgeComm(self.hComPort, win32.PURGE_TXCLEAR | win32.PURGE_TXABORT)
def sendBreak(self, duration=0.25):
"""Send break condition. Timed, returns to idle state after given duration."""
if not self.hComPort: raise portNotOpenError
import time
win32.SetCommBreak(self.hComPort)
time.sleep(duration)
win32.ClearCommBreak(self.hComPort)
def setBreak(self, level=1):
"""Set break: Controls TXD. When active, to transmitting is possible."""
if not self.hComPort: raise portNotOpenError
if level:
win32.SetCommBreak(self.hComPort)
else:
win32.ClearCommBreak(self.hComPort)
def setRTS(self, level=1):
"""Set terminal status line: Request To Send"""
if not self.hComPort: raise portNotOpenError
if level:
self._rtsState = win32.RTS_CONTROL_ENABLE
win32.EscapeCommFunction(self.hComPort, win32.SETRTS)
else:
self._rtsState = win32.RTS_CONTROL_DISABLE
win32.EscapeCommFunction(self.hComPort, win32.CLRRTS)
def setDTR(self, level=1):
"""Set terminal status line: Data Terminal Ready"""
if not self.hComPort: raise portNotOpenError
if level:
self._dtrState = win32.DTR_CONTROL_ENABLE
win32.EscapeCommFunction(self.hComPort, win32.SETDTR)
else:
self._dtrState = win32.DTR_CONTROL_DISABLE
win32.EscapeCommFunction(self.hComPort, win32.CLRDTR)
def _GetCommModemStatus(self):
stat = win32.DWORD()
win32.GetCommModemStatus(self.hComPort, ctypes.byref(stat))
return stat.value
def getCTS(self):
"""Read terminal status line: Clear To Send"""
if not self.hComPort: raise portNotOpenError
return win32.MS_CTS_ON & self._GetCommModemStatus() != 0
def getDSR(self):
"""Read terminal status line: Data Set Ready"""
if not self.hComPort: raise portNotOpenError
return win32.MS_DSR_ON & self._GetCommModemStatus() != 0
def getRI(self):
"""Read terminal status line: Ring Indicator"""
if not self.hComPort: raise portNotOpenError
return win32.MS_RING_ON & self._GetCommModemStatus() != 0
def getCD(self):
"""Read terminal status line: Carrier Detect"""
if not self.hComPort: raise portNotOpenError
return win32.MS_RLSD_ON & self._GetCommModemStatus() != 0
# - - platform specific - - - -
def setXON(self, level=True):
"""Platform specific - set flow state."""
if not self.hComPort: raise portNotOpenError
if level:
win32.EscapeCommFunction(self.hComPort, win32.SETXON)
else:
win32.EscapeCommFunction(self.hComPort, win32.SETXOFF)
def outWaiting(self):
"""return how many characters the in the outgoing buffer"""
flags = win32.DWORD()
comstat = win32.COMSTAT()
if not win32.ClearCommError(self.hComPort, ctypes.byref(flags), ctypes.byref(comstat)):
raise SerialException('call to ClearCommError failed')
return comstat.cbOutQue
# assemble Serial class with the platform specific implementation and the base
# for file-like behavior. for Python 2.6 and newer, that provide the new I/O
# library, derive from io.RawIOBase
try:
import io
except ImportError:
# classic version with our own file-like emulation
class Serial(Win32Serial, FileLike):
pass
else:
# io library present
class Serial(Win32Serial, io.RawIOBase):
pass
# Nur Testfunktion!!
if __name__ == '__main__':
s = Serial(0)
sys.stdout.write("%s\n" % s)
s = Serial()
sys.stdout.write("%s\n" % s)
s.baudrate = 19200
s.databits = 7
s.close()
s.port = 0
s.open()
sys.stdout.write("%s\n" % s)
I'm on windows 7 64 bit, with python 2.6, and it's giving me the same error.
ser = serial.Serial(3,115200,timeout=1)
ser.read()
#or ser.write("whatever")
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
ser.read(1)
File "build\bdist.win-amd64\egg\serial\serialwin32.py", line 236, in read
raise SerialException("ReadFile failed (%s)" % ctypes.WinError())
SerialException: ReadFile failed ([Error 6] The handle is invalid.)
When using a similar program using a c library, the same port responds correctly. What happens here? Sounds like a bug in either pyserial or ctypes. Are you using 64 bit too?
the source code for writing in pyserial looks very simple
def write(self, data):
"""Output the given string over the serial port."""
if not self.hComPort: raise portNotOpenError
#~ if not isinstance(data, (bytes, bytearray)):
#~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
# convert data (needed in case of memoryview instance: Py 3.1 io lib), ctypes doesn't like memoryview
data = bytes(data)
if data:
#~ win32event.ResetEvent(self._overlappedWrite.hEvent)
n = win32.DWORD()
err = win32.WriteFile(self.hComPort, data, len(data), ctypes.byref(n), self._overlappedWrite)
if not err and win32.GetLastError() != win32.ERROR_IO_PENDING:
raise SerialException("WriteFile failed (%s)" % ctypes.WinError())
perhaps a problem with 64 bit ctypes?
Update:
Definitly a 64 bit problem atleast for me. I just installed an x86 version of python (3.1 this time), and it now works fine. Apperantly 64 bit ctypes can only import 64 bits libraries. Sounds very strange not being able to reach operating system libraries though.
I observed this problem with Python 2.7 win7 x64, and PySerial 2.5 installed automatically from easy_install.exe
The problem is not there with PySerial 2.4, so if your code is compatible with 2.4, just use that one instead and the problem is solved. Notice that you have to use pywin32 also, and chose the version that correspond to your python (e.g. pywin32-216.win-amd64-py2.7.exe).
See also https://sourceforge.net/tracker/?func=detail&aid=2921959&group_id=46487&atid=446302%5D2921959
This happened to me too and it was actually due to the serial port being closed when I tried to access it. This is because I was using a 'with' structure which makes sure to close the port afterwards and a bad code refactoring lead to this issue.
Use pyserial version 2.4:
http://sourceforge.net/projects/pyserial/files/pyserial/2.4/pyserial-2.4.win32.exe/download

Categories