Skip to content

runtime

Module that compiles the base DLL on load.

Attributes

mlogger = logger.get_logger(__name__) module-attribute

INTERFACE_TYPES_DIR = RUNTIME_DIR module-attribute

DOTNET_DIR = op.join(os.getenv('windir'), 'Microsoft.NET', 'Framework') module-attribute

DOTNET64_DIR = op.join(os.getenv('windir'), 'Microsoft.NET', 'Framework64') module-attribute

DOTNET_SDK_DIR = op.join(os.getenv('programfiles(x86)'), 'Reference Assemblies', 'Microsoft', 'Framework', '.NETFramework') module-attribute

DOTNET_FRAMEWORK_DIRS = sorted([x for x in os.listdir(DOTNET_DIR) if x.startswith('v4.') and 'X' not in x], reverse=True) module-attribute

DOTNET64_FRAMEWORK_DIRS = sorted([x for x in os.listdir(DOTNET64_DIR) if x.startswith('v4.') and 'X' not in x], reverse=True) module-attribute

DOTNET_TARGETPACK_DIRS = sorted([x for x in os.listdir(DOTNET_SDK_DIR) if x.startswith('v4.') and 'X' not in x], reverse=True) module-attribute

RUNTIME_NAMESPACE = 'PyRevitLabs.PyRevit.Runtime' module-attribute

CMD_EXECUTOR_TYPE_NAME = '{}.{}'.format(RUNTIME_NAMESPACE, 'ScriptCommand') module-attribute

CMD_AVAIL_TYPE_NAME_EXTENDED = coreutils.make_canonical_name(RUNTIME_NAMESPACE, 'ScriptCommandExtendedAvail') module-attribute

CMD_AVAIL_TYPE_NAME_SELECTION = coreutils.make_canonical_name(RUNTIME_NAMESPACE, 'ScriptCommandSelectionAvail') module-attribute

CMD_AVAIL_TYPE_NAME_ZERODOC = coreutils.make_canonical_name(RUNTIME_NAMESPACE, 'ScriptCommandZeroDocAvail') module-attribute

CMD_AVAIL_NAME_POSTFIX = '-avail' module-attribute

SOURCE_FILE_EXT = '.cs' module-attribute

SOURCE_FILE_FILTER = '(\\.cs)' module-attribute

CPYTHON_ENGINE = user_config.get_active_cpython_engine() module-attribute

BASE_TYPES_DIR_HASH = coreutils.get_str_hash(coreutils.calculate_dir_hash(INTERFACE_TYPES_DIR, '', SOURCE_FILE_FILTER) + EXEC_PARAMS.engine_ver + str(CPYTHON_ENGINE.Version) if CPYTHON_ENGINE else '0')[:HASH_CUTOFF_LENGTH] module-attribute

RUNTIME_ASSM_FILE_ID = '{}_{}'.format(BASE_TYPES_DIR_HASH, RUNTIME_NAMESPACE) module-attribute

RUNTIME_ASSM_FILE = op.join(BIN_DIR, 'pyRevitLabs.PyRevit.Runtime.{}.dll'.format(HOST_APP.version)) module-attribute

RUNTIME_ASSM_NAME = op.splitext(op.basename(RUNTIME_ASSM_FILE))[0] module-attribute

RUNTIME_ASSM = None module-attribute

assm_list = assmutils.find_loaded_asm(RUNTIME_ASSM_NAME) module-attribute

CMD_EXECUTOR_TYPE = assmutils.find_type_by_name(RUNTIME_ASSM, CMD_EXECUTOR_TYPE_NAME) module-attribute

CMD_AVAIL_TYPE_EXTENDED = assmutils.find_type_by_name(RUNTIME_ASSM, CMD_AVAIL_TYPE_NAME_EXTENDED) module-attribute

CMD_AVAIL_TYPE_SELECTION = assmutils.find_type_by_name(RUNTIME_ASSM, CMD_AVAIL_TYPE_NAME_SELECTION) module-attribute

CMD_AVAIL_TYPE_ZERODOC = assmutils.find_type_by_name(RUNTIME_ASSM, CMD_AVAIL_TYPE_NAME_ZERODOC) module-attribute

Classes

Functions:

get_references()

Get list of all referenced assemblies.

Resolved once per host process, then reused by later session loads: the shipped assemblies that resolving loads stay loaded, and host framework locations don't change while the host runs.

Returns:

Type Description
list

referenced assemblies

Source code in pyrevitlib/pyrevit/runtime/__init__.py
def get_references():
    """Get list of all referenced assemblies.

    Resolved once per host process, then reused by later session loads: the
    shipped assemblies that resolving loads stay loaded, and host framework
    locations don't change while the host runs.

    Returns:
        (list): referenced assemblies
    """
    ref_list = [
        # system stuff
        "System",
        "System.Core",
        "System.Runtime",
        "System.Linq",
        "System.Collections",
        "System.Collections.Immutable",
        "System.Console",
        "System.Xaml",
        "System.Web",
        "System.Xml",
        "System.Numerics",
        "System.Drawing",
        "System.Windows.Forms",
        "System.ComponentModel.Primitives",
        "System.ComponentModel.TypeConverter",
        "PresentationCore",
        "PresentationFramework",
        "WindowsBase",
        "WindowsFormsIntegration",
        # legacy csharp/vb.net compiler
        "Microsoft.CSharp",
        # iron python engine
        "{prefix}Microsoft.Dynamic".format(prefix=eng.EnginePrefix),
        "{prefix}Microsoft.Scripting".format(prefix=eng.EnginePrefix),
        "{prefix}IronPython".format(prefix=eng.EnginePrefix),
        "{prefix}IronPython.Modules".format(prefix=eng.EnginePrefix),
        # revit api
        "RevitAPI",
        "RevitAPIUI",
        "AdWindows",
        "UIFramework",
        # pyrevit loader assembly
        "pyRevitLoader",
        # pyrevit labs
        "pyRevitLabs.Common",
        "pyRevitLabs.CommonWPF",
        "pyRevitLabs.MahAppsMetro",
        "pyRevitLabs.NLog",
        "pyRevitLabs.Json",
        "pyRevitLabs.Emojis",
        "pyRevitLabs.TargetApps.Revit",
        "pyRevitLabs.PyRevit",
        "pyRevitLabs.PyRevit.Runtime.Shared",
    ]

    # netcore depends
    if NETCORE:
        ref_list.extend(
            [
                "System.Drawing.Common",
                "System.Diagnostics.Process",
                "System.Diagnostics.FileVersionInfo",
                "System.Text.RegularExpressions",
            ]
        )

    # another revit api
    ref_list.extend(["Xceed.Wpf.AvalonDock"])

    cache_key = "PYREVITResolvedReferences{}{}".format(
        eng.EnginePrefix,
        coreutils.get_str_hash(BIN_DIR + "|" + "|".join(ref_list)),
    )
    cached_refs = framework.AppDomain.CurrentDomain.GetData(cache_key)
    if cached_refs:
        cached_ref_files = cached_refs.split(coreutils.DEFAULT_SEPARATOR)
        if all(op.exists(ref_file) for ref_file in cached_ref_files):
            return cached_ref_files

    refs = (_get_reference_file(ref_name) for ref_name in ref_list)
    resolved_refs = [r for r in refs if r]
    framework.AppDomain.CurrentDomain.SetData(
        cache_key, coreutils.DEFAULT_SEPARATOR.join(resolved_refs)
    )
    return resolved_refs

create_ipyengine_configs(clean=False, full_frame=False, persistent=False)

Return the configuration for ipython engine.

Parameters:

Name Type Description Default
clean bool

Engine should be clean. Defaults to False.

False
full_frame bool

Engine shoul be full frame. Defaults to False.

False
persistent bool

Engine should persist. Defaults to False.

False

Returns:

Type Description
str

Configuration

Source code in pyrevitlib/pyrevit/runtime/__init__.py
def create_ipyengine_configs(clean=False, full_frame=False, persistent=False):
    """Return the configuration for ipython engine.

    Args:
        clean (bool, optional): Engine should be clean. Defaults to False.
        full_frame (bool, optional): Engine shoul be full frame. Defaults to False.
        persistent (bool, optional): Engine should persist. Defaults to False.

    Returns:
        (str): Configuration
    """
    return json.dumps(
        {
            exts.MDATA_ENGINE_CLEAN: clean,
            exts.MDATA_ENGINE_FULLFRAME: full_frame,
            exts.MDATA_ENGINE_PERSISTENT: persistent,
        }
    )

create_ext_command_attrs()

Create dotnet attributes for Revit external commands.

This method is used in creating custom dotnet types for pyRevit commands and compiling them into a DLL assembly. Current implementation sets RegenerationOption.Manual and TransactionMode.Manual

Returns:

Type Description
list[CustomAttributeBuilder]

object for RegenerationOption and TransactionMode attributes.

Source code in pyrevitlib/pyrevit/runtime/__init__.py
def create_ext_command_attrs():
    """Create dotnet attributes for Revit external commands.

    This method is used in creating custom dotnet types for pyRevit commands
    and compiling them into a DLL assembly. Current implementation sets
    ``RegenerationOption.Manual`` and ``TransactionMode.Manual``

    Returns:
        (list[CustomAttributeBuilder]): object for `RegenerationOption`
            and `TransactionMode` attributes.
    """
    regen_const_info = framework.clr.GetClrType(
        api.Attributes.RegenerationAttribute
    ).GetConstructor(
        framework.Array[framework.Type]((api.Attributes.RegenerationOption,))
    )

    regen_attr_builder = framework.CustomAttributeBuilder(
        regen_const_info,
        framework.Array[object]((api.Attributes.RegenerationOption.Manual,)),
    )

    # add TransactionAttribute to framework.Type
    trans_constructor_info = framework.clr.GetClrType(
        api.Attributes.TransactionAttribute
    ).GetConstructor(framework.Array[framework.Type]((api.Attributes.TransactionMode,)))

    trans_attrib_builder = framework.CustomAttributeBuilder(
        trans_constructor_info,
        framework.Array[object]((api.Attributes.TransactionMode.Manual,)),
    )

    return [regen_attr_builder, trans_attrib_builder]

create_type(modulebuilder, type_class, class_name, custom_attr_list, *args)

Create a dotnet type for a pyRevit command.

See baseclasses.cs code for the template pyRevit command dotnet type and its constructor default arguments that must be provided here.

Parameters:

Name Type Description Default
modulebuilder (

obj:ModuleBuilder): dotnet module builder

required
type_class type

source dotnet type for the command

required
class_name str

name for the new type

required
custom_attr_list (

obj:list): list of dotnet attributes for the type

required
*args Any

list of arguments to be used with type constructor

()

Returns:

Type Description
type

returns created dotnet type

Examples:

asm_builder = AppDomain.CurrentDomain.DefineDynamicAssembly(
win_asm_name, AssemblyBuilderAccess.RunAndSave, filepath
)
module_builder = asm_builder.DefineDynamicModule(
ext_asm_file_name, ext_asm_full_file_name
)
create_type(
    module_builder,
    runtime.ScriptCommand,
    "PyRevitSomeCommandUniqueName",
    runtime.create_ext_command_attrs(),
    [scriptpath, atlscriptpath, searchpath, helpurl, name,
    bundle, extension, uniquename, False, False])

Source code in pyrevitlib/pyrevit/runtime/__init__.py
def create_type(modulebuilder, type_class, class_name, custom_attr_list, *args):
    """Create a dotnet type for a pyRevit command.

    See ``baseclasses.cs`` code for the template pyRevit command dotnet type
    and its constructor default arguments that must be provided here.

    Args:
        modulebuilder (:obj:`ModuleBuilder`): dotnet module builder
        type_class (type): source dotnet type for the command
        class_name (str): name for the new type
        custom_attr_list (:obj:`list`): list of dotnet attributes for the type
        *args (Any): list of arguments to be used with type constructor

    Returns:
        (type): returns created dotnet type

    Examples:
        ```python
        asm_builder = AppDomain.CurrentDomain.DefineDynamicAssembly(
        win_asm_name, AssemblyBuilderAccess.RunAndSave, filepath
        )
        module_builder = asm_builder.DefineDynamicModule(
        ext_asm_file_name, ext_asm_full_file_name
        )
        create_type(
            module_builder,
            runtime.ScriptCommand,
            "PyRevitSomeCommandUniqueName",
            runtime.create_ext_command_attrs(),
            [scriptpath, atlscriptpath, searchpath, helpurl, name,
            bundle, extension, uniquename, False, False])
        ```
        <type PyRevitSomeCommandUniqueName>
    """
    # create type builder
    type_builder = modulebuilder.DefineType(
        class_name,
        framework.TypeAttributes.Class | framework.TypeAttributes.Public,
        type_class,
    )

    for custom_attr in custom_attr_list:
        type_builder.SetCustomAttribute(custom_attr)

    # prepare a list of input param types to find the matching constructor
    type_list = []
    param_list = []
    for param in args:
        if isinstance(param, str) or isinstance(param, int):
            type_list.append(type(param))
            param_list.append(param)

    # call base constructor
    constructor = type_class.GetConstructor(framework.Array[framework.Type](type_list))
    # create class constructor builder
    const_builder = type_builder.DefineConstructor(
        framework.MethodAttributes.Public,
        framework.CallingConventions.Standard,
        framework.Array[framework.Type](()),
    )
    # add constructor parameters to stack
    gen = const_builder.GetILGenerator()
    gen.Emit(framework.OpCodes.Ldarg_0)  # Load "this" onto eval stack

    # add constructor input params to the stack
    for param_type, param in zip(type_list, param_list):
        if param_type == str:
            gen.Emit(framework.OpCodes.Ldstr, param)
        elif param_type == int:
            gen.Emit(framework.OpCodes.Ldc_I4, param)

    # call base constructor (consumes "this" and the created stack)
    gen.Emit(framework.OpCodes.Call, constructor)
    # Fill some space - this is how it is generated for equivalent C# code
    gen.Emit(framework.OpCodes.Nop)
    gen.Emit(framework.OpCodes.Nop)
    gen.Emit(framework.OpCodes.Nop)
    gen.Emit(framework.OpCodes.Ret)
    return type_builder.CreateType()