mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-06 14:37:29 -06:00
Convert doxygen to rst for GcodeWriter, LegacyProfileReader,
MachineSettingsAction, ModelChecker
This commit is contained in:
parent
40327c4259
commit
553b09b6cf
5 changed files with 117 additions and 87 deletions
|
@ -14,34 +14,40 @@ from cura.Machines.ContainerTree import ContainerTree
|
|||
from UM.i18n import i18nCatalog
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
## Writes g-code to a file.
|
||||
#
|
||||
# While this poses as a mesh writer, what this really does is take the g-code
|
||||
# in the entire scene and write it to an output device. Since the g-code of a
|
||||
# single mesh isn't separable from the rest what with rafts and travel moves
|
||||
# and all, it doesn't make sense to write just a single mesh.
|
||||
#
|
||||
# So this plug-in takes the g-code that is stored in the root of the scene
|
||||
# node tree, adds a bit of extra information about the profiles and writes
|
||||
# that to the output device.
|
||||
class GCodeWriter(MeshWriter):
|
||||
## The file format version of the serialised g-code.
|
||||
#
|
||||
# It can only read settings with the same version as the version it was
|
||||
# written with. If the file format is changed in a way that breaks reverse
|
||||
# compatibility, increment this version number!
|
||||
version = 3
|
||||
|
||||
## Dictionary that defines how characters are escaped when embedded in
|
||||
# g-code.
|
||||
#
|
||||
# Note that the keys of this dictionary are regex strings. The values are
|
||||
# not.
|
||||
class GCodeWriter(MeshWriter):
|
||||
"""Writes g-code to a file.
|
||||
|
||||
While this poses as a mesh writer, what this really does is take the g-code
|
||||
in the entire scene and write it to an output device. Since the g-code of a
|
||||
single mesh isn't separable from the rest what with rafts and travel moves
|
||||
and all, it doesn't make sense to write just a single mesh.
|
||||
|
||||
So this plug-in takes the g-code that is stored in the root of the scene
|
||||
node tree, adds a bit of extra information about the profiles and writes
|
||||
that to the output device.
|
||||
"""
|
||||
|
||||
version = 3
|
||||
"""The file format version of the serialised g-code.
|
||||
|
||||
It can only read settings with the same version as the version it was
|
||||
written with. If the file format is changed in a way that breaks reverse
|
||||
compatibility, increment this version number!
|
||||
"""
|
||||
|
||||
escape_characters = {
|
||||
re.escape("\\"): "\\\\", # The escape character.
|
||||
re.escape("\n"): "\\n", # Newlines. They break off the comment.
|
||||
re.escape("\r"): "\\r" # Carriage return. Windows users may need this for visualisation in their editors.
|
||||
}
|
||||
"""Dictionary that defines how characters are escaped when embedded in
|
||||
|
||||
g-code.
|
||||
|
||||
Note that the keys of this dictionary are regex strings. The values are
|
||||
not.
|
||||
"""
|
||||
|
||||
_setting_keyword = ";SETTING_"
|
||||
|
||||
|
@ -50,17 +56,19 @@ class GCodeWriter(MeshWriter):
|
|||
|
||||
self._application = Application.getInstance()
|
||||
|
||||
## Writes the g-code for the entire scene to a stream.
|
||||
#
|
||||
# Note that even though the function accepts a collection of nodes, the
|
||||
# entire scene is always written to the file since it is not possible to
|
||||
# separate the g-code for just specific nodes.
|
||||
#
|
||||
# \param stream The stream to write the g-code to.
|
||||
# \param nodes This is ignored.
|
||||
# \param mode Additional information on how to format the g-code in the
|
||||
# file. This must always be text mode.
|
||||
def write(self, stream, nodes, mode = MeshWriter.OutputMode.TextMode):
|
||||
"""Writes the g-code for the entire scene to a stream.
|
||||
|
||||
Note that even though the function accepts a collection of nodes, the
|
||||
entire scene is always written to the file since it is not possible to
|
||||
separate the g-code for just specific nodes.
|
||||
|
||||
:param stream: The stream to write the g-code to.
|
||||
:param nodes: This is ignored.
|
||||
:param mode: Additional information on how to format the g-code in the
|
||||
file. This must always be text mode.
|
||||
"""
|
||||
|
||||
if mode != MeshWriter.OutputMode.TextMode:
|
||||
Logger.log("e", "GCodeWriter does not support non-text mode.")
|
||||
self.setInformation(catalog.i18nc("@error:not supported", "GCodeWriter does not support non-text mode."))
|
||||
|
@ -88,8 +96,9 @@ class GCodeWriter(MeshWriter):
|
|||
self.setInformation(catalog.i18nc("@warning:status", "Please prepare G-code before exporting."))
|
||||
return False
|
||||
|
||||
## Create a new container with container 2 as base and container 1 written over it.
|
||||
def _createFlattenedContainerInstance(self, instance_container1, instance_container2):
|
||||
"""Create a new container with container 2 as base and container 1 written over it."""
|
||||
|
||||
flat_container = InstanceContainer(instance_container2.getName())
|
||||
|
||||
# The metadata includes id, name and definition
|
||||
|
@ -106,15 +115,15 @@ class GCodeWriter(MeshWriter):
|
|||
|
||||
return flat_container
|
||||
|
||||
## Serialises a container stack to prepare it for writing at the end of the
|
||||
# g-code.
|
||||
#
|
||||
# The settings are serialised, and special characters (including newline)
|
||||
# are escaped.
|
||||
#
|
||||
# \param settings A container stack to serialise.
|
||||
# \return A serialised string of the settings.
|
||||
def _serialiseSettings(self, stack):
|
||||
"""Serialises a container stack to prepare it for writing at the end of the g-code.
|
||||
|
||||
The settings are serialised, and special characters (including newline)
|
||||
are escaped.
|
||||
|
||||
:param stack: A container stack to serialise.
|
||||
:return: A serialised string of the settings.
|
||||
"""
|
||||
container_registry = self._application.getContainerRegistry()
|
||||
|
||||
prefix = self._setting_keyword + str(GCodeWriter.version) + " " # The prefix to put before each line.
|
||||
|
|
|
@ -16,58 +16,67 @@ from UM.Settings.InstanceContainer import InstanceContainer # The new profile t
|
|||
from cura.ReaderWriters.ProfileReader import ProfileReader # The plug-in type to implement.
|
||||
|
||||
|
||||
## A plugin that reads profile data from legacy Cura versions.
|
||||
#
|
||||
# It reads a profile from an .ini file, and performs some translations on it.
|
||||
# Not all translations are correct, mind you, but it is a best effort.
|
||||
class LegacyProfileReader(ProfileReader):
|
||||
## Initialises the legacy profile reader.
|
||||
#
|
||||
# This does nothing since the only other function is basically stateless.
|
||||
"""A plugin that reads profile data from legacy Cura versions.
|
||||
|
||||
It reads a profile from an .ini file, and performs some translations on it.
|
||||
Not all translations are correct, mind you, but it is a best effort.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialises the legacy profile reader.
|
||||
|
||||
This does nothing since the only other function is basically stateless.
|
||||
"""
|
||||
|
||||
super().__init__()
|
||||
|
||||
## Prepares the default values of all legacy settings.
|
||||
#
|
||||
# These are loaded from the Dictionary of Doom.
|
||||
#
|
||||
# \param json The JSON file to load the default setting values from. This
|
||||
# should not be a URL but a pre-loaded JSON handle.
|
||||
# \return A dictionary of the default values of the legacy Cura version.
|
||||
def prepareDefaults(self, json: Dict[str, Dict[str, str]]) -> Dict[str, str]:
|
||||
"""Prepares the default values of all legacy settings.
|
||||
|
||||
These are loaded from the Dictionary of Doom.
|
||||
|
||||
:param json: The JSON file to load the default setting values from. This
|
||||
should not be a URL but a pre-loaded JSON handle.
|
||||
:return: A dictionary of the default values of the legacy Cura version.
|
||||
"""
|
||||
|
||||
defaults = {}
|
||||
if "defaults" in json:
|
||||
for key in json["defaults"]: # We have to copy over all defaults from the JSON handle to a normal dict.
|
||||
defaults[key] = json["defaults"][key]
|
||||
return defaults
|
||||
|
||||
## Prepares the local variables that can be used in evaluation of computing
|
||||
# new setting values from the old ones.
|
||||
#
|
||||
# This fills a dictionary with all settings from the legacy Cura version
|
||||
# and their values, so that they can be used in evaluating the new setting
|
||||
# values as Python code.
|
||||
#
|
||||
# \param config_parser The ConfigParser that finds the settings in the
|
||||
# legacy profile.
|
||||
# \param config_section The section in the profile where the settings
|
||||
# should be found.
|
||||
# \param defaults The default values for all settings in the legacy Cura.
|
||||
# \return A set of local variables, one for each setting in the legacy
|
||||
# profile.
|
||||
def prepareLocals(self, config_parser, config_section, defaults):
|
||||
"""Prepares the local variables that can be used in evaluation of computing
|
||||
|
||||
new setting values from the old ones.
|
||||
|
||||
This fills a dictionary with all settings from the legacy Cura version
|
||||
and their values, so that they can be used in evaluating the new setting
|
||||
values as Python code.
|
||||
|
||||
:param config_parser: The ConfigParser that finds the settings in the
|
||||
legacy profile.
|
||||
:param config_section: The section in the profile where the settings
|
||||
should be found.
|
||||
:param defaults: The default values for all settings in the legacy Cura.
|
||||
:return: A set of local variables, one for each setting in the legacy
|
||||
profile.
|
||||
"""
|
||||
copied_locals = defaults.copy() # Don't edit the original!
|
||||
for option in config_parser.options(config_section):
|
||||
copied_locals[option] = config_parser.get(config_section, option)
|
||||
return copied_locals
|
||||
|
||||
## Reads a legacy Cura profile from a file and returns it.
|
||||
#
|
||||
# \param file_name The file to read the legacy Cura profile from.
|
||||
# \return The legacy Cura profile that was in the file, if any. If the
|
||||
# file could not be read or didn't contain a valid profile, \code None
|
||||
# \endcode is returned.
|
||||
def read(self, file_name):
|
||||
"""Reads a legacy Cura profile from a file and returns it.
|
||||
|
||||
:param file_name: The file to read the legacy Cura profile from.
|
||||
:return: The legacy Cura profile that was in the file, if any. If the
|
||||
file could not be read or didn't contain a valid profile, None is returned.
|
||||
"""
|
||||
|
||||
if file_name.split(".")[-1] != "ini":
|
||||
return None
|
||||
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
||||
|
|
|
@ -13,7 +13,7 @@ import UM.PluginRegistry # To mock the plug-in registry out.
|
|||
import UM.Settings.ContainerRegistry # To mock the container registry out.
|
||||
import UM.Settings.InstanceContainer # To intercept the serialised data from the read() function.
|
||||
|
||||
import LegacyProfileReader as LegacyProfileReaderModule # To get the directory of the module.
|
||||
import LegacyProfileReader as LegacyProfileReaderModule # To get the directory of the module.
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -126,9 +126,11 @@ test_prepareLocalsNoSectionErrorData = [
|
|||
)
|
||||
]
|
||||
|
||||
## Test cases where a key error is expected.
|
||||
|
||||
@pytest.mark.parametrize("parser_data, defaults", test_prepareLocalsNoSectionErrorData)
|
||||
def test_prepareLocalsNoSectionError(legacy_profile_reader, parser_data, defaults):
|
||||
"""Test cases where a key error is expected."""
|
||||
|
||||
parser = configparser.ConfigParser()
|
||||
parser.read_dict(parser_data)
|
||||
|
||||
|
|
|
@ -23,9 +23,11 @@ if TYPE_CHECKING:
|
|||
catalog = UM.i18n.i18nCatalog("cura")
|
||||
|
||||
|
||||
## This action allows for certain settings that are "machine only") to be modified.
|
||||
# It automatically detects machine definitions that it knows how to change and attaches itself to those.
|
||||
class MachineSettingsAction(MachineAction):
|
||||
"""This action allows for certain settings that are "machine only") to be modified.
|
||||
|
||||
It automatically detects machine definitions that it knows how to change and attaches itself to those.
|
||||
"""
|
||||
def __init__(self, parent: Optional["QObject"] = None) -> None:
|
||||
super().__init__("MachineSettingsAction", catalog.i18nc("@action", "Machine Settings"))
|
||||
self._qml_url = "MachineSettingsAction.qml"
|
||||
|
@ -56,9 +58,11 @@ class MachineSettingsAction(MachineAction):
|
|||
if isinstance(container, DefinitionContainer) and container.getMetaDataEntry("type") == "machine":
|
||||
self._application.getMachineActionManager().addSupportedAction(container.getId(), self.getKey())
|
||||
|
||||
## Triggered when the global container stack changes or when the g-code
|
||||
# flavour setting is changed.
|
||||
def _updateHasMaterialsInContainerTree(self) -> None:
|
||||
"""Triggered when the global container stack changes or when the g-code
|
||||
|
||||
flavour setting is changed.
|
||||
"""
|
||||
global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack()
|
||||
if global_stack is None:
|
||||
return
|
||||
|
|
|
@ -18,8 +18,8 @@ catalog = i18nCatalog("cura")
|
|||
|
||||
|
||||
class ModelChecker(QObject, Extension):
|
||||
## Signal that gets emitted when anything changed that we need to check.
|
||||
onChanged = pyqtSignal()
|
||||
"""Signal that gets emitted when anything changed that we need to check."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
@ -47,11 +47,13 @@ class ModelChecker(QObject, Extension):
|
|||
if not isinstance(args[0], Camera):
|
||||
self._change_timer.start()
|
||||
|
||||
## Called when plug-ins are initialized.
|
||||
#
|
||||
# This makes sure that we listen to changes of the material and that the
|
||||
# button is created that indicates warnings with the current set-up.
|
||||
def _pluginsInitialized(self):
|
||||
"""Called when plug-ins are initialized.
|
||||
|
||||
This makes sure that we listen to changes of the material and that the
|
||||
button is created that indicates warnings with the current set-up.
|
||||
"""
|
||||
|
||||
Application.getInstance().getMachineManager().rootMaterialChanged.connect(self.onChanged)
|
||||
self._createView()
|
||||
|
||||
|
@ -106,8 +108,12 @@ class ModelChecker(QObject, Extension):
|
|||
if node.callDecoration("isSliceable"):
|
||||
yield node
|
||||
|
||||
## Creates the view used by show popup. The view is saved because of the fairly aggressive garbage collection.
|
||||
def _createView(self):
|
||||
"""Creates the view used by show popup.
|
||||
|
||||
The view is saved because of the fairly aggressive garbage collection.
|
||||
"""
|
||||
|
||||
Logger.log("d", "Creating model checker view.")
|
||||
|
||||
# Create the plugin dialog component
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue