Completed
Push — pulsed_with_queued_connections ( b02de1...6b1460 )
by
unknown
03:27
created

Qudi.exit()   A

Complexity

Conditions 1

Size

Total Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
# -*- coding: utf-8 -*-
2
"""
3
Jupyter notebook kernel executable file for Qudi.
4
5
Qudi is free software: you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation, either version 3 of the License, or
8
(at your option) any later version.
9
10
Qudi is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
GNU General Public License for more details.
14
15
You should have received a copy of the GNU General Public License
16
along with Qudi. If not, see <http://www.gnu.org/licenses/>.
17
18
Copyright (c) the Qudi Developers. See the COPYRIGHT.txt file at the
19
top-level directory of this distribution and at <https://github.com/Ulm-IQO/qudi/>
20
"""
21
22
import os
23
import sys
24
import rpyc
25
import json
26
import logging
27
import signal
28
import atexit
29
import shutil
30
import tempfile
31
32
from parentpoller import ParentPollerUnix, ParentPollerWindows
33
34
rpyc.core.protocol.DEFAULT_CONFIG['allow_pickle'] = True
35
36
class Qudi:
37
38
    def __init__(self):
39
        self.host = 'localhost'
40
        self.port = 12345
41
        self.conn_config = {'allow_all_attrs': True}
42
        self.parent_handle = int(os.environ.get('JPY_PARENT_PID') or 0)
43
        self.interrupt = int(os.environ.get('JPY_INTERRUPT_EVENT') or 0)
44
        self.kernelid = None
45
46
    def connect(self, **kwargs):
47
        self.connection = rpyc.connect(self.host, self.port, config=self.conn_config)
48
49
    def getModule(self, name):
50
        return self.connection.root.getModule(name)
51
52
    def startKernel(self, connfile):
53
        m = self.getModule('kernellogic')
54
        config = json.loads("".join(open(connfile).readlines()))
55
        self.kernelid = m.startKernel(config, self)
56
        logging.info('Kernel up: {}'.format(self.kernelid))
57
58
    def stopKernel(self):
59
        logging.info('Shutting down: {}'.format(self.kernelid))
60
        sys.stdout.flush()
61
        m = self.getModule('kernellogic')
62
        if self.kernelid is not None:
63
            m.stopKernel(self.kernelid)
64
            logging.info('Down!')
65
            sys.stdout.flush()
66
67
    def initSignal(self):
68
        signal.signal(signal.SIGINT, signal.SIG_IGN)
69
70
    def initPoller(self):
71
        if sys.platform == 'win32':
72
            if self.interrupt or self.parent_handle:
73
                self.poller = ParentPollerWindows(self.interrupt, self.parent_handle)
74
        elif self.parent_handle:
75
            self.poller = ParentPollerUnix()
76
77
    def exit(self):
78
        sys.exit()
79
80
81
def install_kernel():
82
        from jupyter_client.kernelspec import KernelSpecManager
83
        logging.info('Installing Qudi kernel.')
84
85
        try:
86
            # prepare temporary kernelspec folder
87
            tempdir = tempfile.mkdtemp(suffix='_kernels')
88
            path = os.path.join(tempdir, 'qudi')
89
            resourcepath = os.path.join(path, 'resources')
90
            kernelpath = os.path.abspath(__file__)
91
            os.mkdir(path)
92
            os.mkdir(resourcepath)
93
94
            kernel_dict = {
95
                'argv': [sys.executable, kernelpath, '{connection_file}'],
96
                'display_name': 'Qudi',
97
                'language': 'python',
98
                }
99
            # write the kernelspe file
100
            with open(os.path.join(path, 'kernel.json'), 'w') as f:
101
                json.dump(kernel_dict, f, indent=1)
102
103
            # copy logo
104
            logopath = os.path.abspath(os.path.join(os.path.dirname(kernelpath), '..', 'artwork', 'logo'))
105
            shutil.copy(os.path.join(logopath, 'logo-qudi-32x32.png'), os.path.join(resourcepath, 'logo-32x32.png'))
106
            shutil.copy(os.path.join(logopath, 'logo-qudi-32x32.png'), os.path.join(resourcepath, 'logo-32x32.png'))
107
108
            # install kernelspec folder
109
            kernel_spec_manager = KernelSpecManager()
110
            dest = kernel_spec_manager.install_kernel_spec(path, kernel_name='qudi', user=True)
111
            logging.info('Installed kernelspec qudi in {}'.format(dest))
112
        except OSError as e:
113
            if e.errno == errno.EACCES:
114
                print(e, file=sys.stderr)
115
                sys.exit(1)
116
        finally:
117
            if os.path.isdir(tempdir):
118
                shutil.rmtree(tempdir)
119
120
121
if __name__ == '__main__':
122
    logging.basicConfig(
123
        level=logging.INFO,
124
        format="[%(levelname)1.1s %(asctime)s.%(msecs).03d %(name)s] %(message)s"
125
        )
126
    if len(sys.argv) > 1:
127
        if sys.argv[1] == 'install':
128
            install_kernel()
129
        else:
130
            q = Qudi()
131
            q.initSignal()
132
            q.initPoller()
133
            q.connect()
134
            q.startKernel(sys.argv[1])
135
            atexit.register(q.stopKernel)
136
            logging.info('Sleeping.')
137
            q.poller.run()
138
            logging.info('Quitting.')
139
            sys.stdout.flush()
140
    else:
141
        print('qudikernel usage is {0} <connectionfile> or {0} install'.format(sys.argv[0]), file=sys.stderr)
142