Python - Abstract class subclassing - python

I'm trying to find the best for users of my python library to implement an abstract class I wrote.
Namely, my abstract class define an API to access specific values stored in a database, but I would like to let the user choose how to store it (simple text file, json, sqlite, etc.)
My problem is, how should I retrieve the class the user create and use it in my library ?
This is the solution I came up with, but I don't find it very graceful and wonder if there is a more pythonic way.
In my library:
from abc import ABC, abstractmethod
class Database(ABC):
#abstractmethod
def get(self, index):
pass
#abstractmethod
def insert(self, data):
pass
def get_database():
"""call this anywhere I need a concrete database class"""
return Database.__subclasses__()[-1]
In the user code
class SqliteDatabase(Database):
def get(self, index):
# sqlite SELECT and such
return data
def insert(self, data):
# sqlite INSERT INTO
# return data with index provided
return data
Of course, I will return a better error than IndexError if there is no subclass defined, but you get the idea.
Thank you in advance !

I finally settled for something else, as Blorgbeard suggested
_databases = {}
def register(dbname="default"):
def wrapper(klass):
_databases[dbname] = klass
return klass
return wrapper
def get_db(name="default"):
return _databases[name]
And the user only needs to declare
#register()
class SqliteDatabase:
def __get__(self, index):
# retrieve data
if data is None:
raise KeyError(index)
return data
This way, anybody can declare as many as databases as they want.
If you have improvements over this version, I'll gladly take them.

Related

Can #property be used to return a value if it exists, but to set the value if it does not yet exist?

I want to have a class that is used just for accessing read-only data. If the data is requested from the class but does not exist yet, I want the class to handle getting the data. I'm just wondering if the following code makes sense; can you see any potential issues with this?
class Data:
#property
def some_data(self):
if hasattr(Data, "_some_data"):
return Data._some_data
else:
Data._some_data = function_that_gets_data()
return Data._some_data
# other definitions for more data go here ...
D = Data()
# access data
print(D.some_data)
I'm doing basically this exact thing in my code base and it's been working great for me, it's been a great way of caching information.
class ItemBase(BaseClass):
_soup = None
#property
def soup(self):
if not self._soup:
self._soup = get_info()
return self._soup

Recurring code in Django views: how to avoid repetition?

For many - but not all - of my views I have to do some validation to make sure the user that is logged in has access to the object they are trying to access. For 30+ views I have this code:
def whatever_view_name(request, id, access_id):
check = Access.objects.filter(user=request.user, id=access_id)
if check:
access_object = check[0]
else:
return redirect(reverse("create_new_access_object"))
.... and now my view-specific code will follow ...
So I need to check if a particular database record (Access) exists for this particular user. This code is repeated a lot, which does not seem to be right. I've been thinking about using middleware, but there are two problems: a) I need to use this object in the view (see variable access_object so I fear I'd have to query it twice if I put it in the middleware), and b) I don't need to do this ALWAYS so I wonder how to only run it for some views and not all if this is middleware.
Any thoughts?
You can write a decorator for this:
from functools import wraps
def check_access(function):
#wraps(function)
def wrap(request, id, access_id, *args, **kwargs):
check = Access.objects.filter(user=request.user, id=access_id)
if check.exists():
return function(request, id, access_id, *args, **kwargs)
else:
return redirect(reverse("create_new_access_object"))
return wrap
# usage
#check_access
def whatever_view_name(request, id, access_id):
return ...
One way that I can think of is using inheritance. We can refactor out the common stuff into a super view class and then extend the same in child view classes.
Something like this :
We can have a super class like this
class AccessVerifiedView(View):
def get(self, request, *args, **kwargs):
check = Access.objects.filter(user=request.user, id=kwargs["access_id"])
if check:
access_object = check[0]
self.verified_get(access_object)
else:
return redirect(reverse("create_new_access_object"))
def verified_get(self, access_object):
raise NotImplementedError
Then we can extend that class and the use in our views.
class MyView(AccessVerifiedView):
def verified_get(self, access_object):
return access_object
This approach see bit more readable. Anyone seeing the code can see the super class and understand the code flow.
Other few ways to do it is
Decorator : We can have a decorator which will do the same thing. And then we can decorate the view which we want to verify.

Python, how to instantiate classes from a class stored in a database?

I'm using Django and want to be able to store classes in a database for things like forms and models so that I can easily make them creatable through a user interface since they are just stored in the database as opposed to a regular file. I don't really know a whole lot about this and am not sure if this is a situation where I need to use exec in python or if there is some other way. My searches on this aren't turning up much of anything.
Basically, it would just be where I do a database call and get the contents of a class, then I want to instantiate it. Any advice is appreciated on how to best do this sort of thing.
EDIT: In response to the idea of a malicious __init__ in the class, these are only for things like forms or models where it is tightly controlled through validation what goes in the class, there would never be an __init__ in the class and it would be basically impossible, since I would validate everything server side, to put anything malicious in the class.
Do not store code in the database!!!
Imagine a class with a malicious __init__ method finding it's way in your "class repository" in the database. This means whoever has write access to those database tables has the ability to read any file from your web server and even nuke it's file system, since they have the ability to execute any python code on it.
Don't store the class itself, store the import path as a string in the database (e.g. 'django.forms.CharField')
I started doing this same thing for another project, and saved off the code in my local repository. To address the security concerns I was going to add an argument to the field constructor of allowed base classes. If you do implement this, let me know, I'd love to have it.
helpers.py
def get_class_from_concrete_classpath(class_path):
# Unicode will throw errors in the __import__ (at least in 2.6)
class_path = str(class_path)
mod_list = class_path.split('.')
module_path = '.'.join(mod_list[:-1])
class_name = mod_list[-1]
base_mod = __import__(module_path, fromlist=[class_name,])
return getattr(base_mod, class_name)
def get_concrete_name_of_class(klass):
"""Given a class return the concrete name of the class.
klass - The reference to the class we're interested in.
Raises a `TypeError` if klass is not a class.
"""
if not isinstance(klass, (type, ClassType)):
raise TypeError('The klass argument must be a class. Got type %s; %s' %
(type(klass), klass))
return '%s.%s' % (klass.__module__, klass.__name__)
fields.py
class ClassFormField(forms.Field):
def to_python(self, value):
return get_concrete_name_of_class(value)
class ClassField(models.CharField):
__metaclass__ = models.SubfieldBase
"""Field used for storing a class as a string for later retrieval"""
MAX_LENGTH = 255
default_error_messages = {
'invalid': _(u'Enter a valid class variable.'),
}
def __init__(self, *args, **kwargs):
kwargs['max_length'] = kwargs.get('max_length', ClassField.MAX_LENGTH)
super(ClassField, self).__init__(*args, **kwargs)
def get_prep_value(self, value):
if isinstance(value, (basestring, NoneType)):
return value
return get_concrete_name_of_class(value)
def to_python(self, value):
if isinstance(value, basestring):
return get_class_from_concrete_classpath(value)
return value
def formfield(self, **kwargs):
defaults = {'form_class' : ClassFormField}
defaults.update(kwargs)
return super(ClassField, self).formfield(**defaults)

Polymorphism or Inheritance or any other suggestion?

I trying my hands on python. I am trying to implement a crypto class which does enc/dec . In my crypto class i require user to pass 3 args to do the enc dec operations. Till now i was reading key from file and doing the operations. Now i want to provide a generate key function also. But problem is that to call generate keys i dont want user to provide any arguments while initiating the class.
So what essentially i am trying to achieve is that when the crypto class is instantiated without giving any arguments, i just want to expose generate_key function. and when all the 3 args are provided while instantiating class, I want to expose all other enc/dec functions but not key gen function.
I am not able to understand is it a polymorphism situation, or inheritance or should i just use 2 different classes one having generate keys and other for enc dec functions..
Please give me some suggestion about how can i handle this situation efficiently?
Example:
class crypto:
def __init__(self,id, val1):
self._id = id
self._val1 = val1
def encrypt(self):
""" encryption here """
def save(self):
""" save to file """
def load(self):
""" load from file"""
def decrypt(self):
""" decryption here"""
def gen_keys(self):
""" gen key here"""
So Now, when this crypto class is instantiate with no arguments, i just want to expose gen keys function. and if it is instantiated with the id and val1, then i want to expose all functions but not gen keys.
I hope this will provide some clarification about my question. Please suggest me how can i achieve this.
Thanks,
Jon
You want a factory with either inherited or duck-typed objects. For example:
class CryptoBasic(object):
def __init__(self, *args):
"""Do what you need to do."""
def basic_method(self, *args):
"""Do some basic method."""
class CryptoExtended(CryptoBasic):
def __init__(self, *args):
"""Do what you need to do."""
def extended_method(self, *args):
"""Do more."""
# This is the factory method
def create_crypto(req_arg, opt_arg=None):
if opt_arg:
return CryptoExtended(req_arg, opt_arg)
else:
return CryptoBasic(req_arg)

Python decorators and class inheritance

I'm trying to use decorators in order to manage the way users may or may not access resources within a web application (running on Google App Engine). Please note that I'm not allowing users to log in with their Google accounts, so setting specific access rights to specific routes within app.yaml is not an option.
I used the following resources :
- Bruce Eckel's guide to decorators
- SO : get-class-in-python-decorator2
- SO : python-decorators-and-inheritance
- SO : get-class-in-python-decorator
However I'm still a bit confused...
Here's my code ! In the following example, current_user is a #property method which belong to the RequestHandler class. It returns a User(db.model) object stored in the datastore, with a level IntProperty().
class FoobarController(RequestHandler):
# Access decorator
def requiredLevel(required_level):
def wrap(func):
def f(self, *args):
if self.current_user.level >= required_level:
func(self, *args)
else:
raise Exception('Insufficient level to access this resource')
return f
return wrap
#requiredLevel(100)
def get(self, someparameters):
#do stuff here...
#requiredLevel(200)
def post(self):
#do something else here...
However, my application uses different controllers for different kind of resources. In order to use the #requiredLevel decorator within all subclasses, I need to move it to the parent class (RequestHandler) :
class RequestHandler(webapp.RequestHandler):
#Access decorator
def requiredLevel(required_level):
#See code above
My idea is to access the decorator in all controller subclasses using the following code :
class FoobarController(RequestHandler):
#RequestHandler.requiredLevel(100)
def get(self):
#do stuff here...
I think I just reached the limit of my knowledge about decorators and class inheritance :). Any thoughts ?
Your original code, with two small tweaks, should also work. A class-based approach seems rather heavy-weight for such a simple decorator:
class RequestHandler(webapp.RequestHandler):
# The decorator is now a class method.
#classmethod # Note the 'klass' argument, similar to 'self' on an instance method
def requiredLevel(klass, required_level):
def wrap(func):
def f(self, *args):
if self.current_user.level >= required_level:
func(self, *args)
else:
raise Exception('Insufficient level to access this resource')
return f
return wrap
class FoobarController(RequestHandler):
#RequestHandler.requiredLevel(100)
def get(self, someparameters):
#do stuff here...
#RequestHandler.requiredLevel(200)
def post(self):
#do something else here...
Alternately, you could use a #staticmethod instead:
class RequestHandler(webapp.RequestHandler):
# The decorator is now a static method.
#staticmethod # No default argument required...
def requiredLevel(required_level):
The reason the original code didn't work is that requiredLevel was assumed to be an instance method, which isn't going to be available at class-declaration time (when you were decorating the other methods), nor will it be available from the class object (putting the decorator on your RequestHandler base class is an excellent idea, and the resulting decorator call is nicely self-documenting).
You might be interested to read the documentation about #classmethod and #staticmethod.
Also, a little bit of boilerplate I like to put in my decorators:
#staticmethod
def requiredLevel(required_level):
def wrap(func):
def f(self, *args):
if self.current_user.level >= required_level:
func(self, *args)
else:
raise Exception('Insufficient level to access this resource')
# This will maintain the function name and documentation of the wrapped function.
# Very helpful when debugging or checking the docs from the python shell:
wrap.__doc__ = f.__doc__
wrap.__name__ = f.__name__
return f
return wrap
After digging through StackOverflow, and carefully reading Bruce Eckel's guide to decorators, I think I found a possible solution.
It involves implementing the decorator as a class in the Parent class :
class RequestHandler(webapp.RequestHandler):
# Decorator class :
class requiredLevel(object):
def __init__(self, required_level):
self.required_level = required_level
def __call__(self, f):
def wrapped_f(*f_args):
if f_args[0].current_user.level >= self.required_level:
return f(*f_args)
else:
raise Exception('User has insufficient level to access this resource')
return wrapped_f
This does the work ! Using f_args[0] seems a bit dirty to me, I'll edit this answer if I find something prettier.
Then you can decorate methods in subclasses the following way :
FooController(RequestHandler):
#RequestHandler.requiredLevel(100)
def get(self, id):
# Do something here
#RequestHandler.requiredLevel(250)
def post(self)
# Do some stuff here
BarController(RequestHandler):
#RequestHandler.requiredLevel(500)
def get(self, id):
# Do something here
Feel free to comment or propose an enhancement.

Categories

Resources