I'm writing a script that requests some data from an IMAP server using the imaplib library. Having initiated a connection (c), I make the following calls:
rv, data = c.login(EMAIL_ACCOUNT, EMAIL_PASS)
if rv != 'OK':
print('login error')
else:
print(rv, data)
rv, mailboxes = c.list()
if rv != 'OK':
print('mailbox error')
else:
print(rv, data)
rv, data = c.select(EMAIL_FOLDER)
if rv != 'OK':
print('folder error')
else:
print(rv, data)
How could I rewrite this to use some sort of a wrapper function to reuse the logic of checking the error code and printing the data? I assume the function would take an error message as an argument and also the command to execute (select, login, etc.). How could I call a select connection function by passing it's name in an argument?
The way I understood you would like to check Decorators for your task.
class Wrapper:
def __init__(self, error_message):
self.error_message = error_message
def __call__(self, wrapped):
def func(*args, **kwargs):
rv, data = wrapped(*args, **kwargs)
if rv=="OK":
return(rv, data)
else:
print(self.error_message)
return(rv, data)
return func
#Wrapper("Folder Error")
def select(email_folder):
return "OK", "OLOLO"
#Wrapper("Folder Error")
def select_err(email_folder):
return "FAIL", "OLOLO"
print select("")
print select_err("")
yields
('OK', 'OLOLO')
Folder Error
('FAIL', 'OLOLO')
You can check reply inside of Wrapper's __call__ function and treat it the way you want to. For exampl you can return "False" or raise errors if rv not equals to "OK"
But It might be overly complicated for your case.
To re-use any code, look at the things that stay the same (e.g. the fact that rv and data come out of your imaplib calls in that order, and that rv=='OK' means things are OK) and write the logic that involves them, once. Then look at the things that change (e.g. the exact error message that needs to be printed). Parameterize the things that change, as in this example where the description argument changes the error message:
def check(description, rvdata):
rv, data = rvdata
if rv == 'OK':
print(data)
return data
else:
print(description + ' error')
return None
data = check('login', c.login(EMAIL_ACCOUNT, EMAIL_PASS))
mailboxes = check('mailbox', c.list())
selection = check('folder', c.select(EMAIL_FOLDER))
Related
I'm wondering if there's any pythonic or short-form method to achieve the following:
error_response = self.check_conditions(request)
# If we have an error response, return it, otherwise continue as normal.
if error_response:
return error_response
Something like:
(return self.check_conditions(request)) or pass
Alternatively, is it possible for a function to return the calling method, such as:
self.check_conditions(request)
def check_conditions(self, request):
error_response = do_stuff()
if error_response:
return_parent error_response
I get the feeling the second concept is breaking a ton of programming laws to prevent chaos and the apocalypse, just a thought though :)
No, there is no short form for a conditional return.
But, to get to the second part of your question:
There are exceptions in Python. You can write something like this:
class MyErrorResponse(Exception): pass
class MyClass:
...
def check_conditions(self, request):
error_response = do_stuff()
if error_response:
raise MyErrorResponse(error_response)
def do_the_main_stuff():
try:
self.check_conditions()
...
except MyErrorResponse as e:
return e.args[0]
That depends a lot on what check_conditions does under the hood. It's likely that you can move error handling down a level of abstraction and handle things directly:
Compare:
error = False
def foo(request):
global error
try:
result = do_something_with(request)
except SomeWellDefinedError:
error = True
def check_conditions(request):
foo(request)
return error
def main():
error_response = check_conditions(some_request)
if error_response:
# freak out!
With
def foo(request):
try:
result = do_something_with(request)
except SomeWellDefinedError:
# you can try to handle the error here, or...
raise # uh oh!
def main():
try:
foo(some_request)
except SomeWellDefinedError:
# handle the error here, instead!
I wonder if there is a python hackish way to achieve the following:
I found myself using an assert like structure in my views a lot:
def view(request):
if not condition:
return HttpResponseServerError("error")
if not condition2:
return HttpResponseServerError("error2")
[...]
return HttpResponse("OK!")
So I thought about using an assert like function:
def view(request):
def err(msg=None):
msg = msg if msg else "Illegal Parameters"
resp = {"msg": msg}
resp = json.dumps(resp)
return HttpResponseServerError(resp)
def verify(exp, msg=None):
if not exp:
err(msg)
verify(condition, "error")
verify(condition2, "error2")
return HttpResponse("OK")
Obviously, this does not work, as the result of the error function is never returned. Furthermore, I would also need to return the Response all the way to the view function and run return verify(), which will make my code prevent from execution of course.
One possible solution would be a decorator that either returns an error or the view function after all asserts went through. However, I would like to prevent that, as I also need some of the values I am establishing (imagine parsing one number after another and then having to pass a list of numbers).
Another solution I could think of is to actually do use a decorator and make my function a generator, yielding the result of verify. The decorator is a loop over that generator and keeps going until a response is yielded.
But in this post I am really looking for a more hackish way, to let the nested function return a reponse instead of the parent function and therefore prevent execution.
I will post my yield "solution" in a separate answer so you can get the picture :)
What about an exception, and a nice decorator to catch it:
class AssertError(Exception):
pass
def assertLike(view):
def wrap(request, *args, **kwargs):
try:
return view(request, *args, **kwargs):
except AssertError as e:
return HttpResponseServerError(...)
return wrap
#assertLike
def createTask(request):
import json
....
if not exp:
raise AssertError()
....
return HttpResponse("Ok")
Here I present the generator based solution:
def assertLike(view):
def wrap(request, *args, **kwargs):
for response in view(request, *args, **kwargs):
if response:
return response
return wrap
#other_django_views
#another_django_view
#assertLike
def createTask(request):
import json
def err(msg=None):
msg = msg if msg else "Illegal Parameters"
resp = {"msg": msg}
resp = json.dumps(resp)
return HttpResponseServerError(resp)
def verify(exp, msg=None):
if not exp:
return err(msg)
# only react to ajax requests
yield verify(True, "This is not an error")
yield verify(False, "Here it should stop!")
yield HttpResponse("This is the final response!")
I wrote the following python module to handle ssh connections in my program:
#!/usr/bin/env python
from vxpty import VX_PTY
class SSHError(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return repr(self.msg)
class SSHShell:
def __init__(self, host, port, user, password):
self.host = host
self.port = port
self.user = user
self.password = password
self.authenticated = False
def authenticate(self):
self.tty = VX_PTY(['/usr/bin/ssh', 'ssh', '-p'+str(self.port), self.user+'#'+self.host])
resp = self.tty.read()
if "authenticity of host" in resp:
self.tty.println('yes')
while 1:
resp = self.tty.read()
if "added" in resp:
break
resp = self.tty.read()
if "assword:" in resp:
self.tty.println(self.password)
tmp_resp = self.tty.read()
tmp_resp += self.tty.read()
if "denied" in tmp_resp or "assword:" in tmp_resp:
raise(SSHError("Authentication failed"))
else:
self.authenticated = True
self.tty.println("PS1=''")
return self.authenticated
def execute(self, os_cmd):
self.tty.println(os_cmd)
resp_buf = self.tty.read().replace(os_cmd+'\r\n', '')
return resp_buf
Which uses a pty module I wrote earlier:
#!/usr/bin/env python
import os,pty
class PTYError(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return repr(self.msg)
class VX_PTY:
def __init__(self, execlp_args):
self.execlp_args = execlp_args
self.pty_execlp(execlp_args)
def pty_execlp(self, execlp_args):
(self.pid, self.f) = pty.fork()
if self.pid==0:
os.execlp(*execlp_args)
elif self.pid<0:
raise(PTYError("Failed to fork pty"))
def read(self):
data = None
try:
data = os.read(self.f, 1024)
except Exception:
raise(PTYError("Read failed"))
return data
def write(self, data):
try:
os.write(self.f, data)
except Exception:
raise(PTYError("Write failed"))
def fsync(self):
os.fsync(self.f)
def seek_end(self):
os.lseek(self.f, os.SEEK_END, os.SEEK_CUR)
def println(self, ln):
self.write(ln+'\n')
However, whenever I call the execute() method, I end up reading the output from the first line:
>>> import SSH;shell=SSH.SSHShell('localhost',22,'735tesla','notmypassword');shell.authenticate()
True
>>> shell.execute('whoami')
"\x1b[?1034hLaptop:~ 735Tesla$ PS1=''\r\n"
>>>
Then the second time I call read() I get the output:
>>> shell.tty.read()
'whoami\r\n735Tesla\r\n'
>>>
Removing whoami\r\n from the output is not problem but is there any way to clear the output so I don't have to call read twice with the first command?
I think your problem is deeper than you realize. Luckily, it's also easier to solve than you realize.
What you seem to want is for os.read to return the entirety of what the shell has to send to you in one call. That's not something you can ask for. Depending on several factors, including, but not limited to, the shell's implementation, network bandwidth and latency, and the behavior of the PTYs (yours and the remote host's), the amount of data you'll get back in each call to read can be as much as, well, everything, and as little as a single character.
If you want to receive just the output of your command, you should bracket it with unique markers, and don't worry about messing with PS1. What I mean is that you need to make the shell output a unique string before your command executes and another one after your command executes. Your tty.read method should then return all the text it finds in between these two marker strings. The easiest way to make the shell output these unique strings is just to use the echo command.
For multiline commands, you have to wrap the command in a shell function, and echo the markers before and after executing the function.
A simple implementation is as follows:
def execute(self, cmd):
if '\n' in cmd:
self.pty.println(
'__cmd_func__(){\n%s\n' % cmd +
'}; echo __"cmd_start"__; __cmd_func__; echo __"cmd_end"__; unset -f __cmd_func__'
)
else:
self.pty.println('echo __"cmd_start"__; %s; echo __"cmd_end"__' % cmd)
resp = ''
while not '__cmd_start__\r\n' in resp:
resp += self.pty.read()
resp = resp[resp.find('__cmd_start__\r\n') + 15:] # 15 == len('__cmd_start__\r\n')
while not '_cmd_end__' in resp:
resp += self.pty.read()
return resp[:resp.find('__cmd_end__')]
I have been working around with a XBEE S2B Pro and a ConnectPort X4 and I have some questions about the drives xbee_sensor.py that can be found in folder
C:\Program Files\Digi\python\DevTools-2.1\Dia\Dia_2.1.0\src\devices\xbee\xbee_devices\xbee_sensor.py
I have inserted some Traces in the drives to understand how it works.
In one of my traces, I could see that inside the
def sample_indication(self, buf, addr):
the snippet
if self.__tracer.info():
msg = []
TRACER.critical('msg = [] %s', self.__tracer.info())
else:
msg = None
TRACER.critical('msg = None %s', self.__tracer.info())
returns msg = None False
As the subsequent code depends on the content of the msg
if msg is not None:
msg.append("%d %s" % (temperature, scale))
the temperature is not appended in msg buffer, which leads to msg buffer is not filled with any data.
My question is: why is the test self.__tracer.info() done?
Antonio, there is some undocumented behavior going on...
Looking at src/core/tracing.py on line 921, we have
def info(self, msg=None, *args):
'''
Send a message at the warning level.
'''
return self.log(LEVELS['INFO'], msg, *args)
and
def log(self, level, msg, *args):
'''
All other exposed Tracer methods call this method with their
respective numerical values as the level argument.
'''
# basic cut-off
if self.level > level:
return False
if msg == None:
True
...
on line 866.
So
self.__tracer.info()
returns True if info level messages will be logged.
This seems like a remedial topic, but I'm a bit unsure of how to deal with this. Every solution I think of seems messy.
I'm working with some code that builds up a message while performing several actions, then ultimately returns that msg with an http response. Currently it looks somewhat like this:
try:
pdict = parser.parseProtocol(id)
msg = "parsing worked"
except:
msg = "parsing failed"
try:
file = parser.getFile(pdict['filePath'])
msg += "file retrieved"
except:
msg += "file not found"
Say I want to encapsulate the code into functions. How could do I have a message that gets updated throughout? Strings are immutable, so I can't just pass them to a function and modify them. A super ugly solution would be:
(pdict, msg) = parseSomething()
if pdict:
(file, msg) = retrieveFile(pdict, msg)
def parseSomething():
try:
pdict = parser.parseProtocol(id)
return (pdict, "parsing worked")
except:
return (None, "parsing failed")
def retrieveFile(pdict, msg)
try:
file = parser.getFile(pdict['filePath'])
return (file, msg + "file retrieved")
except:
return (None, msg + "file not found")
Super ugly.
I could create a message class, or use a list of length 1, and that would be prettier, but still not very pythonic, right? I think I just want these functions to take a message string and modify it, without having to return it, but strings are immutable so that's not the default behavior.
There's gotta be a smooth way to do this that I'm just blanking on. Help?
Consider putting your messages in a list and appending to it as you go?
messages = []
try:
pdict = parser.parseProtocol(id)
messages.append("parsing worked")
except:
messages.append("parsing failed")
try:
file = parser.getFile(pdict['filePath'])
messages.append("file retrieved")
except:
messages.append("file not found")
print '\n'.join(messages)
If your codepath is particularly convuluted, consider embedding them in a class:
class Tests(object):
def __init__(self):
messages = []
self.pdict = None
def parsetest(self):
try:
self.pdict = parser.parseProtocol(id)
except:
self.messages.append("parsing failed")
else:
self.messages.append("parsing worked")
def retrievetest(self):
if self.pdict is None:
raise Exception("called retrievetest() before successfully parsing")
try:
file = parser.getFile(self.pdict['filePath'])
except:
self.messages.append("file not found")
else:
self.messages.append("file retrieved")
And then later:
tests = Tests()
tests.parsetest()
if condition:
tests.retrievetest()
print '\n'.join(tests.messages)
put your message in an array, pass it around, and just append each part to it.
just before sending it, do a ''.join(msg).
Make your message a member of a class, and pass around an instance of the class.
Better yet, make all these function methods on a class, and keep the message as an attribute of the object.