architecture-building-systems / revitpythonshell

An IronPython scripting environment for Autodesk Revit and Vasari
MIT License
490 stars 112 forks source link

PyRevitCPythonNotSupported #155

Open jpdon2503 opened 4 months ago

jpdon2503 commented 4 months ago

I am using revit 2024 and revit python shell 2.0.2, i cant import forms from pyrevit( from pyrevit import forms) i get this error Exception : System.Exception: PyRevitCPythonNotSupported at Microsoft.Scripting.Interpreter.ThrowInstruction.Run(InterpretedFrame frame) at Microsoft.Scripting.Interpreter.Interpreter.HandleException(InterpretedFrame frame, Exception exception) at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame) at Microsoft.Scripting.Interpreter.LightLambda.Run2[T0,T1,TRet](T0 arg0, T1 arg1) at IronPython.Runtime.Method.MethodBinding.SelfTarget(CallSite site, CodeContext context, Object target) at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1) at Microsoft.Scripting.Interpreter.FuncCallInstruction5.Run(InterpretedFrame frame) at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame) at Microsoft.Scripting.Interpreter.LightLambda.Run3[T0,T1,T2,TRet](T0 arg0, T1 arg1, T2 arg2) at IronPython.Compiler.Ast.CallExpression.Invoke0Instruction.Run(InterpretedFrame frame) at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame) at Microsoft.Scripting.Interpreter.LightLambda.Run3[T0,T1,T2,TRet](T0 arg0, T1 arg1, T2 arg2) at System.Dynamic.UpdateDelegates.UpdateAndExecute4[T0,T1,T2,T3,TRet](CallSite site, T0 arg0, T1 arg1, T2 arg2, T3 arg3) at IronPython.Runtime.Method.MethodBinding1.SelfTarget(CallSite site, CodeContext context, Object target, T0 arg0) at IronPython.Compiler.Ast.CallExpression.Invoke1Instruction.Run(InterpretedFrame frame) at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame) at Microsoft.Scripting.Interpreter.LightLambda.Run3[T0,T1,T2,TRet](T0 arg0, T1 arg1, T2 arg2) at Microsoft.Scripting.Interpreter.FuncCallInstruction5.Run(InterpretedFrame frame) at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame) at Microsoft.Scripting.Interpreter.LightLambda.Run7[T0,T1,T2,T3,T4,T5,T6,TRet](T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) at System.Dynamic.UpdateDelegates.UpdateAndExecute6[T0,T1,T2,T3,T4,T5,TRet](CallSite site, T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) at Microsoft.Scripting.Interpreter.FuncCallInstruction9.Run(InterpretedFrame frame) at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame) at Microsoft.Scripting.Interpreter.LightLambda.Run7[T0,T1,T2,T3,T4,T5,T6,TRet](T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) at _check_name_wrapper$683(Closure , PythonFunction , Object , Object , Object , Object ) at System.Dynamic.UpdateDelegates.UpdateAndExecute4[T0,T1,T2,T3,TRet](CallSite site, T0 arg0, T1 arg1, T2 arg2, T3 arg3) at IronPython.Runtime.Method.MethodBinding1.SelfTarget(CallSite site, CodeContext context, Object target, T0 arg0) at System.Dynamic.UpdateDelegates.UpdateAndExecute3[T0,T1,T2,TRet](CallSite site, T0 arg0, T1 arg1, T2 arg2) at Microsoft.Scripting.Interpreter.FuncCallInstruction6.Run(InterpretedFrame frame) at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame) at Microsoft.Scripting.Interpreter.LightLambda.Run4[T0,T1,T2,T3,TRet](T0 arg0, T1 arg1, T2 arg2, T3 arg3) at IronPython.Runtime.PythonContext.Call(CodeContext context, Object func, Object arg0) at IronPython.Runtime.Importer.FindAndLoadModuleFromImporter(CodeContext context, Object importer, String fullName, PythonList path, Object& ret) at IronPython.Runtime.Importer.TryLoadMetaPathModule(CodeContext context, String fullName, PythonList path, Object& ret) at IronPython.Runtime.Importer.ImportNestedModule(CodeContext context, PythonModule module, ArraySegment1 parts, PythonList path, String scopeModuleName) at IronPython.Runtime.Importer.ImportFrom(CodeContext context, Object from, String name) at IronPython.Modules.Builtin.__import__(CodeContext context, String name, Object globals, Object locals, Object fromlist, Int32 level) at Microsoft.Scripting.Interpreter.FuncCallInstruction7.Run(InterpretedFrame frame) at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame) at Microsoft.Scripting.Interpreter.LightLambda.Run8[T0,T1,T2,T3,T4,T5,T6,T7,TRet](T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) at IronPython.Runtime.Importer.ImportLightThrow(CodeContext context, String fullName, PythonTuple from, Int32 level) at Microsoft.Scripting.Interpreter.FuncCallInstruction`5.Run(InterpretedFrame frame) at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame) at Microsoft.Scripting.Interpreter.LightLambda.Run2[T0,T1,TRet](T0 arg0, T1 arg1) at IronPython.Compiler.PythonScriptCode.RunWorker(CodeContext ctx) at Microsoft.Scripting.Hosting.ScriptSource.Execute(ScriptScope scope) at Microsoft.Scripting.Hosting.ScriptSource.ExecuteAndWrap(ScriptScope scope, ObjectHandle& exception)

ay-ex commented 2 months ago

@jpdon2503 : Since it might be related to: #46 , may I suggest a different issue title? Something along those lines: "pyrevit forms are not loading in RPS"

I had the same error message, so I checked in the pyrevit source code at: C:\ProgramData\pyrevit_4.8.14\pyrevitlib\pyrevit\forms\__init__.py where the message is thrown:

if PY3 and not IRONPY340:
    raise PyRevitCPythonNotSupported('pyrevit.forms')

Since Ironpython in RPS 2.0.2 is Ironpython3.4.1, and the pyrevit IRONPY340 check is only looking for specifically 3.4.0 python version, the error is thrown.

After going back to RPS 2.0.1 which has exactly the checked 3.4.0 IronPython version, that error will not appear anymore. πŸ™‚

...BUT: Unfortunately for something like:

from pyrevit import forms

user_input = forms.ask_for_string()

you might get this error instead: πŸ€”

... from pyrevit import forms

>>> user_input = forms.ask_for_string(default="default_", prompt="prompt_", title="title_")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\ProgramData\pyrevit_4.8.14\pyrevitlib\pyrevit\forms\__init__.py", line 3389, in ask_for_string
  File "C:\ProgramData\pyrevit_4.8.14\pyrevitlib\pyrevit\forms\__init__.py", line 705, in show
  File "C:\ProgramData\pyrevit_4.8.14\pyrevitlib\pyrevit\forms\__init__.py", line 667, in __init__
  File "C:\ProgramData\pyrevit_4.8.14\pyrevitlib\pyrevit\forms\__init__.py", line 171, in __init__
  File "C:\ProgramData\pyrevit_4.8.14\pyrevitlib\pyrevit\forms\__init__.py", line 194, in load_xaml
TypeError: LoadComponent() takes exactly 3 arguments (2 given)

Where it seems like wpf.LoadComponent (or more precisely IronPython.Modules.Wpf.LoadComponent ) in version 3.4.0 needs three args (an additional CodeContext) instead of two. Here the comparison:

So if someone has suggestions to get the pyrevit.forms working on RPS, that would be highly appreciated. πŸ™

jmcouffin commented 2 months ago

with latest pyRevit, on the develop-4 branch the issue has been resolved https://github.com/eirannejad/pyRevit/pull/2188/files#diff-a515bad6f5702c6da744665845255026e089352d268615b295e4af01c42fa314

try changing the ipy engine for something newer than 2.7.7.0

you could use the wip installers of pyrevit to get the fix

ay-ex commented 2 months ago

@jmcouffin thank for the quick feedback! πŸ™‚ I will try that. (for the above test on rps 2.0.1 both: my pyrevit engine and rps ironpyhton were set to 3.4.0 πŸ€” )

jmcouffin commented 2 months ago

this error is a common one and due to the way the ironpython wpf is brought in. Depending on the way, it requires the CodeContext passed as well _ which is unwanted. Proper usgae of LoadComponent should be 2 args only.

ay-ex commented 2 months ago

thank you for the explanation. this is great news: the wpf issue is one of the main reasons we kept installs of pyrevit in our office at ipy277 version, so we have a reliable matching version of rps (ipy 277). looking forward to switch to matching set of rps(ipy 3.4) and pyrevit(ipy3.4) 😌

jmcouffin commented 2 months ago

looking forward to switch to matching set of rps(ipy 3.4) and pyrevit(ipy3.4)

Not sure, it will happen anytime soon, not like this year, I mean. Not many things are compatible with ipy340 in pyrevit and its library. But I may be wrong

ay-ex commented 2 months ago

I see. thank you for the estimation. well the pyrevit preview IPY340PR engine was there since a while, but I guess most users still target the tried and true 2.7x πŸ€”

so far tests on my end look promising - after removing all dependencies to rpw, most of our pyrevit buttons seem ready. πŸ™‚

( I mean in an ideal world, I would switch to only CPython in pyRevit, having a wonderfully ergonomic ptpython repl/console/shell invoked directly from pyRevit. ☺️ (and although I was actually recently able to get ptpython to embed into cpython pyrvt, unfortunately the console there is not a cmd-like terminal environment, so ptpython is not working there properly.) )

ay-ex commented 2 months ago

@jmcouffin thank you so much! linking directly to the ipy340 wpf dll path, similar to your linked patch worked! now I got the pyrevit.forms working for both pyrevit (ipy3.4.0) and rps (3.4.0) : πŸ˜€ image

ay-ex commented 2 months ago

ok, I spoke to soon: while does now work reliably on rps, it does not always on pyrevit. πŸ€” @jmcouffin do you now what the trigger is, that sometimes it wants the 3 args instead of the 2? Is it a timing thing, which addon gets to load which dlls first?

jmcouffin commented 2 months ago

ok, I spoke to soon: while does now work reliably on rps, it does not always on pyrevit. πŸ€” @jmcouffin do you now what the trigger is, that sometimes it wants the 3 args instead of the 2? Is it a timing thing, which addon gets to load which dlls first?

Maybe a persistent engine is required?

ay-ex commented 2 months ago

@jmcouffin what would this persistent engine look like?


it seems like I have pyrevit.forms wpf reliably working now on this machine, for both rps (ipy3.4.0) and pyrevit(py3.4.0) :

wpf_dllpath = r"C:\ProgramData\pyrevit_4.8.14\bin\engines\IPY340PR\pyRevitLabs.IronPython.Wpf.dll" clr.AddReferenceToFileAndPath(wpf_dllpath) import wpf

* pyrevit: I reverted to pyRevit 4.8.14 to before the linked patch above.

_BUT_: 
in pyrevt, as soon as I `AddReference` as shown above in the screenshot, 
again I get the 2/3-args-wpf-loadcomponent-error from above.
but only in pyrevit, not in rps. 
with the following snippets I can reproducibly run or break it on my current machine:

* this works for rps and pyrevit:
```python
import clr

def show_clr_refs_filtered(search_text):
    print("show_clr_refs_filtered:")
    for ref in clr.References:
        if search_text.lower() in ref.ToString().lower():
            print(35*"-")
            print(ref)
            print(ref.Location)
    print(35*"=")

show_clr_refs_filtered("wpf")

from pyrevit import forms

user_input = forms.ask_for_string(default="received_user_input")
print(user_input)

import wpf
print(wpf.LoadComponent.__doc__)

show_clr_refs_filtered("wpf")

import clr

def show_clr_refs_filtered(search_text): print("show_clr_refs_filtered:") for ref in clr.References: if search_text.lower() in ref.ToString().lower(): print(35"-") print(ref) print(ref.Location) print(35"=")

show_clr_refs_filtered("wpf")

from pyrevit import forms

user_input = forms.ask_for_string(default="received_user_input") print(user_input)

show_clr_refs_filtered("wpf")



which is rather puzzling to me, since I assumed the pyrevit wpf dll referenced to in the second snippet, 
is exactly the one I am using for the `pyrevit.forms`.  πŸ€” 

equally puzzling I find, that in pyrevit in both cases - the one with the error and the one without - 
the call signature for `wpf.LoadComponent` shows 2 args for all overloads:  πŸ€” 

![image](https://github.com/architecture-building-systems/revitpythonshell/assets/127405908/52644a29-e6fd-4e1b-bd5e-15052f845744)

but the errors with the message it would need 3 args.

@jmcouffin  or maybe @eirannejad : do you know what is going on there?
ay-ex commented 2 months ago

aha, I think now I got at least a lead: πŸ•΅οΈ `wpf is a different thing in different places: it seems to be a module in the pyrevit button script context, but a class inside pyrevit init.py

image

ay-ex commented 2 months ago

ok and if for ipy340 engine in C:\ProgramData\pyrevit_4.8.14\pyrevitlib\pyrevit\framework.py wpf is loaded with clr.AddReferenceToFileAndPath(wpf_dllpath) instead of wpf = IronPython.Modules.Wpf it works πŸŽ‰ for pyrvt(ipy340):

image

image

as they are now in both contexts a module. ☺️

so my interpretation is (please correct me if I am wrong): just PY3 does not help to distinguish python3 from ironpython3, as a not yet existing PY_IMPL = sys.implementation.name could.

I assume the wpf = IronPython.Modules.Wpf was meant for PY3/PY_IMPL="cpython" and the clr.AddReferenceToFileAndPath(wpf_dllpath);import wpf should be used for PY3/PY_IMPL="ironpython" ?

ay-ex commented 2 months ago

@jpdon2503 does the following resolve your error message?:

for rps 2.0.1: in init.py import wpf:

import clr
wpf_dllpath = r"C:\ProgramData\pyrevit_4.8.14\bin\engines\IPY340PR\pyRevitLabs.IronPython.Wpf.dll"
clr.AddReferenceToFileAndPath(wpf_dllpath)
import wpf

you would need to replace wpf_dllpath with your pyrevit wpf dll path in the above.