Hardening Python class or over engineering - python

I'm rather new to Python, but have grown to like it. I am starting our first Python project and am doing some prototyping. The "Python philosophy" confuses me in terms of typing and exceptions. Can someone please shoot at this excerpt? Am I over engineering or missing some fundamental Python methodology?
class URIPartError(Exception):
pass
class WCFClient(object):
def __init__(self, host, scheme='http', port=80, path='/', user=None, password=None):
super(WCFClient, self).__init__()
#Store our variables
try:
self.__host = str(host).lower()
self.__scheme = str(scheme).lower()
self.__port = int(port)
self.__path = str(path)
self.__user = str(user) if user else None
self.__password = str(password) if password else None
except (TypeError, ValueError), e:
raise URIPartError('Invalid URI part')
#Are our inputs valid?
if not self.__scheme == 'http' and not self.__scheme == 'https':
raise URIPartError('Invalid URI scheme')
if not path.startswith('/') or not path.endswith('/'):
raise URIPartError('Invalid URI path')
#Generate valid URI for baseurl
if (self.__scheme == 'http' and self.__port == 80) or (self.__scheme == 'https' and self.__port == 443):
self.__baseurl = '{0}://{1}{2}'.format(self.__scheme, self.__host, self.__path)
else:
self.__baseurl = '{0}://{1}:{2}{3}'.format(self.__scheme, self.__host, self.__port, self.__path)
def baseurl(self):
return self.__baseurl
Thanks!

There's nothing wrong here in terms of typing. You're not insisting on types, you're doing exactly the right thing by checking values - if a user passes invalid parameters, it's perfectly valid to raise exceptions.
The only comment I would make here is that it's very unPythonic to use "private" double-underscore variables together with getters. Rather than setting self.__baseurl and then providing a baseurl() method, just set self.baseurl directly.

Seeing as how your WCFClient inherits from object (which btw only makes sense if you are using Python 2.x, since in Python 3 this is default), it does not really make sense to call the constructor of the object class. This means that you can remove the line
super(WCFClient, self).__init__()
For the rest it is all ok :)

Related

Is there a python idiom for downcasting?

I'm writing a web-application based on the webapp2 framework. I'm using a common base exception for all the errors I'm explicitly throwing, like
class MyBaseException(Exception):
def __init__(self, status, code, message):
self.status_code = status
self.error_code = code
self.error_message = message
and have a BaseRequestHandler that outputs a simple JSON response for errors, defaulting to a 500/Generic error for unexpected exceptions.
class BaseHandler(webapp2.RequestHandler):
def handle_exception(self, e, debug):
logger.exception(e)
status = e.status_code if isinstance(e, MyBaseException) else 500
code = e.error_code if isinstance(e, MyBaseException) else 'GENERIC_ERROR'
message = e.error_message if isinstance(e, MyBaseException) else 'Blah blah blah'
self.response.set_status(status)
self.response.content_type = 'application/json'
self.response.write(json.encode({"code": code, "message": message})
Those isinstance checks look ugly to me, so I'm thinking there has to be a better way. Suggestions?
EDIT What has this to do with downcasting?
In java, my "native" language, I'd do something like
MyBaseException b = (MyBaseException) e;
JSONObject j = new JSONObject();
j.put("error_code", e.getCode());
j.put("error_message", e.getErrorMessage());
...
but python has no explicit type casts so... is it possible to do something like that?
The usual Python idiom is to ignore the class of the object altogether, so you'd just do:
status = e.status_code
code = e.error_code
message = e.error_message
This is referred to as duck typing.
If you may need to handle other types of exceptions (where, in your Java example you'd get a ClassCastException) the standard Python idiom is to just wrap the whole thing in a try...catch:
try:
status = e.status_code
etc.
catch AttributeError: # i.e. e doesn't have one of the listed attributes
status = "500"
etc.

#EndpointsAliasProperty and #Model.query_method causes BadRequestError(Key path element must not be incomplete:...)

Hey so right now I'm developing backend api using Google ProtoRPC and Endpoints. I'm using the endpoints-proto-datastore library.
So strange things happen here, here is the EndpointsModel class
class AssetData(EndpointsModel):
type = msgprop.EnumProperty(AssetType, indexed=True)
def auth_id_set(self, value):
if ApplicationID.get_by_id(value) is None:
raise endpoints.UnauthorizedException('no auth_id')
self._auth_id = value
#EndpointsAliasProperty(required=True, setter=auth_id_set, property_type=messages.IntegerField)
def auth_id(self):
return self._auth_id
def app_id_set(self, value):
if ApplicationID.query(ApplicationID.app_id == value).get() is None:
raise endpoints.UnauthorizedException('wrong app_id')
self._app_id = value
if self.check_auth_app_id_pair(self.auth_id, value):
self._app_id = value
else:
raise endpoints.BadRequestException('auth_id and app_id mismatch')
#EndpointsAliasProperty(required=True, setter=app_id_set)
def app_id(self):
return self._app_id
#staticmethod
def check_auth_app_id_pair(authen_id, applic_id):
dat = ApplicationID.get_by_id(authen_id)
if dat.app_id != applic_id:
return False
else:
return True
and this is the API class
#endpoints.api(...)
class AssetDatabaseAPI(remote.Service):
#AssetData.query_method(query_fields=('limit', 'order', 'pageToken', 'type', 'auth_id', 'app_id'),
path='assets', http_method='GET', name='assets.getAssetMultiple')
def assets_get_multiple(self, query):
return query
When I deploy this, everytime I tried to access assets.getMultipleAssets it just gives me this error
raised BadRequestError(Key path element must not be incomplete: [ApplicationID: ]). Strangely enough this only happen to method using #Model.query_method, I have other methods using the same system but using #Model.method and it just runs ok.
If I tried it in development server, sometimes it just gives me RuntimeError: BadRequestError('missing key id/name',) then if I just re-save the .py file and retry it, it will work (sometimes not and another re-save can also make the error happens again).
Can anyone tell me my mistake?
Thanks
I think your problem is how you call this method - it's a static method, so you have to access it through class, not the instance (self):
if AssetData.check_auth_app_id_pair(self.auth_id, value):
self._app_id = value
else:
raise endpoints.BadRequestException('auth_id and app_id mismatch')

Python class variable not updating

I have a class that is taking in an Id and trying to update the variable current_account but when I print out the details of the current_account it hasn't updated.
Anyone got any ideas for this? New to python so might be doing something stupid that I can't see.
class UserData:
def __init__(self, db_conn=None):
if None == db_conn:
raise Exception("DB Connection Required.")
self.db = db_conn
self.set_my_account()
self.set_accounts()
self.set_current_account()
def set_current_account(self, account_id=None):
print account_id
if None == account_id:
self.current_account = self.my_account
else:
if len(self.accounts) > 0:
for account in self.accounts:
if account['_id'] == account_id:
self.current_account = account
print self.current_account['_id']
else:
raise Exception("No accounts available.")
Assume that set_my_account() gets a dictionary of account data and that set_accounts() get a list of dictionaries of account data.
So when I do the following:
user_data = UserData(db_conn=db_conn)
user_data.set_current_account(account_id=account_id)
Where db_conn is a valid database connection and account_id is a valid account id.
I get the following out of the above two lines.
None
518a310356c02c0756764b4e
512754cfc1f3d16c25c350b7
So the None value is from the declaration of the class and then the next two are from the call to set_current_account(). The first id value is what I'm trying to set. The second id value is what was already set from the class __init__() method.
There were a lot of redundancies an un-Pythonic constructions. I cleaned up the code to help me understand what you trying to do.
class UserData(object):
def __init__(self, db_conn):
self.db = db_conn
self.set_my_account()
self.set_accounts()
self.set_current_account()
def set_current_account(self, account_id=None):
print account_id
if account_id is None:
self.current_account = self.my_account
else:
if not self.accounts:
raise Exception("No accounts available.")
for account in self.accounts:
if account['_id'] == account_id:
self.current_account = account
print self.current_account['_id']
user_data = UserData(db_conn)
user_data.set_current_account(account_id)
You used default arguments (db_conn=None) when a call without an explicit argument is invalid. Yes, you can now call __init__(None) but you could also call __init__('Nalum'); you can't protect against everything.
By moving the "No accounts" exception the block fast-fails and you save one level of indention.
The call UserData(db_conn=db_conn) is valid but unecessarily repetitive.
Unfortunately, I still can't figure out what you are trying to accomplish and this is perhaps the largest flaw. Variable names are terribly important for help the reader (which may be the future you) make sense of code. current_account, my_account, account_id and current_account['_id'] so obscure the intention that you should really consider more distinct, informative names.
Figured out what it was.
The data was being changed else where in the code base. It is now working as expected.
Thanks guys for pointing out the Python centric things that I was doing wrong, good to get it.

Best approach to pass and handle arguments to function

After some reading, I found myself struggling with two different approaches to pass a list of arguments to a function. I read some indications. That's what I figured out so far:
Actual code:
file caller.py:
import worker
worker.version_check(iserver,login,password,proxyUser,proxyPass,
proxyServer,packageInfo)
worker.version_get(iserver,login,password,proxyUser,proxyPass,
proxyServer,packageInfo)
worker.version_send(iserver,login,password,proxyUser,proxyPass,
proxyServer,packageInfo)
File: worker.py:
def version_check(iserver,login,password,proxyUser,proxyPass,proxyServer,service):
#code and more code
def version_get(iserver,login,password,proxyUser,proxyPass,proxyServer,service):
#code and more code
def version_send(iserver,login,password,proxyUser,proxyPass,proxyServer,service):
#code and more code
And now I have:
file caller.py:
import worker
args = (env, family, host, password, prefix, proxyServer,
proxyUser, proxyPass, option, jokerVar
)
worker.version_check(*args)
worker.version_get(*args)
worker.version_send(*args)
File: worker.py:
def version_check(*args):
env = args[0]
family = args[1]
host = args[2]
password = args[3]
prefix = args[4]
proxyServer = args[5]
proxyUser = args[6]
proxyPass = args[7]
option = args[8]
jokerVar = args[9]
#code and more code
def version_get((*args):
env = args[0]
family = args[1]
host = args[2]
password = args[3]
prefix = args[4]
proxyServer = args[5]
proxyUser = args[6]
proxyPass = args[7]
option = args[8]
jokerVar = args[9]
#code and more code
def version_send(*args):
env = args[0]
family = args[1]
host = args[2]
password = args[3]
prefix = args[4]
proxyServer = args[5]
proxyUser = args[6]
proxyPass = args[7]
option = args[8]
jokerVar = args[9]
#code and more code
Using the old approach (actual code) I believe it is more "friendly" to call a function in one line only (as you can see on worker.py). But, using the new approach, I think the code get more extensive because for each function I have to define all the same variables. But is this the best practice? I'm still learning Python on a slow curve, so, sorry for any mistakes in the code.
And one important thing, most of the variables are retrieved from a database, so they are not stactic.
I really don't recommend defining functions like def version_check(*args): unless you specifically need to. Quick, without reading the source: what order are the arguments in? How do you specify a default value for proxyServer? Remember, "explicit is better than implicit".
The one time I routinely deviate from that rule is when I'm wrapping another function like:
def foo(bar):
print 'Bar:', bar
def baz(qux, *args):
print 'Qux:', qux
foo(*args)
I'd never do it for such a simple example, but suppose foo is a function from a 3rd-party package outside my control with lots of defaults, keyword arguments, etc. In that case, I'd rather punt the argument parsing to Python than attempt it myself.
Personally, I'd write that as a class like:
class Worker(object):
def __init__(iserver,login,password,proxyUser,proxyPass,proxyServer,service):
self.iserver = iserver
self.login = login
self.password = password
self.proxyUser = proxyUser
self.proxyPass = proxyPass
self.proxyServer = proxyServer
self.service = service
def version_check(self): ...
def version_get(self): ...
def version_send(self): ...
And then in the client, write:
from worker import Worker
w = Worker(iserver,login,password,proxyUser,proxyPass,proxyServer,service)
w.version_check()
w.version_get()
w.version_send()
If you really need to write functions with lots of arguments instead of encapsulating that state in a class - which is a more typically Pythonic way to do it - then consider the namedtuple datatype from recent Python versions. It lets you specify a tuple where items are addressable by keyword and can make for some very clean, elegant code.
There are many approaches, depending on what those arguments represent.
If they are just a grab-bag of arguments (especially if some are optional), use keyword arguments:
myargs = {'iserver':'server','login':'username','password':'Pa2230rd'}
version_get(**myargs)
If they represent some thing with its own state, then use classes:
If the arguments represent a single state that your functions are modifying, then accept the arguments in the object constructor and make your version_* methods functions of that class:
class Version(object):
def __init__(self,iserver,login,password,
proxyUser,proxyPass,proxyServer,service):
self.iserver = iserver
self.login = login
#etc
def check(self):
self.iserver
def get(self):
pass
#etc
myversion = Version('iserver','login',...)
myversion.check()
If you have some kind of resource those arguments represent that your functions are merely using, in that case use a separate class, and supply it as an object parameter to your functions:
class Connection(Object):
def __init__(self, iserver, ...):
self.iserver # etc
myconn = Connection('iserver',...)
version_check(myconn)
Most likely, these are two different resources and should be two classes. In this case you can combine these approaches:
#Connection() class as above
class Version(object):
def __init__(self, connection):
self.connection = connection
def check(self):
self.connection.iserver # ....
myconn = Connection('iserver', ...)
conn_versioner = Version(myconn)
conn_versioner.check()
Possibly, your arguments represent more than one object (e.g., a connection and a transparent proxy object) In that case, try to create an object with the smallest public interface methods like version_* would need and encapsulate the state represented by the other arguments using object composition.
For example, if you have proxy connections, you can create a Connection() class which just knows about server, login and password, and a ConnectionProxy() class which has all the methods of a Connection, but forwards to another Connection object. This allows you to separate the proxy* arguments, and means that your version_* functions can be ignorant of whether they're using a proxy or not.
If your arguments are just state and don't have any methods proper to them, consider using a namedtuple(). This will act like a smarter tuple (including tuple unpacking, slicing, etc) and have minimal impact on your existing code while still being easier to use.
Connection = namedtuple('Connection', 'iserver login password etc')
myconn = Connection('iserver', 'loginname', 'passw3rd')
version_check(*myconn)
You can create instance an object or define a class. e.g.
file caller.py:
import worker
info=object()
info.env=0
info.family='something'
info.host='something'
info.password='***'
info.prefix=''
info.proxyServer=''
info.proxyUser=''
info.proxyPass=''
info.option=''
info.jokerVar=''
worker.version_check(info)
worker.version_get(info)
worker.version_send(info)
file worker.py:
def version_check(info):
#you may access values from info
#code and more code
def version_get(info):
#code and more code
def version_send(info):
#code and more code

How can I get the name of the class of a bound method from the interpreter stack?

I have an awesome little function that looks like this:
def verbose_print(message, *args, **kwargs):
"""Prints `message` with a helpful prefix when in verbose mode
Args:
message (str): The message to print. Can be a format string, e.g.
`A %s with some %s in it`
*args: Variables for the message format
**kwargs: Keyword variables for the message format
"""
# Only print when in verbose mode
if not config.verbose:
return
# Ready a prefix for the message
try:
s = inspect.stack()
module_name = inspect.getmodule(s[1][0]).__name__
func_name = s[1][3]
prefix = '### %s->%s' % (module_name, func_name)
except Exception as e:
prefix = '### [stack unavailable]'
if args:
message = message % args
elif kwargs:
message = message % kwargs
print '%s: %s' % (prefix, message)
The point of the function is that I can call it from anywhere with a message, and if my project config file is set to verbose mode, all the messages will be printed with a helpful prefix to show where it was called. Here's an example of some output:
### avesta.webserver->check_login: Checking login for client at 127.0.0.1
### avesta.webserver->check_login: Found credentials cookie with username: tomas, token: blablabla
### avesta.webserver->check_login: Login valid, refreshing session
### avesta.webserver->get_flash_memory: Fetched flash data: None
### avesta.webserver->get: Fetched data from empty path ('previous_values', 'name'), returning ''
### avesta.webserver->get: Fetched data from empty path ('previous_values', 'description'), returning ''
### avesta.webserver->get: Fetched data from empty path ('validation_errors', 'name'), returning ''
The format is "### module->function: message".
Now most of the time this is really helpful, but it's not perfect. In the example above, the "get" function is actually a bound method of a class, but that's not visible. What I'm trying to accomplish is that when a function is a bound method, I print with this format instead:
"### module->ClassName.function"
But the problem is:
I only get the function name from the stack, so I can't really check if it's a bound method
Even if I had the function reference, how would I extrapolate the class name it's bound to?
Thanks for any answers that can help me figure this out.
I thought this was going to be easy, but it turned out to be a bit complicated. If you have a reference to the bound method, you can get its class name via boundMethod.im_class.__name__. However, when you're grabbing the stack, you can't easily get a reference to the bound method, just to stack frames.
However all is not lost! The inspect module can get you function arguments from a stack frame using the getargvalues function. You do have to cheat a little, by relying on the convention that methods always have their first argument named "self". You can check for that, then grab the "self" value from the function's locals dict, and from there it's easy to get the class name. Try replacing your current try block with his code:
s = inspect.stack()
module_name = inspect.getmodule(s[1][0]).__name__
func_name = s[1][3]
arginfo = inspect.getargvalues(s[1][0])
if len(arginfo.args) > 0 and arginfo.args[0] == "self":
func_name = "%s.%s" (arginfo.locals["self"].__class__.__name__, func_name)
prefix = '### %s->%s' % (module_name, func_name)

Categories

Resources