Salome HOME
Merge tag 'V8_3_0a2' into ngr/python3_dev
authorNicolas Geimer <nicolas.geimer@edf.fr>
Mon, 20 Mar 2017 17:20:10 +0000 (18:20 +0100)
committerNicolas Geimer <nicolas.geimer@edf.fr>
Mon, 20 Mar 2017 17:20:10 +0000 (18:20 +0100)
Version 8.3.0 alpha 2

1  2 
src/SMESH_SWIG/smeshBuilder.py

index cb3244dafa69a9146da5fb28d63bf045bd3a2f88,d87d0d5539a7083c97d429bd129a6d06e99797fe..d5e80de438af0cfb0d40cc32296b0de678e73c82
@@@ -90,7 -90,6 +90,7 @@@ from   salome.smesh.smesh_algorithm imp
  import SALOME
  import SALOMEDS
  import os
 +import collections
  
  ## Private class used to workaround a problem that sometimes isinstance(m, Mesh) returns False
  #
@@@ -124,7 -123,7 +124,7 @@@ def ParseParameters(*args)
      Parameters = ""
      hasVariables = False
      varModifFun=None
 -    if args and callable( args[-1] ):
 +    if args and isinstance( args[-1], collections.Callable):
          args, varModifFun = args[:-1], args[-1]
      for parameter in args:
  
          if isinstance(parameter,str):
              # check if there is an inexistent variable name
              if not notebook.isVariable(parameter):
 -                raise ValueError, "Variable with name '" + parameter + "' doesn't exist!!!"
 +                raise ValueError("Variable with name '" + parameter + "' doesn't exist!!!")
              parameter = notebook.get(parameter)
              hasVariables = True
              if varModifFun:
@@@ -163,7 -162,8 +163,7 @@@ SMESH.PointStruct.__init__ = __initPoin
  #  Parameters are stored in AxisStruct.parameters attribute
  def __initAxisStruct(ax,*args):
      if len( args ) != 6:
 -        raise RuntimeError,\
 -              "Bad nb args (%s) passed in SMESH.AxisStruct(x,y,z,dx,dy,dz)"%(len( args ))
 +        raise RuntimeError("Bad nb args (%s) passed in SMESH.AxisStruct(x,y,z,dx,dy,dz)"%(len( args )))
      ax.x, ax.y, ax.z, ax.vx, ax.vy, ax.vz, ax.parameters,hasVars = ParseParameters(*args)
      pass
  SMESH.AxisStruct.__init__ = __initAxisStruct
@@@ -208,7 -208,7 +208,7 @@@ def GetName(obj)
              # unknown non-CORBA object, having GetName() method
              return obj.GetName()
          pass
 -    raise RuntimeError, "Null or invalid object"
 +    raise RuntimeError("Null or invalid object")
  
  ## Print error message if a hypothesis was not assigned.
  def TreatHypoStatus(status, hypName, geomName, isAlgo, mesh):
              if meshName and meshName != NO_NAME:
                  where = '"%s" shape in "%s" mesh ' % ( geomName, meshName )
      if status < HYP_UNKNOWN_FATAL and where:
 -        print '"%s" was assigned to %s but %s' %( hypName, where, reason )
 +        print('"%s" was assigned to %s but %s' %( hypName, where, reason ))
      elif where:
 -        print '"%s" was not assigned to %s : %s' %( hypName, where, reason )
 +        print('"%s" was not assigned to %s : %s' %( hypName, where, reason ))
      else:
 -        print '"%s" was not assigned : %s' %( hypName, reason )
 +        print('"%s" was not assigned : %s' %( hypName, reason ))
          pass
  
  ## Private method. Add geom (sub-shape of the main shape) into the study if not yet there
@@@ -286,7 -286,7 +286,7 @@@ def AssureGeomPublished(mesh, geom, nam
  def FirstVertexOnCurve(mesh, edge):
      vv = mesh.geompyD.SubShapeAll( edge, geomBuilder.geomBuilder.ShapeType["VERTEX"])
      if not vv:
 -        raise TypeError, "Given object has no vertices"
 +        raise TypeError("Given object has no vertices")
      if len( vv ) == 1: return vv[0]
      v0   = mesh.geompyD.MakeVertexOnCurve(edge,0.)
      xyz  = mesh.geompyD.PointCoordinates( v0 ) # coords of the first vertex
@@@ -314,7 -314,7 +314,7 @@@ created = Fals
  ## This class allows to create, load or manipulate meshes.
  #  It has a set of methods to create, load or copy meshes, to combine several meshes, etc.
  #  It also has methods to get infos and measure meshes.
 -class smeshBuilder(object, SMESH._objref_SMESH_Gen):
 +class smeshBuilder(SMESH._objref_SMESH_Gen):
  
      # MirrorType enumeration
      POINT = SMESH_MeshEditor.POINT
      PrecisionConfusion = smeshPrecisionConfusion
  
      # TopAbs_State enumeration
 -    [TopAbs_IN, TopAbs_OUT, TopAbs_ON, TopAbs_UNKNOWN] = range(4)
 +    [TopAbs_IN, TopAbs_OUT, TopAbs_ON, TopAbs_UNKNOWN] = list(range(4))
  
      # Methods of splitting a hexahedron into tetrahedra
      Hex_5Tet, Hex_6Tet, Hex_24Tet, Hex_2Prisms, Hex_4Prisms = 1, 2, 3, 1, 2
  
 -    def __new__(cls):
 +    def __new__(cls, *args):
          global engine
          global smeshInst
          global doLcc
          #print "====2 ", smeshInst
          return smeshInst
  
 -    def __init__(self):
 +    def __init__(self, *args):
          global created
          #print "--------------- smeshbuilder __init__ ---", created
          if not created:
 -          created = True
 -          SMESH._objref_SMESH_Gen.__init__(self)
 +            created = True
 +            SMESH._objref_SMESH_Gen.__init__(self, *args)
  
      ## Dump component to the Python script
      #  This method overrides IDL function to allow default values for the parameters.
          elif isinstance(c, str):
              val = c
          else:
 -            raise ValueError, "Color value should be of string or SALOMEDS.Color type"
 +            raise ValueError("Color value should be of string or SALOMEDS.Color type")
          return val
  
      ## Get PointStruct from vertex
      def GetDirStruct(self,theVector):
          vertices = self.geompyD.SubShapeAll( theVector, geomBuilder.geomBuilder.ShapeType["VERTEX"] )
          if(len(vertices) != 2):
 -            print "Error: vector object is incorrect."
 +            print("Error: vector object is incorrect.")
              return None
          p1 = self.geompyD.PointCoordinates(vertices[0])
          p2 = self.geompyD.PointCoordinates(vertices[1])
          aSmeshMesh, error = SMESH._objref_SMESH_Gen.CreateMeshesFromGMF(self,
                                                                          theFileName,
                                                                          True)
 -        if error.comment: print "*** CreateMeshesFromGMF() errors:\n", error.comment
 +        if error.comment: print("*** CreateMeshesFromGMF() errors:\n", error.comment)
          return Mesh(self, self.geompyD, aSmeshMesh), error
  
      ## Concatenate the given meshes into one mesh. All groups of input meshes will be
      def GetSubShapesId( self, theMainObject, theListOfSubObjects ):
          return SMESH._objref_SMESH_Gen.GetSubShapesId(self,theMainObject, theListOfSubObjects)
  
 -    ## Create a pattern mapper. 
 +    ## Create a pattern mapper.
      #  @return an instance of SMESH_Pattern
      #
      #  <a href="../tui_modifying_meshes_page.html#tui_pattern_mapping">Example of Patterns usage</a>
                       BinaryOp=FT_Undefined,
                       Tolerance=1e-07):
          if not CritType in SMESH.FunctorType._items:
 -            raise TypeError, "CritType should be of SMESH.FunctorType"
 +            raise TypeError("CritType should be of SMESH.FunctorType")
          aCriterion               = self.GetEmptyCriterion()
          aCriterion.TypeOfElement = elementType
          aCriterion.Type          = self.EnumToLong(CritType)
              elif isinstance( aThreshold, str ):
                  aCriterion.ThresholdStr = aThreshold
              else:
 -                raise TypeError, "The Threshold should be a shape."
 +                raise TypeError("The Threshold should be a shape.")
              if isinstance(UnaryOp,float):
                  aCriterion.Tolerance = UnaryOp
                  UnaryOp = FT_Undefined
              # Check that Threshold is a group
              if isinstance(aThreshold, SMESH._objref_SMESH_GroupBase):
                  if aThreshold.GetType() != elementType:
 -                    raise ValueError, "Group type mismatches Element type"
 +                    raise ValueError("Group type mismatches Element type")
                  aCriterion.ThresholdStr = aThreshold.GetName()
                  aCriterion.ThresholdID  = salome.orb.object_to_string( aThreshold )
                  study = self.GetCurrentStudy()
                          if entry:
                              aCriterion.ThresholdID = entry
              else:
 -                raise TypeError, "The Threshold should be a Mesh Group"
 +                raise TypeError("The Threshold should be a Mesh Group")
          elif CritType == FT_RangeOfIds:
              # Check that Threshold is string
              if isinstance(aThreshold, str):
                  aCriterion.ThresholdStr = aThreshold
              else:
 -                raise TypeError, "The Threshold should be a string."
 +                raise TypeError("The Threshold should be a string.")
          elif CritType == FT_CoplanarFaces:
              # Check the Threshold
              if isinstance(aThreshold, int):
              elif isinstance(aThreshold, str):
                  ID = int(aThreshold)
                  if ID < 1:
 -                    raise ValueError, "Invalid ID of mesh face: '%s'"%aThreshold
 +                    raise ValueError("Invalid ID of mesh face: '%s'"%aThreshold)
                  aCriterion.ThresholdID = aThreshold
              else:
 -                raise TypeError,\
 -                      "The Threshold should be an ID of mesh face and not '%s'"%aThreshold
 +                raise TypeError("The Threshold should be an ID of mesh face and not '%s'"%aThreshold)
          elif CritType == FT_ConnectedElements:
              # Check the Threshold
              if isinstance(aThreshold, geomBuilder.GEOM._objref_GEOM_Object): # shape
                  aCriterion.Threshold = aThreshold
              elif isinstance(aThreshold, list): # 3 point coordinates
                  if len( aThreshold ) < 3:
 -                    raise ValueError, "too few point coordinates, must be 3"
 +                    raise ValueError("too few point coordinates, must be 3")
                  aCriterion.ThresholdStr = " ".join( [str(c) for c in aThreshold[:3]] )
              elif isinstance(aThreshold, str):
                  if aThreshold.isdigit():
                  else:
                      aCriterion.ThresholdStr = aThreshold # hope that it's point coordinates
              else:
 -                raise TypeError,\
 -                      "The Threshold should either a VERTEX, or a node ID, "\
 -                      "or a list of point coordinates and not '%s'"%aThreshold
 +                raise TypeError("The Threshold should either a VERTEX, or a node ID, "\
 +                      "or a list of point coordinates and not '%s'"%aThreshold)
          elif CritType == FT_ElemGeomType:
              # Check the Threshold
              try:
                  if isinstance(aThreshold, int):
                      aCriterion.Threshold = aThreshold
                  else:
 -                    raise TypeError, "The Threshold should be an integer or SMESH.GeometryType."
 +                    raise TypeError("The Threshold should be an integer or SMESH.GeometryType.")
                  pass
              pass
          elif CritType == FT_EntityType:
                  if isinstance(aThreshold, int):
                      aCriterion.Threshold = aThreshold
                  else:
 -                    raise TypeError, "The Threshold should be an integer or SMESH.EntityType."
 +                    raise TypeError("The Threshold should be an integer or SMESH.EntityType.")
                  pass
              pass
 -        
 +
          elif CritType == FT_GroupColor:
              # Check the Threshold
              try:
                  aCriterion.ThresholdStr = self.ColorToString(aThreshold)
              except:
 -                raise TypeError, "The threshold value should be of SALOMEDS.Color type"
 +                raise TypeError("The threshold value should be of SALOMEDS.Color type")
              pass
          elif CritType in [FT_FreeBorders, FT_FreeEdges, FT_FreeNodes, FT_FreeFaces,
                            FT_LinearOrQuadratic, FT_BadOrientedVolume,
                  aThreshold = float(aThreshold)
                  aCriterion.Threshold = aThreshold
              except:
 -                raise TypeError, "The Threshold should be a number."
 +                raise TypeError("The Threshold should be a number.")
                  return None
  
          if Threshold ==  FT_LogicalNOT or UnaryOp ==  FT_LogicalNOT:
          elif theCriterion == FT_BallDiameter:
              functor = aFilterMgr.CreateBallDiameter()
          else:
 -            print "Error: given parameter is not numerical functor type."
 +            print("Error: given parameter is not numerical functor type.")
          aFilterMgr.UnRegister()
          return functor
  
              if not meth_name.startswith("Get") and \
                 not meth_name in dir ( SMESH._objref_SMESH_Hypothesis ):
                  method = getattr ( hyp.__class__, meth_name )
 -                if callable(method):
 +                if isinstance(method, collections.Callable):
                      setattr( hyp, meth_name, hypMethodWrapper( hyp, method ))
  
          return hyp
@@@ -1193,7 -1195,7 +1193,7 @@@ def New( study, instance=None)
      global doLcc
      engine = instance
      if engine is None:
 -      doLcc = True
 +        doLcc = True
      smeshInst = smeshBuilder()
      assert isinstance(smeshInst,smeshBuilder), "Smesh engine class is %s but should be smeshBuilder.smeshBuilder. Import salome.smesh.smeshBuilder before creating the instance."%smeshInst.__class__
      smeshInst.init_smesh(study)
  #  It also has methods to define groups of mesh elements, to modify a mesh (by addition of
  #  new nodes and elements and by changing the existing entities), to get information
  #  about a mesh and to export a mesh in different formats.
 -class Mesh:
 -    __metaclass__ = MeshMeta
 -
 +class Mesh(metaclass=MeshMeta):
      geom = 0
      mesh = 0
      editor = 0
              #self.mesh.UnRegister()
              pass
          pass
 -        
 +
      ## Initialize the Mesh object from an instance of SMESH_Mesh interface
      #  @param theMesh a SMESH_Mesh object
      #  @ingroup l2_construct
              if discardModifs and self.mesh.HasModificationsToDiscard(): # issue 0020693
                  self.mesh.Clear()
              ok = self.smeshpyD.Compute(self.mesh, geom)
 -        except SALOME.SALOME_Exception, ex:
 -            print "Mesh computation failed, exception caught:"
 -            print "    ", ex.details.text
 +        except SALOME.SALOME_Exception as ex:
 +            print("Mesh computation failed, exception caught:")
 +            print("    ", ex.details.text)
          except:
              import traceback
 -            print "Mesh computation failed, exception caught:"
 +            print("Mesh computation failed, exception caught:")
              traceback.print_exc()
          if True:#not ok:
              allReasons = ""
                  else:  msg += " has not been computed"
                  if allReasons != "": msg += ":"
                  else:                msg += "."
 -                print msg
 -                print allReasons
 +                print(msg)
 +                print(allReasons)
              pass
          if salome.sg.hasDesktop() and self.mesh.GetStudyId() >= 0:
              if not isinstance( refresh, list): # not a call from subMesh.Compute()
              pass
  
          groups = []
 -        for algoName, shapes in algo2shapes.items():
 +        for algoName, shapes in list(algo2shapes.items()):
              while shapes:
                  groupType = self.smeshpyD.EnumToLong( shapes[0].GetShapeType() )
                  otherTypeShapes = []
      #  @ingroup l2_construct
      def Clear(self, refresh=False):
          self.mesh.Clear()
 -        if ( salome.sg.hasDesktop() and 
 +        if ( salome.sg.hasDesktop() and
               salome.myStudyManager.GetStudyByID( self.mesh.GetStudyId() ) ):
              smeshgui = salome.ImportComponentGUI("SMESH")
              smeshgui.Init(self.mesh.GetStudyId())
              return self.mesh.RemoveHypothesis( shape, hyp )
          hypName = GetName( hyp )
          geoName = GetName( shape )
 -        print "WARNING: RemoveHypothesis() failed as '%s' is not assigned to '%s' shape" % ( hypName, geoName )
 +        print("WARNING: RemoveHypothesis() failed as '%s' is not assigned to '%s' shape" % ( hypName, geoName ))
          return None
  
      ## Get the list of hypotheses added on a geometry
      #         - 3D in the rest cases.<br>
      #         If @a autoDimension is @c False, the space dimension is always 3.
      #  @param fields list of GEOM fields defined on the shape to mesh.
 -    #  @param geomAssocFields each character of this string means a need to export a 
 +    #  @param geomAssocFields each character of this string means a need to export a
      #         corresponding field; correspondence between fields and characters is following:
      #         - 'v' stands for "_vertices _" field;
      #         - 'e' stands for "_edges _" field;
      # ----------------------
  
      ## Create an empty mesh group
 -    #  @param elementType the type of elements in the group; either of 
 +    #  @param elementType the type of elements in the group; either of
      #         (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME)
      #  @param name the name of the mesh group
      #  @return SMESH_Group
      #  the name is the same as the geometrical group name
      #  @param grp  a geometrical group, a vertex, an edge, a face or a solid
      #  @param name the name of the mesh group
 -    #  @param typ  the type of elements in the group; either of 
 +    #  @param typ  the type of elements in the group; either of
      #         (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME). If not set, it is
      #         automatically detected by the type of the geometry
      #  @return SMESH_GroupOnGeom
          elif tgeo == "COMPOUND":
              sub = self.geompyD.SubShapeAll( shape, self.geompyD.ShapeType["SHAPE"])
              if not sub:
 -                raise ValueError,"_groupTypeFromShape(): empty geometric group or compound '%s'" % GetName(shape)
 +                raise ValueError("_groupTypeFromShape(): empty geometric group or compound '%s'" % GetName(shape))
              return self._groupTypeFromShape( sub[0] )
          else:
 -            raise ValueError, \
 -                  "_groupTypeFromShape(): invalid geometry '%s'" % GetName(shape)
 +            raise ValueError("_groupTypeFromShape(): invalid geometry '%s'" % GetName(shape))
          return typ
  
      ## Create a mesh group with given \a name based on the \a filter which
      ## is a special type of group dynamically updating it's contents during
      ## mesh modification
 -    #  @param typ  the type of elements in the group; either of 
 +    #  @param typ  the type of elements in the group; either of
      #         (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME).
      #  @param name the name of the mesh group
      #  @param filter the filter defining group contents
  
      ## Create a mesh group by the given ids of elements
      #  @param groupName the name of the mesh group
 -    #  @param elementType the type of elements in the group; either of 
 +    #  @param elementType the type of elements in the group; either of
      #         (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME).
      #  @param elemIDs either the list of ids, group, sub-mesh, or filter
      #  @return SMESH_Group
  
      ## Get the list of groups existing in the mesh in the order
      #  of creation (starting from the oldest one)
 -    #  @param elemType type of elements the groups contain; either of 
 +    #  @param elemType type of elements the groups contain; either of
      #         (SMESH.ALL, SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME);
      #         by default groups of elements of all types are returned
      #  @return a sequence of SMESH_GroupBase
  
      ## Find groups by name and type
      #  @param name name of the group of interest
 -    #  @param elemType type of elements the groups contain; either of 
 +    #  @param elemType type of elements the groups contain; either of
      #         (SMESH.ALL, SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME);
      #         by default one group of any type of elements is returned
      #         if elemType == SMESH.ALL then all groups of any type are returned
              if group.GetName() == name:
                  if elemType is None:
                      return [group]
 -                if ( elemType == SMESH.ALL or 
 +                if ( elemType == SMESH.ALL or
                       group.GetType() == elemType ):
                      groups.append( group )
          return groups
      #  @return an instance of SMESH_Group
      #  @ingroup l2_grps_operon
      def UnionListOfGroups(self, groups, name):
 -      return self.mesh.UnionListOfGroups(groups, name)
 +        return self.mesh.UnionListOfGroups(groups, name)
  
      ## Prodice an intersection of two groups.
      #  A new group is created. All mesh elements that are common
      #  @return an instance of SMESH_Group
      #  @ingroup l2_grps_operon
      def IntersectListOfGroups(self, groups, name):
 -      return self.mesh.IntersectListOfGroups(groups, name)
 +        return self.mesh.IntersectListOfGroups(groups, name)
  
      ## Produce a cut of two groups.
      #  A new group is created. All mesh elements that are present in
      ##
      #  Create a standalone group of entities basing on nodes of other groups.
      #  \param groups - list of reference groups, sub-meshes or filters, of any type.
 -    #  \param elemType - a type of elements to include to the new group; either of 
 +    #  \param elemType - a type of elements to include to the new group; either of
      #         (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME).
      #  \param name - a name of the new group.
      #  \param nbCommonNodes - a criterion of inclusion of an element to the new group
      def Add0DElement( self, IDOfNode, DuplicateElements=True ):
          return self.editor.Add0DElement( IDOfNode, DuplicateElements )
  
 -    ## Create 0D elements on all nodes of the given elements except those 
 +    ## Create 0D elements on all nodes of the given elements except those
      #  nodes on which a 0D element already exists.
      #  @param theObject an object on whose nodes 0D elements will be created.
      #         It can be mesh, sub-mesh, group, list of element IDs or a holder
      #         and/or found on nodes of \a theObject.
      #  @param DuplicateElements to add one more 0D element to a node or not
      #  @return an object (a new group or a temporary SMESH_IDSource) holding
 -    #          IDs of new and/or found 0D elements. IDs of 0D elements 
 +    #          IDs of new and/or found 0D elements. IDs of 0D elements
      #          can be retrieved from the returned object by calling GetIDs()
      #  @ingroup l2_modif_add
      def Add0DElementsToAllNodes(self, theObject, theGroupName="", DuplicateElements=False):
              VertexID = Vertex
          try:
              self.editor.SetNodeOnVertex(NodeID, VertexID)
 -        except SALOME.SALOME_Exception, inst:
 -            raise ValueError, inst.details.text
 +        except SALOME.SALOME_Exception as inst:
 +            raise ValueError(inst.details.text)
          return True
  
  
              EdgeID = Edge
          try:
              self.editor.SetNodeOnEdge(NodeID, EdgeID, paramOnEdge)
 -        except SALOME.SALOME_Exception, inst:
 -            raise ValueError, inst.details.text
 +        except SALOME.SALOME_Exception as inst:
 +            raise ValueError(inst.details.text)
          return True
  
      ## @brief Stores node position on a face
              FaceID = Face
          try:
              self.editor.SetNodeOnFace(NodeID, FaceID, u, v)
 -        except SALOME.SALOME_Exception, inst:
 -            raise ValueError, inst.details.text
 +        except SALOME.SALOME_Exception as inst:
 +            raise ValueError(inst.details.text)
          return True
  
      ## @brief Binds a node to a solid
              SolidID = Solid
          try:
              self.editor.SetNodeInVolume(NodeID, SolidID)
 -        except SALOME.SALOME_Exception, inst:
 -            raise ValueError, inst.details.text
 +        except SALOME.SALOME_Exception as inst:
 +            raise ValueError(inst.details.text)
          return True
  
      ## @brief Bind an element to a shape
              ShapeID = Shape
          try:
              self.editor.SetMeshElementOnShape(ElementID, ShapeID)
 -        except SALOME.SALOME_Exception, inst:
 -            raise ValueError, inst.details.text
 +        except SALOME.SALOME_Exception as inst:
 +            raise ValueError(inst.details.text)
          return True
  
  
      #  @param x  the X coordinate of a point
      #  @param y  the Y coordinate of a point
      #  @param z  the Z coordinate of a point
 -    #  @param elementType type of elements to find; either of 
 +    #  @param elementType type of elements to find; either of
      #         (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME); SMESH.ALL type
      #         means elements of any type excluding nodes, discrete and 0D elements.
      #  @param meshPart a part of mesh (group, sub-mesh) to search within
          pattern = self.smeshpyD.GetPattern()
          isDone  = pattern.LoadFromFile(pattern_tetra)
          if not isDone:
 -            print 'Pattern.LoadFromFile :', pattern.GetErrorCode()
 +            print('Pattern.LoadFromFile :', pattern.GetErrorCode())
              return isDone
  
          pattern.ApplyToHexahedrons(self.mesh, theObject.GetIDs(), theNode000, theNode001)
          isDone = pattern.MakeMesh(self.mesh, False, False)
 -        if not isDone: print 'Pattern.MakeMesh :', pattern.GetErrorCode()
 +        if not isDone: print('Pattern.MakeMesh :', pattern.GetErrorCode())
  
          # split quafrangle faces near triangular facets of volumes
          self.SplitQuadsNearTriangularFacets()
          pattern = self.smeshpyD.GetPattern()
          isDone  = pattern.LoadFromFile(pattern_prism)
          if not isDone:
 -            print 'Pattern.LoadFromFile :', pattern.GetErrorCode()
 +            print('Pattern.LoadFromFile :', pattern.GetErrorCode())
              return isDone
  
          pattern.ApplyToHexahedrons(self.mesh, theObject.GetIDs(), theNode000, theNode001)
          isDone = pattern.MakeMesh(self.mesh, False, False)
 -        if not isDone: print 'Pattern.MakeMesh :', pattern.GetErrorCode()
 +        if not isDone: print('Pattern.MakeMesh :', pattern.GetErrorCode())
  
          # Split quafrangle faces near triangular facets of volumes
          self.SplitQuadsNearTriangularFacets()
                  self.editor.ConvertToQuadratic(theForce3d)
          error = self.editor.GetLastError()
          if error and error.comment:
 -            print error.comment
 +            print(error.comment)
          return error
 -            
 +
      ## Convert the mesh from quadratic to ordinary,
      #  deletes old quadratic elements, \n replacing
      #  them with ordinary mesh elements with the same id.
          return mesh, group
  
      ##
 -    # @brief Create missing boundary elements around either the whole mesh or 
 +    # @brief Create missing boundary elements around either the whole mesh or
      #    groups of elements
      #  @param dimension - defines type of boundary elements to create, either of
      #                     { SMESH.BND_2DFROM3D, SMESH.BND_1DFROM3D, SMESH.BND_1DFROM2D }
      #  @param groupName - a name of group to store all boundary elements in,
      #    "" means not to create the group
 -    #  @param meshName - a name of a new mesh, which is a copy of the initial 
 +    #  @param meshName - a name of a new mesh, which is a copy of the initial
      #    mesh + created boundary elements; "" means not to create the new mesh
      #  @param toCopyAll - if true, the whole initial mesh will be copied into
      #    the new mesh else only boundary elements will be copied into the new mesh
          if isinstance( basePoint, int):
              xyz = self.GetNodeXYZ( basePoint )
              if not xyz:
 -                raise RuntimeError, "Invalid node ID: %s" % basePoint
 +                raise RuntimeError("Invalid node ID: %s" % basePoint)
              basePoint = xyz
          if isinstance( basePoint, geomBuilder.GEOM._objref_GEOM_Object ):
              basePoint = self.geompyD.PointCoordinates( basePoint )
              Elements = [ Elements.GetMesh() ]
          if isinstance( Elements, list ):
              if not Elements:
 -                raise RuntimeError, "Elements empty!"
 +                raise RuntimeError("Elements empty!")
              if isinstance( Elements[0], int ):
                  Elements = self.GetIDSource( Elements, SMESH.ALL )
                  unRegister.set( Elements )
          if ( isinstance( thePoint, list )):
              thePoint = PointStruct( thePoint[0], thePoint[1], thePoint[2] )
          if ( isinstance( theScaleFact, float )):
 -             theScaleFact = [theScaleFact]
 +            theScaleFact = [theScaleFact]
          if ( isinstance( theScaleFact, int )):
 -             theScaleFact = [ float(theScaleFact)]
 +            theScaleFact = [ float(theScaleFact)]
  
          self.mesh.SetParameters(thePoint.parameters)
  
          if ( isinstance( thePoint, list )):
              thePoint = PointStruct( thePoint[0], thePoint[1], thePoint[2] )
          if ( isinstance( theScaleFact, float )):
 -             theScaleFact = [theScaleFact]
 +            theScaleFact = [theScaleFact]
          if ( isinstance( theScaleFact, int )):
 -             theScaleFact = [ float(theScaleFact)]
 +            theScaleFact = [ float(theScaleFact)]
  
          self.mesh.SetParameters(thePoint.parameters)
          mesh = self.editor.ScaleMakeMesh(theObject, thePoint, theScaleFact,
      #  @param NodesToKeep nodes to keep in the mesh: a list of groups, sub-meshes or node IDs.
      #         If @a NodesToKeep does not include a node to keep for some group to merge,
      #         then the first node in the group is kept.
+     #  @param AvoidMakingHoles prevent merging nodes which cause removal of elements becoming
+     #         invalid
      #  @ingroup l2_modif_trsf
-     def MergeNodes (self, GroupsOfNodes, NodesToKeep=[]):
+     def MergeNodes (self, GroupsOfNodes, NodesToKeep=[], AvoidMakingHoles=False):
          # NodesToKeep are converted to SMESH_IDSource in meshEditor.MergeNodes()
-         self.editor.MergeNodes(GroupsOfNodes,NodesToKeep)
+         self.editor.MergeNodes( GroupsOfNodes, NodesToKeep, AvoidMakingHoles )
  
      ## Find the elements built on the same nodes.
      #  @param MeshOrSubMeshOrGroup Mesh or SubMesh, or Group of elements for searching
      #  @ingroup l2_modif_trsf
      def FindCoincidentFreeBorders (self, tolerance=0.):
          return self.editor.FindCoincidentFreeBorders( tolerance )
 -        
 +
      ## Sew FreeBorder's of each group
      #  @param freeBorders either a SMESH.CoincidentFreeBorders structure or a list of lists
      #         where each enclosed list contains node IDs of a group of coincident free
              coincidentGroups = []
              for nodeList in freeBorders:
                  if not nodeList or len( nodeList ) % 3:
 -                    raise ValueError, "Wrong number of nodes in this group: %s" % nodeList
 +                    raise ValueError("Wrong number of nodes in this group: %s" % nodeList)
                  group = []
                  while nodeList:
                      group.append  ( SMESH.FreeBorderPart( len(borders), 0, 1, 2 ))
      def ClearLastCreated(self):
          self.editor.ClearLastCreated()
  
 -    ## Create duplicates of given elements, i.e. create new elements based on the 
 +    ## Create duplicates of given elements, i.e. create new elements based on the
      #  same nodes as the given ones.
      #  @param theElements - container of elements to duplicate. It can be a Mesh,
      #         sub-mesh, group, filter or a list of element IDs. If \a theElements is
      #  @param theGroupName - a name of group to contain the generated elements.
      #                    If a group with such a name already exists, the new elements
      #                    are added to the existng group, else a new group is created.
 -    #                    If \a theGroupName is empty, new elements are not added 
 +    #                    If \a theGroupName is empty, new elements are not added
      #                    in any group.
      # @return a group where the new elements are added. None if theGroupName == "".
      #  @ingroup l2_modif_duplicat
      #  @return TRUE if operation has been completed successfully, FALSE otherwise
      #  @ingroup l2_modif_duplicat
      def DoubleNodesOnGroupBoundaries(self, theDomains, createJointElems, onAllBoundaries=False ):
 -       return self.editor.DoubleNodesOnGroupBoundaries( theDomains, createJointElems, onAllBoundaries )
 +        return self.editor.DoubleNodesOnGroupBoundaries( theDomains, createJointElems, onAllBoundaries )
  
      ## Double nodes on some external faces and create flat elements.
      #  Flat elements are mainly used by some types of mechanic calculations.
 -    #  
 +    #
      #  Each group of the list must be constituted of faces.
      #  Triangles are transformed in prisms, and quadrangles in hexahedrons.
      #  @param theGroupsOfFaces - list of groups of faces
      #  @ingroup l2_modif_duplicat
      def CreateFlatElementsOnFacesGroups(self, theGroupsOfFaces ):
          return self.editor.CreateFlatElementsOnFacesGroups( theGroupsOfFaces )
 -    
 +
      ## identify all the elements around a geom shape, get the faces delimiting the hole
      #
      def CreateHoleSkin(self, radius, theShape, groupName, theNodesCoords):
@@@ -5109,7 -5116,7 +5111,7 @@@ class meshEditor(SMESH._objref_SMESH_Me
              return getattr( self.mesh, name )
          if name == "ExtrusionAlongPathObjX":
              return getattr( self.mesh, "ExtrusionAlongPathX" ) # other method name
 -        print "meshEditor: attribute '%s' NOT FOUND" % name
 +        print("meshEditor: attribute '%s' NOT FOUND" % name)
          return None
      def __deepcopy__(self, memo=None):
          new = self.__class__()
      def FindCoincidentNodesOnPart(self,*args): # a 3d arg added (SeparateCornerAndMediumNodes)
          if len( args ) == 2: args += False,
          return SMESH._objref_SMESH_MeshEditor.FindCoincidentNodesOnPart( self, *args )
-     def MergeNodes(self,*args): # a 2nd arg added (NodesToKeep)
+     def MergeNodes(self,*args): # 2 args added (NodesToKeep,AvoidMakingHoles)
          if len( args ) == 1:
-             return SMESH._objref_SMESH_MeshEditor.MergeNodes( self, args[0], [] )
+             return SMESH._objref_SMESH_MeshEditor.MergeNodes( self, args[0], [], False )
          NodesToKeep = args[1]
+         AvoidMakingHoles = args[2] if len( args ) == 3 else False
          unRegister  = genObjUnRegister()
          if NodesToKeep:
              if isinstance( NodesToKeep, list ) and isinstance( NodesToKeep[0], int ):
                  NodesToKeep = self.MakeIDSource( NodesToKeep, SMESH.NODE )
              if not isinstance( NodesToKeep, list ):
                  NodesToKeep = [ NodesToKeep ]
-         return SMESH._objref_SMESH_MeshEditor.MergeNodes( self, args[0], NodesToKeep )
+         return SMESH._objref_SMESH_MeshEditor.MergeNodes( self, args[0], NodesToKeep, AvoidMakingHoles )
      pass
  omniORB.registerObjref(SMESH._objref_SMESH_MeshEditor._NP_RepositoryId, meshEditor)
  
@@@ -5201,11 -5209,11 +5204,11 @@@ class algoCreator
              if isinstance( arg, str ) and arg:
                  algoType = arg
          if not algoType and self.algoTypeToClass:
 -            algoType = self.algoTypeToClass.keys()[0]
 -        if self.algoTypeToClass.has_key( algoType ):
 +            algoType = list(self.algoTypeToClass.keys())[0]
 +        if algoType in self.algoTypeToClass:
              #print "Create algo",algoType
              return self.algoTypeToClass[ algoType ]( self.mesh, geom )
 -        raise RuntimeError, "No class found for algo type %s" % algoType
 +        raise RuntimeError("No class found for algo type %s" % algoType)
          return None
  
  ## Private class used to substitute and store variable parameters of hypotheses.
@@@ -5230,11 -5238,11 +5233,11 @@@ class hypMethodWrapper
          except omniORB.CORBA.BAD_PARAM: # raised by hypothesis method call
              # maybe there is a replaced string arg which is not variable
              result = self.method( self.hyp, *args )
 -        except ValueError, detail: # raised by ParseParameters()
 +        except ValueError as detail: # raised by ParseParameters()
              try:
                  result = self.method( self.hyp, *args )
              except omniORB.CORBA.BAD_PARAM:
 -                raise ValueError, detail # wrong variable name
 +                raise ValueError(detail) # wrong variable name
  
          return result
      pass
@@@ -5270,9 -5278,9 +5273,9 @@@ for pluginName in os.environ[ "SMESH_Me
      pluginBuilderName = pluginName + "Builder"
      try:
          exec( "from salome.%s.%s import *" % (pluginName, pluginBuilderName))
 -    except Exception, e:
 -      from salome_utils import verbose
 -      if verbose(): print "Exception while loading %s: %s" % ( pluginBuilderName, e )
 +    except Exception as e:
 +        from salome_utils import verbose
 +        if verbose(): print("Exception while loading %s: %s" % ( pluginBuilderName, e ))
          continue
      exec( "from salome.%s import %s" % (pluginName, pluginBuilderName))
      plugin = eval( pluginBuilderName )