SingleInstance   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 64
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 64
rs 10
wmc 12

2 Methods

Rating   Name   Duplication   Size   Complexity  
B __del__() 0 18 6
B __init__() 0 31 6
1
#! /usr/bin/env python
2
3
import sys
4
import os
5
import tempfile
6
7
8
class SingleInstanceException(BaseException):
9
    pass
10
11
12
class SingleInstance:
13
14
    """
15
    If you want to prevent your script from running in parallel just instantiate SingleInstance() class.
16
    If is there another instance already running it will throw a `SingleInstanceException`.
17
    >>> import tendo
18
    ... me = SingleInstance()
19
    This option is very useful if you have scripts executed by crontab at small amounts of time.
20
    Remember that this works by creating a lock file with a filename based on the full path to the script file.
21
    Providing a flavor_id will augment the filename with the provided flavor_id, allowing you to create
22
    multiple singleton instances from the same file. This is particularly useful if you want specific
23
    functions to have their own singleton instances.
24
    """
25
26
    def __init__(self, flavor_id=""):
27
        import sys
28
        self.initialized = False
29
        basename = os.path.splitext(os.path.abspath(sys.argv[0]))[0].replace(
30
            "/", "-").replace(":", "").replace("\\", "-") + '-%s' % flavor_id + '.lock'
31
        # os.path.splitext(os.path.abspath(sys.modules['__main__'].__file__))[0].replace("/", "-").
32
        # replace(":", "").replace("\\", "-") + '-%s' % flavor_id + '.lock'
33
        self.lockfile = os.path.normpath(
34
            tempfile.gettempdir() + '/' + basename)
35
36
        if sys.platform == 'win32':
37
            try:
38
                # file already exists, we try to remove (in case previous
39
                # execution was interrupted)
40
                if os.path.exists(self.lockfile):
41
                    os.unlink(self.lockfile)
42
                self.fd = os.open(
43
                    self.lockfile, os.O_CREAT | os.O_EXCL | os.O_RDWR)
44
            except OSError:
45
                type, e, tb = sys.exc_info()
46
                if e.errno == 13:
47
                    return
48
        else:  # non Windows
49
            import fcntl
50
            self.fp = open(self.lockfile, 'w')
51
            self.fp.flush()
52
            try:
53
                fcntl.lockf(self.fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
54
            except IOError:
55
                return
56
        self.initialized = True
57
58
    def __del__(self):
59
        import sys
60
        import os
61
        if not self.initialized:
62
            return
63
        try:
64
            if sys.platform == 'win32':
65
                if hasattr(self, 'fd'):
66
                    os.close(self.fd)
67
                    os.unlink(self.lockfile)
68
            else:
69
                import fcntl
70
                fcntl.lockf(self.fp, fcntl.LOCK_UN)
71
                # os.close(self.fp)
72
                if os.path.isfile(self.lockfile):
73
                    os.unlink(self.lockfile)
74
        except Exception as e:
75
            raise
76
77
78
def f(name):
79
    # tmp = logger.level
80
    # logger.setLevel(logging.CRITICAL)  # we do not want to see the warning
81
    try:
82
        me2 = SingleInstance(flavor_id=name)  # noqa
83
    except SingleInstanceException:
84
        sys.exit(-1)
85
    # logger.setLevel(tmp)
86
    pass
87