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 interpreter not working #1749

Closed
narrsam opened this issue Mar 3, 2023 · 19 comments
Closed

CPython interpreter not working #1749

narrsam opened this issue Mar 3, 2023 · 19 comments

Comments

@narrsam
Copy link

narrsam commented Mar 3, 2023

I am trying a execute a very simple script as a test in preparation to using a CPython library in my script:

#! python3

import Autodesk.Revit.DB as DB
from Autodesk.Revit.UI import TaskDialog
from pyrevit import revit

doc = __revit__.ActiveUIDocument.Document
td = TaskDialog.Show("testing", doc.PathName)

The script works fine when I remove the first line (#! python3), but crashes with this error if I leave it:

CPython Traceback:
KeyNotFoundException : KeyError
 at IronPython.Runtime.PythonDictionary.GetItem(Object key)
 at IronPython.Runtime.PythonDictionary.get_Item(Object[] key)

pyRevitLabs.PythonNet
[' File "<string>", line 5, in <module>\n', ' File "C:\\Program Files\\pyRevit-Master\\pyrevitlib\\pyrevit\\revit\\__init__.py", line 23, in <module>\n from pyrevit.revit import ui\n', ' File "C:\\Program Files\\pyRevit-Master\\pyrevitlib\\pyrevit\\revit\\ui.py", line 12, in <module>\n from pyrevit.runtime import types\n', ' File "C:\\Program Files\\pyRevit-Master\\pyrevitlib\\pyrevit\\runtime\\__init__.py", line 20, in <module>\n from pyrevit.userconfig import user_config\n', ' File "C:\\Program Files\\pyRevit-Master\\pyrevitlib\\pyrevit\\userconfig.py", line 50, in <module>\n from pyrevit.versionmgr import upgrade\n', ' File "C:\\Program Files\\pyRevit-Master\\pyrevitlib\\pyrevit\\versionmgr\\__init__.py", line 18, in <module>\n from pyrevit.coreutils import git\n', ' File "C:\\Program Files\\pyRevit-Master\\pyrevitlib\\pyrevit\\coreutils\\git.py", line 29, in <module>\n mlogger.debug(\'Loading dll: %s\', LIBGIT_DLL)\n', ' File "logging\\__init__.py", line 1421, in debug\n', ' File "C:\\Program Files\\pyRevit-Master\\pyrevitlib\\pyrevit\\coreutils\\logger.py", line 148, in isEnabledFor\n envvars.get_pyrevit_env_var(envvars.FILELOGGING_ENVVAR)\n', ' File "C:\\Program Files\\pyRevit-Master\\pyrevitlib\\pyrevit\\coreutils\\envvars.py", line 104, in get_pyrevit_env_var\n return data_dict[param_name

Revit v2020.2.9
PyRevit v2.4.12
Windows 10

@vmarquar
Copy link

Same issue here with Revit 2022.1 and CPython

@dsquad96
Copy link

dsquad96 commented Mar 28, 2023

UPDATE It seems isolated to CPython 3.8.5. I just switched over to 3.7.8 and importing pyRevit works fine.
I also have this issue in Revit 2023.1. I tested the "Test CPython Command" in the pyRevitDev tab and it prints everything right up until the "import pyRevit" line of code and throws the same error

@vmarquar
Copy link

vmarquar commented Jun 7, 2023

Unfortunately, I can't confirm that. Both versions of CPython 3.8.5 and 3.7.8 result in the same error, when I try to import pyrevit.

I'm using Revit 2023.1.1 and pyrevit 4.8.12

@Kervin14
Copy link

Now following this thread as I'm also getting this exception using CPython 3.8.5, R2022.2 and ((shakes fist at screen)) not able to import pyrevit python module

@vmarquar
Copy link

vmarquar commented Jun 12, 2023

I've investigated the problem a bit more and i've found a workaround to use at least environment variables:

#! python3
import sys
print(sys.version)



###### WORKING EXAMPLE / WORKAROUND TO GET ENVIRONMENTAL VARIABLES WORKING
from pyrevit.coreutils import envvars
env_dict = envvars.get_pyrevit_env_vars() # env_dict is of type IronPython.Runtime.PythonDictionary

# Iterating this dict (IronPython.Runtime.PythonDictionary) works and print all environment variables and their values
for k, v in env_dict.iteritems():
    print(k, v)

# Getting the value directly works after getting the complete env_dict into the script
my_env_value = env_dict.get('MY_ENV_VARIABLE')
print(f"MY_ENV_VARIABLE: {my_env_value}")



###### NOT WORKING EXAMPLE
print(envvars.get_pyrevit_env_var('MY_ENV_VARIABLE')) ### --> this fails with following error messages:
#KeyNotFoundException : KeyError
#bei IronPython.Runtime.PythonDictionary.GetItem(Object key)
#bei IronPython.Runtime.PythonDictionary.get_Item(Object[] key)

The Problem is caused in line 104 in envvars.py file:

def get_pyrevit_env_var(param_name):
    """Get value of a parameter shared between all scripts.

    Args:
        param_name (str): name of environment variable

    Returns:
        object: any object stored as the environment variable value
    """
    # This function returns None if it can not find the parameter.
    # Thus value of None should not be used for params

    data_dict = AppDomain.CurrentDomain.GetData(ENV_VAR_DICT_NAME)
    if data_dict: 
        try:
            return data_dict[param_name]   ## ANY NEW LINE HERE, EVEN A print "test" CAUSES AN ERROR?
        except KeyError:  ## KeyNotFoundException will be raised from Ironpython, I dont know if this will be mapped to a python3 KeyError?
            return None
    else:
        return None

@sanzoghenzo
Copy link
Contributor

Hi, I encountered this a while ago as reported in this old issue while trying to make pyrevitlib CPyhon compatible.

I couldn't get what's going on in those lines and I gave up.

Could it be that GetData returns a data structure not entierly compatible with python?

maybe instead of using the try/except, a data_dict.get(param_name) would work... I'll test it and get back to you

@vmarquar
Copy link

vmarquar commented Jun 22, 2023

I've tested 'data_dict.get(param_name)' or even a simple print("foo bar bla") without success.

I think it is related to a logging issue.

@sanzoghenzo
Copy link
Contributor

sanzoghenzo commented Jun 23, 2023

I don't know why this works, but I made it work by DRYing the code (that is, calling get_pyrevit_env_vars in the other envvars functions):

def get_pyrevit_env_vars():
    """Get the root dictionary, holding all environment variables."""
    return AppDomain.CurrentDomain.GetData(ENV_VAR_DICT_NAME)


def get_pyrevit_env_var(param_name):
    """Get value of a parameter shared between all scripts.

    Args:
        param_name (str): name of environment variable

    Returns:
        object: any object stored as the environment variable value
    """
    # This function returns None if it can not find the parameter.
    # Thus value of None should not be used for params

    data_dict = get_pyrevit_env_vars()
    return data_dict.get(param_name) if data_dict else None


def set_pyrevit_env_var(param_name, param_value):
    """Set value of a parameter shared between all scripts.

    Args:
        param_name (str): name of environment variable
        param_value (object): any python object
    """
    # Get function returns None if it can not find the parameter.
    # Thus value of None should not be used for params
    data_dict = get_pyrevit_env_vars() or {}
    data_dict[param_name] = param_value
    AppDomain.CurrentDomain.SetData(ENV_VAR_DICT_NAME, data_dict)

Of course this doesn't completely solves the OP issue, since the execution stumbles on another exception, but at least we ruled the envvars out.

Can you try it and confirm that works for you? If so, I'll do a PR ASAP

@sanzoghenzo
Copy link
Contributor

@vmarquar have you got the chance to check if my patch works for you?

@sanzoghenzo
Copy link
Contributor

sanzoghenzo commented Jul 5, 2023

@eirannejad @jmcouffin

I suppose that all those CPython issues (here and on the forum) should be adressed by first updating the pythonnet libary.
I could take a stab at this, but I need some directions.
I see that the python.net library is a sumbodule in dev/modules, should it be enough to upgrade that sumbodule to the 3.0.1 release commit and then rebuild everything to see if it still works?

I see that now pythonnet supports up to python3.11, so another thing to do is to add the whenever needed. Is there a list of those places or should I do a global search on the codebase?

@jmcouffin
Copy link
Contributor

I would not be the one to guide you @sanzoghenzo
It is way above my league
If @eirannejad gets a chance...

@vmarquar
Copy link

vmarquar commented Jul 5, 2023

@vmarquar have you got the chance to check if my patch works for you?

Yes, i've just tested it and your workaround works (at least for the envvars import) 🥳

Testing code:

  1. edit the envvars.py file according to sanzoghenzo's comment
  2. run follwowing code as revit extension
#! python3
import sys
print("running test - github issue #1749")
print(sys.version) #prints on my machine: 3.8.5 (tags/v3.8.5:580fbb0, Jul 20 2020, 15:57:54) [MSC v.1924 64 bit (AMD64)]

# TESTING sanzoghenzo workaround (edit envvars.py file)
from pyrevit.coreutils import envvars
envvars.set_pyrevit_env_var("testkey", "mytestvalue")

mytestvalue = envvars.get_pyrevit_env_var("testkey")
print(mytestvalue)
all_env_vars = envvars.get_pyrevit_env_vars()
print(all_env_vars) # =IronPython.Runtime.PythonDictionary
for k in all_env_vars:
    print(k)

print("finished script - everything ok!")

But as you mentioned importing pyrevit or some of its submodules doesn't work yet:

#from pyrevit.coreutils import envvars #--> Works (But this has worked before as well I think...)
from pyrevit import script # ---> Fails: TypeError : No method matches given arguments for CompileCSharp: ()

sanzoghenzo added a commit to sanzoghenzo/pyRevit that referenced this issue Jul 6, 2023
@julillosamaral
Copy link

Hi Guys,

I'm facing this exact same issue. Is there any timeline on the fix?
Is there a way I can help?

Thanks,
Julio

@sanzoghenzo
Copy link
Contributor

Hi @julillosamaral

I submitted the fix for the envvars module a few hours ago, but it might take a while for it to be published in an official release.

For the bigger issue of cpython compatibility, I can't promise any ETA because I just started analyzing pyrevitlabs and pythonnet c# code.

Some of my findings (@eirannejad correct me if I'm wrong):

  • now pythonnet can be compiled once for all the python versions, it's just a matter of setting the Runtime.PythonDLL property or PYTHONNET_PYDLL environment variable to the path of the python3xx.dll, so the build process must be changed to reflect that
  • There is still the need to maintain a fork of the library to expose some internal methods used by pyrevit; maybe in the future the parts of pyrevit's code that access those internal methods can be moved to the upstream pythonnet repo for everyone to enjoy (I only analyze two methods/usages, not sure if this can be done yet)
  • after that, there will be the need to adapt the code to prevent troubles with pythonnet 3 breaking changes and deprecations.
  • since pythonnet supports python up to version 3.11, we can add all the supported engines to pyrevit. I still haven't looked at how this should be done other than the pyRevitFile

@sanzoghenzo
Copy link
Contributor

Little update: after many hour of searching I discovered that Runtime.LoadModule was removed in favor of the new PyModule.Import method (Already filled an issue in the pythonnet github to ask to update the documentation).

I should have found a way to convert the search paths python list into a .NET list without having to access the PyList_GetItem directly;

I'll be away for the weekend, but I really appreciate if @eirannejad could advise me on how to do proper testing for when I get back. How can I run the visual studio project in revit? it seems that there are no debug/running config, is it on purpose?

@imigas434
Copy link

This issue is unfortunately still present in:
Revit 2023.1
pyRevit 4.8.13.23182
on engine CPython 3.8.5

I don't know why this works, but I made it work by DRYing the code (that is, calling get_pyrevit_env_vars in the other envvars functions):

def get_pyrevit_env_vars():
    """Get the root dictionary, holding all environment variables."""
    return AppDomain.CurrentDomain.GetData(ENV_VAR_DICT_NAME)


def get_pyrevit_env_var(param_name):
    """Get value of a parameter shared between all scripts.

    Args:
        param_name (str): name of environment variable

    Returns:
        object: any object stored as the environment variable value
    """
    # This function returns None if it can not find the parameter.
    # Thus value of None should not be used for params

    data_dict = get_pyrevit_env_vars()
    return data_dict.get(param_name) if data_dict else None


def set_pyrevit_env_var(param_name, param_value):
    """Set value of a parameter shared between all scripts.

    Args:
        param_name (str): name of environment variable
        param_value (object): any python object
    """
    # Get function returns None if it can not find the parameter.
    # Thus value of None should not be used for params
    data_dict = get_pyrevit_env_vars() or {}
    data_dict[param_name] = param_value
    AppDomain.CurrentDomain.SetData(ENV_VAR_DICT_NAME, data_dict)

Of course this doesn't completely solves the OP issue, since the execution stumbles on another exception, but at least we ruled the envvars out.

Can you try it and confirm that works for you? If so, I'll do a PR ASAP

I tried this, but I'm not sure if it works or not, because different error showed up immediately. So probably the issue is much deeper..

@sanzoghenzo
Copy link
Contributor

This issue is unfortunately still present in: Revit 2023.1 pyRevit 4.8.13.23182 on engine CPython 3.8.5

Yes, the fix is on the development branch, so you either use a WIP release or wait for the next release.

I tried this, but I'm not sure if it works or not, because different error showed up immediately. So probably the issue is much deeper..

That's exactly what I stated under the code 😉

I'm still waiting/hoping for @eirannejad (btw, I hope you are OK!) to explain how to test/debug the addon from visual studio, then I can proceed with the pythonnet upgrade and start to resolve this issues...

@imigas434
Copy link

Yes, the fix is on the development branch, so you either use a WIP release or wait for the next release.

Perfect. Thank you 👍

@s-github-2
Copy link

s-github-2 commented Jan 18, 2024

I faced same issue and here is what I get with C Python 3.7.8 ( I will try 3.8.5 next but expect similar issue)

CPython Traceback:
TypeError : No method matches given arguments for CompileCSharp: ()
File "C:\Users\user\OneDrive\Documents\Myc\pyrevit_custom_buttons\MyExtensions\MyExtensions.extension\Myc.tab\Myc.panel\circuits_info.pushbutton\script.py", line 16, in
import pyrevit.revit
File "C:\Users\user\AppData\Roaming\pyRevit-Master\pyrevitlib\pyrevit\revit_init_.py", line 24, in
from pyrevit.revit import ui
File "C:\Users\user\AppData\Roaming\pyRevit-Master\pyrevitlib\pyrevit\revit\ui.py", line 15, in
from pyrevit.runtime import types
File "C:\Users\user\AppData\Roaming\pyRevit-Master\pyrevitlib\pyrevit\runtime_init_.py", line 486, in
RUNTIME_ASSM = get_runtime_asm()
File "C:\Users\user\AppData\Roaming\pyRevit-Master\pyrevitlib\pyrevit\runtime_init
.py", line 328, in _get_runtime_asm
return generate_runtime_asm()
File "C:\Users\user\AppData\Roaming\pyRevit-Master\pyrevitlib\pyrevit\runtime_init
.py", line 304, in _generate_runtime_asm
debug=False

pyRevitLabs.PythonNet
at Python.Runtime.Runtime.CheckExceptionOccurred()
at Python.Runtime.PyScope.Exec(String code, IntPtr _globals, IntPtr _locals)
at Python.Runtime.PyScope.Exec(String code, PyDict locals)
at PyRevitLabs.PyRevit.Runtime.CPythonEngine.Execute(ScriptRuntime& runtime)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants