I have Python 2.7 amd64 running on Windows 7 + latest Twisted 12
I have very simple programm which connects stdin/stdout with remote tcp server
from twisted.internet import stdio, reactor, protocol
from twisted.protocols import basic
class Echo(basic.LineReceiver):
def connectionMade(self):
self.factory = CFactory()
self.connector = reactor.connectTCP('remote', 8585, self.factory)
def lineReceived(self, line):
self.connector.transport.write("%s\n" % line)
class Client(basic.LineReceiver):
def lineReceived(self, line):
delimiter = '\n'
print "%s" % line
class CFactory(protocol.ClientFactory):
protocol = Client
def main():
stdio.StandardIO(Echo())
reactor.run()
if __name__ == '__main__':
main()
On Linux it works just fine. But on Windows my input to stdin is being ignored. So nothing being sent to remote side
Any idea why?
class Client(basic.LineReceiver):
def lineReceived(self, line):
delimiter = '\n'
print "%s" % line
The delimiter = '\n' line here has no useful consequences. It defines a new name in the local scope of the lineReceived function, and then ignores that local name.
What you intended to do, I think, is:
class Client(basic.LineReceiver):
delimiter = '\n'
def lineReceived(self, line):
print "%s" % line
This defines a new attribute of the Client class, delimiter, which controls how the base class, basic.LineReceiver, splits up lines.
However, your example program only defines Client, it doesn't actually use it. So this isn't the cause of the problem. The cause of the problem is very similar, though. Echo is used to handle standard input, and it does not override the default LineReceiver delimiter at all. The default is '\r\n', which is not the line delimiter used on Windows standard input.
Start off your Echo definition like this:
class Echo(basic.LineReceiver):
delimiter = '\n'
and I think the program will behave as you want, since Windows uses "\n" to delimit lines on standard input (no Windows machine around to verify that, though, so you might want to double check; if that's not the case, a very useful response to make would be to explain what the delimiter is; if it is the case, verifying that information would also be a good thing).
Try dataReceived, it might work.:
class Echo(basic.LineReceiver):
...
def dataReceived(self, data):
self.connector.transport.write("%s\n" % data)
...
On Windows a patch is required to fix the problem of receiving input from Std I/O.
Refer to solution posted to ticket # 2157 on twistedmatrix.com here: http://twistedmatrix.com/trac/ticket/2157
The solution has several attachments - for individual patches. And there is a consolidated patch file which is an unified diff.
I have a 64-bit Python 2.7.3. running on a Windows 7 64-bit machine with Twisted 12.3.0 and I applied the above unified patch to the _win32stdio.py, _pollingfile.py, conio.py. This allows the input and output to/from Std I/O for IProtocol implementations.
Related
I distribute a software package for windows via distutils and py2exe. For development purposes, I'd like to be able to have access to a python console inside the py2exe build. I see there is a python27.dll file in the py2exe build, so I hope I can leverage that to launch a python terminal.
Is it possible to take an existing, or modify distutils/py2exe to get end user access to a Python shell in the py2exe environment?
There's a really bare-bones way to accomplish this as documented by Matt Anderson from the pymntos google group. I've seen some variations on it, but this one came up first when I googled. :p
The juice is in the stdlib code module, leveraging code.InteractiveInterpeter. The only thing you'd have to do is add this in as a thread as the application starts. Then, when the app starts you can telnet 'localhost 7777' and you should drop into a Python interpreter.
The problem with doing it as a thread though - you can't very easily twiddle variables / data in the main thread without doing some sort of queue and passing things around.
You could alternatively have an async socket - that way you could twiddle stuff as a main-thread participant. Thats inherently dangerous for a host of reasons. But, we're talking bare metal.
If you use the Twisted library, you could use Twisted Conch, which allows you to create an SSH or Telnet server that can talk to the rest of your app. However, this might be a problem since you're using the event loop from the UI to process events - you can't have two event loops. If you're using Qt, there is a Twisted Qt Reactor event loop. If it's windows or something else.. I have no idea. But, this should at least give you a few things to consider.
Original link is: https://groups.google.com/forum/?fromgroups#!topic/pymntos/-Mjviu7R2bs
import socket
import code
import sys
class MyConsole(code.InteractiveConsole):
def __init__(self, rfile, wfile, locals=None):
self.rfile = rfile
self.wfile = wfile
code.InteractiveConsole.__init__(
self, locals=locals, filename='<MyConsole>')
def raw_input(self, prompt=''):
self.wfile.write(prompt)
return self.rfile.readline().rstrip()
def write(self, data):
self.wfile.write(data)
netloc = ('', 7777)
servsock = socket.socket()
servsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
servsock.bind(netloc)
servsock.listen(5)
print 'listening'
sock, _ = servsock.accept()
print 'accepted'
rfile = sock.makefile('r', 0)
sys.stdout = wfile = sock.makefile('w', 0)
console = MyConsole(rfile, wfile)
console.interact()
I'm having a bizarre issue. Basically, the problem I have right now is dealing with two different LineReceiver servers that are connected to each other. Essentially, if I were to input something into server A, then I want some output to appear in server B. And I would like to do this vice versa. I am running two servers on two different source files (also running them on different processes via & shellscript) ServerA.py and ServerB.py where the ports are (12650 and 12651) respectively. I am also connecting to each server using telnet.
from twisted.internet import protocol, reactor
from twisted.protocols.basic import LineReceiver
class ServerA(LineReceiver);
def connectionMade(self):
self.transport.write("Is Server A\n")
def dataReceived(self, data):
self.sendLine(data)
def lineReceived(self, line):
self.transport.write(line)
def main():
client = protocol.ClientFactory()
client.protocol = ServerA
reactor.connectTCP("localhost", 12650, client)
server = protocol.ServerFactory()
server.protocol = ServerA
reactor.listenTCP(12651, server)
reactor.run()
if __name__ == '__main__':
main()
My issue is the use of sendLine. When I try to do a sendLine call from serverA with some arbitrary string, serverA ends up spitting out the exact string instead of sending it down the connection which was done in main(). Exactly why is this happening? I've been looking around and tried each solution I came across and I can't seem to get it to work properly. The bizarre thing is my friend is essentially doing the same thing and he gets some working results but this is the simplest program I could think of to try to figure out the cause for this strange phenomenon.
In any case, the gist is, I'm expecting to get the input I put into serverA to appear in serverB.
Note: Server A and Server B have the exact same source code save for the class names and ports.
You have overridden dataReceived. That means that lineReceived will never be called, because it is LineReceiver's dataReceived implementation that eventually calls lineReceived, and you're never calling up to it.
You should only need to override lineReceived and then things should work as you expect.
I have following code from wesley chun's core python application programming book
#!/usr/bin/env python
"""
tcp server
"""
from socket import AF_INET, SOCK_STREAM, socket
from time import ctime
HOST = ''
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST, PORT)
tcp_server_socket = socket(AF_INET, SOCK_STREAM)
tcp_server_socket.bind(ADDR)
#maximum number of incoming connection before connection is refused
tcp_server_socket.listen(5)
while True:
print "waiting for connection"
tcpCliSock, addr = tcp_server_socket.accept()
print "... connected from:" , addr
while True:
DATA = tcpCliSock.recv(BUFSIZE)
if not DATA:
break
tcpCliSock.send('[%s] %s' % (ctime(), DATA))
tcpCliSock.close()
tcp_server_socket.close()
I did some modifications to the original code however I am still confused how best to modify it to be more compliant
here are all the messages I am getting
C: 14,0: Invalid name "tcp_server_socket" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)
C: 21,4: Invalid name "tcpCliSock" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)
C: 21,16: Invalid name "addr" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)
E: 25,15: Instance of '_socketobject' has no 'recv' member
E: 28,8: Instance of '_socketobject' has no 'send' member
I suppose first three just want me to use all caps variable names, is that the standard practice for these type of scripts, I don't see the code becoming more readable by using this convention, on the contrary it will look less readable, what are the motivation behind such rule in pylint and how to make code more compliant, I hardly think writer of such stature would write code like this without reason, be it readablity, beginner friendliness or anything else.
The two errors about _socketobject you are seeing are a quirk of how the socket module works. This issue has come up on StackOverflow once before, and the linked question provides a couple of answers to help you get rid of those errors.
The first three messages you are getting are convention warnings. They are complaining that the names tcp_server_socket, tcpCliSock and addr do not match the regular expression for constant members. Because your code is at 'top-level' (i.e. outside of any functions or classes), members are expected to be constant, and names of constants should match the regular expression given.
Suppose your Python script was saved in a file tcp_server.py. If you then write import tcp_server either from the Python interpreter or from another Python script, your TCP server will start. This isn't typically what you would want to happen. If you import a module, it can define functions, classes and constants, but it shouldn't run any code.
I'd recommend moving all of the code from the line tcp_server_socket = socket(....) downwards into a separate function, (let's call it start_server), and then adding to the bottom of your script the following lines:
if __name__ == "__main__":
start_server()
These two lines will then start your server if you run the script directly, but not if you import tcp_server from somewhere else.
Once you've done that, the warnings about variable names will go, but you will get some further convention warnings. Two of them will complain about DATA and tcpCliSock not matching the naming convention for variable names, and the other will nag you that your start_server function doesn't have a docstring.
I'm trying to write a client in python 2.7 using Twisted. My code works just fine in linux (debian squeeze), but when I tried it on windows (xp and 7) I got a constant stream of error messages. A screenshot of these messages is here.
I have narrowed down the bug and was able to write a very stripped down version of my client that still contains the bug:
from twisted.internet.protocol import Protocol,ClientFactory
from twisted.protocols.basic import LineReceiver
from twisted.internet import reactor
class TheClient(LineReceiver):
def lineReceived(self,line):
print line
def connectionLost(self,reason):
reactor.stop()
class TheFactory(ClientFactory):
protocol = TheClient
class Test(object):
def doRead(self):
pass
def fileno(self):
return 0
def connectionLost(self,reason):
print 'connection lost'
def logPrefix(self):
return 'Client'
def main():
print 'starting'
test = Test()
reactor.addReader(test)
reactor.run()
if __name__ == '__main__':
main()
If the line containing 'reactor.addReader(test)' is commented out, I do not get any error messages. If I run this code on linux without commenting out any lines, I do not get any error messages.
I found this question, I don't think its the same problem, but as expected, it did not function properly on windows.
Is this code correct, and this is a windows bug, or do I have to do things differently for it to work in windows?
The Windows implementation of select only supports sockets. Presumably file descriptor 0 in your process does not represent a socket. More likely it represents something related to standard I/O.
If you'd just like to use standard I/O, then there's twisted.internet.stdio, though you may run into some rough edges with it on Windows (bug reports and fixes appreciated!).
If you're not interested in standard I/O and 0 was just an arbitrary test, you'll probably need to decide on what kind of input you're trying to do in particular. Depending on what kind of file descriptor you have, there will probably be a different approach to successfully reading from it.
I have written this short script (which I've stripped away some minor detail for size) and I'm getting a very simple error, yet, I don't understand why! I'm very new to Python, so maybe someone can explain the issue and why it's not working?
The error seems to fall when I wish to print the full custom serial write string back to the console, it doesn't seem to recognise the Args I sent to the function.
Perhaps I have misunderstood something very simple. Should be simple for anyone even with the tiniest of Python understanding
Cheers
The Code:
#! /usr/bin/env python
# IMPORTS APPEAR HERE ***
ser = serial.Serial(
port='/dev/ttyUSB0',
baudrate=115200,
parity='N',
stopbits=1,
bytesize=8
)
# Sets motor number
motor_no = "2"
# Lets create our main GUI class
class ArialApp(object):
# Default init stuff
def __init__(self):
# Create a builder object and create the objects from the .glade file
self.builder = gtk.Builder()
self.builder.add_from_file("../res/main.glade")
self.builder.connect_signals(self)
# Open the serial connection to the encoder and keep it open
ser.open()
# Custom function for sending commands down the serial. Needed to wrap defaults
# arround the custom 'serial.write' command.
self.send_command('A')
# Code removed for space.....
# Custom method for sending commands down serial with default ammendments
def send_command(self, nanotech):
# Send the command with the #, then motor number which should be global, then the command
# sent the the method followed by a return
ser.write("#" + motor_no + nanotech + '\r\n')
# Print to the console the full command sent down the pipe
# [[[ ERROR GOES HERE ]]]
print "#" + motor_no + nanotech + '\r\n'
# Just to show its in here...
if __name__ == "__main__":
app = ArialApp()
gtk.main()
The error:
File "main.py", line 62, in ArialApp
print "#" + motor_no + commands + '\r\n'
NameError: name 'commands' is not defined
Finally, just to shed some context on the situation:
I am writing a small GUI app in Glade and Python / PyGTK to control a stepper motor over serial using the PySerial module. However, I would like to package up my own "write" function so I can append default values to the 'send' down the cable. For example, the motor number and always appending returns on the end of the instructions. Other things like reading back the response straight away in the same function would be useful to gauge responses too, so, wrapping it up into a custom function seemed like the sensible thing to do.
Any advice or help on the above would be appreciated.
Thank-you kindly.
Andy
UPDATE: I have addresses the original issue of not including "self" and I've managed to get Stack to accept the tabs I normally use so its cleaner to look at. Also wanted to note the only code I removed was simple variable setting. However, the issue persists!
It could be because you're missing the self argument:
def send_command(self, commands):
you've got an indentation error in def send_command(commands):
and your first parameter should be "self" :
class ArialApp(object):
<snap>
def send_command(self, commands):
ser.write("#" + motor_no + commands + '\r\n')
Firstly, you should use more than a single space for indentation. White space is significant in Python, and it's very hard to see that you've got it right if you're only using one space. Four is the usually accepted amount.
The main issue with your send_command method is that you've forgotten that the first argument to any method in Python is (by convention) self. So the signature should be:
def send_command(self, commands):
However, the code you have shown would not give the error you state: it would instead give this:
TypeError: send_command() takes exactly 1 argument (2 given)
In addition, in your method it's not commands which is not defined, but motor_no. This is why it's always important to show the actual code you're running, cut down enough to actually reproduce the error.