> For the complete documentation index, see [llms.txt](https://primer2.dynamobim.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://primer2.dynamobim.org/1_developer_primer_intro/0-introduction/4-obstacles-and-workaround.md).

# Obstacles encountered with PythonNet3 and workarounds

### Properties of type “Indexer”

Properties of type “Indexer” (like access to *Space* in the Revit API) are no longer handled directly with the bracket syntax. The indexer must be replaced by the corresponding *get* method.

**Example:**

**Old code:**

```py
space = elem.Space[phase]
```

**New code:**

```py
space = elem.get_Space(phase)
```

### Error in Python set collection

The Python Collection *set()* does not accept objects of type *ElementId.InvalidId*.

**Workarounds:**

* Filter invalid IDs when building the *set()*
* Use the .NET class \_HashSet\<T>

**Example(Filtering):**

```py
setViewsIds = set([w.OwnerViewId for w in allWires if w.OwnerViewId != ElementId.InvalidElementId])
```

### "with" statement on .NET objects

The use of the keyword *with* on .NET objects (which implement the interface *IDisposable*) currently throws an error with PythonNet3, unlike IronPython.

**Workaround:** Build a custom context manager to explicitly handle the method *Dispose()*.

**Example (Custom Context Manager CManager):**

```py
import sys
import clr
import System

# Add Assemblies for AutoCAD and Civil3D
clr.AddReference('AcMgd')
clr.AddReference('AcCoreMgd')
clr.AddReference('AcDbMgd')
clr.AddReference('AecBaseMgd')
clr.AddReference('AecPropDataMgd')
clr.AddReference('AeccDbMgd')

# Import references from AutoCAD
from Autodesk.AutoCAD.Runtime import *
from Autodesk.AutoCAD.ApplicationServices import *
from Autodesk.AutoCAD.EditorInput import *
from Autodesk.AutoCAD.DatabaseServices import *
from Autodesk.AutoCAD.Geometry import *

# Import references from Civil3D
from Autodesk.Civil.ApplicationServices import *
from Autodesk.Civil.DatabaseServices import *

# The inputs to this node will be stored as a list in the IN variables.
dataEnteringNode = IN

adoc = Application.DocumentManager.MdiActiveDocument
editor = adoc.Editor

class CManager:
    """
    a custom context manager for Disposable Object
    """
    def __init__(self, obj):
        self.obj = obj
       
    def __enter__(self):
        return self.obj
       
    def __exit__(self, exc_type, exc_value, exc_tb):
        self.obj.Dispose()
        if exc_type:
            error = f"{exc_value} at line {exc_tb.tb_lineno}"
            raise ValueError( error)
        return self
             
        
dynCADObjects = IN[0]
with adoc.LockDocument():
    with CManager(adoc.Database) as db:
        print(db)
        with CManager(db.TransactionManager.StartTransaction()) as t:
            print(t)
            for dynObj in dynCADObjects:
                ent = t.GetObject(dynObj.AcadObjectId, OpenMode.ForWrite)
                ent.Layer = "Layer1"
                #a = 10 /0
            t.Commit()

print(f"{db.IsDisposed=}")
print(f"{t.IsDisposed=}")
```

### .NET Objects that Inherit from an Interface

In the case of objects that inherit from a .NET Interface, it may be necessary to cast (convert) the object to that interface to use the inherited methods.

**Example (Call&#x20;*****BeginInit()*****&#x20;on a&#x20;*****PictureBox*****):**

In the example below, you will find the PythonNet syntax to perform an explicit cast to a .NET interface.

```py
class Form8(Form):
    def __init__(self):
        super().__init__() # necessary  if you override the __init__ method
        self.InitializeComponent()
   
    def InitializeComponent(self):
        self._pictureBox1 = System.Windows.Forms.PictureBox()
        System.ComponentModel.ISupportInitialize(self._pictureBox1).BeginInit()
        self.SuspendLayout()
```

The line \_System.ComponentModel.ISupportInitialize(self.*pictureBox1).BeginInit()* is therefore a method call on an explicit interface:

* It “casts” (or rather, it accesses) the object \_self.*pictureBox1* via its implementation of the interface *ISupportInitialize*.
* It then calls the method *BeginInit()* of this interface

### Attributes lost on .NET Class Instances when assigning to *OUT*

Python class instances deriving from a .NET class may have their attributes removed by the Dynamo Wrapper when assigning to the variable *OUT*.

**Workaround**:

Wrap the .NET object in a simple Python class before assigning it to *OUT*.

**Example**:

```py
# Load the Python Standard and DesignScript Libraries
import sys
import clr

clr.AddReference('System.Drawing')
clr.AddReference('System.Windows.Forms')
import System.Drawing
import System.Windows.Forms

from System.Drawing import *
from System.Windows.Forms import *

class WrappNetObj:
     def __init__(self, obj):
         self.InnerObject = obj
     def __repr__(self):
         return "WrappNetObj_" + self.InnerObject.GetType().ToString()

class Form8(Form):
    def __init__(self):
        super().__init__()
        self.out_value = 7
        self.InitializeComponent()
   
    def InitializeComponent(self):
        self.SuspendLayout()
        #
        #Form8
        #
        self.ClientSize = System.Drawing.Size(284, 261)
        self.Name = "Form8"
        self.Text = "Form8"
        self.ResumeLayout(False)

win_obj = Form8()
OUT = WrappNetObj(win_obj)
```

![inner object](/files/hqdz8O77fnd9gzaKH8oi)

![no inner object](/files/nfQWCXz6sD3uLxmwrAes)

### Missing error line

In rare cases, the error line number in the Python node error message may be missing.

Here are some solutions while waiting for a fix:

Implement a try-except block with the *traceback* library and print the error. Implement a try-except block with a *logger* and write the error. Implement a debugger, for example, using *sys.settrace()*.

**Conclusion** PythonNet3 establishes itself not only as the current standard but as the only sustainable path forward for development in Dynamo.
