Merge branch 'master' of github.com:Ultimaker/Cura

This commit is contained in:
Jaime van Kessel 2019-11-01 15:15:31 +01:00
commit b3bf77524b
No known key found for this signature in database
GPG key ID: 3710727397403C91
31 changed files with 267 additions and 273 deletions

View file

@ -41,11 +41,11 @@ class IntentCategoryModel(ListModel):
}
_translations["engineering"] = {
"name": catalog.i18nc("@label", "Engineering"),
"description": catalog.i18nc("@text", "Suitable for engineering work")
"description": catalog.i18nc("@text", "Optimized for higher accuracy")
}
_translations["smooth"] = {
"name": catalog.i18nc("@label", "Smooth"),
"description": catalog.i18nc("@text", "Optimized for a smooth surfaces")
_translations["quick"] = {
"name": catalog.i18nc("@label", "Draft"),
"description": catalog.i18nc("@text", "Optimized for fast results")
}

View file

@ -1,4 +1,4 @@
# Copyright (c) 2018 Ultimaker B.V.
# Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import numpy
@ -72,7 +72,7 @@ class GcodeStartEndFormatter(Formatter):
value = default_value_str
# "-1" is global stack, and if the setting value exists in the global stack, use it as the fallback value.
if key in kwargs["-1"]:
value = kwargs["-1"]
value = kwargs["-1"][key]
if str(extruder_nr) in kwargs and key in kwargs[str(extruder_nr)]:
value = kwargs[str(extruder_nr)][key]

View file

@ -143,6 +143,52 @@ UM.Dialog
}
}
UM.TooltipArea {
Layout.fillWidth:true
height: childrenRect.height
text: catalog.i18nc("@info:tooltip","For lithophanes a simple logarithmic model for translucency is available. For height maps the pixel values correspond to heights linearly.")
Row {
width: parent.width
Label {
text: "Color Model"
width: 150 * screenScaleFactor
anchors.verticalCenter: parent.verticalCenter
}
ComboBox {
id: color_model
objectName: "ColorModel"
model: [ catalog.i18nc("@item:inlistbox","Linear"), catalog.i18nc("@item:inlistbox","Translucency") ]
width: 180 * screenScaleFactor
onCurrentIndexChanged: { manager.onColorModelChanged(currentIndex) }
}
}
}
UM.TooltipArea {
Layout.fillWidth:true
height: childrenRect.height
text: catalog.i18nc("@info:tooltip","The percentage of light penetrating a print with a thickness of 1 millimeter. Lowering this value increases the contrast in dark regions and decreases the contrast in light regions of the image.")
visible: color_model.currentText == catalog.i18nc("@item:inlistbox","Translucency")
Row {
width: parent.width
Label {
text: catalog.i18nc("@action:label", "1mm Transmittance (%)")
width: 150 * screenScaleFactor
anchors.verticalCenter: parent.verticalCenter
}
TextField {
id: transmittance
objectName: "Transmittance"
focus: true
validator: RegExpValidator {regExp: /^[1-9]\d{0,2}([\,|\.]\d*)?$/}
width: 180 * screenScaleFactor
onTextChanged: { manager.onTransmittanceChanged(text) }
}
}
}
UM.TooltipArea {
Layout.fillWidth:true
height: childrenRect.height

View file

@ -3,6 +3,8 @@
import numpy
import math
from PyQt5.QtGui import QImage, qRed, qGreen, qBlue
from PyQt5.QtCore import Qt
@ -46,9 +48,9 @@ class ImageReader(MeshReader):
def _read(self, file_name):
size = max(self._ui.getWidth(), self._ui.getDepth())
return self._generateSceneNode(file_name, size, self._ui.peak_height, self._ui.base_height, self._ui.smoothing, 512, self._ui.lighter_is_higher)
return self._generateSceneNode(file_name, size, self._ui.peak_height, self._ui.base_height, self._ui.smoothing, 512, self._ui.lighter_is_higher, self._ui.use_transparency_model, self._ui.transmittance_1mm)
def _generateSceneNode(self, file_name, xz_size, peak_height, base_height, blur_iterations, max_size, lighter_is_higher):
def _generateSceneNode(self, file_name, xz_size, peak_height, base_height, blur_iterations, max_size, lighter_is_higher, use_transparency_model, transmittance_1mm):
scene_node = SceneNode()
mesh = MeshBuilder()
@ -99,12 +101,14 @@ class ImageReader(MeshReader):
for x in range(0, width):
for y in range(0, height):
qrgb = img.pixel(x, y)
avg = float(qRed(qrgb) + qGreen(qrgb) + qBlue(qrgb)) / (3 * 255)
height_data[y, x] = avg
if use_transparency_model:
height_data[y, x] = (0.299 * math.pow(qRed(qrgb) / 255.0, 2.2) + 0.587 * math.pow(qGreen(qrgb) / 255.0, 2.2) + 0.114 * math.pow(qBlue(qrgb) / 255.0, 2.2))
else:
height_data[y, x] = (0.212655 * qRed(qrgb) + 0.715158 * qGreen(qrgb) + 0.072187 * qBlue(qrgb)) / 255 # fast computation ignoring gamma and degamma
Job.yieldThread()
if not lighter_is_higher:
if lighter_is_higher == use_transparency_model:
height_data = 1 - height_data
for _ in range(0, blur_iterations):
@ -124,8 +128,15 @@ class ImageReader(MeshReader):
Job.yieldThread()
height_data *= scale_vector.y
height_data += base_height
if use_transparency_model:
divisor = 1.0 / math.log(transmittance_1mm / 100.0) # log-base doesn't matter here. Precompute this value for faster computation of each pixel.
min_luminance = (transmittance_1mm / 100.0) ** (peak_height - base_height)
for (y, x) in numpy.ndindex(height_data.shape):
mapped_luminance = min_luminance + (1.0 - min_luminance) * height_data[y, x]
height_data[y, x] = base_height + divisor * math.log(mapped_luminance) # use same base as a couple lines above this
else:
height_data *= scale_vector.y
height_data += base_height
heightmap_face_count = 2 * height_minus_one * width_minus_one
total_face_count = heightmap_face_count + (width_minus_one * 2) * (height_minus_one * 2) + 2

View file

@ -34,6 +34,8 @@ class ImageReaderUI(QObject):
self.peak_height = 2.5
self.smoothing = 1
self.lighter_is_higher = False;
self.use_transparency_model = True;
self.transmittance_1mm = 50.0; # based on pearl PLA
self._ui_lock = threading.Lock()
self._cancelled = False
@ -75,6 +77,7 @@ class ImageReaderUI(QObject):
self._ui_view.findChild(QObject, "Base_Height").setProperty("text", str(self.base_height))
self._ui_view.findChild(QObject, "Peak_Height").setProperty("text", str(self.peak_height))
self._ui_view.findChild(QObject, "Transmittance").setProperty("text", str(self.transmittance_1mm))
self._ui_view.findChild(QObject, "Smoothing").setProperty("value", self.smoothing)
def _createConfigUI(self):
@ -144,3 +147,11 @@ class ImageReaderUI(QObject):
@pyqtSlot(int)
def onImageColorInvertChanged(self, value):
self.lighter_is_higher = (value == 1)
@pyqtSlot(int)
def onColorModelChanged(self, value):
self.use_transparency_model = (value == 0)
@pyqtSlot(int)
def onTransmittanceChanged(self, value):
self.transmittance_1mm = value

View file

@ -66,6 +66,13 @@ class VersionUpgrade43to44(VersionUpgrade):
# Alternate skin rotation should be translated to top/bottom line directions.
if "skin_alternate_rotation" in parser["values"] and parseBool(parser["values"]["skin_alternate_rotation"]):
parser["values"]["skin_angles"] = "[45, 135, 0, 90]"
# Unit of adaptive layers topography size changed.
if "adaptive_layer_height_threshold" in parser["values"]:
val = parser["values"]["adaptive_layer_height_threshold"]
if val.startswith("="):
val = val[1:]
val = "=({val}) / 1000".format(val = val) # Convert microns to millimetres. Works even if the profile contained a formula.
parser["values"]["adaptive_layer_height_threshold"] = val
result = io.StringIO()
parser.write(result)

View file

@ -7074,11 +7074,12 @@
},
"adaptive_layer_height_threshold":
{
"label": "Adaptive Layers Threshold",
"description": "Threshold whether to use a smaller layer or not. This number is compared to the tan of the steepest slope in a layer.",
"label": "Adaptive Layers Topography Size",
"description": "Target horizontal distance between two adjacent layers. Reducing this setting causes thinner layers to be used to bring the edges of the layers closer together.",
"type": "float",
"enabled": "adaptive_layer_height_enabled",
"default_value": 200.0,
"default_value": 0.2,
"unit": "mm",
"settable_per_mesh": false,
"settable_per_extruder": false,
"settable_per_meshgroup": false

View file

@ -18,12 +18,12 @@
"supports_usb_connection": false,
"machine_extruder_trains":
{
"0": "alya3dp_extruder_0"
"0": "kupido_extruder_0"
}
},
"overrides": {
"machine_name": { "default_value": "ALYA 3DP" },
"machine_name": { "default_value": "KUPIDO" },
"machine_heated_bed": { "default_value": true },
"machine_width": { "default_value": 195 },
"machine_height": { "default_value": 190 },

View file

@ -67,8 +67,6 @@
"extruder_prime_pos_abs": { "default_value": true },
"machine_start_gcode": { "default_value": "" },
"machine_end_gcode": { "default_value": "" },
"prime_tower_position_x": { "value": "345" },
"prime_tower_position_y": { "value": "222.5" },
"prime_blob_enable": { "enabled": true, "default_value": false },
"speed_travel":

View file

@ -1,45 +1,45 @@
{
"version": 2,
"name": "Extruder 1",
"inherits": "fdmextruder",
"metadata": {
"machine": "BIBO2 dual",
"position": "0"
},
"overrides": {
"extruder_nr": {
"default_value": 0,
"maximum_value": "1"
},
"material_diameter": {
"default_value": 1.75
},
"machine_nozzle_size": {
"default_value": 0.4
},
"machine_nozzle_offset_x": {
"default_value": 0.0
},
"machine_nozzle_offset_y": {
"default_value": 0.0
},
"machine_extruder_start_pos_abs": {
"default_value": true
},
"machine_extruder_start_pos_x": {
"value": "prime_tower_position_x"
},
"machine_extruder_start_pos_y": {
"value": "prime_tower_position_y"
},
"machine_extruder_end_pos_abs": {
"default_value": true
},
"machine_extruder_end_pos_x": {
"value": "prime_tower_position_x"
},
"machine_extruder_end_pos_y": {
"value": "prime_tower_position_y"
}
}
"version": 2,
"name": "Extruder 1",
"inherits": "fdmextruder",
"metadata": {
"machine": "bibo2_dual",
"position": "0"
},
"overrides": {
"extruder_nr": {
"default_value": 0,
"maximum_value": "1"
},
"material_diameter": {
"default_value": 1.75
},
"machine_nozzle_size": {
"default_value": 0.4
},
"machine_nozzle_offset_x": {
"default_value": 0.0
},
"machine_nozzle_offset_y": {
"default_value": 0.0
},
"machine_extruder_start_pos_abs": {
"default_value": true
},
"machine_extruder_start_pos_x": {
"value": "prime_tower_position_x"
},
"machine_extruder_start_pos_y": {
"value": "prime_tower_position_y"
},
"machine_extruder_end_pos_abs": {
"default_value": true
},
"machine_extruder_end_pos_x": {
"value": "prime_tower_position_x"
},
"machine_extruder_end_pos_y": {
"value": "prime_tower_position_y"
}
}
}

View file

@ -1,45 +1,45 @@
{
"version": 2,
"name": "Extruder 2",
"inherits": "fdmextruder",
"metadata": {
"machine": "BIBO2 dual",
"position": "1"
},
"overrides": {
"extruder_nr": {
"default_value": 1,
"maximum_value": "1"
},
"material_diameter": {
"default_value": 1.75
},
"machine_nozzle_size": {
"default_value": 0.4
},
"machine_nozzle_offset_x": {
"default_value": 0.0
},
"machine_nozzle_offset_y": {
"default_value": 0.0
},
"machine_extruder_start_pos_abs": {
"default_value": true
},
"machine_extruder_start_pos_x": {
"value": "prime_tower_position_x"
},
"machine_extruder_start_pos_y": {
"value": "prime_tower_position_y"
},
"machine_extruder_end_pos_abs": {
"default_value": true
},
"machine_extruder_end_pos_x": {
"value": "prime_tower_position_x"
},
"machine_extruder_end_pos_y": {
"value": "prime_tower_position_y"
}
}
"version": 2,
"name": "Extruder 2",
"inherits": "fdmextruder",
"metadata": {
"machine": "bibo2_dual",
"position": "1"
},
"overrides": {
"extruder_nr": {
"default_value": 1,
"maximum_value": "1"
},
"material_diameter": {
"default_value": 1.75
},
"machine_nozzle_size": {
"default_value": 0.4
},
"machine_nozzle_offset_x": {
"default_value": 0.0
},
"machine_nozzle_offset_y": {
"default_value": 0.0
},
"machine_extruder_start_pos_abs": {
"default_value": true
},
"machine_extruder_start_pos_x": {
"value": "prime_tower_position_x"
},
"machine_extruder_start_pos_y": {
"value": "prime_tower_position_y"
},
"machine_extruder_end_pos_abs": {
"default_value": true
},
"machine_extruder_end_pos_x": {
"value": "prime_tower_position_x"
},
"machine_extruder_end_pos_y": {
"value": "prime_tower_position_y"
}
}
}

View file

@ -3,7 +3,7 @@
"name": "Left Extruder",
"inherits": "fdmextruder",
"metadata": {
"machine": "Creality CR-X",
"machine": "creality_cr-x",
"position": "0"
},

View file

@ -3,7 +3,7 @@
"name": "Right Extruder",
"inherits": "fdmextruder",
"metadata": {
"machine": "Creality CR-X",
"machine": "creality_cr-x",
"position": "1"
},

View file

@ -3,7 +3,7 @@
"name": "Extruder 1",
"inherits": "fdmextruder",
"metadata": {
"machine": "Creatable_D3",
"machine": "creatable_d3",
"position": "0"
},

View file

@ -3,7 +3,7 @@
"name": "Extruder 1",
"inherits": "fdmextruder",
"metadata": {
"machine": "hellbot_magna_i",
"machine": "hellbot_magna_I",
"position": "0"
},

View file

@ -3,7 +3,7 @@
"name": "0.4mm Nozzle",
"inherits": "fdmextruder",
"metadata": {
"machine": "Tyro",
"machine": "key3d_tyro",
"position": "0"
},

View file

@ -6,7 +6,7 @@ definition = ultimaker_s3
[metadata]
setting_version = 10
type = intent
intent_category = smooth
intent_category = quick
quality_type = draft
material = generic_abs
variant = AA 0.4

View file

@ -1,17 +0,0 @@
[general]
version = 4
name = Visual
definition = ultimaker_s3
[metadata]
setting_version = 10
type = intent
intent_category = visual
quality_type = draft
material = generic_abs
variant = AA 0.4
[values]
speed_infill = 50
wall_thickness = =wall_line_width * 3
top_bottom_thickness = =wall_thickness

View file

@ -6,7 +6,7 @@ definition = ultimaker_s3
[metadata]
setting_version = 10
type = intent
intent_category = smooth
intent_category = quick
quality_type = draft
material = generic_pla
variant = AA 0.4

View file

@ -1,17 +0,0 @@
[general]
version = 4
name = Visual
definition = ultimaker_s3
[metadata]
setting_version = 10
type = intent
quality_type = draft
intent_category = visual
material = generic_pla
variant = AA 0.4
[values]
speed_infill = 50
wall_thickness = =wall_line_width * 3
top_bottom_thickness = =wall_thickness

View file

@ -6,7 +6,7 @@ definition = ultimaker_s3
[metadata]
setting_version = 10
type = intent
intent_category = smooth
intent_category = quick
quality_type = draft
material = generic_tough_pla
variant = AA 0.4

View file

@ -1,17 +0,0 @@
[general]
version = 4
name = Visual
definition = ultimaker_s3
[metadata]
setting_version = 10
type = intent
quality_type = draft
intent_category = visual
material = generic_tough_pla
variant = AA 0.4
[values]
speed_infill = 50
wall_thickness = =wall_line_width * 3
top_bottom_thickness = =wall_thickness

View file

@ -6,7 +6,7 @@ definition = ultimaker_s5
[metadata]
setting_version = 10
type = intent
intent_category = smooth
intent_category = quick
quality_type = draft
material = generic_abs
variant = AA 0.4

View file

@ -1,16 +0,0 @@
[general]
version = 4
name = Visual
definition = ultimaker_s5
[metadata]
setting_version = 10
type = intent
intent_category = visualquality_type = draft
material = generic_abs
variant = AA 0.4
[values]
speed_infill = 50
wall_thickness = =wall_line_width * 3
top_bottom_thickness = =wall_thickness

View file

@ -6,7 +6,7 @@ definition = ultimaker_s5
[metadata]
setting_version = 10
type = intent
intent_category = smooth
intent_category = quick
quality_type = draft
material = generic_pla
variant = AA 0.4

View file

@ -1,17 +0,0 @@
[general]
version = 4
name = Visual
definition = ultimaker_s5
[metadata]
setting_version = 10
type = intent
quality_type = draft
intent_category = visual
material = generic_pla
variant = AA 0.4
[values]
speed_infill = 50
wall_thickness = =wall_line_width * 3
top_bottom_thickness = =wall_thickness

View file

@ -6,7 +6,7 @@ definition = ultimaker_s5
[metadata]
setting_version = 10
type = intent
intent_category = smooth
intent_category = quick
quality_type = draft
material = generic_tough_pla
variant = AA 0.4

View file

@ -1,16 +0,0 @@
[general]
version = 4
name = Visual
definition = ultimaker_s5
[metadata]
setting_version = 10
type = intent
intent_category = visual
material = generic_tough_pla
variant = AA 0.4
[values]
speed_infill = 50
wall_thickness = =wall_line_width * 3
top_bottom_thickness = =wall_thickness

View file

@ -124,18 +124,6 @@ Item
elide: Text.ElideRight
}
NoIntentIcon
{
affected_extruders: Cura.MachineManager.extruderPositionsWithNonActiveIntent
intent_type: model.name
anchors.right: intentCategoryLabel.right
anchors.rightMargin: UM.Theme.getSize("narrow_margin").width
width: intentCategoryLabel.height * 0.75
anchors.verticalCenter: parent.verticalCenter
height: width
visible: Cura.MachineManager.activeIntentCategory == model.intent_category && affected_extruders.length
}
Cura.RadioCheckbar
{
anchors
@ -164,8 +152,9 @@ Item
isCheckedFunction: checkedFunction
}
MouseArea // tooltip hover area
MouseArea // Intent description tooltip hover area
{
id: intentDescriptionHoverArea
anchors.fill: parent
hoverEnabled: true
enabled: model.description !== undefined
@ -181,6 +170,20 @@ Item
}
onExited: base.hideTooltip()
}
NoIntentIcon // This icon has hover priority over intentDescriptionHoverArea, so draw it above it.
{
affected_extruders: Cura.MachineManager.extruderPositionsWithNonActiveIntent
intent_type: model.name
anchors.right: intentCategoryLabel.right
anchors.rightMargin: UM.Theme.getSize("narrow_margin").width
width: intentCategoryLabel.height * 0.75
anchors.verticalCenter: parent.verticalCenter
height: width
visible: Cura.MachineManager.activeIntentCategory == model.intent_category && affected_extruders.length
}
}
}

View file

@ -137,38 +137,17 @@ def test_materialAdded_update(container_registry, machine_node, metadata, change
def test_preferredMaterialExactMatch(empty_variant_node):
empty_variant_node.materials = {
"some_different_material": MagicMock(getMetaDataEntry = lambda x: 3),
"preferred_material_base_file": MagicMock(getMetaDataEntry = lambda x: 3) # Exact match.
"preferred_material": MagicMock(getMetaDataEntry = lambda x: 3) # Exact match.
}
assert empty_variant_node.preferredMaterial(approximate_diameter = 3) == empty_variant_node.materials["preferred_material_base_file"], "It should match exactly on this one since it's the preferred material."
## Tests the preferred material when a submaterial is available in the
# materials list for this node.
def test_preferredMaterialSubmaterial(empty_variant_node):
empty_variant_node.materials = {
"some_different_material": MagicMock(getMetaDataEntry = lambda x: 3),
"preferred_material_base_file_aa04": MagicMock(getMetaDataEntry = lambda x: 3) # This is a submaterial of the preferred material.
}
assert empty_variant_node.preferredMaterial(approximate_diameter = 3) == empty_variant_node.materials["preferred_material_base_file_aa04"], "It should match on the submaterial just as well."
## Tests the preferred material matching on the approximate diameter of the
# filament.
def test_preferredMaterialDiameter(empty_variant_node):
empty_variant_node.materials = {
"some_different_material": MagicMock(getMetaDataEntry = lambda x: 3),
"preferred_material_wrong_diameter": MagicMock(getMetaDataEntry = lambda x: 2), # Approximate diameter is 2 instead of 3.
"preferred_material_correct_diameter": MagicMock(getMetaDataEntry = lambda x: 3) # Correct approximate diameter.
}
assert empty_variant_node.preferredMaterial(approximate_diameter = 3) == empty_variant_node.materials["preferred_material_correct_diameter"], "It should match only on the material with correct diameter."
assert empty_variant_node.preferredMaterial(approximate_diameter = 3) == empty_variant_node.materials["preferred_material"], "It should match exactly on this one since it's the preferred material."
## Tests the preferred material matching on a different material if the
# diameter is wrong.
def test_preferredMaterialDiameterNoMatch(empty_variant_node):
empty_variant_node.materials = collections.OrderedDict()
empty_variant_node.materials["some_different_material"] = MagicMock(getMetaDataEntry = lambda x: 3) # This one first so that it gets iterated over first.
empty_variant_node.materials["preferred_material_wrong_diameter"] = MagicMock(getMetaDataEntry = lambda x: 2)
empty_variant_node.materials["preferred_material"] = MagicMock(getMetaDataEntry = lambda x: 2) # Wrong diameter.
assert empty_variant_node.preferredMaterial(approximate_diameter = 3) == empty_variant_node.materials["some_different_material"], "It should match on another material with the correct diameter if the preferred one is unavailable."
@ -177,7 +156,7 @@ def test_preferredMaterialDiameterNoMatch(empty_variant_node):
def test_preferredMaterialDiameterPreference(empty_variant_node):
empty_variant_node.materials = collections.OrderedDict()
empty_variant_node.materials["some_different_material"] = MagicMock(getMetaDataEntry = lambda x: 2) # This one first so that it gets iterated over first.
empty_variant_node.materials["preferred_material_wrong_diameter"] = MagicMock(getMetaDataEntry = lambda x: 2) # Matches on ID but not diameter.
empty_variant_node.materials["preferred_material"] = MagicMock(getMetaDataEntry = lambda x: 2) # Matches on ID but not diameter.
empty_variant_node.materials["not_preferred_but_correct_diameter"] = MagicMock(getMetaDataEntry = lambda x: 3) # Matches diameter but not ID.
assert empty_variant_node.preferredMaterial(approximate_diameter = 3) == empty_variant_node.materials["not_preferred_but_correct_diameter"], "It should match on the correct diameter even if it's not the preferred one."

View file

@ -17,6 +17,10 @@ Resources.addSearchPath(os.path.abspath(os.path.join(os.path.dirname(__file__),
machine_filepaths = sorted(os.listdir(os.path.join(os.path.dirname(__file__), "..", "..", "resources", "definitions")))
machine_filepaths = [os.path.join(os.path.dirname(__file__), "..", "..", "resources", "definitions", filename) for filename in machine_filepaths]
extruder_filepaths = sorted(os.listdir(os.path.join(os.path.dirname(__file__), "..", "..", "resources", "extruders")))
extruder_filepaths = [os.path.join(os.path.dirname(__file__), "..", "..", "resources", "extruders", filename) for filename in extruder_filepaths]
definition_filepaths = machine_filepaths + extruder_filepaths
all_meshes = os.listdir(os.path.join(os.path.dirname(__file__), "..", "..", "resources", "meshes"))
all_images = os.listdir(os.path.join(os.path.dirname(__file__), "..", "..", "resources", "images"))
@ -29,17 +33,16 @@ def definition_container():
## Tests all definition containers
@pytest.mark.parametrize("file_name", machine_filepaths)
def test_validateMachineDefinitionContainer(file_name, definition_container):
@pytest.mark.parametrize("file_path", machine_filepaths)
def test_validateMachineDefinitionContainer(file_path, definition_container):
file_name = os.path.basename(file_path)
if file_name == "fdmprinter.def.json" or file_name == "fdmextruder.def.json":
return # Stop checking, these are root files.
definition_path = os.path.join(os.path.dirname(__file__), "..", "..", "resources", "definitions")
assertIsDefinitionValid(definition_container, definition_path, file_name)
assertIsDefinitionValid(definition_container, file_path)
def assertIsDefinitionValid(definition_container, path, file_name):
with open(os.path.join(path, file_name), encoding = "utf-8") as data:
def assertIsDefinitionValid(definition_container, file_path):
with open(file_path, encoding = "utf-8") as data:
json = data.read()
parser, is_valid = definition_container.readAndValidateSerialized(json)
assert is_valid #The definition has invalid JSON structure.
@ -57,10 +60,9 @@ def assertIsDefinitionValid(definition_container, path, file_name):
# When a definition container defines a "default_value" but inherits from a
# definition that defines a "value", the "default_value" is ineffective. This
# test fails on those things.
@pytest.mark.parametrize("file_name", machine_filepaths)
def test_validateOverridingDefaultValue(file_name: str):
definition_path = os.path.join(os.path.dirname(__file__), "..", "..", "resources", "definitions", file_name)
with open(definition_path, encoding = "utf-8") as f:
@pytest.mark.parametrize("file_path", definition_filepaths)
def test_validateOverridingDefaultValue(file_path: str):
with open(file_path, encoding = "utf-8") as f:
doc = json.load(f)
if "inherits" not in doc:
@ -69,8 +71,8 @@ def test_validateOverridingDefaultValue(file_name: str):
return # No settings are being overridden. No need to check anything.
parent_settings = getInheritedSettings(doc["inherits"])
for key, val in doc["overrides"].items():
if "value" in parent_settings[key]:
assert "default_value" not in val, "Unnecessary default_value for {key} in {file_name}".format(key = key, file_name = file_name) # If there is a value in the parent settings, then the default_value is not effective.
if key in parent_settings and "value" in parent_settings[key]:
assert "default_value" not in val, "Unnecessary default_value for {key} in {file_name}".format(key = key, file_name = file_path) # If there is a value in the parent settings, then the default_value is not effective.
## Get all settings and their properties from a definition we're inheriting
# from.
@ -130,10 +132,46 @@ def merge_dicts(base: Dict[str, Any], overrides: Dict[str, Any]) -> Dict[str, An
#
# ID fields are legacy. They should not be used any more. This is legacy that
# people don't seem to be able to get used to.
@pytest.mark.parametrize("file_name", machine_filepaths)
def test_noId(file_name):
definition_path = os.path.join(os.path.dirname(__file__), "..", "..", "resources", "definitions", file_name)
with open(definition_path, encoding = "utf-8") as f:
@pytest.mark.parametrize("file_path", definition_filepaths)
def test_noId(file_path: str):
with open(file_path, encoding = "utf-8") as f:
doc = json.load(f)
assert "id" not in doc, "Definitions should not have an ID field."
assert "id" not in doc, "Definitions should not have an ID field."
## Verifies that extruders say that they work on the same extruder_nr as what
# is listed in their machine definition.
@pytest.mark.parametrize("file_path", extruder_filepaths)
def test_extruderMatch(file_path: str):
extruder_id = os.path.basename(file_path).split(".")[0]
with open(file_path, encoding = "utf-8") as f:
doc = json.load(f)
if "metadata" not in doc:
return # May not be desirable either, but it's probably unfinished then.
if "machine" not in doc["metadata"] or "position" not in doc["metadata"]:
return # FDMextruder doesn't have this since it's not linked to a particular printer.
machine = doc["metadata"]["machine"]
position = doc["metadata"]["position"]
# Find the machine definition.
for machine_filepath in machine_filepaths:
machine_id = os.path.basename(machine_filepath).split(".")[0]
if machine_id == machine:
break
else:
assert False, "The machine ID {machine} is not found.".format(machine = machine)
with open(machine_filepath, encoding = "utf-8") as f:
machine_doc = json.load(f)
# Make sure that the two match up.
assert "metadata" in machine_doc, "Machine definition missing metadata entry."
assert "machine_extruder_trains" in machine_doc["metadata"], "Machine must define extruder trains."
extruder_trains = machine_doc["metadata"]["machine_extruder_trains"]
assert position in extruder_trains, "There must be a reference to the extruder in the machine definition."
assert extruder_trains[position] == extruder_id, "The extruder referenced in the machine definition must match up."
# Also test if the extruder_nr setting is properly overridden.
if "overrides" not in doc or "extruder_nr" not in doc["overrides"] or "default_value" not in doc["overrides"]["extruder_nr"]:
assert position == "0" # Default to 0 is allowed.
assert doc["overrides"]["extruder_nr"]["default_value"] == int(position)