From ForgeType to Datatype

Ok - so how does one go from ForgeTypeId (spec) to a DATATYPE you can use in a Shared Parameter file?

You can’t just use the text as both of these (and maybe more?) have an additional prefix… In this case HVAC_

Then YesNo needs to be parsed to YESNO - not YES_NO like others with camel case.

Or is this just one of those tedious thing in Revit API? (once upon a time it was simple…)

------

autodesk.spec.aec.energy:thermalConductivity-2.0.0

Thermal Conductivity

THERMAL_CONDUCTIVITY

------

------

autodesk.spec.aec.structural:thermalExpansionCoefficient-2.0.0

Thermal Expansion Coefficient

THERMAL_EXPANSION_COEFFICIENT

------

from Autodesk.Revit import DB
from Autodesk.Revit.DB import LabelUtils
import clr
import System
import re

flags = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static

name_map = {}

def add_names(dotnet_type, prefix=""):
    for p in dotnet_type.GetProperties(flags):
        try:
            val = p.GetValue(None, None)
            name_map[val.TypeId] = prefix + p.Name
        except:
            pass

# Build mapping
add_names(clr.GetClrType(DB.SpecTypeId))
add_names(clr.GetClrType(DB.SpecTypeId.Boolean))
add_names(clr.GetClrType(DB.SpecTypeId.Int))
add_names(clr.GetClrType(DB.SpecTypeId.String))
add_names(clr.GetClrType(DB.SpecTypeId.Reference))

def to_clean(name):
    if not name:
        return "UNKNOWN"

    s1 = re.sub(r'(.)([A-Z][a-z]+)', r'\1_\2', name)
    s2 = re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', s1)

    if s2 == "Yes_No":
        s2 = "YESNO"

    return s2.replace(" ", "").upper()

results = set()

for spec_id in DB.SpecUtils.GetAllSpecs():
    raw = name_map.get(spec_id.TypeId, "")
    forge = spec_id.TypeId
    forgename = LabelUtils.GetLabelForSpec(spec_id)
    myname = to_clean(raw)
    results.add((myname, forgename, forge))

for r in sorted(results):
    print("------")
    print(r[2])
    print(r[1])
    print(r[0])
    print("------")

Try

UnitUtils.GetTypeCatalogStringForSpec(spec_id)

No go. UnitUtils is for unit ForgetType, not spec types.

I see that UnitUtils only includes the ones with units - makes sense sort of given the name. Running this there are only 10 exceptions for which your to_clean() function will work. Instead of the try/except you could check “IsMeasurableSpec”. Anyway deals with all the HVAC_* and the like.

from Autodesk.Revit.DB import (
    UnitUtils,
    LabelUtils,
    SpecUtils,
)

def forgetype_to_datatype():
    print("Print all specs")
    results = set()

    # spec_ids = UnitUtils.GetAllMeasurableSpecs()
    # spec_ids = UnitUtils.GetAllSpecs()
    spec_ids = SpecUtils.GetAllSpecs()
    print(len(spec_ids))
    for spec_id in spec_ids:
        forge = spec_id.TypeId
        forgename = LabelUtils.GetLabelForSpec(spec_id)
        try:
            myname = UnitUtils.GetTypeCatalogStringForSpec(spec_id)
        except:
            myname = "not measurable"
        try:
            results.add((myname, forgename, forge))
        except:
            pass

    for r in sorted(results):
        print(r[2])
        print(r[1])
        print(r[0])
        print("------")

if __name__ == '__main__':
    forgetype_to_datatype()

Thanks, between the two and some cleanup, I think I can get where I need to be.
Looks like the older datatypes are just being interpreted under the hood from the shared param file. Time for a 2.0 param file format. Probably JSON to one can add in localization to shared params.