Add python function to import parameters from file.
Add test for checking importing parameters.
Add "Import file" button in parameter manager to import parameters.
Update documentation.
aLoop->registerListener(this, ModelAPI_ParameterEvalMessage::eventId(), NULL, true);
aLoop->registerListener(this, ModelAPI_BuildEvalMessage::eventId(), NULL, true);
aLoop->registerListener(this, ModelAPI_ComputePositionsMessage::eventId(), NULL, true);
+ aLoop->registerListener(this, ModelAPI_ImportParametersMessage::eventId(), NULL, true);
myInterp = std::shared_ptr<InitializationPlugin_PyInterp>(new InitializationPlugin_PyInterp());
myInterp->initialize();
}
aMsg->setResults(aParamsList, anError);
}
+ else if (theMessage->eventID() == ModelAPI_ImportParametersMessage::eventId())
+ {
+ std::shared_ptr<ModelAPI_ImportParametersMessage> aMsg =
+ std::dynamic_pointer_cast<ModelAPI_ImportParametersMessage>(theMessage);
+ std::string anImportScript("from salome.shaper import model;");
+ std::string aDocScript("doc = model.activeDocument();");
+ std::string anParamImpScript("model.importParameters(doc, \"");
+ std::string aPath = aMsg->filename();
+ myInterp->runString(anImportScript + aDocScript + anParamImpScript + aPath + "\")");
+ }
}
//=================================================================================================
return myError;
}
+/// Creates an empty message
+ModelAPI_ImportParametersMessage::ModelAPI_ImportParametersMessage(const Events_ID theID, const void* theSender)
+ :Events_Message(theID, theSender)
+{
+
+}
+
+ModelAPI_ImportParametersMessage::~ModelAPI_ImportParametersMessage()
+{
+}
+
+std::string ModelAPI_ImportParametersMessage::filename() const
+{
+ return myFilename;
+}
+
+void ModelAPI_ImportParametersMessage::setFilename(std::string theFilename)
+{
+ myFilename = theFilename;
+}
+
ModelAPI_BuildEvalMessage::ModelAPI_BuildEvalMessage(
const Events_ID theID, const void* theSender)
: Events_Message(theID, theSender), myIsProcessed(false)
MODELAPI_EXPORT const std::string& error() const;
};
+class ModelAPI_ImportParametersMessage : public Events_Message
+{
+ std::string myFilename; ///< filename where where parameters are stored
+ std::string myError; ///< error of processing, empty if there is no error
+
+public:
+ /// Static. Returns EventID of the message.
+ MODELAPI_EXPORT static Events_ID& eventId()
+ {
+ static const char* MY_PARAMETER_EVALUATION_EVENT_ID("ImportParametersMessage");
+ static Events_ID anId = Events_Loop::eventByName(MY_PARAMETER_EVALUATION_EVENT_ID);
+ return anId;
+ }
+
+ /// Useful method that creates and sends the event.
+ /// Returns the message, processed, with the resulting fields filled.
+ MODELAPI_EXPORT static std::shared_ptr<ModelAPI_ImportParametersMessage>
+ send(std::string theParameter, const void* theSender)
+ {
+ std::shared_ptr<ModelAPI_ImportParametersMessage> aMessage =
+ std::shared_ptr<ModelAPI_ImportParametersMessage>(
+ new ModelAPI_ImportParametersMessage(eventId(), theSender));
+ aMessage->setFilename(theParameter);
+ Events_Loop::loop()->send(aMessage);
+ return aMessage;
+ }
+
+ /// Creates an empty message
+ MODELAPI_EXPORT ModelAPI_ImportParametersMessage(const Events_ID theID, const void* theSender = 0);
+ /// The virtual destructor
+ MODELAPI_EXPORT virtual ~ModelAPI_ImportParametersMessage();
+
+ /// Returns a filename stored in the message
+ MODELAPI_EXPORT std::string filename() const;
+ /// Sets a filename to the message
+ MODELAPI_EXPORT void setFilename(std::string theFilename);
+};
+
class ModelAPI_BuildEvalMessage : public Events_Message
{
FeaturePtr myParam; ///< parameters that should be evaluated
ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
const std::shared_ptr<ModelAPI_AttributeString>& theAttrStr)
{
- *myDumpStorage << "\"" << theAttrStr->value() << "\"";
+ // escaping the quote sign in the string under dumping
+ std::string aStr = theAttrStr->value();
+ size_t aPos = aStr.find("\"");
+ while (aPos != std::string::npos) {
+ aStr.insert(aPos, "\\");
+ aPos = aStr.find("\"", aPos + 2);
+ }
+ *myDumpStorage << "'" << aStr << "'";
return *this;
}
theAttribute->setValue(theValue);
}
+//--------------------------------------------------------------------------------------
+void fillAttribute(const std::wstring & theValue,
+ const std::shared_ptr<ModelAPI_AttributeString> & theAttribute)
+{
+ theAttribute->setValue(theValue);
+}
+
//--------------------------------------------------------------------------------------
void fillAttribute(const char * theValue,
const std::shared_ptr<ModelAPI_AttributeString> & theAttribute)
MODELHIGHAPI_EXPORT
void fillAttribute(const std::string & theValue,
const std::shared_ptr<ModelAPI_AttributeString> & theAttribute);
+
+MODELHIGHAPI_EXPORT
+void fillAttribute(const std::wstring & theValue,
+ const std::shared_ptr<ModelAPI_AttributeString> & theAttribute);
+
MODELHIGHAPI_EXPORT
void fillAttribute(const char * theValue,
const std::shared_ptr<ModelAPI_AttributeString> & theAttribute);
%{
#include "ParametersAPI_swig.h"
+
+ // fix for SWIG v2.0.4
+ #define SWIGPY_SLICE_ARG(obj) ((PyObject*)(obj))
+
+ #define SWIGPY_UNICODE_ARG(obj) ((PyObject*) (obj))
%}
%include "doxyhelp.i"
// shared pointers
%shared_ptr(ParametersAPI_Parameter)
+// exception handler
+%exception addParameter {
+ try {
+ $action
+ } catch (const std::string& str) {
+ PyErr_SetString(PyExc_SyntaxError, str.c_str());
+ return NULL;
+ }
+}
+
// all supported interfaces
%include "ParametersAPI_Parameter.h"
const std::shared_ptr<ModelAPI_Feature> & theFeature,
const std::string & theName,
const std::string & theExpression,
- const std::string & theComment)
+ const std::wstring & theComment)
: ModelHighAPI_Interface(theFeature)
{
if (initialize()) {
ParameterPtr addParameter(const std::shared_ptr<ModelAPI_Document> & thePart,
const std::string & theName,
const std::string & theExpression,
- const std::string & theComment)
+ const std::wstring & theComment)
{
std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(ParametersAPI_Parameter::ID());
- return ParameterPtr(new ParametersAPI_Parameter(aFeature, theName, theExpression, theComment));
+ ParameterPtr aParam(new ParametersAPI_Parameter(aFeature, theName, theExpression, theComment));
+
+ if (!aParam->feature()->error().empty())
+ {
+ std::string anError("Error with parameter \"");
+ anError += theName + "\": " + aParam->feature()->error();
+ throw anError;
+ }
+ return aParam;
}
//--------------------------------------------------------------------------------------
explicit ParametersAPI_Parameter(const std::shared_ptr<ModelAPI_Feature> & theFeature,
const std::string & theName,
const std::string & theExpression,
- const std::string & theComment = std::string());
+ const std::wstring & theComment = std::wstring());
/// Destructor
PARAMETERSAPI_EXPORT
virtual ~ParametersAPI_Parameter();
ParameterPtr addParameter(const std::shared_ptr<ModelAPI_Document> & thePart,
const std::string & theName,
const std::string & theExpression,
- const std::string & theComment = std::string());
+ const std::wstring & theComment = std::wstring());
/**\ingroup CPPHighAPI
* \brief Remove Parameter feature and substitute it by the value in referred features
endforeach(tfile ${TEST_NAMES})
install(FILES ${TMP_TESTS_NAMES} DESTINATION ${TEST_INSTALL_DIRECTORY})
+ install(DIRECTORY Test/data DESTINATION ${TEST_INSTALL_DIRECTORY})
endif(${HAVE_SALOME})
#include <QKeyEvent>
#include <QDialogButtonBox>
#include <QShortcut>
+#include <QFileDialog>
enum ColumnType {
Col_Name,
connect(myInsertBtn, SIGNAL(clicked(bool)), SLOT(onInsert()));
aBtnLayout->addWidget(myInsertBtn);
+ myImportBtn = new QPushButton(translate("Import file"), this);
+ connect(myImportBtn, SIGNAL(clicked(bool)), SLOT(onImport()));
+ aBtnLayout->addWidget(myImportBtn);
+
myRemoveBtn = new QPushButton(translate("Remove"), this);
connect(myRemoveBtn, SIGNAL(clicked(bool)), SLOT(onRemove()));
aBtnLayout->addWidget(myRemoveBtn);
FeaturePtr aFeature = myParametersList.at(myDelegate->editIndex().row());
QTreeWidgetItem* aItem = myParameters->child(myDelegate->editIndex().row());
int aColumn = myDelegate->editIndex().column();
+ int aRow = myDelegate->editIndex().row();
QString aText = aItem->text(aColumn);
bool isModified = false;
while (aText.indexOf(" ") != -1) {
aText.replace(" ", "");
}
- if (hasName(aText)) {
+ if (hasName(aText, aRow)) {
myMessage = translate("Name '%1' already exists.").arg(aText);
QTimer::singleShot(50, this, SLOT(sendWarning()));
return;
case Col_Comment:
{
AttributeStringPtr aStringAttr = aFeature->string(ParametersPlugin_Parameter::COMMENT_ID());
- aStringAttr->setValue(aText.toStdString());
+ aStringAttr->setValue(aText.toStdWString());
isModified = true;
}
break;
}
}
+void ParametersPlugin_WidgetParamsMgr::onImport()
+{
+ std::string aWinText("Select txt file");
+ std::string aFileType("Text files (*.txt);;All files (*.*)");
+ QString aQPath = QFileDialog::getOpenFileName(nullptr,
+ aWinText.c_str(), "",
+ aFileType.c_str());
+ if (aQPath.size() == 0)
+ return;
+
+ std::string aPath(aQPath.toStdString());
+ std::shared_ptr<ModelAPI_ImportParametersMessage> aMessage =
+ std::shared_ptr<ModelAPI_ImportParametersMessage>(
+ new ModelAPI_ImportParametersMessage(ModelAPI_ImportParametersMessage::eventId()));
+ aMessage->setFilename(aPath);
+ Events_Loop::loop()->send(aMessage);
+
+ updateParametersFeatures();
+ updateParametersPart();
+}
+
void ParametersPlugin_WidgetParamsMgr::onUp()
{
QTreeWidgetItem* aCurrentItem = selectedItem();
}
-bool ParametersPlugin_WidgetParamsMgr::hasName(const QString& theName) const
+bool ParametersPlugin_WidgetParamsMgr::hasName(const QString& theName, int theIndex) const
{
- int aCurrent = myDelegate->editIndex().row();
int i = 0;
foreach(FeaturePtr aFeature, myParametersList) {
- if ((i != aCurrent) && (aFeature->data()->name() == theName.toStdWString()))
+ if ((i != theIndex) && (aFeature->data()->name() == theName.toStdWString()))
return true;
i++;
}
//myRemoveBtn->setEnabled(isParameter);
myUpBtn->setEnabled(isParameter);
myDownBtn->setEnabled(isParameter);
+ myImportBtn->setEnabled(true);
} else {
myInsertBtn->setEnabled(false);
//myRemoveBtn->setEnabled(false);
myUpBtn->setEnabled(false);
myDownBtn->setEnabled(false);
+ myImportBtn->setEnabled(false);
}
myRemoveBtn->setEnabled(!aItemsList.isEmpty());
}
//myRemoveBtn->setEnabled(theEnable);
myUpBtn->setEnabled(theEnable);
myDownBtn->setEnabled(theEnable);
+ myImportBtn->setEnabled(theEnable);
}
myOkCancelBtn->button(QDialogButtonBox::Ok)->setEnabled(theEnable);
}
aItem = myParameters->child(i);
if ((aItem->text(Col_Name) == NoName) ||
(aItem->text(Col_Equation) == translate(NoValue)) ||
- (!ModelAPI_Expression::isVariable(aItem->text(Col_Name).toStdString())) ) {
+ (!ModelAPI_Expression::isVariable(aItem->text(Col_Name).toStdString())) ||
+ (hasName(aItem->text(Col_Name), i)) ) {
return false;
}
}
/// Slot for reaction on remove parameter
void onRemove();
+ /// Slot for reaction on import parameter
+ void onImport();
+
/// Slot for reaction on shift up
void onUp();
bool isValid();
/// Returns true if parameter with the given name already exists
- bool hasName(const QString& theName) const;
+ bool hasName(const QString& theName, int theIndex) const;
/// Enable or disable buttons for parameters managemnt
void enableButtons(bool theEnable);
QPushButton* myAddBtn;
QPushButton* myInsertBtn;
QPushButton* myRemoveBtn;
+ QPushButton* myImportBtn;
QToolButton* myUpBtn;
QToolButton* myDownBtn;
--- /dev/null
+# Copyright (C) 2014-2021 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+import inspect, os
+
+data_dir = os.path.join(os.path.dirname(inspect.getfile(lambda: None)), "data")
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+nameFile = "invalid_parameters.txt"
+
+aDir = os.path.join(data_dir, nameFile)
+
+aListOfParameters = model.importParameters(Part_1_doc, aDir)
+
+assert(len(aListOfParameters) == 0)
--- /dev/null
+# Copyright (C) 2014-2021 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+import inspect, os
+
+data_dir = os.path.join(os.path.dirname(inspect.getfile(lambda: None)), "data")
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+nameFile = "parameters.txt"
+
+aDir = os.path.join(data_dir, nameFile)
+
+aListOfParameters = model.importParameters(Part_1_doc, aDir)
+
+Box_1 = model.addBox(Part_1_doc, "Longueur", "Largeur", "Hauteur")
+
+assert(len(Box_1.feature().error()) == 0)
+assert(len(aListOfParameters) == 5)
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2014-2021 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+
+### Create Part
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+aPart1 = model.addParameter(Part_1_doc, "Doing", "123", "Longueur de la pièce")
+try:
+ aPart2 = model.addParameter(Part_1_doc, "Doing", "323", "Long")
+except SyntaxError as anError:
+ assert(anError != "")
+ assert(str(anError).find("Variable name is not unique.") != -1)
+
+model.end()
model.begin()
partSet = model.moduleDocument()
# check error on empty name
-Param1 = model.addParameter(partSet, "", "100")
-assert(Param1.feature().error() != "")
+try:
+ Param1 = model.addParameter(partSet, "", "100")
+except SyntaxError as anError:
+ assert(str(anError).find("Attribute \"variable\" value is empty.") != -1)
# check error on empty value
-Param2 = model.addParameter(partSet, "L", "")
-assert(Param2.feature().error() != "")
+try:
+ Param2 = model.addParameter(partSet, "L", "")
+except SyntaxError as anError:
+ assert(str(anError).find("Expression is empty.") != -1)
# check error if name is not variable
-Param3 = model.addParameter(partSet, "100", "100")
-assert(Param3.feature().error() != "")
+try:
+ Param3 = model.addParameter(partSet, "100", "100")
+except SyntaxError as anError:
+ assert(str(anError).find("Incorrect variable name.") != -1)
# check error on wrong value expression
-Param4 = model.addParameter(partSet, "N", "+-.so&@")
-assert(Param4.feature().error() != "")
+try:
+ Param4 = model.addParameter(partSet, "N", "+-.so&@")
+except SyntaxError as anError:
+ assert(str(anError).find("invalid syntax") != -1)
model.end()
--- /dev/null
+Hauteur Longueur*Largeur
+
+Largeur3 #Comment
+# Comment
+ # Comm
--- /dev/null
+Longueur 36. # "Longueur de la pièce"
+Largeur 24. # Largeur de la pièce
+Hauteur Longueur*Largeur
+A12 5. * 5.
+Longueur2 36. #\"Comment\" #Comm #Comm
\ No newline at end of file
:language: python
:download:`Download this script <examples/parameter.py>`
+:download:`Download parameters file sample <examples/File.txt>`
--- /dev/null
+Width 10.0 #Width of square
+Height 15.0 # Height of square
+Area Width*Height # Area of square
\ No newline at end of file
model.begin()
partSet = model.moduleDocument()
model.addParameter(partSet, "angle", "60*3.141/180", "main angle")
+model.importParameters(partSet, "File.txt")
model.end()
.. |param_up| image:: images/parameters_up.png
.. |param_down| image:: images/parameters_down.png
+To edit a parameter, double-click on parameter in object browser.
+
**Input fields**:
- **Name** defines parameter name. Name follows the naming rules of the python language for variables;
- **Add** button adds a new empty string in the end of table. Default **Name** is *<NoName>*, **Expression** is *<NoValue>*
- **Insert** button adds a new empty string before the selected parameter;
- **Delete** button removes the selected parameter from the table;
+- **Import** button import parameters from .txt files. Parameters must be written in file in separate lines like example: **Name** **Expression** #**Comment**
+Sample.txt:
+''Longueur 36. # Longueur de la pièce''
+''Largeur 24 #Largeur de la pièce''
+''Hauteur Longueur * Largeur''
- **Modify parameter position** button moves the selected parameter
| |param_up| one string higher in the table,
| |param_down| one string lower in the table.
+**TUI Command**:
+
+.. py:function:: model.importParameters(Part_doc, filename)
+
+ :param part: The current part object
+ :param filename: The txt file with parameters
+ :return: Created objects.
+
+**See Also** a sample TUI Script of a :ref:`tui_parameterFeature` operation.
**See Also** :ref:`parameter` operation.
:param string: The parameter comment
:return: Created object.
+Write error in Python console if:
+- parameter name is empty.
+- parameter don't have unique name.
+- parameter expression is empty or incorrect.
+
**See Also** a sample TUI Script of a :ref:`tui_parameterFeature` operation.
Result
Test2392.py
Test2474.py
Test19036.py
+ TestImportParameters.py
+ TestImportInvalidParameters.py
)
#include <ModelAPI_ResultConstruction.h>
#include <ModelAPI_AttributeIntArray.h>
#include <ModelAPI_ResultGroup.h>
+#include <ModelAPI_ResultParameter.h>
#include <GeomDataAPI_Point2D.h>
#include <GeomDataAPI_Point.h>
if (aPartFeature.get() && (aPartFeature->getKind() == PartSetPlugin_Part::ID())) {
aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aPartFeature->firstResult());
}
+ if (aObj.get())
+ {
+ if (!aPart.get() && aObj->groupName() == ModelAPI_ResultParameter::group())
+ {
+ QObjectPtrList aObjects = aWorkshop->objectBrowser()->selectedObjects();
+ FeaturePtr aFeature;
+ ResultParameterPtr aParam;
+ foreach(ObjectPtr aObj, aObjects) {
+ aParam = std::dynamic_pointer_cast<ModelAPI_ResultParameter>(aObj);
+ if (aParam.get())
+ break;
+ }
+ if (aParam.get())
+ aFeature = ModelAPI_Feature::feature(aParam);
+
+ if (aFeature.get())
+ editFeature(aFeature);
+ }
+ }
}
if (aPart.get()) { // if this is a part
if (aPart->partDoc() == aMgr->activeDocument()) {
"""Package for Parameter plugin for the Parametric Geometry API of the Modeler.
"""
-from ParametersAPI import addParameter, removeParameter
\ No newline at end of file
+from ParametersAPI import addParameter, removeParameter
+
+from .import_parameter import *
--- /dev/null
+# Copyright (C) 2014-2021 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+import codecs, sys
+
+def changeTab(theLine):
+ aResult = theLine.split("#")[0].replace("\t"," ")
+ aResult += theLine[len(aResult):]
+ return aResult
+
+def importParameters(theDocument, theFileName):
+
+ aResult = []
+ try:
+ aFile = codecs.open(theFileName, 'r', encoding = 'utf_8_sig')
+ except IOError:
+ return aResult
+
+ for aLine in aFile:
+ aLine = aLine.rstrip("\n")
+ aLine = changeTab(aLine)
+
+ aName = ""
+ aParameter = ""
+ aComment = ""
+
+ aFirstText = aLine.split(" ")[0]
+
+ aName = aFirstText.split("#")[0].strip()
+
+ aLine = aLine.lstrip(aName)
+
+ aParameter = aLine.split("#")[0]
+
+ aLine = aLine.lstrip(aParameter)
+ aLine = aLine.lstrip("#")
+
+ aComment = aLine
+
+ if(len(aName) > 0):
+ try:
+ aResult.append(model.addParameter(theDocument, aName, aParameter.strip(), aComment.strip()))
+ except SyntaxError as anError:
+ print(anError, file = sys.stderr)
+
+ aFile.close()
+ return aResult