Merge pull request #4032 from Ultimaker/fix_tests_cura_engine_backend

Fix MyPy issues
This commit is contained in:
Ian Paschal 2018-07-10 11:19:18 +02:00 committed by GitHub
commit c36d089113
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 119 additions and 61 deletions

1
Jenkinsfile vendored
View File

@ -1,5 +1,6 @@
parallel_nodes(['linux && cura', 'windows && cura']) { parallel_nodes(['linux && cura', 'windows && cura']) {
timeout(time: 2, unit: "HOURS") { timeout(time: 2, unit: "HOURS") {
// Prepare building // Prepare building
stage('Prepare') { stage('Prepare') {
// Ensure we start with a clean build directory. // Ensure we start with a clean build directory.

View File

@ -21,6 +21,7 @@ from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Settings.Interfaces import DefinitionContainerInterface from UM.Settings.Interfaces import DefinitionContainerInterface
from UM.Settings.SettingInstance import SettingInstance #For typing. from UM.Settings.SettingInstance import SettingInstance #For typing.
from UM.Tool import Tool #For typing. from UM.Tool import Tool #For typing.
from UM.Mesh.MeshData import MeshData #For typing.
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
from cura.Settings.ExtruderManager import ExtruderManager from cura.Settings.ExtruderManager import ExtruderManager
@ -62,15 +63,15 @@ class CuraEngineBackend(QObject, Backend):
if Platform.isLinux() and not default_engine_location: if Platform.isLinux() and not default_engine_location:
if not os.getenv("PATH"): if not os.getenv("PATH"):
raise OSError("There is something wrong with your Linux installation.") raise OSError("There is something wrong with your Linux installation.")
for pathdir in os.getenv("PATH").split(os.pathsep): for pathdir in cast(str, os.getenv("PATH")).split(os.pathsep):
execpath = os.path.join(pathdir, executable_name) execpath = os.path.join(pathdir, executable_name)
if os.path.exists(execpath): if os.path.exists(execpath):
default_engine_location = execpath default_engine_location = execpath
break break
self._application = CuraApplication.getInstance() #type: CuraApplication self._application = CuraApplication.getInstance() #type: CuraApplication
self._multi_build_plate_model = None #type: MultiBuildPlateModel self._multi_build_plate_model = None #type: Optional[MultiBuildPlateModel]
self._machine_error_checker = None #type: MachineErrorChecker self._machine_error_checker = None #type: Optional[MachineErrorChecker]
if not default_engine_location: if not default_engine_location:
raise EnvironmentError("Could not find CuraEngine") raise EnvironmentError("Could not find CuraEngine")
@ -120,7 +121,7 @@ class CuraEngineBackend(QObject, Backend):
self._engine_is_fresh = True #type: bool # Is the newly started engine used before or not? self._engine_is_fresh = True #type: bool # Is the newly started engine used before or not?
self._backend_log_max_lines = 20000 #type: int # Maximum number of lines to buffer self._backend_log_max_lines = 20000 #type: int # Maximum number of lines to buffer
self._error_message = None #type: Message # Pop-up message that shows errors. self._error_message = None #type: Optional[Message] # Pop-up message that shows errors.
self._last_num_objects = defaultdict(int) #type: Dict[int, int] # Count number of objects to see if there is something changed self._last_num_objects = defaultdict(int) #type: Dict[int, int] # Count number of objects to see if there is something changed
self._postponed_scene_change_sources = [] #type: List[SceneNode] # scene change is postponed (by a tool) self._postponed_scene_change_sources = [] #type: List[SceneNode] # scene change is postponed (by a tool)
@ -145,7 +146,9 @@ class CuraEngineBackend(QObject, Backend):
self._multi_build_plate_model = self._application.getMultiBuildPlateModel() self._multi_build_plate_model = self._application.getMultiBuildPlateModel()
self._application.getController().activeViewChanged.connect(self._onActiveViewChanged) self._application.getController().activeViewChanged.connect(self._onActiveViewChanged)
self._multi_build_plate_model.activeBuildPlateChanged.connect(self._onActiveViewChanged)
if self._multi_build_plate_model:
self._multi_build_plate_model.activeBuildPlateChanged.connect(self._onActiveViewChanged)
self._application.globalContainerStackChanged.connect(self._onGlobalStackChanged) self._application.globalContainerStackChanged.connect(self._onGlobalStackChanged)
self._onGlobalStackChanged() self._onGlobalStackChanged()
@ -246,7 +249,7 @@ class CuraEngineBackend(QObject, Backend):
if self._application.getPrintInformation() and build_plate_to_be_sliced == active_build_plate: if self._application.getPrintInformation() and build_plate_to_be_sliced == active_build_plate:
self._application.getPrintInformation().setToZeroPrintInformation(build_plate_to_be_sliced) self._application.getPrintInformation().setToZeroPrintInformation(build_plate_to_be_sliced)
if self._process is None: if self._process is None: # type: ignore
self._createSocket() self._createSocket()
self.stopSlicing() self.stopSlicing()
self._engine_is_fresh = False # Yes we're going to use the engine self._engine_is_fresh = False # Yes we're going to use the engine
@ -284,12 +287,12 @@ class CuraEngineBackend(QObject, Backend):
if self._application.getUseExternalBackend(): if self._application.getUseExternalBackend():
return return
if self._process is not None: if self._process is not None: # type: ignore
Logger.log("d", "Killing engine process") Logger.log("d", "Killing engine process")
try: try:
self._process.terminate() self._process.terminate() # type: ignore
Logger.log("d", "Engine process is killed. Received return code %s", self._process.wait()) Logger.log("d", "Engine process is killed. Received return code %s", self._process.wait()) # type: ignore
self._process = None self._process = None # type: ignore
except Exception as e: # terminating a process that is already terminating causes an exception, silently ignore this. except Exception as e: # terminating a process that is already terminating causes an exception, silently ignore this.
Logger.log("d", "Exception occurred while trying to kill the engine %s", str(e)) Logger.log("d", "Exception occurred while trying to kill the engine %s", str(e))
@ -328,6 +331,9 @@ class CuraEngineBackend(QObject, Backend):
if job.getResult() == StartJobResult.SettingError: if job.getResult() == StartJobResult.SettingError:
if self._application.platformActivity: if self._application.platformActivity:
if not self._global_container_stack:
Logger.log("w", "Global container stack not assigned to CuraEngineBackend!")
return
extruders = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId())) extruders = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId()))
error_keys = [] #type: List[str] error_keys = [] #type: List[str]
for extruder in extruders: for extruder in extruders:
@ -361,6 +367,9 @@ class CuraEngineBackend(QObject, Backend):
if not stack: if not stack:
continue continue
for key in stack.getErrorKeys(): for key in stack.getErrorKeys():
if not self._global_container_stack:
Logger.log("e", "CuraEngineBackend does not have global_container_stack assigned.")
continue
definition = cast(DefinitionContainerInterface, self._global_container_stack.getBottom()).findDefinitions(key = key) definition = cast(DefinitionContainerInterface, self._global_container_stack.getBottom()).findDefinitions(key = key)
if not definition: if not definition:
Logger.log("e", "When checking settings for errors, unable to find definition for key {key} in per-object stack.".format(key = key)) Logger.log("e", "When checking settings for errors, unable to find definition for key {key} in per-object stack.".format(key = key))
@ -409,7 +418,8 @@ class CuraEngineBackend(QObject, Backend):
# Notify the user that it's now up to the backend to do it's job # Notify the user that it's now up to the backend to do it's job
self.backendStateChange.emit(BackendState.Processing) self.backendStateChange.emit(BackendState.Processing)
Logger.log("d", "Sending slice message took %s seconds", time() - self._slice_start_time ) if self._slice_start_time:
Logger.log("d", "Sending slice message took %s seconds", time() - self._slice_start_time )
## Determine enable or disable auto slicing. Return True for enable timer and False otherwise. ## Determine enable or disable auto slicing. Return True for enable timer and False otherwise.
# It disables when # It disables when
@ -476,15 +486,12 @@ class CuraEngineBackend(QObject, Backend):
else: else:
# we got a single scenenode # we got a single scenenode
if not source.callDecoration("isGroup"): if not source.callDecoration("isGroup"):
if source.getMeshData() is None: mesh_data = source.getMeshData()
return if mesh_data and mesh_data.getVertices() is None:
if source.getMeshData().getVertices() is None:
return return
build_plate_changed.add(source_build_plate_number) build_plate_changed.add(source_build_plate_number)
build_plate_changed.discard(None)
build_plate_changed.discard(-1) # object not on build plate
if not build_plate_changed: if not build_plate_changed:
return return
@ -577,9 +584,10 @@ class CuraEngineBackend(QObject, Backend):
# #
# \param message The protobuf message containing sliced layer data. # \param message The protobuf message containing sliced layer data.
def _onOptimizedLayerMessage(self, message: Arcus.PythonMessage) -> None: def _onOptimizedLayerMessage(self, message: Arcus.PythonMessage) -> None:
if self._start_slice_job_build_plate not in self._stored_optimized_layer_data: if self._start_slice_job_build_plate:
self._stored_optimized_layer_data[self._start_slice_job_build_plate] = [] if self._start_slice_job_build_plate not in self._stored_optimized_layer_data:
self._stored_optimized_layer_data[self._start_slice_job_build_plate].append(message) self._stored_optimized_layer_data[self._start_slice_job_build_plate] = []
self._stored_optimized_layer_data[self._start_slice_job_build_plate].append(message)
## Called when a progress message is received from the engine. ## Called when a progress message is received from the engine.
# #
@ -619,7 +627,8 @@ class CuraEngineBackend(QObject, Backend):
gcode_list[index] = replaced gcode_list[index] = replaced
self._slicing = False self._slicing = False
Logger.log("d", "Slicing took %s seconds", time() - self._slice_start_time ) if self._slice_start_time:
Logger.log("d", "Slicing took %s seconds", time() - self._slice_start_time )
Logger.log("d", "Number of models per buildplate: %s", dict(self._numObjectsPerBuildPlate())) Logger.log("d", "Number of models per buildplate: %s", dict(self._numObjectsPerBuildPlate()))
# See if we need to process the sliced layers job. # See if we need to process the sliced layers job.
@ -658,7 +667,11 @@ class CuraEngineBackend(QObject, Backend):
## Creates a new socket connection. ## Creates a new socket connection.
def _createSocket(self, protocol_file: str = None) -> None: def _createSocket(self, protocol_file: str = None) -> None:
if not protocol_file: if not protocol_file:
protocol_file = os.path.abspath(os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "Cura.proto")) plugin_path = PluginRegistry.getInstance().getPluginPath(self.getPluginId())
if not plugin_path:
Logger.log("e", "Could not get plugin path!", self.getPluginId())
return
protocol_file = os.path.abspath(os.path.join(plugin_path, "Cura.proto"))
super()._createSocket(protocol_file) super()._createSocket(protocol_file)
self._engine_is_fresh = True self._engine_is_fresh = True
@ -773,9 +786,9 @@ class CuraEngineBackend(QObject, Backend):
# We should reset our state and start listening for new connections. # We should reset our state and start listening for new connections.
def _onBackendQuit(self) -> None: def _onBackendQuit(self) -> None:
if not self._restart: if not self._restart:
if self._process: if self._process: # type: ignore
Logger.log("d", "Backend quit with return code %s. Resetting process and socket.", self._process.wait()) Logger.log("d", "Backend quit with return code %s. Resetting process and socket.", self._process.wait()) # type: ignore
self._process = None self._process = None # type: ignore
## Called when the global container stack changes ## Called when the global container stack changes
def _onGlobalStackChanged(self) -> None: def _onGlobalStackChanged(self) -> None:
@ -831,6 +844,9 @@ class CuraEngineBackend(QObject, Backend):
self._change_timer.start() self._change_timer.start()
def _extruderChanged(self) -> None: def _extruderChanged(self) -> None:
if not self._multi_build_plate_model:
Logger.log("w", "CuraEngineBackend does not have multi_build_plate_model assigned!")
return
for build_plate_number in range(self._multi_build_plate_model.maxBuildPlate + 1): for build_plate_number in range(self._multi_build_plate_model.maxBuildPlate + 1):
if build_plate_number not in self._build_plates_to_be_sliced: if build_plate_number not in self._build_plates_to_be_sliced:
self._build_plates_to_be_sliced.append(build_plate_number) self._build_plates_to_be_sliced.append(build_plate_number)

View File

@ -5,7 +5,7 @@ import numpy
from string import Formatter from string import Formatter
from enum import IntEnum from enum import IntEnum
import time import time
from typing import Any, Dict, List, Optional, Set from typing import Any, cast, Dict, List, Optional, Set
import re import re
import Arcus #For typing. import Arcus #For typing.
@ -209,12 +209,15 @@ class StartSliceJob(Job):
if temp_list: if temp_list:
object_groups.append(temp_list) object_groups.append(temp_list)
extruders_enabled = {position: stack.isEnabled for position, stack in CuraApplication.getInstance().getGlobalContainerStack().extruders.items()} global_stack = CuraApplication.getInstance().getGlobalContainerStack()
if not global_stack:
return
extruders_enabled = {position: stack.isEnabled for position, stack in global_stack.extruders.items()}
filtered_object_groups = [] filtered_object_groups = []
has_model_with_disabled_extruders = False has_model_with_disabled_extruders = False
associated_disabled_extruders = set() associated_disabled_extruders = set()
for group in object_groups: for group in object_groups:
stack = CuraApplication.getInstance().getGlobalContainerStack() stack = global_stack
skip_group = False skip_group = False
for node in group: for node in group:
extruder_position = node.callDecoration("getActiveExtruderPosition") extruder_position = node.callDecoration("getActiveExtruderPosition")
@ -318,7 +321,7 @@ class StartSliceJob(Job):
# \param default_extruder_nr Stack nr to use when no stack nr is specified, defaults to the global stack # \param default_extruder_nr Stack nr to use when no stack nr is specified, defaults to the global stack
def _expandGcodeTokens(self, value: str, default_extruder_nr: int = -1) -> str: def _expandGcodeTokens(self, value: str, default_extruder_nr: int = -1) -> str:
if not self._all_extruders_settings: if not self._all_extruders_settings:
global_stack = CuraApplication.getInstance().getGlobalContainerStack() global_stack = cast(ContainerStack, CuraApplication.getInstance().getGlobalContainerStack())
# NB: keys must be strings for the string formatter # NB: keys must be strings for the string formatter
self._all_extruders_settings = { self._all_extruders_settings = {

View File

@ -286,6 +286,7 @@ class FlavorParser:
self._cancelled = False self._cancelled = False
# We obtain the filament diameter from the selected extruder to calculate line widths # We obtain the filament diameter from the selected extruder to calculate line widths
global_stack = CuraApplication.getInstance().getGlobalContainerStack() global_stack = CuraApplication.getInstance().getGlobalContainerStack()
if not global_stack: if not global_stack:
return None return None

View File

@ -11,7 +11,7 @@ from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura") catalog = i18nCatalog("cura")
# Ignore windows error popups. Fixes the whole "Can't open drive X" when user has an SD card reader. # Ignore windows error popups. Fixes the whole "Can't open drive X" when user has an SD card reader.
ctypes.windll.kernel32.SetErrorMode(1) ctypes.windll.kernel32.SetErrorMode(1) #type: ignore
# WinAPI Constants that we need # WinAPI Constants that we need
# Hardcoded here due to stupid WinDLL stuff that does not give us access to these values. # Hardcoded here due to stupid WinDLL stuff that does not give us access to these values.
@ -29,7 +29,7 @@ OPEN_EXISTING = 3 # [CodeStyle: Windows Enum value]
# Setup the DeviceIoControl function arguments and return type. # Setup the DeviceIoControl function arguments and return type.
# See ctypes documentation for details on how to call C functions from python, and why this is important. # See ctypes documentation for details on how to call C functions from python, and why this is important.
ctypes.windll.kernel32.DeviceIoControl.argtypes = [ ctypes.windll.kernel32.DeviceIoControl.argtypes = [ #type: ignore
wintypes.HANDLE, # _In_ HANDLE hDevice wintypes.HANDLE, # _In_ HANDLE hDevice
wintypes.DWORD, # _In_ DWORD dwIoControlCode wintypes.DWORD, # _In_ DWORD dwIoControlCode
wintypes.LPVOID, # _In_opt_ LPVOID lpInBuffer wintypes.LPVOID, # _In_opt_ LPVOID lpInBuffer
@ -39,7 +39,7 @@ ctypes.windll.kernel32.DeviceIoControl.argtypes = [
ctypes.POINTER(wintypes.DWORD), # _Out_opt_ LPDWORD lpBytesReturned ctypes.POINTER(wintypes.DWORD), # _Out_opt_ LPDWORD lpBytesReturned
wintypes.LPVOID # _Inout_opt_ LPOVERLAPPED lpOverlapped wintypes.LPVOID # _Inout_opt_ LPOVERLAPPED lpOverlapped
] ]
ctypes.windll.kernel32.DeviceIoControl.restype = wintypes.BOOL ctypes.windll.kernel32.DeviceIoControl.restype = wintypes.BOOL #type: ignore
## Removable drive support for windows ## Removable drive support for windows

View File

@ -16,7 +16,7 @@ from UM.i18n import i18nCatalog
from UM.Logger import Logger from UM.Logger import Logger
from UM.PluginRegistry import PluginRegistry from UM.PluginRegistry import PluginRegistry
from UM.Qt.Duration import DurationFormat from UM.Qt.Duration import DurationFormat
from typing import cast, Optional
from .SliceInfoJob import SliceInfoJob from .SliceInfoJob import SliceInfoJob
@ -79,11 +79,16 @@ class SliceInfo(QObject, Extension):
return dialog return dialog
@pyqtSlot(result = str) @pyqtSlot(result = str)
def getExampleData(self) -> str: def getExampleData(self) -> Optional[str]:
if self._example_data_content is None: if self._example_data_content is None:
file_path = os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "example_data.json") plugin_path = PluginRegistry.getInstance().getPluginPath(self.getPluginId())
with open(file_path, "r", encoding = "utf-8") as f: if not plugin_path:
self._example_data_content = f.read() Logger.log("e", "Could not get plugin path!", self.getPluginId())
return None
file_path = os.path.join(plugin_path, "example_data.json")
if file_path:
with open(file_path, "r", encoding = "utf-8") as f:
self._example_data_content = f.read()
return self._example_data_content return self._example_data_content
@pyqtSlot(bool) @pyqtSlot(bool)

View File

@ -6,7 +6,7 @@ import json
import os import os
import tempfile import tempfile
import platform import platform
from typing import List from typing import cast, List
from PyQt5.QtCore import QUrl, QObject, pyqtProperty, pyqtSignal, pyqtSlot from PyQt5.QtCore import QUrl, QObject, pyqtProperty, pyqtSignal, pyqtSlot
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply
@ -240,7 +240,10 @@ class Toolbox(QObject, Extension):
if not plugin_path: if not plugin_path:
return None return None
path = os.path.join(plugin_path, "resources", "qml", qml_name) path = os.path.join(plugin_path, "resources", "qml", qml_name)
dialog = self._application.createQmlComponent(path, {"toolbox": self}) dialog = self._application.createQmlComponent(path, {"toolbox": self})
if not dialog:
raise Exception("Failed to create toolbox dialog")
return dialog return dialog

View File

@ -1,7 +1,7 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from typing import Any, cast, Set, Tuple, Union from typing import Any, cast, Optional, Set, Tuple, Union
from UM.FileHandler.FileHandler import FileHandler from UM.FileHandler.FileHandler import FileHandler
from UM.FileHandler.FileWriter import FileWriter #To choose based on the output file mode (text vs. binary). from UM.FileHandler.FileWriter import FileWriter #To choose based on the output file mode (text vs. binary).
@ -9,6 +9,7 @@ from UM.FileHandler.WriteFileJob import WriteFileJob #To call the file writer as
from UM.Logger import Logger from UM.Logger import Logger
from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
from UM.Mesh.MeshWriter import MeshWriter # For typing
from UM.Message import Message from UM.Message import Message
from UM.Qt.Duration import Duration, DurationFormat from UM.Qt.Duration import Duration, DurationFormat
from UM.OutputDevice import OutputDeviceError #To show that something went wrong when writing. from UM.OutputDevice import OutputDeviceError #To show that something went wrong when writing.
@ -104,10 +105,11 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
file_formats = CuraApplication.getInstance().getMeshFileHandler().getSupportedFileTypesWrite() file_formats = CuraApplication.getInstance().getMeshFileHandler().getSupportedFileTypesWrite()
global_stack = CuraApplication.getInstance().getGlobalContainerStack() global_stack = CuraApplication.getInstance().getGlobalContainerStack()
#Create a list from the supported file formats string.
if not global_stack: if not global_stack:
Logger.log("e", "Missing global stack!")
return return
#Create a list from the supported file formats string.
machine_file_formats = global_stack.getMetaDataEntry("file_formats").split(";") machine_file_formats = global_stack.getMetaDataEntry("file_formats").split(";")
machine_file_formats = [file_type.strip() for file_type in machine_file_formats] machine_file_formats = [file_type.strip() for file_type in machine_file_formats]
#Exception for UM3 firmware version >=4.4: UFP is now supported and should be the preferred file format. #Exception for UM3 firmware version >=4.4: UFP is now supported and should be the preferred file format.
@ -134,6 +136,9 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
return return
#This function pauses with the yield, waiting on instructions on which printer it needs to print with. #This function pauses with the yield, waiting on instructions on which printer it needs to print with.
if not writer:
Logger.log("e", "Missing file or mesh writer!")
return
self._sending_job = self._sendPrintJob(writer, preferred_format, nodes) self._sending_job = self._sendPrintJob(writer, preferred_format, nodes)
self._sending_job.send(None) #Start the generator. self._sending_job.send(None) #Start the generator.
@ -213,16 +218,14 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
yield #To prevent having to catch the StopIteration exception. yield #To prevent having to catch the StopIteration exception.
def _sendPrintJobWaitOnWriteJobFinished(self, job: WriteFileJob) -> None: def _sendPrintJobWaitOnWriteJobFinished(self, job: WriteFileJob) -> None:
# This is the callback when the job finishes, where the message is created if self._write_job_progress_message:
assert(self._write_job_progress_message is not None) self._write_job_progress_message.hide()
self._write_job_progress_message.hide()
self._progress_message = Message(i18n_catalog.i18nc("@info:status", "Sending data to printer"), lifetime = 0, dismissable = False, progress = -1, self._progress_message = Message(i18n_catalog.i18nc("@info:status", "Sending data to printer"), lifetime = 0, dismissable = False, progress = -1,
title = i18n_catalog.i18nc("@info:title", "Sending Data")) title = i18n_catalog.i18nc("@info:title", "Sending Data"))
self._progress_message.addAction("Abort", i18n_catalog.i18nc("@action:button", "Cancel"), icon = None, description = "") self._progress_message.addAction("Abort", i18n_catalog.i18nc("@action:button", "Cancel"), icon = None, description = "")
self._progress_message.actionTriggered.connect(self._progressMessageActionTriggered) self._progress_message.actionTriggered.connect(self._progressMessageActionTriggered)
self._progress_message.show() self._progress_message.show()
parts = [] parts = []
target_printer, preferred_format, stream = self._dummy_lambdas target_printer, preferred_format, stream = self._dummy_lambdas
@ -259,7 +262,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
self.activePrinterChanged.emit() self.activePrinterChanged.emit()
def _onPostPrintJobFinished(self, reply: QNetworkReply) -> None: def _onPostPrintJobFinished(self, reply: QNetworkReply) -> None:
if self._progress_message is not None: if self._progress_message:
self._progress_message.hide() self._progress_message.hide()
self._compressing_gcode = False self._compressing_gcode = False
self._sending_gcode = False self._sending_gcode = False

View File

@ -3,7 +3,7 @@
import os.path import os.path
import time import time
from typing import Optional from typing import cast, Optional
from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot, QObject from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot, QObject

View File

@ -1,16 +1,32 @@
#!env python #!/usr/bin/env python
import os import os
import sys import sys
import subprocess import subprocess
# A quick Python implementation of unix 'where' command. # A quick Python implementation of unix 'where' command.
def where(exeName, searchPath=os.getenv("PATH")): def where(exe_name: str, search_path: str = os.getenv("PATH")) -> str:
paths = searchPath.split(";" if sys.platform == "win32" else ":") if search_path is None:
for path in paths: search_path = ""
candidatePath = os.path.join(path, exeName) paths = search_path.split(os.pathsep)
if os.path.exists(candidatePath): result = ""
return candidatePath print(" -> sys.executable location: %s" % sys.executable)
return None sys_exec_dir = os.path.dirname(sys.executable)
root_dir = os.path.dirname(sys_exec_dir)
paths += [sys_exec_dir,
os.path.join(root_dir, "bin"),
os.path.join(root_dir, "scripts"),
]
paths = set(paths)
for path in sorted(paths):
print(" -> Searching %s" % path)
candidate_path = os.path.join(path, exe_name)
if os.path.exists(candidate_path):
result = candidate_path
break
return result
def findModules(path): def findModules(path):
result = [] result = []
@ -19,6 +35,7 @@ def findModules(path):
result.append(entry.name) result.append(entry.name)
return result return result
def main(): def main():
# Find Uranium via the PYTHONPATH var # Find Uranium via the PYTHONPATH var
uraniumUMPath = where("UM", os.getenv("PYTHONPATH")) uraniumUMPath = where("UM", os.getenv("PYTHONPATH"))
@ -26,16 +43,19 @@ def main():
uraniumUMPath = os.path.join("..", "Uranium") uraniumUMPath = os.path.join("..", "Uranium")
uraniumPath = os.path.dirname(uraniumUMPath) uraniumPath = os.path.dirname(uraniumUMPath)
mypyPathParts = [".", os.path.join(".", "plugins"), os.path.join(".", "plugins", "VersionUpgrade"), mypy_path_parts = [".", os.path.join(".", "plugins"), os.path.join(".", "plugins", "VersionUpgrade"),
uraniumPath, os.path.join(uraniumPath, "stubs")] uraniumPath, os.path.join(uraniumPath, "stubs")]
if sys.platform == "win32": if sys.platform == "win32":
os.putenv("MYPYPATH", ";".join(mypyPathParts)) os.putenv("MYPYPATH", ";".join(mypy_path_parts))
else: else:
os.putenv("MYPYPATH", ":".join(mypyPathParts)) os.putenv("MYPYPATH", ":".join(mypy_path_parts))
# Mypy really needs to be run via its Python script otherwise it can't find its data files. # Mypy really needs to be run via its Python script otherwise it can't find its data files.
mypyExe = where("mypy.bat" if sys.platform == "win32" else "mypy") mypy_exe_name = "mypy.exe" if sys.platform == "win32" else "mypy"
mypyModule = os.path.join(os.path.dirname(mypyExe), "mypy") mypy_exe_dir = where(mypy_exe_name)
mypy_module = os.path.join(os.path.dirname(mypy_exe_dir), mypy_exe_name)
print("Found mypy exe path: %s" % mypy_exe_dir)
print("Found mypy module path: %s" % mypy_module)
plugins = findModules("plugins") plugins = findModules("plugins")
plugins.sort() plugins.sort()
@ -44,11 +64,17 @@ def main():
for mod in mods: for mod in mods:
print("------------- Checking module {mod}".format(**locals())) print("------------- Checking module {mod}".format(**locals()))
result = subprocess.run([sys.executable, mypyModule, "-p", mod, "--ignore-missing-imports"]) if sys.platform == "win32":
result = subprocess.run([mypy_module, "-p", mod, "--ignore-missing-imports"])
else:
result = subprocess.run([sys.executable, mypy_module, "-p", mod, "--ignore-missing-imports"])
if result.returncode != 0: if result.returncode != 0:
print("\nModule {mod} failed checking. :(".format(**locals())) print("\nModule {mod} failed checking. :(".format(**locals()))
return 1 return 1
else: else:
print("\n\nDone checking. All is good.") print("\n\nDone checking. All is good.")
return 0 return 0
sys.exit(main())
if __name__ == "__main__":
sys.exit(main())