Selenium and singleton in Python – part two

Metaclass and Singleton

Introduction

As I promised, we are coming back with the second part of the tutorial related to singleton implementation in Python 3. Here we will cover two different approaches, much easier to understand and more Python-friendly. We will start with Metaclasses and in the last part, we will cover the singleton based on Python decorators.

Singleton and metaclasses

What is a metaclass? It’s actually the class of a class. To make a similarity just think: a class defines how its instance behaves, so a metaclass defines how a class behaves. A class is an instance of a metaclass. In this way, we can create classes of their own type from the predefined Python classes.

Implementation

class MetaClassSingleton(type):
    """
    Meta class implementation
    """
    _instances = {}

    def __call__(cls, *args, **kwargs):
        """
        Override __call__ special method based on singleton pattern
        """
        if cls not in cls._instances:
            cls._instances[cls] = super(MetaClassSingleton, cls).__call__(*args, **kwargs)

        return cls._instances[cls]


class Driver(metaclass=MetaClassSingleton):
    """
    Driver class decorated by the meta class: MetaClassSingleton.
    Behaviour changed in singleton
    """
    connection = None

    def connect(self):
        """
        Set the connection with the web driver
        :return: web driver
        """
        if self.connection is None:
            self.connection = webdriver.Chrome()

        return self.connection

Usage

# When we want to perform different interaction with a view, the driver class can be instantiated
# for multiple times, but only one object is created
dr1 = Driver().connect()
dr2 = Driver().connect()
print('Web driver object 1 ', dr1)
print('Web driver object 2', dr2)

Singleton based on ‘decorators’

A short intro about decorators and their usage. Actually, a decorator is the Python approach to change the behavior of a method. To do this, you just have to add an annotation before the definition of the method. The actual annotation for providing a singleton could be done by implementing first the decorator and afterward to integrate it. Below using the first function:  my_singleton we’ve implemented the singleton decorator so it could be used by the class MyDriver The good part is that in Python you don’t even have to do this because there is an already existing package singleton_decorator, so just to use it, like the classDriver.

Implementation

from singleton_decorator import singleton

def my_singleton(*args):
    """

    :param cls: class to be changed as a singleton
    :return: instance of the singleton
    """
    instances = dict()

    def get_instance():
        if args[0] not in instances:
            instances[args[0]] = args[0]()
        # else: #uncomment this part in order to raise a warning related to instantiation
        #     raise UserWarning("An instantiation already exists!")
        return instances[args[0]]

    return get_instance

@my_singleton
class MyDriver:
    @staticmethod
    def get_driver():
        return webdriver.Chrome()

@singleton
class Driver:
    @staticmethod
    def get_driver():
        return webdriver.Chrome()

Usage

For this usage scenario, we’ve implemented a unittest class, where we check if both objects are identical after the instantiation.

class TestDecoratorSingleton(TestCase):
    def test_singleton(self):
        dr1 = Driver()
        dr1.get_driver().get('https://en.wikipedia.org/')
        dr2 = Driver()

        self.assertEqual(dr1, dr2)

    def test_my_singleton(self):
        dr1 = MyDriver()
        dr1.get_driver().get('https://en.wikipedia.org/')
        dr2 = MyDriver()

        self.assertEqual(dr1, dr2)

Conclusion

This is it about singleton implementation, looking back using metaclasses or decorators, it’s for sure the clearest way of defining it, but if you don’t want to spend to much time thinking about it, just use the already existing package: singleton_decorator. It’s also a best practice when developing something new in Python, look behind and maybe someone has already done this before and all you have to do is pip install ...

The source code of this article could be also found here

4 thoughts on “Selenium and singleton in Python – part two

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.