Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CPython Interface Implementation failed #686

Closed
htlcnn opened this issue Sep 11, 2019 · 6 comments
Closed

CPython Interface Implementation failed #686

htlcnn opened this issue Sep 11, 2019 · 6 comments
Labels
Python 3 Issues related to cpython engines [subsystem]

Comments

@htlcnn
Copy link
Contributor

htlcnn commented Sep 11, 2019

Describe the bug
I implemented an ISelectionFilter interface in my script and use it for uidoc.Selection.PickObjects. Here is my script:

#! python3
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitAPIUI')
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import UIDocument, Selection
from Autodesk.Revit.Exceptions import OperationCanceledException

from System.Collections.Generic import List

import os
import tempfile

from PIL import Image

uiapp = __revit__
uidoc = uiapp.ActiveUIDocument
app = uiapp.Application
doc = uidoc.Document

import time

class CategoriesFilter(Selection.ISelectionFilter):
    # https://stackoverflow.com/a/50462691
    __namespace__ = 'HTL %s' % int(time.time())
    # __namespace__ = 'HTL'
    def __init__(self, names):
        self.names = names
    def AllowElement(self, element):
        return element.Category.Name in self.names

def select_objects_by_category(*names):
    prompt = 'Pick {}'.format(', '.join(names))
    references = uidoc.Selection.PickObjects(Selection.ObjectType.Element,
                                           CategoriesFilter(names), prompt)
    return [doc.GetElement(reference) for reference in references]

def select_object_by_category(name):
    prompt = 'Pick {}'.format(name)
    reference = uidoc.Selection.PickObject(Selection.ObjectType.Element,
                                           CategoriesFilter(name), prompt)
    return doc.GetElement(reference)

def main():
    rebars = select_objects_by_category('Structural Rebar')
    print(rebars)

try:
    main()
except OperationCanceledException:
    pass

Note that in order to run the script without exception, I had to append time.time() to my class' __namespace__. If I didn't do that, I would get this exception:

CPython Traceback:
TypeError : Duplicate type name within an assembly.
 File "E:\Setup\UCE\Autodesk\Revit\pyRevit extensions\htl.extension\HTL Rebar.tab\Schedule.panel\CreateRebarImage.pushbutton\script.py", line 23, in <module>
class CategoriesFilter(Selection.ISelectionFilter):

pyRevitLabs.PythonNet
at pyRevitLabs.PythonNet.Runtime.CheckExceptionOccurred()
 at pyRevitLabs.PythonNet.PythonEngine.RunString(String code, Nullable`1 globals, Nullable`1 locals, RunFlagType flag, Encoding encoding)
 at pyRevitLabs.PythonNet.PythonEngine.ExecUTF8(String code, Nullable`1 globals, Nullable`1 locals)
 at PyRevitLabs.PyRevit.Runtime.CPythonEngine.Execute(ScriptRuntime& runtime)

To Reproduce
Steps to reproduce the behavior:

  1. Run the script above with the line __namespace__ = 'HTL' uncommented
  2. Run the script again

Expected behavior
Script run without exception. Is there any method to avoid recreation of classes (or to override them) if they already exist in certain namespace?

Desktop

  • OS: Windows 10 x64
  • pyRevit Version 4.7-beta 2
  • pyRevit Environment: Open a command prompt and run the command below. Replace these lines with the results. Take a look at this markdown guide and wrap the command results in ``` when pasting here for correct formatting.
C:\Users\HTL>pyrevit env
==> Registered Clones (full git repos)
==> Registered Clones (deployed from archive/image)
master | Deploy: "basepublic" | Branch: "master" | Version: "4.7-beta2" | Path: "C:\Users\HTL\AppData\Roaming\pyRevit-Master"
==> Attachments
master | Product: "2020.1 Update" | Engine: 277 | Path: "C:\Users\HTL\AppData\Roaming\pyRevit-Master" | Manifest: "C:\Users\HTL\AppData\Roaming\Autodesk\Revit\Addins\2020\pyRevit.addin"
master | Product: "2018.3.1" | Engine: 277 | Path: "C:\Users\HTL\AppData\Roaming\pyRevit-Master" | Manifest: "C:\Users\HTL\AppData\Roaming\Autodesk\Revit\Addins\2018\pyRevit.addin"
==> Installed Extensions
htl | Type: Unknown | Repo: "git@gitlab.com:hoangthanhlong/pyrevitscripts.git" | Installed: "E:\Setup\UCE\Autodesk\Revit\pyRevit extensions\htl.extension"
==> Default Extension Search Path
C:\Users\HTL\AppData\Roaming\pyRevit\Extensions
==> Extension Search Paths
E:\Setup\UCE\Autodesk\Revit\pyRevit extensions
D:\HTL\Desktop
==> Extension Sources - Default
https://github.com/eirannejad/pyRevit/raw/master/extensions/extensions.json
==> Extension Sources - Additional
==> Installed Revits
2020.1 Update | Version: 20.1.0.81 | Build: 20190725_1135(x64) | Language: 1033 | Path: "C:\Program Files\Autodesk\Revit 2020"
2018.3.1 | Version: 18.3.1.2 | Build: 20180423_1000(x64) | Language: 1033 | Path: "C:\Program Files\Autodesk\Revit 2018"
==> Running Revit Instances
PID: 10920 | 2020.1 Update | Version: 20.1.0.81 | Build: 20190725_1135(x64) | Language: 0 | Path: "C:\Program Files\Autodesk\Revit 2020"
==> User Environment
Microsoft Windows 10 [Version 10.0.17134]
Executing User: HTL\HTL
Active User: HTL\HTL
Adming Access: No
%APPDATA%: "C:\Users\HTL\AppData\Roaming"
Latest Installed .Net Framework: 4.8
Installed .Net Target Packs: v3.5 v4.0 v4.5 v4.5.1 v4.5.2 v4.6 v4.6.1 v4.6.2 v4.7 v4.7.1 v4.7.2 v4.8 v4.X
Installed .Net-Core Target Packs: v2.1.602
pyRevit CLI 0.14.0.0
@eirannejad
Copy link
Owner

eirannejad commented Sep 11, 2019

Great find with the __namespace__. I didn't know it's there. It would be great if you can write up your findings on using the CPython with Revit in a markdown file and I'll publish on the Wiki

I'm going to add a __timestamp__ global variable to the pyRevit engine. This way you can:

class CategoriesFilter(UI.Selection.ISelectionFilter):
    __namespace__ = __commanduniqueid__ + __timestamp__

Keep us posted on your findings please.

@eirannejad
Copy link
Owner

eirannejad commented Sep 11, 2019

Okay implemented timestamp and execid (unique id for each execution). The code can be simplified as

from pyrevit import EXEC_PARAMS
class CategoriesFilter(UI.Selection.ISelectionFilter):
    __namespace__ = EXEC_PARAMS.exec_id

or less safer but with not pyrevit import

from pyrevit import EXEC_PARAMS
class CategoriesFilter(UI.Selection.ISelectionFilter):
    __namespace__ = __execid__

Will publish this soon with 4.7-beta3

@htlcnn
Copy link
Contributor Author

htlcnn commented Sep 11, 2019

I don't know much about underlying Python Engine of .NET. I just don't know if appending timestamp is proper way to do it, or it would polute the namespace or raise memory etc.

Anyways, I attach markdown writeup below:

cpython net interface implementation.zip

@eirannejad
Copy link
Owner

Send me your info so I can add as part of Community

@eirannejad eirannejad added the Python 3 Issues related to cpython engines [subsystem] label Sep 11, 2019
@htlcnn
Copy link
Contributor Author

htlcnn commented Sep 11, 2019

I've emailed you my info. Thanks!

@htlcnn
Copy link
Contributor Author

htlcnn commented Sep 11, 2019

@eirannejad I've read your commit above (0073bbc), I'd like to add that IronPython works fine without __namespace__ defined.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Python 3 Issues related to cpython engines [subsystem]
Projects
None yet
Development

No branches or pull requests

2 participants