Merge branch 'master' of github.com:Ultimaker/Cura into CURA-7090-addition

This commit is contained in:
Dimitriovski 2020-01-21 15:08:24 +01:00
commit 369329c476
No known key found for this signature in database
GPG key ID: 4E62757E2B0D304D
10 changed files with 120 additions and 15 deletions

View file

@ -56,6 +56,13 @@ function(cura_add_test)
endif() endif()
endfunction() endfunction()
#Add test for import statements which are not compatible with all builds
add_test(
NAME "invalid-imports"
COMMAND ${Python3_EXECUTABLE} scripts/check_invalid_imports.py
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
cura_add_test(NAME pytest-main DIRECTORY ${CMAKE_SOURCE_DIR}/tests PYTHONPATH "${CMAKE_SOURCE_DIR}|${URANIUM_DIR}") cura_add_test(NAME pytest-main DIRECTORY ${CMAKE_SOURCE_DIR}/tests PYTHONPATH "${CMAKE_SOURCE_DIR}|${URANIUM_DIR}")
file(GLOB_RECURSE _plugins plugins/*/__init__.py) file(GLOB_RECURSE _plugins plugins/*/__init__.py)

View file

@ -13,6 +13,8 @@ export PKG_CONFIG_PATH="${CURA_BUILD_ENV_PATH}/lib/pkgconfig:${PKG_CONFIG_PATH}"
cd "${PROJECT_DIR}" cd "${PROJECT_DIR}"
# #
# Clone Uranium and set PYTHONPATH first # Clone Uranium and set PYTHONPATH first
# #

View file

@ -152,7 +152,7 @@ UM.Dialog{
} // End of ScrollView } // End of ScrollView
Cura.ActionButton Cura.PrimaryButton
{ {
id: nextButton id: nextButton
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
@ -160,6 +160,8 @@ UM.Dialog{
anchors.margins: UM.Theme.getSize("default_margin").height anchors.margins: UM.Theme.getSize("default_margin").height
text: catalog.i18nc("@button", "Next") text: catalog.i18nc("@button", "Next")
onClicked: accept() onClicked: accept()
leftPadding: UM.Theme.getSize("dialog_primary_button_padding").width
rightPadding: UM.Theme.getSize("dialog_primary_button_padding").width
} }
} }
} }

View file

@ -10,6 +10,7 @@ import QtQuick.Controls.Styles 1.4
// TODO: Switch to QtQuick.Controls 2.x and remove QtQuick.Controls.Styles // TODO: Switch to QtQuick.Controls 2.x and remove QtQuick.Controls.Styles
import UM 1.1 as UM import UM 1.1 as UM
import Cura 1.6 as Cura
UM.Dialog UM.Dialog
{ {
@ -51,18 +52,22 @@ UM.Dialog
} }
rightButtons: rightButtons:
[ [
Button Cura.PrimaryButton
{ {
id: acceptButton leftPadding: UM.Theme.getSize("dialog_primary_button_padding").width
anchors.margins: UM.Theme.getSize("default_margin").width rightPadding: UM.Theme.getSize("dialog_primary_button_padding").width
text: catalog.i18nc("@action:button", "Accept")
text: catalog.i18nc("@button", "Agree")
onClicked: { handler.onLicenseAccepted() } onClicked: { handler.onLicenseAccepted() }
}, }
Button ]
leftButtons:
[
Cura.SecondaryButton
{ {
id: declineButton id: declineButton
anchors.margins: UM.Theme.getSize("default_margin").width text: catalog.i18nc("@button", "Decline and remove from account")
text: catalog.i18nc("@action:button", "Decline")
onClicked: { handler.onLicenseDeclined() } onClicked: { handler.onLicenseDeclined() }
} }
] ]

View file

@ -18,3 +18,11 @@ class CloudApiModel:
cloud_api_root=cloud_api_root, cloud_api_root=cloud_api_root,
cloud_api_version=cloud_api_version, cloud_api_version=cloud_api_version,
) )
## https://api.ultimaker.com/cura-packages/v1/user/packages/{package_id}
@classmethod
def userPackageUrl(cls, package_id: str) -> str:
return (CloudApiModel.api_url_user_packages + "/{package_id}").format(
package_id=package_id
)

View file

@ -16,3 +16,8 @@ class CloudPackageManager:
data=data.encode(), data=data.encode(),
scope=self._scope scope=self._scope
) )
def unsubscribe(self, package_id: str) -> None:
url = CloudApiModel.userPackageUrl(package_id)
self._request_manager.delete(url=url, scope=self._scope)

View file

@ -1,8 +1,10 @@
import os import os
from typing import List, Dict, Any, cast from typing import List, Dict, Any, cast
from UM import i18n_catalog
from UM.Extension import Extension from UM.Extension import Extension
from UM.Logger import Logger from UM.Logger import Logger
from UM.Message import Message
from UM.PluginRegistry import PluginRegistry from UM.PluginRegistry import PluginRegistry
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
from .CloudPackageChecker import CloudPackageChecker from .CloudPackageChecker import CloudPackageChecker
@ -64,7 +66,10 @@ class SyncOrchestrator(Extension):
# \param success_items: Dict[package_id, file_path] # \param success_items: Dict[package_id, file_path]
# \param error_items: List[package_id] # \param error_items: List[package_id]
def _onDownloadFinished(self, success_items: Dict[str, str], error_items: List[str]) -> None: def _onDownloadFinished(self, success_items: Dict[str, str], error_items: List[str]) -> None:
# todo handle error items if error_items:
message = i18n_catalog.i18nc("@info:generic", "{} plugins failed to download".format(len(error_items)))
self._showErrorMessage(message)
plugin_path = cast(str, PluginRegistry.getInstance().getPluginPath(self.getPluginId())) plugin_path = cast(str, PluginRegistry.getInstance().getPluginPath(self.getPluginId()))
self._license_presenter.present(plugin_path, success_items) self._license_presenter.present(plugin_path, success_items)
@ -78,15 +83,20 @@ class SyncOrchestrator(Extension):
if item["accepted"]: if item["accepted"]:
# install and subscribe packages # install and subscribe packages
if not self._package_manager.installPackage(item["package_path"]): if not self._package_manager.installPackage(item["package_path"]):
Logger.error("could not install {}".format(item["package_id"])) message = "Could not install {}".format(item["package_id"])
self._showErrorMessage(message)
continue continue
self._cloud_package_manager.subscribe(item["package_id"]) self._cloud_package_manager.subscribe(item["package_id"])
has_changes = True has_changes = True
else: else:
# todo unsubscribe declined packages self._cloud_package_manager.unsubscribe(item["package_id"])
pass
# delete temp file # delete temp file
os.remove(item["package_path"]) os.remove(item["package_path"])
if has_changes: if has_changes:
self._restart_presenter.present() self._restart_presenter.present()
## Logs an error and shows it to the user
def _showErrorMessage(self, text: str):
Logger.error(text)
Message(text, lifetime=0).show()

View file

@ -5688,7 +5688,7 @@
"unit": "mm", "unit": "mm",
"enabled": "resolveOrValue('prime_tower_enable')", "enabled": "resolveOrValue('prime_tower_enable')",
"default_value": 200, "default_value": 200,
"value": "machine_width - max(extruderValue(adhesion_extruder_nr, 'brim_width') * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 if adhesion_type == 'brim' or (prime_tower_brim_enable and adhesion_type != 'raft') else (extruderValue(adhesion_extruder_nr, 'raft_margin') if adhesion_type == 'raft' else (extruderValue(adhesion_extruder_nr, 'skirt_gap') if adhesion_type == 'skirt' else 0)), max(extruderValues('travel_avoid_distance'))) - max(extruderValues('support_offset')) - sum(extruderValues('skirt_brim_line_width')) * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 - (resolveOrValue('draft_shield_dist') if resolveOrValue('draft_shield_enabled') else 0) - 1", "value": "machine_width - max(extruderValue(adhesion_extruder_nr, 'brim_width') * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 if adhesion_type == 'brim' or (prime_tower_brim_enable and adhesion_type != 'raft') else (extruderValue(adhesion_extruder_nr, 'raft_margin') if adhesion_type == 'raft' else (extruderValue(adhesion_extruder_nr, 'skirt_gap') if adhesion_type == 'skirt' else 0)), max(extruderValues('travel_avoid_distance'))) - max(extruderValues('support_offset')) - sum(extruderValues('skirt_brim_line_width')) * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 - (resolveOrValue('draft_shield_dist') if resolveOrValue('draft_shield_enabled') else 0) - max(map(abs, extruderValues('machine_nozzle_offset_x'))) - 1",
"maximum_value": "machine_width / 2 if machine_center_is_zero else machine_width", "maximum_value": "machine_width / 2 if machine_center_is_zero else machine_width",
"minimum_value": "resolveOrValue('prime_tower_size') - machine_width / 2 if machine_center_is_zero else resolveOrValue('prime_tower_size')", "minimum_value": "resolveOrValue('prime_tower_size') - machine_width / 2 if machine_center_is_zero else resolveOrValue('prime_tower_size')",
"settable_per_mesh": false, "settable_per_mesh": false,
@ -5702,7 +5702,7 @@
"unit": "mm", "unit": "mm",
"enabled": "resolveOrValue('prime_tower_enable')", "enabled": "resolveOrValue('prime_tower_enable')",
"default_value": 200, "default_value": 200,
"value": "machine_depth - prime_tower_size - max(extruderValue(adhesion_extruder_nr, 'brim_width') * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 if adhesion_type == 'brim' or (prime_tower_brim_enable and adhesion_type != 'raft') else (extruderValue(adhesion_extruder_nr, 'raft_margin') if adhesion_type == 'raft' else (extruderValue(adhesion_extruder_nr, 'skirt_gap') if adhesion_type == 'skirt' else 0)), max(extruderValues('travel_avoid_distance'))) - max(extruderValues('support_offset')) - sum(extruderValues('skirt_brim_line_width')) * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 - (resolveOrValue('draft_shield_dist') if resolveOrValue('draft_shield_enabled') else 0) - 1", "value": "machine_depth - prime_tower_size - max(extruderValue(adhesion_extruder_nr, 'brim_width') * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 if adhesion_type == 'brim' or (prime_tower_brim_enable and adhesion_type != 'raft') else (extruderValue(adhesion_extruder_nr, 'raft_margin') if adhesion_type == 'raft' else (extruderValue(adhesion_extruder_nr, 'skirt_gap') if adhesion_type == 'skirt' else 0)), max(extruderValues('travel_avoid_distance'))) - max(extruderValues('support_offset')) - sum(extruderValues('skirt_brim_line_width')) * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 - (resolveOrValue('draft_shield_dist') if resolveOrValue('draft_shield_enabled') else 0) - max(map(abs, extruderValues('machine_nozzle_offset_y'))) - 1",
"maximum_value": "machine_depth / 2 - resolveOrValue('prime_tower_size') if machine_center_is_zero else machine_depth - resolveOrValue('prime_tower_size')", "maximum_value": "machine_depth / 2 - resolveOrValue('prime_tower_size') if machine_center_is_zero else machine_depth - resolveOrValue('prime_tower_size')",
"minimum_value": "machine_depth / -2 if machine_center_is_zero else 0", "minimum_value": "machine_depth / -2 if machine_center_is_zero else 0",
"settable_per_mesh": false, "settable_per_mesh": false,

View file

@ -520,6 +520,7 @@
"action_button": [15.0, 2.5], "action_button": [15.0, 2.5],
"action_button_icon": [1.0, 1.0], "action_button_icon": [1.0, 1.0],
"action_button_radius": [0.15, 0.15], "action_button_radius": [0.15, 0.15],
"dialog_primary_button_padding": [3.0, 0],
"radio_button": [1.3, 1.3], "radio_button": [1.3, 1.3],

View file

@ -0,0 +1,65 @@
import os
import re
import sys
from pathlib import Path
"""
Run this file with the Cura project root as the working directory
Checks for invalid imports. When importing from plugins, there will be no problems when running from source,
but for some build types the plugins dir is not on the path, so relative imports should be used instead. eg:
from ..UltimakerCloudScope import UltimakerCloudScope <-- OK
import plugins.Toolbox.src ... <-- NOT OK
"""
class InvalidImportsChecker:
# compile regex
REGEX = re.compile(r"^\s*(from plugins|import plugins)")
def check(self):
""" Checks for invalid imports
:return: True if checks passed, False when the test fails
"""
cwd = os.getcwd()
cura_result = checker.check_dir(os.path.join(cwd, "cura"))
plugins_result = checker.check_dir(os.path.join(cwd, "plugins"))
result = cura_result and plugins_result
if not result:
print("error: sources contain invalid imports. Use relative imports when referencing plugin source files")
return result
def check_dir(self, root_dir: str) -> bool:
""" Checks a directory for invalid imports
:return: True if checks passed, False when the test fails
"""
passed = True
for path_like in Path(root_dir).rglob('*.py'):
if not self.check_file(str(path_like)):
passed = False
return passed
def check_file(self, file_path):
""" Checks a file for invalid imports
:return: True if checks passed, False when the test fails
"""
passed = True
with open(file_path, 'r', encoding = "utf-8") as inputFile:
# loop through each line in file
for line_i, line in enumerate(inputFile, 1):
# check if we have a regex match
match = self.REGEX.search(line)
if match:
path = os.path.relpath(file_path)
print("{path}:{line_i}:{match}".format(path=path, line_i=line_i, match=match.group(1)))
passed = False
return passed
if __name__ == "__main__":
checker = InvalidImportsChecker()
sys.exit(0 if checker.check() else 1)