I have a Django 3 application, using an LDAP service class, like this :
class LDAPService:
def init(self, host: str, user: str, password: str, ssl: bool = True):
...
def bind(): # The connection is done here, __init__ just sets values
....
def create_ou(base: str, ou_name: str):
....
Where (or when) should I initialize the service to use it in views ? The bind step takes about 2 seconds to apply, I can not do it on every request. How can I keep an instance of this class shared, and not done every single time ? I may have a solution using singleton, and/or initializing it in like settings files, but i think there is a better way to do it.
I know in production, there may be multiple workers, so multiple instances, but i am ok with it.
Another question: How can everything above be done, with connections credentials from a database model (so not at django startup, but at anytime)
I am totally new to the django ecosystem, the things i have found about a service layer were all about django models. I want to do the same interface i would do for models in a regular service layer, but working on something else than django models.
I think the LDAP connection itself should not be there, only the CRUD methods, but i do not know where to place it, and how to make django interact with.
Thanks in advance for your suggestions :)
You can use a memoized factory function:
def get_ldap_service() -> LDAPService:
if not hasattr(get_ldap_service, 'instance'):
get_ldap_service.instance = LDAPService(**input_from_somewhere)
return get_ldap_service.instance
This is cleaner than a Singleton and allows for easier testability of the service class.
Additionally, it might be a better design to send the low-level connection logic to another class, say
class LDAPConnection:
def __init__(self, host: str, user: str, password: str, ssl: bool = True):
...
and then your service layer would take that as a dependency at run-time (dependency injection)
class LDAPService:
def __init__(self, connection: LDAPConnection):
self.connection = connection
# CRUD operations
def create_ou(self, base: str, ou_name: str):
# Do operations via self.connection
...
This allows for different connections exposing the same interface.
You can build from these two ideas (dependency injection and caching) to get more complicated general structures in a maintainable way.
Related
Is it possible to nest an arbitrary number Singleton classes within a Singleton class in Python?
There's no problem in changing my approach to solving this issue if a simpler alternative exists. I am just using the "tools in my toolset", if you will. I'm simulating some larger processes so bear with me if it seems a bit far-fetched.
An arbitrary number of gRPC servers can be started up and each server will be listening on a different port. So for a client to communicate with these servers, separate channels and thus separate stubs will need to be created for a client to communicate to a given server.
You could just create a new channel and a new stub every time a client needs to make a request to a server, but I am trying to incorporate some best practices and reuse the channels and stubs. My idea is to create a Singleton class that is comprised of Singleton subclasses that house a channel and stub pair as instance attributes. I would have to build the enclosing class in a way that allows me to add additional subclasses whenever needed, but I have never seen this type of thing done before.
The advantage to this approach is that any module that instantiates the main Singleton class will have access to the existing state of the channel and stub pairs, without having to recreate anything.
I should note that I already initialize channels and stubs from within Singleton classes and can reuse them with no problem. But the main goal here is to create a data structure that allows me to reuse/share a variable amount of gRPC channel and stub pairs.
The following is code for reusing the gRPC Channel object; the stubs are built in a very similar way, only difference is they accept the channel as an arguement.
class gRPCChannel(object):
_instance, _channel = None, None
port: int = 50051
def __new__(cls):
"""Subsequent calls to instance() return the singleton without repeating the initialization step"""
if cls._instance is None:
cls._instance = super(gRPCChannel, cls).__new__(cls)
# The following is any initialization that needs to happen for the channel object
cls._channel = grpc.insecure_channel(f'localhost:{cls.port}', options=(('grpc.enable_http_proxy', 0),))
return cls._channel
def __exit__(self, cls):
cls._channel.close()
I think this is simpler than the "singleton pattern":
# grpc.py
import functools as ft
class GrpcChannel:
pass # normal class, no funny __new__ overload business
#ft.lru_cache
def channel():
return GrpcChannel()
Usage:
import grpc
channel = grpc.channel()
assert grpc.channel() is channel
If you really want it all namespaced under the class (IMO no reason to, takes more typing & syntax for no extra benefit), then:
class GrpcChannel:
#classmethod
#ft.lru_cache
def instance(cls):
return cls()
# usage
assert grpc.GrpcChannel.instance() is grpc.GrpcChannel.instance()
I would like to create a single "interface" class (in interface.py) through which I can access an underlying class's functionality, where the class accessed is dependent on a xml config_file setting.
Taking connection via ssh, or ftp as an example.
I'd have a variable set in my config file such as
"INTERFACE": "ssh"
Then I'd expect to have code that looks something like this:
# file = interface.py
class Interface(?)
def connect(self, *args, **kwargs):
return self
# file = ssh.py
class SSH(?)
def connect(self, *args, **kwargs):
# Setup a connection
connection = paramiko.SSHClient()
return connection
#file = ftp.py
class FTP(?)
def connect(self, *args, **kwargs):
# Setup a connection
return connection
# And in my calling code I would just like a generic call e.g.
from path.interface import Interface
foo = Interface()
foo.connect(bar) # Where "INTERFACE" : "ssh"
Then the SSH class would (override?) execute its code defined in its version of connect().
If I then change the config setting to config.INTERFACE = "ftp", the same call would "find its way" to the ftp class to establish an ftp connection.
Ideally I'd be able to flip between the different version of connect() with my code, simply by setting:
config.INTERFACE = "ssh"
config.INTERFACE = "ftp"
I assume this isn't some unachievable thing? I don't even know what to google to find out how to do this! Is this overriding?
Any advice would be gratefully received.
Just a topic to google would be a starting point. :)
A standard pattern of doing this is something like this:
from abc import abstractmethod, ABCMeta
class Interface(metaclass=ABCMeta):
#abstractmethod
def upload(self):
raise NotImplementedError('Must implement upload in subclasses')
class SSH(Interface):
def upload(self):
# ssh implementation
class FTP(Interface):
def upload(self):
# ftp implementation
def InterfaceForConfigurationValue(interface_value):
if interface_value == 'ssh':
return SSH()
if interface_value == 'ftp':
return FTP()
raise NotImplementedError('Interface not available for value %s' % (
interface_value,))
Interface is the abstract base class defining the interface you want to use. Useless on its own, it needs concrete subclasses to implement it.
Note that for this to be a useful abstraction and worth the effort, you want to make this more tailored to you applications and provide higher level APIs, such as upload() or get(), or else it's a bit pointless, and you may find it's hard to generalize to different protocols.
SSH and FTP both override the upload() method of their superclass (Interface) and so you can call upload() on your Interface instance without worrying about which particular subclass it is.
InterfaceForConfigurationValue is a factory function that gives you the correct interface subclass based on the configuration option.
In general the most important thing is to ensure that nothing about Interface, SSH or FTP knows or cares what is in the config file, because you may wish to use them elsewhere with a different config system. They just know what they need to do. You add a factory function which is small and contains the knowledge of how to translate your config into a subclass.
Note: your factory function doesn't have to be a global function. Often you'll find there are lots of similar bits of linking you need to do between your config system and your code, so you may want to use a class and have the factory as a method on the class. A subclass of ConfigParser is often a good option.
I need some help in terms of 'pythonic' way of handling a specific scenario.
I'm writing an Ssh class (wraps paramiko) that provides the capability to connect to and executes commands on a device under test (DUT) over ssh.
class Ssh:
def connect(some_params):
# establishes connection
def execute_command(command):
# executes command and returns response
def disconnect(some_params):
# closes connection
Next, I'd like to create a Dut class that represents my device under test. It has other things, besides capability to execute commands on the device over ssh. It exposes a wrapper for command execution that internally invokes the Ssh's execute_command. The Ssh may change to something else in future - hence the wrapper.
def Dut:
def __init__(some params):
self.ssh = Ssh(blah blah)
def execute_command(command)
return self.ssh.execute_command(command)
Next, the device supports a custom command line interface for device under test. So, a class that accepts a DUT object as an input and exposes a method to execute the customised command.
def CustomCli:
def __init__(dut_object):
self.dut = dut_object
def _customize(command):
# return customised command
def execute_custom_command(command):
return self.dut.execute_command(_customize(command))
Each of the classes can be used independently (CustomCli would need a Dut object though).
Now, to simplify things for user, I'd like to expose a wrapper for CustomCli in the Dut class. This'll allow the creator of the Dut class to exeute a simple or custom command.
So, I modify the Dut class as below:
def Dut:
def __init__(some params):
self.ssh = Ssh(blah blah)
self.custom_cli = Custom_cli(self) ;# how to avoid this circular reference in a pythonic way?
def execute_command(command)
return self.ssh.execute_command(command)
def execute_custom_command(command)
return self.custom_cli.execute_custom_command(command)
This will work, I suppose. But, in the process I've created a circular reference - Dut is pointing to CustomCli and CustomCli has a reference to it's creator Dut instance. This doesn't seem to be the correct design.
What's the best/pythonic way to deal with this?
Any help would be appreciated!
Regards
Sharad
In general, circular references aren't a bad thing. Many programs will have them, and people just don't notice because there's another instance in-between like A->B->C->A. Python's garbage collector will properly take care of such constructs.
You can make circular references a bit easier on your conscience by using weak references. See the weakref module. This won't work in your case, however.
If you want to get rid of the circular reference, there are two way:
Have CustomCLI inherit from Dut, so you end up with just one instance. You might want to read up on Mixins.
class CLIMerger(Dut):
def execute_custom_command(command):
return self.execute_command(_customize(command))
# use self^ instead of self.dut
class CLIMixin(object):
# inherit from object, won't work on its own
def execute_custom_command(command):
return self.execute_command(_customize(command))
# use self^ instead of self.dut
class CLIDut(Dut, CLIMixin):
# now the mixin "works", but still could enhance other Duts the same way
pass
The Mixin is advantageous if you need several cases of merging a CLI and Dut.
Have an explicit interface class that combines CustomCli and Dut.
class DutCLI(object):
def __init__(self, *bla, **blah):
self.dut = Dut(*bla, **blah)
self.cli = CustomCLI(self.dut)
This requires you to write boilerplate or magic to forward every call from DutCLI to either dut or cli.
I'm building an application and one of the packages manage multiple auth methods.
Now it supports LDAP and PAM but I want in the future it supports a few more.
I have a package with
PAM.py and
LDAP.py
for example PAM.py contents:
import pam
class pam_auth:
def __init__(self, username=None, password=None):
self.username=username
self.password=password
def login(self):
res_auth=pam.authenticate(username=self.username, password=password)
return res_auth
and in another package I have the next class Login:
class Login:
def __init__(self,method=None):
self.authmethod=method
def login(self):
res_login=self.authmethod.login()
return res_login
Now i'm building my auth code like:
p=pam_auth()
p.username="pep"
p.password="just"
l=Login(method=p)
print l.login
And I believe that it is not the best way to do it, and thinking in multiples and different methods to auth.
For Example may be something like?:
l=Login(method=PAM.pam_auth)
l.username="pep"
l.password="just"
print l.login()
¿What is that I must change in Login Class or PAM class to work in this way?
For the change you mentioned, all you need to do is to instanciate the class inside Login's __init__:
class Login:
def __init__(self,method):
self.authmethod=method()
However, as Stefano Sanfilippo mentioned, this may actually hamper modularity, since suddenly Login must know the constructor parameters of the authentication method.
A couple more tips:
If you're writing python 2, you'll want to create new-style classes:
instead of
class Login:
use
class Login(object):
Also, if you're writing a general authentication layer, you probably don't want to deal explicitly with usernames and passwords: what will happen when you want to use third-factor, smartcard or biometric authentication in the future? You probably should deal with opaque "data", that the authentication method receives, unaltered.
In the code below the User class needs to access a function get_user inside an instance of WebService class, as that contains other functions required for authentication with the web server (last.fm). Actual code is here.
class WebService:
def __init__(self, key):
self.apikey = key
def get_user(self, name):
pass # Omitted
class User:
def __init__(self, name, webservice):
self.name = name
self.ws = webservice
def fill_profile(self):
data = self.ws.GetUser(self.name)
# Omitted
The problem is that a reference needs to be held inside every ´User´. Is there another way of doing this? Or is it just me overcomplicating things, and this is how it actually works in the real world?
As requested:
As to handling things like get_top_albums and get_friends, that depends on how you want to model the system. If you don't want to cache the data locally, I'd say just call the service each time with a user ID. If you do want to cache the data locally, you could pass a User object to the method in WebService, then have the method populate the members of the User. You do have to make a design decision though to either have a WebService and a User (what would probably be best), or just a UserWebService.
You can certainly make the reference a static variable, if the web service object is the same for all users.
The syntax is:
class User:
webservice = ...
...
You will then even be able to access it from User instances, but not to assign to it that way, that would require User.webservice syntax.
You are also getting good design alternatives suggested in the comments.