0

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 !

asked Nov 27, 2017 at 18:33
6
  • Can you elaborate a bit more? Where is the problem? Commented Nov 27, 2017 at 18:36
  • Why are you retrieving the class like that? Shouldn't the client pass in an instance of their subclass? Commented Nov 27, 2017 at 18:37
  • @James There is no problem per se, cause everything work in the current state. I just want to know if there is a better way to do this. Commented Nov 27, 2017 at 19:25
  • @Blorgbeard They could, but I'd rather not have dependency injection if it's avoidable. A simple subclassing should be enough, and my library would do the legwork Commented Nov 27, 2017 at 19:28
  • I wouldn't call myself fluent in python, but I would consider this API quite surprising. I'd expect at least to pass the class to the library rather than have it detect it. What if I have a couple of different implementations for different scenarios? Commented Nov 27, 2017 at 19:32

1 Answer 1

1

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.

answered Dec 4, 2017 at 22:31
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.