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

[Bug]: cpython 3.8.5 shows "<class 'int'>" instead of "<class 'BuiltInParameter'>" enum member of BuiltInParameter #2241

Open
3 of 5 tasks
ay-ex opened this issue May 6, 2024 · 4 comments
Labels
Bug Bug that stops user from using the tool or a major portion of pyRevit functionality [class] Python 3 Issues related to cpython engines [subsystem]

Comments

@ay-ex
Copy link

ay-ex commented May 6, 2024

✈ Pre-Flight checks

  • I don't have SentinelOne antivirus installed (see above for the solution)
  • I have searched in the issues (open and closed) but couldn't find a similar issue
  • I have searched in the pyRevit Forum for similar issues
  • I already followed the installation troubleshooting guide thoroughly
  • I am using the latest pyRevit Version

🐞 Describe the bug

When running these (apart from python3 shebang identical) snippets:
in ironpython:

import clr
clr.AddReference("Autodesk")

from Autodesk.Revit.DB import BuiltInParameter as Bip

import sys


print(sys.version_info)
print(sys.implementation.name)
print("code: `type(Bip.LEVEL_IS_BUILDING_STORY)`")
print(type(Bip.LEVEL_IS_BUILDING_STORY))

and cpython

#! python3
import clr
clr.AddReference("Autodesk")

from Autodesk.Revit.DB import BuiltInParameter as Bip

import sys


print(sys.version_info)
print(sys.implementation.name)
print("code: `type(Bip.LEVEL_IS_BUILDING_STORY)`")
print(type(Bip.LEVEL_IS_BUILDING_STORY))

with pyrevit engines ironpython 3.4.0 and cpython 3.8.5 I get different type results:

  • on ironpython: <class 'BuiltInParameter'> (as expected)
  • on cpython: <class 'int'> (not as expected)

this prevents me from using level.get_Parameter(Bip.LEVEL_IS_BUILDING_STORY)
to access ui-language-agnostic parameter values for built-in-parameters.

image

⌨ Error/Debug Message

if a parameter access is use with the above in cpython like so: 

doc = __revit__.ActiveUIDocument.Document
print(doc.ActiveView.GenLevel.get_Parameter(Bip.LEVEL_IS_BUILDING_STORY))


the resulting error is as expected (it cannot find an overload with int as method argument):

CPython Traceback:
TypeError : No method matches given arguments for get_Parameter: (<class 'int'>)
 File "C:\ProgramData\pyRevit_BH\sandbox.extension\pyRevit_BH.tab\Sandbox.panel\Sandbox.pulldown\bip_test_cPy3_Sandbox.pushbutton\bip_test_cPy3_Sandbox_script.py", line 16, in <module>
print(doc.ActiveView.GenLevel.get_Parameter(Bip.LEVEL_IS_BUILDING_STORY))

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)

# ------

I get the impression that in cpython we get the integer back from the BuiltInParameter Enum instead of the expected BuiltInParameter class object.

♻️ To Reproduce

  1. create new pyrevit button with the above snippets, for both ironpython and cpython.
  2. run them and observe the different type output.

⏲️ Expected behavior

receiving BuiltInParameter type for both python interpreter versions.

🖥️ Hardware and Software Setup (please complete the following information)

* win 10 (19045)
* rvt 2024 (24.1.0.66)
* pyrevit 4.8.14
  * ironpython 3.4.0
  * cpython 3.8.5

Additional context

there is a discussion on the forum describing the same problem:
https://discourse.pyrevitlabs.io/t/getting-parameters-of-element-in-cpython/3011
so far there is no solution mentioned there.

@ay-ex ay-ex added the Bug Bug that stops user from using the tool or a major portion of pyRevit functionality [class] label May 6, 2024
@ay-ex
Copy link
Author

ay-ex commented May 7, 2024

I just tested it on pyRevit 4.8.16 , cpython 3.8.5 - same issue there.

@ay-ex
Copy link
Author

ay-ex commented May 7, 2024

a possible workaround is to go via forge_type_id - it is not pretty though: 🤔

  • via direct access:
from Autodesk.Revit.DB import BuiltInParameter as Bip
from Autodesk.Revit.DB import ForgeTypeId, ParameterUtils


doc = __revit__.ActiveUIDocument.Document
param = doc.ActiveView.GenLevel.GetParameter(ForgeTypeId(ParameterUtils.GetParameterTypeId(getattr(Bip, "LEVEL_IS_BUILDING_STORY")).TypeId))
# instead of just:
# param = doc.ActiveView.GenLevel.get_Parameter(Bip.LEVEL_IS_BUILDING_STORY)

but already the next step: param.StorageType is your yet another enum that only returns int.

  • via creating dict as lookup table for BuiltInCategory:
print(35*"-")
print("bic: forge_type_id_by_cat_name")
from Autodesk.Revit.DB import BuiltInCategory as Bic
from Autodesk.Revit.DB import Category


forge_type_id_by_cat_name = {}

for bic_cat in dir(Bic):
    if bic_cat.startswith("OST_"):
        bic_name = bic_cat.split("OST_")[-1]
        bic = getattr(Bic, bic_cat)
        if Category.IsBuiltInCategoryValid(bic):
            ftid = Category.GetBuiltInCategoryTypeId(bic)
            forge_type_id_by_cat_name[bic_name] = ftid.TypeId
            # print(ftid.TypeId)
        else:
            pass
            # print("skipped: ", bic_name)

print(f"found {} ftids".format(len(forge_type_id_by_cat_name)))
# for k, v in sorted(forge_type_id_by_cat_name.items()):
#     print(k, v)
  • via creating dict as lookup table for BuiltInParameter:
print(35*"-")
print("bip: forge_type_id_by_param_name")
from Autodesk.Revit.DB import BuiltInParameter as Bip
from Autodesk.Revit.DB import ForgeTypeId, ParameterUtils


forge_type_id_by_param_name = {}

skip_names = {
    "INVALID",
    "Overloads",
}

for bip_name in dir(Bip):
    # print(bip_name)
    if bip_name in skip_names:
        continue
    if bip_name.endswith("__"):
        continue
    bip = getattr(Bip, bip_name)
    if "method" in str(bip) or "function" in str(bip):
        continue
    ftid = ParameterUtils.GetParameterTypeId(bip).TypeId
    # print(bip_name, ftid)
    forge_type_id_by_param_name[bip_name] = ftid

print("found {} ftids:".format(len(forge_type_id_by_param_name)))
# for k, v in sorted(forge_type_id_by_param_name.items()):
#     print(k, v)

so ideally there could be a fix with which we could access enums in pyRevit cpython the same way as in ironpython. 🤔

@jmcouffin jmcouffin added the Python 3 Issues related to cpython engines [subsystem] label May 7, 2024
@sanzoghenzo
Copy link
Contributor

Hi @ay-ex, sorry for the delay in the response.

This is a known bug of the version of pythonnet currently used by pyrevit. It was solved in version 3.0.
We're trying to update it alongside the upgrade to the .net8 sdk to support revit 2025.
As this was not our project originally and we're not super c# experts, we're trying to do the best we can to reach this goal.
The upcoming pyrevit version 5 should fix this issue (no ETA yet, unfortunately).

@ay-ex
Copy link
Author

ay-ex commented May 29, 2024

hi @sanzoghenzo ,
no worries and thank you for the notification. 🙂
looking forward to pyRevit 5.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Bug that stops user from using the tool or a major portion of pyRevit functionality [class] Python 3 Issues related to cpython engines [subsystem]
Projects
None yet
Development

No branches or pull requests

3 participants