Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
03028ce
Added dependency on xarray module
ElMartes Jun 24, 2020
c28ee84
Move devices module to services package to avoid circular import with…
philsmt Jun 24, 2020
9b283f5
Add metro.init_mp_support to fix missing initialization with spawn me…
philsmt Jul 6, 2020
0a8b661
No longer import metro.services.devices into the metro namespace as a…
philsmt Jul 6, 2020
941fb57
Rename GenericDevice.__ge__ to isSubDevice and simplify the implement…
philsmt Jul 6, 2020
4c1b712
Restructures the initialization routines in the metro module for clea…
ElMartes Jul 9, 2020
65acd17
Change global flag load_GUI
ElMartes Jul 10, 2020
1df2a31
Fix Python version checking and 'die' routine initialization
ElMartes Jul 10, 2020
a39c1b2
Remove obsolete comments
ElMartes Jul 10, 2020
18dae0c
Style adjustments for flake8 and consistence
ElMartes Jul 13, 2020
0b8181e
Restructures the initialization routines in the metro module for clea…
ElMartes Jul 9, 2020
ad98c83
Change global flag load_GUI
ElMartes Jul 10, 2020
602346a
Fix Python version checking and 'die' routine initialization
ElMartes Jul 10, 2020
f4a3091
Remove obsolete comments
ElMartes Jul 10, 2020
1544455
Style adjustments for flake8 and consistence
ElMartes Jul 13, 2020
0db0795
Merge branch 'change_import' of https://github.com/philsmt/metro-sci …
ElMartes Jul 13, 2020
cb6a784
Add source root path of the metro package to the globals
ElMartes Jul 14, 2020
daa6c41
Fix taskbar icon in Windows
ElMartes Apr 9, 2021
cce8554
Fix problem with loading invisible devices from a profile
ElMartes Apr 9, 2021
0ee4f8a
Merge remote-tracking branch 'origin/master' into change_import
ElMartes Nov 25, 2021
68b267b
Revert style changes in __init__ code, fix minor import bug, rename i…
ElMartes Apr 8, 2024
b4dc16c
Fix parallel_operator to account for renaming of initialization routine
ElMartes Apr 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
191 changes: 109 additions & 82 deletions src/metro/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,112 +55,67 @@ def parse_args(prog_name, cli_hook=None):
return cli.parse_known_args()


def init(args, window_title, local_path='~/.metro',
profile_path='~/.metro/profiles'):
import sys
load_GUI = None

if args.core_mode:
def die(msg):
print('Fatal error during initialization: ' + msg)
sys.exit(0)
else:
def die(msg):
if sys.version_info[0] == 2:
import Tkinter # different name in python2
tkinter = Tkinter
else:
import tkinter

root = tkinter.Tk()
root.wm_title(window_title)

frame = tkinter.Frame(borderwidth=5)

label = tkinter.Label(frame, justify=tkinter.LEFT, wraplength=450,
text='Fatal error during '
'initialization:\n\n' + msg)
label.grid(padx=5, pady=5)
def init_core():
global load_GUI
if load_GUI is None:
load_GUI = False # initialize in core mode
elif not load_GUI:
return # already initialized in core mode

button = tkinter.Button(frame, text='Close',
command=lambda: root.quit())
button.grid(pady=5)

frame.grid()
frame.mainloop()
import sys

if not load_GUI:
def die(msg):
print('Fatal error during initialization: ' + msg)
sys.exit(0)
globals().update({'die': die})

if sys.version_info[:2] < (3, 3):
die('Requires python version >= 3.3 (found {0})'.format(
sys.version[:sys.version.find(' ')]
))
globals()['die']('Requires python version >= 3.3 (found {0})'.format(
sys.version[:sys.version.find(' ')]))

try:
import typing # noqa (F401)
import numpy # noqa (F401)
from PyQt5 import QtCore # noqa (F401)

if not args.core_mode:
from PyQt5 import QtGui # noqa (F401)
from PyQt5 import QtWidgets # noqa (F401)
except ImportError as e:
die('An essential dependency ({0}) could not be imported and is '
'probably missing'.format(str(e)[str(e)[:-1].rfind('\'')+1:-1]))
globals()['die']('An essential dependency ({0}) could not be '
'imported and is probably missing'.format(
str(e)[str(e)[:-1].rfind('\'')+1:-1]))

# Populate the metro namespace with a variety of internal modules
# and parts of Qt. In core mode, several of those are simulated by
# constructed module objects to allow the definition of related
# classes without any actual dependency.

import os
import pkg_resources

local_path = os.path.expanduser(local_path)
os.makedirs(local_path, exist_ok=True)

profile_path = os.path.expanduser(profile_path)
os.makedirs(profile_path, exist_ok=True)

globals().update({
'WINDOW_TITLE': window_title,
'LOCAL_PATH': local_path,
'PROFILE_PATH': profile_path,
'resource_exists': pkg_resources.resource_exists,
'resource_filename': pkg_resources.resource_filename,
'die': die
})

globals().update({
'core_mode': args.core_mode,
'kiosk_mode': args.kiosk_mode,

'QtCore': QtCore,
'QObject': QtCore.QObject,
'QSignal': QtCore.pyqtSignal,
'QSlot': QtCore.pyqtSlot,
'QProperty': QtCore.pyqtProperty,
'QTimer': QtCore.QTimer,
'QThread': QtCore.QThread,
'QConsts': QtCore.Qt,
'QConsts': QtCore.Qt
})

if args.core_mode:
if not load_GUI:
class EmptyQtModule:
def __getattr__(self, name):
return QtCore.QObject

QtGui = EmptyQtModule() # noqa
QtWidgets = EmptyQtModule() # noqa
QtUic = EmptyQtModule()

else:
from PyQt5 import uic as QtUic
QtUic = EmptyQtModule() # noqa

globals().update({
'QtGui': QtGui,
'QtWidgets': QtWidgets,
'QtUic': QtUic
})
globals().update({
'QtGui': QtGui,
'QtWidgets': QtWidgets,
'QtUic': QtUic
})

from .services import channels
globals().update({
Expand Down Expand Up @@ -226,28 +181,100 @@ def __getattr__(self, name):
})


def init_mp_support():
def init_gui():
global load_GUI
if load_GUI is None:
load_GUI = True # initialize GUI modules
elif load_GUI:
return # already initialized GUI modules

import sys

def die(msg):
if sys.version_info[0] == 2:
import Tkinter # different name in python2
tkinter = Tkinter
else:
import tkinter

root = tkinter.Tk()
try:
window_title = globals()['WINDOW_TITLE']
except KeyError:
window_title = 'Metro'
root.wm_title(window_title)

frame = tkinter.Frame(borderwidth=5)

label = tkinter.Label(frame, justify=tkinter.LEFT, wraplength=450,
text='Fatal error during '
'initialization:\n\n' + msg)
label.grid(padx=5, pady=5)

button = tkinter.Button(frame, text='Close',
command=lambda: root.quit())
button.grid(pady=5)

frame.grid()
frame.mainloop()

sys.exit(0)

try:
core_mode
except NameError:
pass
else:
return
from PyQt5 import QtGui # noqa (F401)
from PyQt5 import QtWidgets # noqa (F401)
from PyQt5 import uic as QtUic
except ImportError as e:
die('An essential dependency ({0}) could not be imported and is '
'probably missing'.format(str(e)[str(e)[:-1].rfind('\'')+1:-1]))

globals().update({
'QtGui': QtGui,
'QtWidgets': QtWidgets,
'QtUic': QtUic,
'die': die
})


class _Args:
core_mode = False
kiosk_mode = False
def init(core_mode=False, kiosk_mode=False, window_title='Metro',
local_path='~/.metro', profile_path='~/.metro/profiles'):
import os
import pkg_resources

init(_Args, 'Metro')
src_path = os.path.dirname(os.path.realpath(__file__))

local_path = os.path.expanduser(local_path)
os.makedirs(local_path, exist_ok=True)

profile_path = os.path.expanduser(profile_path)
os.makedirs(profile_path, exist_ok=True)

globals().update({
'WINDOW_TITLE': window_title,
'SRC_ROOT': src_path,
'LOCAL_PATH': local_path,
'PROFILE_PATH': profile_path,
'resource_exists': pkg_resources.resource_exists,
'resource_filename': pkg_resources.resource_filename,
'core_mode': core_mode,
'kiosk_mode': kiosk_mode
})

# Initialize GUI modules if not in core mode
if not core_mode:
init_gui()

# Initialize the core modules
init_core()


def start(prog_name='metro', window_title='Metro', cli_hook=None):
args, argv_left = parse_args(prog_name, cli_hook=cli_hook)
init(args, window_title)
init(args.core_mode, args.kiosk_mode, window_title)

from .frontend import application

if core_mode: # noqa
if args.core_mode:
app_class = application.CoreApplication
else:
app_class = application.GuiApplication
Expand Down
3 changes: 1 addition & 2 deletions src/metro/devices/abstract/parallel_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@
import traceback

import metro
metro.init_mp_support()

metro.init() # reinitialization necessary for multiprocessing

_targets = {}
Target = collections.namedtuple('Target', ['name', 'process', 'active',
Expand Down
11 changes: 11 additions & 0 deletions src/metro/frontend/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ def _bootstrap(self, args, version=None, version_short=None):
# a PyQt5 application in this case.
sys.excepthook = _on_exception

# Set AppUserModelID for Windows 7 and later so that Metro uses
# its assigned taskbar icon instead of grabbing the one with the
# same AppUserModelID (would probably result in no icon at all)
if os.name == 'nt':
try:
myappid = u"{}.{}".format(metro.SRC_ROOT, metro.WINDOW_TITLE)
from ctypes import windll
windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
except AttributeError:
pass

metro.app = self
metro.experimental = args.experimental

Expand Down
2 changes: 2 additions & 0 deletions src/metro/services/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,8 @@ def _prepare(self, name, parent, args, state, entry_point):
if isinstance(self, QtCore.QObject):
self.destroyed.connect(_on_device_destroyed)

# for correct/full initialization set as visible first
self.setVisible(True)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What specific problem does this solve? It seems not ideal to potentially pop up a window briefly, just to hide it immediately.

if 'visible' in state:
self.setVisible(state['visible'])

Expand Down