Skip to content

components

Base classes for pyRevit extension components.

Attributes

mlogger = get_logger(__name__) module-attribute

EXT_HASH_VALUE_KEY = 'dir_hash_value' module-attribute

EXT_HASH_VERSION_KEY = 'pyrvt_version' module-attribute

Classes

NoButton(cmp_path=None, needs_script=True)

Bases: GenericUICommand

This is not a button.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def __init__(self, cmp_path=None, needs_script=True):
    self.needs_script = needs_script
    self.script_file = self.config_script_file = None
    self.arguments = []
    self.context = None
    self.class_name = self.avail_class_name = None
    self.requires_clean_engine = False
    self.requires_fullframe_engine = False
    self.requires_persistent_engine = False
    self.requires_mainthread_engine = False
    # engine options specific to dynamo
    self.dynamo_path = None
    # self.dynamo_path_exec = False
    self.dynamo_path_check_existing = False
    self.dynamo_force_manual_run = False
    self.dynamo_model_nodes_info = None
    # using classname otherwise exceptions in superclasses won't show
    GenericUIComponent.__init__(self, cmp_path=cmp_path)

    mlogger.debug('Maximum host version: %s', self.max_revit_ver)
    mlogger.debug('Minimum host version: %s', self.min_revit_ver)
    mlogger.debug('command tooltip: %s', self._tooltip)
    mlogger.debug('Command author: %s', self.author)
    mlogger.debug('Command help url: %s', self._help_url)

    if self.is_beta:
        mlogger.debug('Command is in beta.')

Attributes

type_id = exts.NOGUI_COMMAND_POSTFIX class-attribute instance-attribute
name = None instance-attribute
is_container property
directory = cmp_path instance-attribute
unique_name = None instance-attribute
parent_ctrl_id = None instance-attribute
icon_file = None instance-attribute
author = None instance-attribute
media_file = None instance-attribute
min_revit_ver = None instance-attribute
max_revit_ver = None instance-attribute
is_beta = False instance-attribute
highlight_type = None instance-attribute
collapsed = False instance-attribute
version = None instance-attribute
meta = {} instance-attribute
meta_file = None instance-attribute
modules = [] instance-attribute
module_paths = [] instance-attribute
binary_path = None instance-attribute
library_path = None instance-attribute
control_id property
ui_title property
tooltip property
help_url property
is_supported property
needs_script = needs_script instance-attribute
script_file = None instance-attribute
config_script_file = None instance-attribute
arguments = [] instance-attribute
context = None instance-attribute
class_name = None instance-attribute
avail_class_name = None instance-attribute
requires_clean_engine = False instance-attribute
requires_fullframe_engine = False instance-attribute
requires_persistent_engine = False instance-attribute
requires_mainthread_engine = False instance-attribute
dynamo_path = None instance-attribute
dynamo_path_check_existing = False instance-attribute
dynamo_force_manual_run = False instance-attribute
dynamo_model_nodes_info = None instance-attribute
script_language property
is_cpython property

Functions

get_cache_data()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_cache_data(self):
    cache_dict = self.__dict__.copy()
    if hasattr(self, TYPE_ID_KEY):
        cache_dict[TYPE_ID_KEY] = getattr(self, TYPE_ID_KEY)
    return cache_dict
load_cache_data(cache_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def load_cache_data(self, cache_dict):
    for k, v in cache_dict.items():
        self.__dict__[k] = v
matches(component_path) classmethod
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def matches(cls, component_path):
    return component_path.lower().endswith(cls.type_id)
make_unique_name(cmp_path) classmethod

Creates a unique name for the command.

This is used to uniquely identify this command and also to create the class in pyRevit dll assembly. Current method create a unique name based on the command full directory address.

Examples:

for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton' unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def make_unique_name(cls, cmp_path):
    """Creates a unique name for the command.

    This is used to uniquely identify this command
    and also to create the class in pyRevit dll assembly.
    Current method create a unique name based on the command
    full directory address.

    Examples:
        for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton'
        unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.
    """
    pieces = []
    inside_ext = False
    for dname in cmp_path.split(op.sep):
        if exts.ExtensionTypes.UI_EXTENSION.POSTFIX in dname:
            inside_ext = True

        name, ext = op.splitext(dname)
        if ext != '' and inside_ext:
            pieces.append(name)
        else:
            continue
    return coreutils.cleanup_string(
        exts.UNIQUE_ID_SEPARATOR.join(pieces),
        skip=[exts.UNIQUE_ID_SEPARATOR]
        ).lower()
get_full_bundle_name()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_full_bundle_name(self):
    return self.name + self.type_id
has_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_module_path(self, path):
    return path in self.module_paths
add_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_module_path(self, path):
    if path and not self.has_module_path(path):
        mlogger.debug('Appending syspath: %s to %s', path, self)
        self.module_paths.append(path)
remove_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def remove_module_path(self, path):
    if path and self.has_module_path(path):
        mlogger.debug('Removing syspath: %s from %s', path, self)
        return self.module_paths.remove(path)
get_bundle_file(file_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_bundle_file(self, file_name):
    if self.directory and file_name:
        file_addr = op.join(self.directory, file_name)
        return file_addr if op.exists(file_addr) else None
find_bundle_file(patterns, finder='postfix')
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_file(self, patterns, finder='postfix'):
    if self.directory:
        for bundle_file in os.listdir(self.directory):
            if 'name' == finder:
                for file_name in patterns:
                    if op.splitext(bundle_file)[0] == file_name:
                        return op.join(self.directory, bundle_file)
            elif 'postfix' == finder:
                for file_postfix in patterns:
                    if bundle_file.endswith(file_postfix):
                        return op.join(self.directory, bundle_file)
            elif 'regex' == finder:
                for regex_pattern in patterns:
                    if re.match(regex_pattern, bundle_file):
                        return op.join(self.directory, bundle_file)
    return None
find_bundle_module(module, by_host=False)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_module(self, module, by_host=False):
    # test of file_name is an actually path to a file
    if op.isfile(module):
        return module

    def build_assm_filename(module_filename):
        # build assembly by host version (assm_file_2020.ext)
        assm_name, assm_ext = op.splitext(module_filename)
        return assm_name + '_' + HOST_APP.version + assm_ext

    if by_host:
        module = build_assm_filename(module)

    # test if module is inside search paths
    for module_path in self.module_paths:
        possible_module_path = op.join(module_path, module)
        if op.isfile(possible_module_path):
            return possible_module_path
configure(config_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def configure(self, config_dict):
    configurable_params = \
        ['_ui_title', '_tooltip', '_help_url', 'author']
    # get root key:value pairs
    for key, value in config_dict.items():
        for param_name in configurable_params:
            self._resolve_liquid_tag(param_name, key, value)
    # get key:value pairs grouped under special key, if exists
    templates = config_dict.get(exts.MDATA_TEMPLATES_KEY, {})
    for key, value in templates.items():
        for param_name in configurable_params:
            self._resolve_liquid_tag(param_name, key, value)
has_config_script()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_config_script(self):
    return self.config_script_file != self.script_file

NoScriptButton(cmp_path=None, needs_commandclass=False)

Bases: GenericUICommand

Base for buttons that doesn't run a script.

Source code in pyrevitlib/pyrevit/extensions/components.py
def __init__(self, cmp_path=None, needs_commandclass=False):
    # using classname otherwise exceptions in superclasses won't show
    GenericUICommand.__init__(self, cmp_path=cmp_path, needs_script=False)
    self.assembly = self.command_class = self.avail_command_class = None
    # read metadata from metadata file
    if self.meta:
        # get the target assembly from metadata
        self.assembly = self.meta.get(exts.MDATA_LINK_BUTTON_ASSEMBLY, None)

        # get the target command class from metadata
        self.command_class = self.meta.get(
            exts.MDATA_LINK_BUTTON_COMMAND_CLASS, None
        )

        # get the target command class from metadata
        self.avail_command_class = self.meta.get(
            exts.MDATA_LINK_BUTTON_AVAIL_COMMAND_CLASS, None
        )

        # for invoke buttons there is no script source so
        # assign the metadata file to the script
        self.script_file = self.config_script_file = self.meta_file
    else:
        mlogger.debug("%s does not specify target assembly::class.", self)

    if self.directory and not self.assembly:
        mlogger.error("%s does not specify target assembly.", self)

    if self.directory and needs_commandclass and not self.command_class:
        mlogger.error("%s does not specify target command class.", self)

    mlogger.debug(
        "%s assembly.class: %s.%s", self, self.assembly, self.command_class
    )

Attributes

assembly = None instance-attribute
command_class = None instance-attribute
avail_command_class = None instance-attribute
script_file = self.meta_file instance-attribute
config_script_file = self.meta_file instance-attribute
type_id = None class-attribute instance-attribute
name = None instance-attribute
is_container property
directory = cmp_path instance-attribute
unique_name = None instance-attribute
parent_ctrl_id = None instance-attribute
icon_file = None instance-attribute
author = None instance-attribute
media_file = None instance-attribute
min_revit_ver = None instance-attribute
max_revit_ver = None instance-attribute
is_beta = False instance-attribute
highlight_type = None instance-attribute
collapsed = False instance-attribute
version = None instance-attribute
meta = {} instance-attribute
meta_file = None instance-attribute
modules = [] instance-attribute
module_paths = [] instance-attribute
binary_path = None instance-attribute
library_path = None instance-attribute
control_id property
ui_title property
tooltip property
help_url property
is_supported property
needs_script = needs_script instance-attribute
arguments = [] instance-attribute
context = None instance-attribute
class_name = None instance-attribute
avail_class_name = None instance-attribute
requires_clean_engine = False instance-attribute
requires_fullframe_engine = False instance-attribute
requires_persistent_engine = False instance-attribute
requires_mainthread_engine = False instance-attribute
dynamo_path = None instance-attribute
dynamo_path_check_existing = False instance-attribute
dynamo_force_manual_run = False instance-attribute
dynamo_model_nodes_info = None instance-attribute
script_language property
is_cpython property

Functions

get_target_assembly(required=False)
Source code in pyrevitlib/pyrevit/extensions/components.py
def get_target_assembly(self, required=False):
    assm_file = self.assembly.lower()
    if not assm_file.endswith(framework.ASSEMBLY_FILE_TYPE):
        assm_file += "." + framework.ASSEMBLY_FILE_TYPE

    # try finding assembly for this specific host version
    target_asm_by_host = self.find_bundle_module(assm_file, by_host=True)
    if target_asm_by_host:
        return target_asm_by_host
    # try find assembly by its name
    target_asm = self.find_bundle_module(assm_file)
    if target_asm:
        return target_asm

    if required:
        mlogger.error("%s can not find target assembly.", self)

    return ""
get_cache_data()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_cache_data(self):
    cache_dict = self.__dict__.copy()
    if hasattr(self, TYPE_ID_KEY):
        cache_dict[TYPE_ID_KEY] = getattr(self, TYPE_ID_KEY)
    return cache_dict
load_cache_data(cache_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def load_cache_data(self, cache_dict):
    for k, v in cache_dict.items():
        self.__dict__[k] = v
matches(component_path) classmethod
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def matches(cls, component_path):
    return component_path.lower().endswith(cls.type_id)
make_unique_name(cmp_path) classmethod

Creates a unique name for the command.

This is used to uniquely identify this command and also to create the class in pyRevit dll assembly. Current method create a unique name based on the command full directory address.

Examples:

for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton' unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def make_unique_name(cls, cmp_path):
    """Creates a unique name for the command.

    This is used to uniquely identify this command
    and also to create the class in pyRevit dll assembly.
    Current method create a unique name based on the command
    full directory address.

    Examples:
        for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton'
        unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.
    """
    pieces = []
    inside_ext = False
    for dname in cmp_path.split(op.sep):
        if exts.ExtensionTypes.UI_EXTENSION.POSTFIX in dname:
            inside_ext = True

        name, ext = op.splitext(dname)
        if ext != '' and inside_ext:
            pieces.append(name)
        else:
            continue
    return coreutils.cleanup_string(
        exts.UNIQUE_ID_SEPARATOR.join(pieces),
        skip=[exts.UNIQUE_ID_SEPARATOR]
        ).lower()
get_full_bundle_name()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_full_bundle_name(self):
    return self.name + self.type_id
has_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_module_path(self, path):
    return path in self.module_paths
add_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_module_path(self, path):
    if path and not self.has_module_path(path):
        mlogger.debug('Appending syspath: %s to %s', path, self)
        self.module_paths.append(path)
remove_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def remove_module_path(self, path):
    if path and self.has_module_path(path):
        mlogger.debug('Removing syspath: %s from %s', path, self)
        return self.module_paths.remove(path)
get_bundle_file(file_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_bundle_file(self, file_name):
    if self.directory and file_name:
        file_addr = op.join(self.directory, file_name)
        return file_addr if op.exists(file_addr) else None
find_bundle_file(patterns, finder='postfix')
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_file(self, patterns, finder='postfix'):
    if self.directory:
        for bundle_file in os.listdir(self.directory):
            if 'name' == finder:
                for file_name in patterns:
                    if op.splitext(bundle_file)[0] == file_name:
                        return op.join(self.directory, bundle_file)
            elif 'postfix' == finder:
                for file_postfix in patterns:
                    if bundle_file.endswith(file_postfix):
                        return op.join(self.directory, bundle_file)
            elif 'regex' == finder:
                for regex_pattern in patterns:
                    if re.match(regex_pattern, bundle_file):
                        return op.join(self.directory, bundle_file)
    return None
find_bundle_module(module, by_host=False)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_module(self, module, by_host=False):
    # test of file_name is an actually path to a file
    if op.isfile(module):
        return module

    def build_assm_filename(module_filename):
        # build assembly by host version (assm_file_2020.ext)
        assm_name, assm_ext = op.splitext(module_filename)
        return assm_name + '_' + HOST_APP.version + assm_ext

    if by_host:
        module = build_assm_filename(module)

    # test if module is inside search paths
    for module_path in self.module_paths:
        possible_module_path = op.join(module_path, module)
        if op.isfile(possible_module_path):
            return possible_module_path
configure(config_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def configure(self, config_dict):
    configurable_params = \
        ['_ui_title', '_tooltip', '_help_url', 'author']
    # get root key:value pairs
    for key, value in config_dict.items():
        for param_name in configurable_params:
            self._resolve_liquid_tag(param_name, key, value)
    # get key:value pairs grouped under special key, if exists
    templates = config_dict.get(exts.MDATA_TEMPLATES_KEY, {})
    for key, value in templates.items():
        for param_name in configurable_params:
            self._resolve_liquid_tag(param_name, key, value)
has_config_script()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_config_script(self):
    return self.config_script_file != self.script_file

LinkButton(cmp_path=None)

Bases: NoScriptButton

Link button.

Source code in pyrevitlib/pyrevit/extensions/components.py
def __init__(self, cmp_path=None):
    # using classname otherwise exceptions in superclasses won't show
    NoScriptButton.__init__(self, cmp_path=cmp_path, needs_commandclass=True)

    if self.context:
        mlogger.warn(
            'Linkbutton bundles do not support "context:". '
            'Use "availability_class:" instead and specify name of '
            "availability class in target assembly | %s",
            self,
        )
        self.context = None

Attributes

type_id = exts.LINK_BUTTON_POSTFIX class-attribute instance-attribute
context = None instance-attribute
name = None instance-attribute
is_container property
directory = cmp_path instance-attribute
unique_name = None instance-attribute
parent_ctrl_id = None instance-attribute
icon_file = None instance-attribute
author = None instance-attribute
media_file = None instance-attribute
min_revit_ver = None instance-attribute
max_revit_ver = None instance-attribute
is_beta = False instance-attribute
highlight_type = None instance-attribute
collapsed = False instance-attribute
version = None instance-attribute
meta = {} instance-attribute
meta_file = None instance-attribute
modules = [] instance-attribute
module_paths = [] instance-attribute
binary_path = None instance-attribute
library_path = None instance-attribute
control_id property
ui_title property
tooltip property
help_url property
is_supported property
needs_script = needs_script instance-attribute
script_file = self.meta_file instance-attribute
config_script_file = self.meta_file instance-attribute
arguments = [] instance-attribute
class_name = None instance-attribute
avail_class_name = None instance-attribute
requires_clean_engine = False instance-attribute
requires_fullframe_engine = False instance-attribute
requires_persistent_engine = False instance-attribute
requires_mainthread_engine = False instance-attribute
dynamo_path = None instance-attribute
dynamo_path_check_existing = False instance-attribute
dynamo_force_manual_run = False instance-attribute
dynamo_model_nodes_info = None instance-attribute
script_language property
is_cpython property
assembly = None instance-attribute
command_class = None instance-attribute
avail_command_class = None instance-attribute

Functions

get_cache_data()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_cache_data(self):
    cache_dict = self.__dict__.copy()
    if hasattr(self, TYPE_ID_KEY):
        cache_dict[TYPE_ID_KEY] = getattr(self, TYPE_ID_KEY)
    return cache_dict
load_cache_data(cache_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def load_cache_data(self, cache_dict):
    for k, v in cache_dict.items():
        self.__dict__[k] = v
matches(component_path) classmethod
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def matches(cls, component_path):
    return component_path.lower().endswith(cls.type_id)
make_unique_name(cmp_path) classmethod

Creates a unique name for the command.

This is used to uniquely identify this command and also to create the class in pyRevit dll assembly. Current method create a unique name based on the command full directory address.

Examples:

for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton' unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def make_unique_name(cls, cmp_path):
    """Creates a unique name for the command.

    This is used to uniquely identify this command
    and also to create the class in pyRevit dll assembly.
    Current method create a unique name based on the command
    full directory address.

    Examples:
        for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton'
        unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.
    """
    pieces = []
    inside_ext = False
    for dname in cmp_path.split(op.sep):
        if exts.ExtensionTypes.UI_EXTENSION.POSTFIX in dname:
            inside_ext = True

        name, ext = op.splitext(dname)
        if ext != '' and inside_ext:
            pieces.append(name)
        else:
            continue
    return coreutils.cleanup_string(
        exts.UNIQUE_ID_SEPARATOR.join(pieces),
        skip=[exts.UNIQUE_ID_SEPARATOR]
        ).lower()
get_full_bundle_name()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_full_bundle_name(self):
    return self.name + self.type_id
has_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_module_path(self, path):
    return path in self.module_paths
add_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_module_path(self, path):
    if path and not self.has_module_path(path):
        mlogger.debug('Appending syspath: %s to %s', path, self)
        self.module_paths.append(path)
remove_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def remove_module_path(self, path):
    if path and self.has_module_path(path):
        mlogger.debug('Removing syspath: %s from %s', path, self)
        return self.module_paths.remove(path)
get_bundle_file(file_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_bundle_file(self, file_name):
    if self.directory and file_name:
        file_addr = op.join(self.directory, file_name)
        return file_addr if op.exists(file_addr) else None
find_bundle_file(patterns, finder='postfix')
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_file(self, patterns, finder='postfix'):
    if self.directory:
        for bundle_file in os.listdir(self.directory):
            if 'name' == finder:
                for file_name in patterns:
                    if op.splitext(bundle_file)[0] == file_name:
                        return op.join(self.directory, bundle_file)
            elif 'postfix' == finder:
                for file_postfix in patterns:
                    if bundle_file.endswith(file_postfix):
                        return op.join(self.directory, bundle_file)
            elif 'regex' == finder:
                for regex_pattern in patterns:
                    if re.match(regex_pattern, bundle_file):
                        return op.join(self.directory, bundle_file)
    return None
find_bundle_module(module, by_host=False)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_module(self, module, by_host=False):
    # test of file_name is an actually path to a file
    if op.isfile(module):
        return module

    def build_assm_filename(module_filename):
        # build assembly by host version (assm_file_2020.ext)
        assm_name, assm_ext = op.splitext(module_filename)
        return assm_name + '_' + HOST_APP.version + assm_ext

    if by_host:
        module = build_assm_filename(module)

    # test if module is inside search paths
    for module_path in self.module_paths:
        possible_module_path = op.join(module_path, module)
        if op.isfile(possible_module_path):
            return possible_module_path
configure(config_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def configure(self, config_dict):
    configurable_params = \
        ['_ui_title', '_tooltip', '_help_url', 'author']
    # get root key:value pairs
    for key, value in config_dict.items():
        for param_name in configurable_params:
            self._resolve_liquid_tag(param_name, key, value)
    # get key:value pairs grouped under special key, if exists
    templates = config_dict.get(exts.MDATA_TEMPLATES_KEY, {})
    for key, value in templates.items():
        for param_name in configurable_params:
            self._resolve_liquid_tag(param_name, key, value)
has_config_script()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_config_script(self):
    return self.config_script_file != self.script_file
get_target_assembly(required=False)
Source code in pyrevitlib/pyrevit/extensions/components.py
def get_target_assembly(self, required=False):
    assm_file = self.assembly.lower()
    if not assm_file.endswith(framework.ASSEMBLY_FILE_TYPE):
        assm_file += "." + framework.ASSEMBLY_FILE_TYPE

    # try finding assembly for this specific host version
    target_asm_by_host = self.find_bundle_module(assm_file, by_host=True)
    if target_asm_by_host:
        return target_asm_by_host
    # try find assembly by its name
    target_asm = self.find_bundle_module(assm_file)
    if target_asm:
        return target_asm

    if required:
        mlogger.error("%s can not find target assembly.", self)

    return ""

InvokeButton(cmp_path=None)

Bases: NoScriptButton

Invoke button.

Source code in pyrevitlib/pyrevit/extensions/components.py
def __init__(self, cmp_path=None):
    # using classname otherwise exceptions in superclasses won't show
    NoScriptButton.__init__(self, cmp_path=cmp_path)

Attributes

type_id = exts.INVOKE_BUTTON_POSTFIX class-attribute instance-attribute
name = None instance-attribute
is_container property
directory = cmp_path instance-attribute
unique_name = None instance-attribute
parent_ctrl_id = None instance-attribute
icon_file = None instance-attribute
author = None instance-attribute
media_file = None instance-attribute
min_revit_ver = None instance-attribute
max_revit_ver = None instance-attribute
is_beta = False instance-attribute
highlight_type = None instance-attribute
collapsed = False instance-attribute
version = None instance-attribute
meta = {} instance-attribute
meta_file = None instance-attribute
modules = [] instance-attribute
module_paths = [] instance-attribute
binary_path = None instance-attribute
library_path = None instance-attribute
control_id property
ui_title property
tooltip property
help_url property
is_supported property
needs_script = needs_script instance-attribute
script_file = self.meta_file instance-attribute
config_script_file = self.meta_file instance-attribute
arguments = [] instance-attribute
context = None instance-attribute
class_name = None instance-attribute
avail_class_name = None instance-attribute
requires_clean_engine = False instance-attribute
requires_fullframe_engine = False instance-attribute
requires_persistent_engine = False instance-attribute
requires_mainthread_engine = False instance-attribute
dynamo_path = None instance-attribute
dynamo_path_check_existing = False instance-attribute
dynamo_force_manual_run = False instance-attribute
dynamo_model_nodes_info = None instance-attribute
script_language property
is_cpython property
assembly = None instance-attribute
command_class = None instance-attribute
avail_command_class = None instance-attribute

Functions

get_cache_data()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_cache_data(self):
    cache_dict = self.__dict__.copy()
    if hasattr(self, TYPE_ID_KEY):
        cache_dict[TYPE_ID_KEY] = getattr(self, TYPE_ID_KEY)
    return cache_dict
load_cache_data(cache_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def load_cache_data(self, cache_dict):
    for k, v in cache_dict.items():
        self.__dict__[k] = v
matches(component_path) classmethod
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def matches(cls, component_path):
    return component_path.lower().endswith(cls.type_id)
make_unique_name(cmp_path) classmethod

Creates a unique name for the command.

This is used to uniquely identify this command and also to create the class in pyRevit dll assembly. Current method create a unique name based on the command full directory address.

Examples:

for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton' unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def make_unique_name(cls, cmp_path):
    """Creates a unique name for the command.

    This is used to uniquely identify this command
    and also to create the class in pyRevit dll assembly.
    Current method create a unique name based on the command
    full directory address.

    Examples:
        for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton'
        unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.
    """
    pieces = []
    inside_ext = False
    for dname in cmp_path.split(op.sep):
        if exts.ExtensionTypes.UI_EXTENSION.POSTFIX in dname:
            inside_ext = True

        name, ext = op.splitext(dname)
        if ext != '' and inside_ext:
            pieces.append(name)
        else:
            continue
    return coreutils.cleanup_string(
        exts.UNIQUE_ID_SEPARATOR.join(pieces),
        skip=[exts.UNIQUE_ID_SEPARATOR]
        ).lower()
get_full_bundle_name()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_full_bundle_name(self):
    return self.name + self.type_id
has_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_module_path(self, path):
    return path in self.module_paths
add_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_module_path(self, path):
    if path and not self.has_module_path(path):
        mlogger.debug('Appending syspath: %s to %s', path, self)
        self.module_paths.append(path)
remove_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def remove_module_path(self, path):
    if path and self.has_module_path(path):
        mlogger.debug('Removing syspath: %s from %s', path, self)
        return self.module_paths.remove(path)
get_bundle_file(file_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_bundle_file(self, file_name):
    if self.directory and file_name:
        file_addr = op.join(self.directory, file_name)
        return file_addr if op.exists(file_addr) else None
find_bundle_file(patterns, finder='postfix')
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_file(self, patterns, finder='postfix'):
    if self.directory:
        for bundle_file in os.listdir(self.directory):
            if 'name' == finder:
                for file_name in patterns:
                    if op.splitext(bundle_file)[0] == file_name:
                        return op.join(self.directory, bundle_file)
            elif 'postfix' == finder:
                for file_postfix in patterns:
                    if bundle_file.endswith(file_postfix):
                        return op.join(self.directory, bundle_file)
            elif 'regex' == finder:
                for regex_pattern in patterns:
                    if re.match(regex_pattern, bundle_file):
                        return op.join(self.directory, bundle_file)
    return None
find_bundle_module(module, by_host=False)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_module(self, module, by_host=False):
    # test of file_name is an actually path to a file
    if op.isfile(module):
        return module

    def build_assm_filename(module_filename):
        # build assembly by host version (assm_file_2020.ext)
        assm_name, assm_ext = op.splitext(module_filename)
        return assm_name + '_' + HOST_APP.version + assm_ext

    if by_host:
        module = build_assm_filename(module)

    # test if module is inside search paths
    for module_path in self.module_paths:
        possible_module_path = op.join(module_path, module)
        if op.isfile(possible_module_path):
            return possible_module_path
configure(config_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def configure(self, config_dict):
    configurable_params = \
        ['_ui_title', '_tooltip', '_help_url', 'author']
    # get root key:value pairs
    for key, value in config_dict.items():
        for param_name in configurable_params:
            self._resolve_liquid_tag(param_name, key, value)
    # get key:value pairs grouped under special key, if exists
    templates = config_dict.get(exts.MDATA_TEMPLATES_KEY, {})
    for key, value in templates.items():
        for param_name in configurable_params:
            self._resolve_liquid_tag(param_name, key, value)
has_config_script()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_config_script(self):
    return self.config_script_file != self.script_file
get_target_assembly(required=False)
Source code in pyrevitlib/pyrevit/extensions/components.py
def get_target_assembly(self, required=False):
    assm_file = self.assembly.lower()
    if not assm_file.endswith(framework.ASSEMBLY_FILE_TYPE):
        assm_file += "." + framework.ASSEMBLY_FILE_TYPE

    # try finding assembly for this specific host version
    target_asm_by_host = self.find_bundle_module(assm_file, by_host=True)
    if target_asm_by_host:
        return target_asm_by_host
    # try find assembly by its name
    target_asm = self.find_bundle_module(assm_file)
    if target_asm:
        return target_asm

    if required:
        mlogger.error("%s can not find target assembly.", self)

    return ""

PushButton(cmp_path=None, needs_script=True)

Bases: GenericUICommand

Push button.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def __init__(self, cmp_path=None, needs_script=True):
    self.needs_script = needs_script
    self.script_file = self.config_script_file = None
    self.arguments = []
    self.context = None
    self.class_name = self.avail_class_name = None
    self.requires_clean_engine = False
    self.requires_fullframe_engine = False
    self.requires_persistent_engine = False
    self.requires_mainthread_engine = False
    # engine options specific to dynamo
    self.dynamo_path = None
    # self.dynamo_path_exec = False
    self.dynamo_path_check_existing = False
    self.dynamo_force_manual_run = False
    self.dynamo_model_nodes_info = None
    # using classname otherwise exceptions in superclasses won't show
    GenericUIComponent.__init__(self, cmp_path=cmp_path)

    mlogger.debug('Maximum host version: %s', self.max_revit_ver)
    mlogger.debug('Minimum host version: %s', self.min_revit_ver)
    mlogger.debug('command tooltip: %s', self._tooltip)
    mlogger.debug('Command author: %s', self.author)
    mlogger.debug('Command help url: %s', self._help_url)

    if self.is_beta:
        mlogger.debug('Command is in beta.')

Attributes

type_id = exts.PUSH_BUTTON_POSTFIX class-attribute instance-attribute
name = None instance-attribute
is_container property
directory = cmp_path instance-attribute
unique_name = None instance-attribute
parent_ctrl_id = None instance-attribute
icon_file = None instance-attribute
author = None instance-attribute
media_file = None instance-attribute
min_revit_ver = None instance-attribute
max_revit_ver = None instance-attribute
is_beta = False instance-attribute
highlight_type = None instance-attribute
collapsed = False instance-attribute
version = None instance-attribute
meta = {} instance-attribute
meta_file = None instance-attribute
modules = [] instance-attribute
module_paths = [] instance-attribute
binary_path = None instance-attribute
library_path = None instance-attribute
control_id property
ui_title property
tooltip property
help_url property
is_supported property
needs_script = needs_script instance-attribute
script_file = None instance-attribute
config_script_file = None instance-attribute
arguments = [] instance-attribute
context = None instance-attribute
class_name = None instance-attribute
avail_class_name = None instance-attribute
requires_clean_engine = False instance-attribute
requires_fullframe_engine = False instance-attribute
requires_persistent_engine = False instance-attribute
requires_mainthread_engine = False instance-attribute
dynamo_path = None instance-attribute
dynamo_path_check_existing = False instance-attribute
dynamo_force_manual_run = False instance-attribute
dynamo_model_nodes_info = None instance-attribute
script_language property
is_cpython property

Functions

get_cache_data()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_cache_data(self):
    cache_dict = self.__dict__.copy()
    if hasattr(self, TYPE_ID_KEY):
        cache_dict[TYPE_ID_KEY] = getattr(self, TYPE_ID_KEY)
    return cache_dict
load_cache_data(cache_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def load_cache_data(self, cache_dict):
    for k, v in cache_dict.items():
        self.__dict__[k] = v
matches(component_path) classmethod
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def matches(cls, component_path):
    return component_path.lower().endswith(cls.type_id)
make_unique_name(cmp_path) classmethod

Creates a unique name for the command.

This is used to uniquely identify this command and also to create the class in pyRevit dll assembly. Current method create a unique name based on the command full directory address.

Examples:

for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton' unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def make_unique_name(cls, cmp_path):
    """Creates a unique name for the command.

    This is used to uniquely identify this command
    and also to create the class in pyRevit dll assembly.
    Current method create a unique name based on the command
    full directory address.

    Examples:
        for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton'
        unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.
    """
    pieces = []
    inside_ext = False
    for dname in cmp_path.split(op.sep):
        if exts.ExtensionTypes.UI_EXTENSION.POSTFIX in dname:
            inside_ext = True

        name, ext = op.splitext(dname)
        if ext != '' and inside_ext:
            pieces.append(name)
        else:
            continue
    return coreutils.cleanup_string(
        exts.UNIQUE_ID_SEPARATOR.join(pieces),
        skip=[exts.UNIQUE_ID_SEPARATOR]
        ).lower()
get_full_bundle_name()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_full_bundle_name(self):
    return self.name + self.type_id
has_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_module_path(self, path):
    return path in self.module_paths
add_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_module_path(self, path):
    if path and not self.has_module_path(path):
        mlogger.debug('Appending syspath: %s to %s', path, self)
        self.module_paths.append(path)
remove_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def remove_module_path(self, path):
    if path and self.has_module_path(path):
        mlogger.debug('Removing syspath: %s from %s', path, self)
        return self.module_paths.remove(path)
get_bundle_file(file_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_bundle_file(self, file_name):
    if self.directory and file_name:
        file_addr = op.join(self.directory, file_name)
        return file_addr if op.exists(file_addr) else None
find_bundle_file(patterns, finder='postfix')
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_file(self, patterns, finder='postfix'):
    if self.directory:
        for bundle_file in os.listdir(self.directory):
            if 'name' == finder:
                for file_name in patterns:
                    if op.splitext(bundle_file)[0] == file_name:
                        return op.join(self.directory, bundle_file)
            elif 'postfix' == finder:
                for file_postfix in patterns:
                    if bundle_file.endswith(file_postfix):
                        return op.join(self.directory, bundle_file)
            elif 'regex' == finder:
                for regex_pattern in patterns:
                    if re.match(regex_pattern, bundle_file):
                        return op.join(self.directory, bundle_file)
    return None
find_bundle_module(module, by_host=False)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_module(self, module, by_host=False):
    # test of file_name is an actually path to a file
    if op.isfile(module):
        return module

    def build_assm_filename(module_filename):
        # build assembly by host version (assm_file_2020.ext)
        assm_name, assm_ext = op.splitext(module_filename)
        return assm_name + '_' + HOST_APP.version + assm_ext

    if by_host:
        module = build_assm_filename(module)

    # test if module is inside search paths
    for module_path in self.module_paths:
        possible_module_path = op.join(module_path, module)
        if op.isfile(possible_module_path):
            return possible_module_path
configure(config_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def configure(self, config_dict):
    configurable_params = \
        ['_ui_title', '_tooltip', '_help_url', 'author']
    # get root key:value pairs
    for key, value in config_dict.items():
        for param_name in configurable_params:
            self._resolve_liquid_tag(param_name, key, value)
    # get key:value pairs grouped under special key, if exists
    templates = config_dict.get(exts.MDATA_TEMPLATES_KEY, {})
    for key, value in templates.items():
        for param_name in configurable_params:
            self._resolve_liquid_tag(param_name, key, value)
has_config_script()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_config_script(self):
    return self.config_script_file != self.script_file

PanelPushButton(cmp_path=None, needs_script=True)

Bases: GenericUICommand

Panel push button.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def __init__(self, cmp_path=None, needs_script=True):
    self.needs_script = needs_script
    self.script_file = self.config_script_file = None
    self.arguments = []
    self.context = None
    self.class_name = self.avail_class_name = None
    self.requires_clean_engine = False
    self.requires_fullframe_engine = False
    self.requires_persistent_engine = False
    self.requires_mainthread_engine = False
    # engine options specific to dynamo
    self.dynamo_path = None
    # self.dynamo_path_exec = False
    self.dynamo_path_check_existing = False
    self.dynamo_force_manual_run = False
    self.dynamo_model_nodes_info = None
    # using classname otherwise exceptions in superclasses won't show
    GenericUIComponent.__init__(self, cmp_path=cmp_path)

    mlogger.debug('Maximum host version: %s', self.max_revit_ver)
    mlogger.debug('Minimum host version: %s', self.min_revit_ver)
    mlogger.debug('command tooltip: %s', self._tooltip)
    mlogger.debug('Command author: %s', self.author)
    mlogger.debug('Command help url: %s', self._help_url)

    if self.is_beta:
        mlogger.debug('Command is in beta.')

Attributes

type_id = exts.PANEL_PUSH_BUTTON_POSTFIX class-attribute instance-attribute
name = None instance-attribute
is_container property
directory = cmp_path instance-attribute
unique_name = None instance-attribute
parent_ctrl_id = None instance-attribute
icon_file = None instance-attribute
author = None instance-attribute
media_file = None instance-attribute
min_revit_ver = None instance-attribute
max_revit_ver = None instance-attribute
is_beta = False instance-attribute
highlight_type = None instance-attribute
collapsed = False instance-attribute
version = None instance-attribute
meta = {} instance-attribute
meta_file = None instance-attribute
modules = [] instance-attribute
module_paths = [] instance-attribute
binary_path = None instance-attribute
library_path = None instance-attribute
control_id property
ui_title property
tooltip property
help_url property
is_supported property
needs_script = needs_script instance-attribute
script_file = None instance-attribute
config_script_file = None instance-attribute
arguments = [] instance-attribute
context = None instance-attribute
class_name = None instance-attribute
avail_class_name = None instance-attribute
requires_clean_engine = False instance-attribute
requires_fullframe_engine = False instance-attribute
requires_persistent_engine = False instance-attribute
requires_mainthread_engine = False instance-attribute
dynamo_path = None instance-attribute
dynamo_path_check_existing = False instance-attribute
dynamo_force_manual_run = False instance-attribute
dynamo_model_nodes_info = None instance-attribute
script_language property
is_cpython property

Functions

get_cache_data()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_cache_data(self):
    cache_dict = self.__dict__.copy()
    if hasattr(self, TYPE_ID_KEY):
        cache_dict[TYPE_ID_KEY] = getattr(self, TYPE_ID_KEY)
    return cache_dict
load_cache_data(cache_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def load_cache_data(self, cache_dict):
    for k, v in cache_dict.items():
        self.__dict__[k] = v
matches(component_path) classmethod
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def matches(cls, component_path):
    return component_path.lower().endswith(cls.type_id)
make_unique_name(cmp_path) classmethod

Creates a unique name for the command.

This is used to uniquely identify this command and also to create the class in pyRevit dll assembly. Current method create a unique name based on the command full directory address.

Examples:

for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton' unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def make_unique_name(cls, cmp_path):
    """Creates a unique name for the command.

    This is used to uniquely identify this command
    and also to create the class in pyRevit dll assembly.
    Current method create a unique name based on the command
    full directory address.

    Examples:
        for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton'
        unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.
    """
    pieces = []
    inside_ext = False
    for dname in cmp_path.split(op.sep):
        if exts.ExtensionTypes.UI_EXTENSION.POSTFIX in dname:
            inside_ext = True

        name, ext = op.splitext(dname)
        if ext != '' and inside_ext:
            pieces.append(name)
        else:
            continue
    return coreutils.cleanup_string(
        exts.UNIQUE_ID_SEPARATOR.join(pieces),
        skip=[exts.UNIQUE_ID_SEPARATOR]
        ).lower()
get_full_bundle_name()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_full_bundle_name(self):
    return self.name + self.type_id
has_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_module_path(self, path):
    return path in self.module_paths
add_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_module_path(self, path):
    if path and not self.has_module_path(path):
        mlogger.debug('Appending syspath: %s to %s', path, self)
        self.module_paths.append(path)
remove_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def remove_module_path(self, path):
    if path and self.has_module_path(path):
        mlogger.debug('Removing syspath: %s from %s', path, self)
        return self.module_paths.remove(path)
get_bundle_file(file_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_bundle_file(self, file_name):
    if self.directory and file_name:
        file_addr = op.join(self.directory, file_name)
        return file_addr if op.exists(file_addr) else None
find_bundle_file(patterns, finder='postfix')
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_file(self, patterns, finder='postfix'):
    if self.directory:
        for bundle_file in os.listdir(self.directory):
            if 'name' == finder:
                for file_name in patterns:
                    if op.splitext(bundle_file)[0] == file_name:
                        return op.join(self.directory, bundle_file)
            elif 'postfix' == finder:
                for file_postfix in patterns:
                    if bundle_file.endswith(file_postfix):
                        return op.join(self.directory, bundle_file)
            elif 'regex' == finder:
                for regex_pattern in patterns:
                    if re.match(regex_pattern, bundle_file):
                        return op.join(self.directory, bundle_file)
    return None
find_bundle_module(module, by_host=False)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_module(self, module, by_host=False):
    # test of file_name is an actually path to a file
    if op.isfile(module):
        return module

    def build_assm_filename(module_filename):
        # build assembly by host version (assm_file_2020.ext)
        assm_name, assm_ext = op.splitext(module_filename)
        return assm_name + '_' + HOST_APP.version + assm_ext

    if by_host:
        module = build_assm_filename(module)

    # test if module is inside search paths
    for module_path in self.module_paths:
        possible_module_path = op.join(module_path, module)
        if op.isfile(possible_module_path):
            return possible_module_path
configure(config_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def configure(self, config_dict):
    configurable_params = \
        ['_ui_title', '_tooltip', '_help_url', 'author']
    # get root key:value pairs
    for key, value in config_dict.items():
        for param_name in configurable_params:
            self._resolve_liquid_tag(param_name, key, value)
    # get key:value pairs grouped under special key, if exists
    templates = config_dict.get(exts.MDATA_TEMPLATES_KEY, {})
    for key, value in templates.items():
        for param_name in configurable_params:
            self._resolve_liquid_tag(param_name, key, value)
has_config_script()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_config_script(self):
    return self.config_script_file != self.script_file

SmartButton(cmp_path=None, needs_script=True)

Bases: GenericUICommand

Smart button.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def __init__(self, cmp_path=None, needs_script=True):
    self.needs_script = needs_script
    self.script_file = self.config_script_file = None
    self.arguments = []
    self.context = None
    self.class_name = self.avail_class_name = None
    self.requires_clean_engine = False
    self.requires_fullframe_engine = False
    self.requires_persistent_engine = False
    self.requires_mainthread_engine = False
    # engine options specific to dynamo
    self.dynamo_path = None
    # self.dynamo_path_exec = False
    self.dynamo_path_check_existing = False
    self.dynamo_force_manual_run = False
    self.dynamo_model_nodes_info = None
    # using classname otherwise exceptions in superclasses won't show
    GenericUIComponent.__init__(self, cmp_path=cmp_path)

    mlogger.debug('Maximum host version: %s', self.max_revit_ver)
    mlogger.debug('Minimum host version: %s', self.min_revit_ver)
    mlogger.debug('command tooltip: %s', self._tooltip)
    mlogger.debug('Command author: %s', self.author)
    mlogger.debug('Command help url: %s', self._help_url)

    if self.is_beta:
        mlogger.debug('Command is in beta.')

Attributes

type_id = exts.SMART_BUTTON_POSTFIX class-attribute instance-attribute
name = None instance-attribute
is_container property
directory = cmp_path instance-attribute
unique_name = None instance-attribute
parent_ctrl_id = None instance-attribute
icon_file = None instance-attribute
author = None instance-attribute
media_file = None instance-attribute
min_revit_ver = None instance-attribute
max_revit_ver = None instance-attribute
is_beta = False instance-attribute
highlight_type = None instance-attribute
collapsed = False instance-attribute
version = None instance-attribute
meta = {} instance-attribute
meta_file = None instance-attribute
modules = [] instance-attribute
module_paths = [] instance-attribute
binary_path = None instance-attribute
library_path = None instance-attribute
control_id property
ui_title property
tooltip property
help_url property
is_supported property
needs_script = needs_script instance-attribute
script_file = None instance-attribute
config_script_file = None instance-attribute
arguments = [] instance-attribute
context = None instance-attribute
class_name = None instance-attribute
avail_class_name = None instance-attribute
requires_clean_engine = False instance-attribute
requires_fullframe_engine = False instance-attribute
requires_persistent_engine = False instance-attribute
requires_mainthread_engine = False instance-attribute
dynamo_path = None instance-attribute
dynamo_path_check_existing = False instance-attribute
dynamo_force_manual_run = False instance-attribute
dynamo_model_nodes_info = None instance-attribute
script_language property
is_cpython property

Functions

get_cache_data()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_cache_data(self):
    cache_dict = self.__dict__.copy()
    if hasattr(self, TYPE_ID_KEY):
        cache_dict[TYPE_ID_KEY] = getattr(self, TYPE_ID_KEY)
    return cache_dict
load_cache_data(cache_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def load_cache_data(self, cache_dict):
    for k, v in cache_dict.items():
        self.__dict__[k] = v
matches(component_path) classmethod
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def matches(cls, component_path):
    return component_path.lower().endswith(cls.type_id)
make_unique_name(cmp_path) classmethod

Creates a unique name for the command.

This is used to uniquely identify this command and also to create the class in pyRevit dll assembly. Current method create a unique name based on the command full directory address.

Examples:

for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton' unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def make_unique_name(cls, cmp_path):
    """Creates a unique name for the command.

    This is used to uniquely identify this command
    and also to create the class in pyRevit dll assembly.
    Current method create a unique name based on the command
    full directory address.

    Examples:
        for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton'
        unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.
    """
    pieces = []
    inside_ext = False
    for dname in cmp_path.split(op.sep):
        if exts.ExtensionTypes.UI_EXTENSION.POSTFIX in dname:
            inside_ext = True

        name, ext = op.splitext(dname)
        if ext != '' and inside_ext:
            pieces.append(name)
        else:
            continue
    return coreutils.cleanup_string(
        exts.UNIQUE_ID_SEPARATOR.join(pieces),
        skip=[exts.UNIQUE_ID_SEPARATOR]
        ).lower()
get_full_bundle_name()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_full_bundle_name(self):
    return self.name + self.type_id
has_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_module_path(self, path):
    return path in self.module_paths
add_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_module_path(self, path):
    if path and not self.has_module_path(path):
        mlogger.debug('Appending syspath: %s to %s', path, self)
        self.module_paths.append(path)
remove_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def remove_module_path(self, path):
    if path and self.has_module_path(path):
        mlogger.debug('Removing syspath: %s from %s', path, self)
        return self.module_paths.remove(path)
get_bundle_file(file_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_bundle_file(self, file_name):
    if self.directory and file_name:
        file_addr = op.join(self.directory, file_name)
        return file_addr if op.exists(file_addr) else None
find_bundle_file(patterns, finder='postfix')
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_file(self, patterns, finder='postfix'):
    if self.directory:
        for bundle_file in os.listdir(self.directory):
            if 'name' == finder:
                for file_name in patterns:
                    if op.splitext(bundle_file)[0] == file_name:
                        return op.join(self.directory, bundle_file)
            elif 'postfix' == finder:
                for file_postfix in patterns:
                    if bundle_file.endswith(file_postfix):
                        return op.join(self.directory, bundle_file)
            elif 'regex' == finder:
                for regex_pattern in patterns:
                    if re.match(regex_pattern, bundle_file):
                        return op.join(self.directory, bundle_file)
    return None
find_bundle_module(module, by_host=False)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_module(self, module, by_host=False):
    # test of file_name is an actually path to a file
    if op.isfile(module):
        return module

    def build_assm_filename(module_filename):
        # build assembly by host version (assm_file_2020.ext)
        assm_name, assm_ext = op.splitext(module_filename)
        return assm_name + '_' + HOST_APP.version + assm_ext

    if by_host:
        module = build_assm_filename(module)

    # test if module is inside search paths
    for module_path in self.module_paths:
        possible_module_path = op.join(module_path, module)
        if op.isfile(possible_module_path):
            return possible_module_path
configure(config_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def configure(self, config_dict):
    configurable_params = \
        ['_ui_title', '_tooltip', '_help_url', 'author']
    # get root key:value pairs
    for key, value in config_dict.items():
        for param_name in configurable_params:
            self._resolve_liquid_tag(param_name, key, value)
    # get key:value pairs grouped under special key, if exists
    templates = config_dict.get(exts.MDATA_TEMPLATES_KEY, {})
    for key, value in templates.items():
        for param_name in configurable_params:
            self._resolve_liquid_tag(param_name, key, value)
has_config_script()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_config_script(self):
    return self.config_script_file != self.script_file

ContentButton(cmp_path=None)

Bases: GenericUICommand

Content Button.

Source code in pyrevitlib/pyrevit/extensions/components.py
def __init__(self, cmp_path=None):
    # using classname otherwise exceptions in superclasses won't show
    GenericUICommand.__init__(self, cmp_path=cmp_path, needs_script=False)

    # Initialize content paths
    self.content = None
    self.content_alt = None

    # Try to get content file from metadata first
    if self.meta:
        content_from_meta = self.meta.get(exts.MDATA_CONTENT, None)
        if content_from_meta:
            resolved_path = self._resolve_content_path(content_from_meta)
            if resolved_path:
                self.script_file = resolved_path
            else:
                mlogger.error(
                    "Content file specified in metadata not found: %s",
                    content_from_meta,
                )

        alt_content_from_meta = self.meta.get(exts.MDATA_CONTENT_ALT, None)
        if alt_content_from_meta:
            resolved_alt_path = self._resolve_content_path(alt_content_from_meta)
            if resolved_alt_path:
                self.config_script_file = resolved_alt_path
            else:
                mlogger.error(
                    "Alternative content file specified in metadata not found: %s",
                    alt_content_from_meta,
                )

    # Fall back to naming convention if not found in metadata
    # find content file
    if not self.script_file:
        self.script_file = self.find_bundle_file(
            [
                exts.CONTENT_VERSION_POSTFIX.format(version=HOST_APP.version),
            ]
        )
        if not self.script_file:
            self.script_file = self.find_bundle_file(
                [
                    exts.CONTENT_POSTFIX,
                ]
            )
    # requires at least one bundles
    if self.directory and not self.script_file:
        mlogger.error("Command %s: Does not have content file.", self)
        self.script_file = ""

    # find alternative content file
    if not self.config_script_file:
        self.config_script_file = self.find_bundle_file(
            [
                exts.ALT_CONTENT_VERSION_POSTFIX.format(version=HOST_APP.version),
            ]
        )
        if not self.config_script_file:
            self.config_script_file = self.find_bundle_file(
                [
                    exts.ALT_CONTENT_POSTFIX,
                ]
            )
    if not self.config_script_file:
        self.config_script_file = self.script_file

Attributes

type_id = exts.CONTENT_BUTTON_POSTFIX class-attribute instance-attribute
content = None instance-attribute
content_alt = None instance-attribute
script_file = resolved_path instance-attribute
config_script_file = resolved_alt_path instance-attribute
name = None instance-attribute
is_container property
directory = cmp_path instance-attribute
unique_name = None instance-attribute
parent_ctrl_id = None instance-attribute
icon_file = None instance-attribute
author = None instance-attribute
media_file = None instance-attribute
min_revit_ver = None instance-attribute
max_revit_ver = None instance-attribute
is_beta = False instance-attribute
highlight_type = None instance-attribute
collapsed = False instance-attribute
version = None instance-attribute
meta = {} instance-attribute
meta_file = None instance-attribute
modules = [] instance-attribute
module_paths = [] instance-attribute
binary_path = None instance-attribute
library_path = None instance-attribute
control_id property
ui_title property
tooltip property
help_url property
is_supported property
needs_script = needs_script instance-attribute
arguments = [] instance-attribute
context = None instance-attribute
class_name = None instance-attribute
avail_class_name = None instance-attribute
requires_clean_engine = False instance-attribute
requires_fullframe_engine = False instance-attribute
requires_persistent_engine = False instance-attribute
requires_mainthread_engine = False instance-attribute
dynamo_path = None instance-attribute
dynamo_path_check_existing = False instance-attribute
dynamo_force_manual_run = False instance-attribute
dynamo_model_nodes_info = None instance-attribute
script_language property
is_cpython property

Functions

get_cache_data()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_cache_data(self):
    cache_dict = self.__dict__.copy()
    if hasattr(self, TYPE_ID_KEY):
        cache_dict[TYPE_ID_KEY] = getattr(self, TYPE_ID_KEY)
    return cache_dict
load_cache_data(cache_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def load_cache_data(self, cache_dict):
    for k, v in cache_dict.items():
        self.__dict__[k] = v
matches(component_path) classmethod
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def matches(cls, component_path):
    return component_path.lower().endswith(cls.type_id)
make_unique_name(cmp_path) classmethod

Creates a unique name for the command.

This is used to uniquely identify this command and also to create the class in pyRevit dll assembly. Current method create a unique name based on the command full directory address.

Examples:

for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton' unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def make_unique_name(cls, cmp_path):
    """Creates a unique name for the command.

    This is used to uniquely identify this command
    and also to create the class in pyRevit dll assembly.
    Current method create a unique name based on the command
    full directory address.

    Examples:
        for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton'
        unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.
    """
    pieces = []
    inside_ext = False
    for dname in cmp_path.split(op.sep):
        if exts.ExtensionTypes.UI_EXTENSION.POSTFIX in dname:
            inside_ext = True

        name, ext = op.splitext(dname)
        if ext != '' and inside_ext:
            pieces.append(name)
        else:
            continue
    return coreutils.cleanup_string(
        exts.UNIQUE_ID_SEPARATOR.join(pieces),
        skip=[exts.UNIQUE_ID_SEPARATOR]
        ).lower()
get_full_bundle_name()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_full_bundle_name(self):
    return self.name + self.type_id
has_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_module_path(self, path):
    return path in self.module_paths
add_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_module_path(self, path):
    if path and not self.has_module_path(path):
        mlogger.debug('Appending syspath: %s to %s', path, self)
        self.module_paths.append(path)
remove_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def remove_module_path(self, path):
    if path and self.has_module_path(path):
        mlogger.debug('Removing syspath: %s from %s', path, self)
        return self.module_paths.remove(path)
get_bundle_file(file_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_bundle_file(self, file_name):
    if self.directory and file_name:
        file_addr = op.join(self.directory, file_name)
        return file_addr if op.exists(file_addr) else None
find_bundle_file(patterns, finder='postfix')
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_file(self, patterns, finder='postfix'):
    if self.directory:
        for bundle_file in os.listdir(self.directory):
            if 'name' == finder:
                for file_name in patterns:
                    if op.splitext(bundle_file)[0] == file_name:
                        return op.join(self.directory, bundle_file)
            elif 'postfix' == finder:
                for file_postfix in patterns:
                    if bundle_file.endswith(file_postfix):
                        return op.join(self.directory, bundle_file)
            elif 'regex' == finder:
                for regex_pattern in patterns:
                    if re.match(regex_pattern, bundle_file):
                        return op.join(self.directory, bundle_file)
    return None
find_bundle_module(module, by_host=False)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_module(self, module, by_host=False):
    # test of file_name is an actually path to a file
    if op.isfile(module):
        return module

    def build_assm_filename(module_filename):
        # build assembly by host version (assm_file_2020.ext)
        assm_name, assm_ext = op.splitext(module_filename)
        return assm_name + '_' + HOST_APP.version + assm_ext

    if by_host:
        module = build_assm_filename(module)

    # test if module is inside search paths
    for module_path in self.module_paths:
        possible_module_path = op.join(module_path, module)
        if op.isfile(possible_module_path):
            return possible_module_path
configure(config_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def configure(self, config_dict):
    configurable_params = \
        ['_ui_title', '_tooltip', '_help_url', 'author']
    # get root key:value pairs
    for key, value in config_dict.items():
        for param_name in configurable_params:
            self._resolve_liquid_tag(param_name, key, value)
    # get key:value pairs grouped under special key, if exists
    templates = config_dict.get(exts.MDATA_TEMPLATES_KEY, {})
    for key, value in templates.items():
        for param_name in configurable_params:
            self._resolve_liquid_tag(param_name, key, value)
has_config_script()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_config_script(self):
    return self.config_script_file != self.script_file

URLButton(cmp_path=None)

Bases: GenericUICommand

URL button.

Source code in pyrevitlib/pyrevit/extensions/components.py
def __init__(self, cmp_path=None):
    # using classname otherwise exceptions in superclasses won't show
    GenericUICommand.__init__(self, cmp_path=cmp_path, needs_script=False)
    self.target_url = None
    # read metadata from metadata file
    if self.meta:
        # get the target url from metadata
        self.target_url = self.meta.get(exts.MDATA_URL_BUTTON_HYPERLINK, None)
        # for url buttons there is no script source so
        # assign the metadata file to the script
        self.script_file = self.config_script_file = self.meta_file
    else:
        mlogger.debug("%s does not specify target assembly::class.", self)

    if self.directory and not self.target_url:
        mlogger.error("%s does not specify target url.", self)

    mlogger.debug("%s target url: %s", self, self.target_url)

Attributes

type_id = exts.URL_BUTTON_POSTFIX class-attribute instance-attribute
target_url = None instance-attribute
script_file = self.meta_file instance-attribute
config_script_file = self.meta_file instance-attribute
name = None instance-attribute
is_container property
directory = cmp_path instance-attribute
unique_name = None instance-attribute
parent_ctrl_id = None instance-attribute
icon_file = None instance-attribute
author = None instance-attribute
media_file = None instance-attribute
min_revit_ver = None instance-attribute
max_revit_ver = None instance-attribute
is_beta = False instance-attribute
highlight_type = None instance-attribute
collapsed = False instance-attribute
version = None instance-attribute
meta = {} instance-attribute
meta_file = None instance-attribute
modules = [] instance-attribute
module_paths = [] instance-attribute
binary_path = None instance-attribute
library_path = None instance-attribute
control_id property
ui_title property
tooltip property
help_url property
is_supported property
needs_script = needs_script instance-attribute
arguments = [] instance-attribute
context = None instance-attribute
class_name = None instance-attribute
avail_class_name = None instance-attribute
requires_clean_engine = False instance-attribute
requires_fullframe_engine = False instance-attribute
requires_persistent_engine = False instance-attribute
requires_mainthread_engine = False instance-attribute
dynamo_path = None instance-attribute
dynamo_path_check_existing = False instance-attribute
dynamo_force_manual_run = False instance-attribute
dynamo_model_nodes_info = None instance-attribute
script_language property
is_cpython property

Functions

get_target_url()
Source code in pyrevitlib/pyrevit/extensions/components.py
def get_target_url(self):
    return self.target_url or ""
get_cache_data()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_cache_data(self):
    cache_dict = self.__dict__.copy()
    if hasattr(self, TYPE_ID_KEY):
        cache_dict[TYPE_ID_KEY] = getattr(self, TYPE_ID_KEY)
    return cache_dict
load_cache_data(cache_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def load_cache_data(self, cache_dict):
    for k, v in cache_dict.items():
        self.__dict__[k] = v
matches(component_path) classmethod
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def matches(cls, component_path):
    return component_path.lower().endswith(cls.type_id)
make_unique_name(cmp_path) classmethod

Creates a unique name for the command.

This is used to uniquely identify this command and also to create the class in pyRevit dll assembly. Current method create a unique name based on the command full directory address.

Examples:

for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton' unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def make_unique_name(cls, cmp_path):
    """Creates a unique name for the command.

    This is used to uniquely identify this command
    and also to create the class in pyRevit dll assembly.
    Current method create a unique name based on the command
    full directory address.

    Examples:
        for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton'
        unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.
    """
    pieces = []
    inside_ext = False
    for dname in cmp_path.split(op.sep):
        if exts.ExtensionTypes.UI_EXTENSION.POSTFIX in dname:
            inside_ext = True

        name, ext = op.splitext(dname)
        if ext != '' and inside_ext:
            pieces.append(name)
        else:
            continue
    return coreutils.cleanup_string(
        exts.UNIQUE_ID_SEPARATOR.join(pieces),
        skip=[exts.UNIQUE_ID_SEPARATOR]
        ).lower()
get_full_bundle_name()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_full_bundle_name(self):
    return self.name + self.type_id
has_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_module_path(self, path):
    return path in self.module_paths
add_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_module_path(self, path):
    if path and not self.has_module_path(path):
        mlogger.debug('Appending syspath: %s to %s', path, self)
        self.module_paths.append(path)
remove_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def remove_module_path(self, path):
    if path and self.has_module_path(path):
        mlogger.debug('Removing syspath: %s from %s', path, self)
        return self.module_paths.remove(path)
get_bundle_file(file_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_bundle_file(self, file_name):
    if self.directory and file_name:
        file_addr = op.join(self.directory, file_name)
        return file_addr if op.exists(file_addr) else None
find_bundle_file(patterns, finder='postfix')
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_file(self, patterns, finder='postfix'):
    if self.directory:
        for bundle_file in os.listdir(self.directory):
            if 'name' == finder:
                for file_name in patterns:
                    if op.splitext(bundle_file)[0] == file_name:
                        return op.join(self.directory, bundle_file)
            elif 'postfix' == finder:
                for file_postfix in patterns:
                    if bundle_file.endswith(file_postfix):
                        return op.join(self.directory, bundle_file)
            elif 'regex' == finder:
                for regex_pattern in patterns:
                    if re.match(regex_pattern, bundle_file):
                        return op.join(self.directory, bundle_file)
    return None
find_bundle_module(module, by_host=False)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_module(self, module, by_host=False):
    # test of file_name is an actually path to a file
    if op.isfile(module):
        return module

    def build_assm_filename(module_filename):
        # build assembly by host version (assm_file_2020.ext)
        assm_name, assm_ext = op.splitext(module_filename)
        return assm_name + '_' + HOST_APP.version + assm_ext

    if by_host:
        module = build_assm_filename(module)

    # test if module is inside search paths
    for module_path in self.module_paths:
        possible_module_path = op.join(module_path, module)
        if op.isfile(possible_module_path):
            return possible_module_path
configure(config_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def configure(self, config_dict):
    configurable_params = \
        ['_ui_title', '_tooltip', '_help_url', 'author']
    # get root key:value pairs
    for key, value in config_dict.items():
        for param_name in configurable_params:
            self._resolve_liquid_tag(param_name, key, value)
    # get key:value pairs grouped under special key, if exists
    templates = config_dict.get(exts.MDATA_TEMPLATES_KEY, {})
    for key, value in templates.items():
        for param_name in configurable_params:
            self._resolve_liquid_tag(param_name, key, value)
has_config_script()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_config_script(self):
    return self.config_script_file != self.script_file

GenericUICommandGroup(cmp_path=None)

Bases: GenericUIContainer

Generic UI command group.

Command groups only include commands. These classes can include GenericUICommand as sub components.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def __init__(self, cmp_path=None):
    self.layout_items = []
    self.components = []
    # using classname otherwise exceptions in superclasses won't show
    GenericUIComponent.__init__(self, cmp_path=cmp_path)

Attributes

allowed_sub_cmps = [GenericUICommand, NoScriptButton] class-attribute instance-attribute
control_id property
type_id = None class-attribute instance-attribute
name = None instance-attribute
is_container property
directory = cmp_path instance-attribute
unique_name = None instance-attribute
parent_ctrl_id = None instance-attribute
icon_file = None instance-attribute
author = None instance-attribute
media_file = None instance-attribute
min_revit_ver = None instance-attribute
max_revit_ver = None instance-attribute
is_beta = False instance-attribute
highlight_type = None instance-attribute
collapsed = False instance-attribute
version = None instance-attribute
meta = {} instance-attribute
meta_file = None instance-attribute
modules = [] instance-attribute
module_paths = [] instance-attribute
binary_path = None instance-attribute
library_path = None instance-attribute
ui_title property
tooltip property
help_url property
is_supported property
layout_items = [] instance-attribute
components = [] instance-attribute

Functions

has_commands()
Source code in pyrevitlib/pyrevit/extensions/components.py
def has_commands(self):
    for component in self:
        if isinstance(component, GenericUICommand):
            return True
get_cache_data()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_cache_data(self):
    cache_dict = self.__dict__.copy()
    if hasattr(self, TYPE_ID_KEY):
        cache_dict[TYPE_ID_KEY] = getattr(self, TYPE_ID_KEY)
    return cache_dict
load_cache_data(cache_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def load_cache_data(self, cache_dict):
    for k, v in cache_dict.items():
        self.__dict__[k] = v
matches(component_path) classmethod
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def matches(cls, component_path):
    return component_path.lower().endswith(cls.type_id)
make_unique_name(cmp_path) classmethod

Creates a unique name for the command.

This is used to uniquely identify this command and also to create the class in pyRevit dll assembly. Current method create a unique name based on the command full directory address.

Examples:

for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton' unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def make_unique_name(cls, cmp_path):
    """Creates a unique name for the command.

    This is used to uniquely identify this command
    and also to create the class in pyRevit dll assembly.
    Current method create a unique name based on the command
    full directory address.

    Examples:
        for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton'
        unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.
    """
    pieces = []
    inside_ext = False
    for dname in cmp_path.split(op.sep):
        if exts.ExtensionTypes.UI_EXTENSION.POSTFIX in dname:
            inside_ext = True

        name, ext = op.splitext(dname)
        if ext != '' and inside_ext:
            pieces.append(name)
        else:
            continue
    return coreutils.cleanup_string(
        exts.UNIQUE_ID_SEPARATOR.join(pieces),
        skip=[exts.UNIQUE_ID_SEPARATOR]
        ).lower()
get_full_bundle_name()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_full_bundle_name(self):
    return self.name + self.type_id
has_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_module_path(self, path):
    return path in self.module_paths
add_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_module_path(self, path):
    if path and not self.has_module_path(path):
        mlogger.debug('Appending syspath: %s to %s', path, self)
        for component in self.components:
            component.add_module_path(path)
        self.module_paths.append(path)
remove_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def remove_module_path(self, path):
    if path and self.has_module_path(path):
        mlogger.debug('Removing syspath: %s from %s', path, self)
        for component in self.components:
            component.remove_module_path(path)
        return self.module_paths.remove(path)
get_bundle_file(file_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_bundle_file(self, file_name):
    if self.directory and file_name:
        file_addr = op.join(self.directory, file_name)
        return file_addr if op.exists(file_addr) else None
find_bundle_file(patterns, finder='postfix')
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_file(self, patterns, finder='postfix'):
    if self.directory:
        for bundle_file in os.listdir(self.directory):
            if 'name' == finder:
                for file_name in patterns:
                    if op.splitext(bundle_file)[0] == file_name:
                        return op.join(self.directory, bundle_file)
            elif 'postfix' == finder:
                for file_postfix in patterns:
                    if bundle_file.endswith(file_postfix):
                        return op.join(self.directory, bundle_file)
            elif 'regex' == finder:
                for regex_pattern in patterns:
                    if re.match(regex_pattern, bundle_file):
                        return op.join(self.directory, bundle_file)
    return None
find_bundle_module(module, by_host=False)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_module(self, module, by_host=False):
    # test of file_name is an actually path to a file
    if op.isfile(module):
        return module

    def build_assm_filename(module_filename):
        # build assembly by host version (assm_file_2020.ext)
        assm_name, assm_ext = op.splitext(module_filename)
        return assm_name + '_' + HOST_APP.version + assm_ext

    if by_host:
        module = build_assm_filename(module)

    # test if module is inside search paths
    for module_path in self.module_paths:
        possible_module_path = op.join(module_path, module)
        if op.isfile(possible_module_path):
            return possible_module_path
configure(config_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def configure(self, config_dict):
    # update self meta
    GenericUIComponent.configure(self, config_dict=config_dict)
    # create an updated dict to pass to children
    updated_dict = copy.deepcopy(config_dict)
    updated_dict = pyutils.merge(updated_dict, self.meta)
    # replace the meta values with the expanded values
    # so children can use the expanded
    updated_dict[exts.MDATA_UI_TITLE] = self.ui_title
    updated_dict[exts.MDATA_TOOLTIP] = self.tooltip
    updated_dict[exts.MDATA_COMMAND_HELP_URL] = self.help_url
    updated_dict[exts.AUTHOR_PARAM] = self.author
    if exts.AUTHORS_PARAM in updated_dict:
        updated_dict.pop(exts.AUTHORS_PARAM)
    for component in self:
        component.configure(updated_dict)
parse_layout_directive(layout_line)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_directive(self, layout_line):
    parts = re.findall(r'(.+)\[(.+):(.*)\]', layout_line)
    if parts:
        source_item, directive, target_value = parts[0]
        # cleanup values
        directive = directive.lower().strip()
        target_value = target_value.strip()
        # process any escape characters in target value
        # https://stackoverflow.com/a/4020824/2350244
        target_value = target_value.encode('utf-8')
        if PY3:
            target_value = target_value.decode('unicode_escape')
        else:
            target_value = target_value.decode('string_escape')
        # create directive obj
        return source_item, LayoutDirective(directive_type=directive,
                                            target=target_value)
    return layout_line, None
parse_layout_item(layout_line)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_item(self, layout_line):
    if layout_line:
        layout_item_name, layout_item_drctv = \
            self.parse_layout_directive(layout_line)
        return LayoutItem(name=layout_item_name,
                          directive=layout_item_drctv)
parse_layout_items(layout_lines)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_items(self, layout_lines):
    for layout_line in layout_lines:
        layout_item = self.parse_layout_item(layout_line)
        if layout_item:
            self.layout_items.append(layout_item)
    mlogger.debug('Layout is: %s', self.layout_items)
parse_layout_metadata()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_metadata(self):
    layout = self.meta.get(exts.MDATA_LAYOUT, [])
    if layout:
        self.parse_layout_items(layout)
        return True
contains(item_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def contains(self, item_name):
    return any([x.name == item_name for x in self.components])
add_component(comp)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_component(self, comp):
    # set search paths
    for path in self.module_paths:
        comp.add_module_path(path)
    # set its own control id on the child component
    if hasattr(comp, 'parent_ctrl_id'):
        comp.parent_ctrl_id = self.control_id
    # now add to list
    self.components.append(comp)
find_components_of_type(cmp_type)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_components_of_type(self, cmp_type):
    sub_comp_list = []
    for sub_comp in self.components:
        if isinstance(sub_comp, cmp_type):
            sub_comp_list.append(sub_comp)
        elif sub_comp.is_container:
            sub_comp_list.extend(sub_comp.find_components_of_type(cmp_type))

    return sub_comp_list
find_layout_items()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_layout_items(self):
    layout_items = []
    layout_items.extend(self.layout_items)
    for sub_comp in self.components:
        if sub_comp.is_container:
            layout_items.extend(sub_comp.find_layout_items())
    return layout_items

PullDownButtonGroup(cmp_path=None)

Bases: GenericUICommandGroup

Pulldown button group.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def __init__(self, cmp_path=None):
    self.layout_items = []
    self.components = []
    # using classname otherwise exceptions in superclasses won't show
    GenericUIComponent.__init__(self, cmp_path=cmp_path)

Attributes

type_id = exts.PULLDOWN_BUTTON_POSTFIX class-attribute instance-attribute
name = None instance-attribute
is_container property
directory = cmp_path instance-attribute
unique_name = None instance-attribute
parent_ctrl_id = None instance-attribute
icon_file = None instance-attribute
author = None instance-attribute
media_file = None instance-attribute
min_revit_ver = None instance-attribute
max_revit_ver = None instance-attribute
is_beta = False instance-attribute
highlight_type = None instance-attribute
collapsed = False instance-attribute
version = None instance-attribute
meta = {} instance-attribute
meta_file = None instance-attribute
modules = [] instance-attribute
module_paths = [] instance-attribute
binary_path = None instance-attribute
library_path = None instance-attribute
control_id property
ui_title property
tooltip property
help_url property
is_supported property
allowed_sub_cmps = [GenericUICommand, NoScriptButton] class-attribute instance-attribute
layout_items = [] instance-attribute
components = [] instance-attribute

Functions

get_cache_data()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_cache_data(self):
    cache_dict = self.__dict__.copy()
    if hasattr(self, TYPE_ID_KEY):
        cache_dict[TYPE_ID_KEY] = getattr(self, TYPE_ID_KEY)
    return cache_dict
load_cache_data(cache_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def load_cache_data(self, cache_dict):
    for k, v in cache_dict.items():
        self.__dict__[k] = v
matches(component_path) classmethod
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def matches(cls, component_path):
    return component_path.lower().endswith(cls.type_id)
make_unique_name(cmp_path) classmethod

Creates a unique name for the command.

This is used to uniquely identify this command and also to create the class in pyRevit dll assembly. Current method create a unique name based on the command full directory address.

Examples:

for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton' unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def make_unique_name(cls, cmp_path):
    """Creates a unique name for the command.

    This is used to uniquely identify this command
    and also to create the class in pyRevit dll assembly.
    Current method create a unique name based on the command
    full directory address.

    Examples:
        for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton'
        unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.
    """
    pieces = []
    inside_ext = False
    for dname in cmp_path.split(op.sep):
        if exts.ExtensionTypes.UI_EXTENSION.POSTFIX in dname:
            inside_ext = True

        name, ext = op.splitext(dname)
        if ext != '' and inside_ext:
            pieces.append(name)
        else:
            continue
    return coreutils.cleanup_string(
        exts.UNIQUE_ID_SEPARATOR.join(pieces),
        skip=[exts.UNIQUE_ID_SEPARATOR]
        ).lower()
get_full_bundle_name()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_full_bundle_name(self):
    return self.name + self.type_id
has_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_module_path(self, path):
    return path in self.module_paths
add_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_module_path(self, path):
    if path and not self.has_module_path(path):
        mlogger.debug('Appending syspath: %s to %s', path, self)
        for component in self.components:
            component.add_module_path(path)
        self.module_paths.append(path)
remove_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def remove_module_path(self, path):
    if path and self.has_module_path(path):
        mlogger.debug('Removing syspath: %s from %s', path, self)
        for component in self.components:
            component.remove_module_path(path)
        return self.module_paths.remove(path)
get_bundle_file(file_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_bundle_file(self, file_name):
    if self.directory and file_name:
        file_addr = op.join(self.directory, file_name)
        return file_addr if op.exists(file_addr) else None
find_bundle_file(patterns, finder='postfix')
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_file(self, patterns, finder='postfix'):
    if self.directory:
        for bundle_file in os.listdir(self.directory):
            if 'name' == finder:
                for file_name in patterns:
                    if op.splitext(bundle_file)[0] == file_name:
                        return op.join(self.directory, bundle_file)
            elif 'postfix' == finder:
                for file_postfix in patterns:
                    if bundle_file.endswith(file_postfix):
                        return op.join(self.directory, bundle_file)
            elif 'regex' == finder:
                for regex_pattern in patterns:
                    if re.match(regex_pattern, bundle_file):
                        return op.join(self.directory, bundle_file)
    return None
find_bundle_module(module, by_host=False)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_module(self, module, by_host=False):
    # test of file_name is an actually path to a file
    if op.isfile(module):
        return module

    def build_assm_filename(module_filename):
        # build assembly by host version (assm_file_2020.ext)
        assm_name, assm_ext = op.splitext(module_filename)
        return assm_name + '_' + HOST_APP.version + assm_ext

    if by_host:
        module = build_assm_filename(module)

    # test if module is inside search paths
    for module_path in self.module_paths:
        possible_module_path = op.join(module_path, module)
        if op.isfile(possible_module_path):
            return possible_module_path
configure(config_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def configure(self, config_dict):
    # update self meta
    GenericUIComponent.configure(self, config_dict=config_dict)
    # create an updated dict to pass to children
    updated_dict = copy.deepcopy(config_dict)
    updated_dict = pyutils.merge(updated_dict, self.meta)
    # replace the meta values with the expanded values
    # so children can use the expanded
    updated_dict[exts.MDATA_UI_TITLE] = self.ui_title
    updated_dict[exts.MDATA_TOOLTIP] = self.tooltip
    updated_dict[exts.MDATA_COMMAND_HELP_URL] = self.help_url
    updated_dict[exts.AUTHOR_PARAM] = self.author
    if exts.AUTHORS_PARAM in updated_dict:
        updated_dict.pop(exts.AUTHORS_PARAM)
    for component in self:
        component.configure(updated_dict)
parse_layout_directive(layout_line)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_directive(self, layout_line):
    parts = re.findall(r'(.+)\[(.+):(.*)\]', layout_line)
    if parts:
        source_item, directive, target_value = parts[0]
        # cleanup values
        directive = directive.lower().strip()
        target_value = target_value.strip()
        # process any escape characters in target value
        # https://stackoverflow.com/a/4020824/2350244
        target_value = target_value.encode('utf-8')
        if PY3:
            target_value = target_value.decode('unicode_escape')
        else:
            target_value = target_value.decode('string_escape')
        # create directive obj
        return source_item, LayoutDirective(directive_type=directive,
                                            target=target_value)
    return layout_line, None
parse_layout_item(layout_line)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_item(self, layout_line):
    if layout_line:
        layout_item_name, layout_item_drctv = \
            self.parse_layout_directive(layout_line)
        return LayoutItem(name=layout_item_name,
                          directive=layout_item_drctv)
parse_layout_items(layout_lines)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_items(self, layout_lines):
    for layout_line in layout_lines:
        layout_item = self.parse_layout_item(layout_line)
        if layout_item:
            self.layout_items.append(layout_item)
    mlogger.debug('Layout is: %s', self.layout_items)
parse_layout_metadata()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_metadata(self):
    layout = self.meta.get(exts.MDATA_LAYOUT, [])
    if layout:
        self.parse_layout_items(layout)
        return True
contains(item_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def contains(self, item_name):
    return any([x.name == item_name for x in self.components])
add_component(comp)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_component(self, comp):
    # set search paths
    for path in self.module_paths:
        comp.add_module_path(path)
    # set its own control id on the child component
    if hasattr(comp, 'parent_ctrl_id'):
        comp.parent_ctrl_id = self.control_id
    # now add to list
    self.components.append(comp)
find_components_of_type(cmp_type)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_components_of_type(self, cmp_type):
    sub_comp_list = []
    for sub_comp in self.components:
        if isinstance(sub_comp, cmp_type):
            sub_comp_list.append(sub_comp)
        elif sub_comp.is_container:
            sub_comp_list.extend(sub_comp.find_components_of_type(cmp_type))

    return sub_comp_list
find_layout_items()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_layout_items(self):
    layout_items = []
    layout_items.extend(self.layout_items)
    for sub_comp in self.components:
        if sub_comp.is_container:
            layout_items.extend(sub_comp.find_layout_items())
    return layout_items
has_commands()
Source code in pyrevitlib/pyrevit/extensions/components.py
def has_commands(self):
    for component in self:
        if isinstance(component, GenericUICommand):
            return True

ComboBoxGroup(cmp_path=None)

Bases: GenericUICommandGroup

ComboBox group.

Source code in pyrevitlib/pyrevit/extensions/components.py
def __init__(self, cmp_path=None):
    GenericUICommandGroup.__init__(self, cmp_path=cmp_path)
    self.members = []

    # Read members from metadata
    if not self.meta:
        return
    raw_members = self.meta.get("members", [])
    if isinstance(raw_members, list):
        # Process list of members - preserve full dict for rich metadata (icons, tooltips, etc.)
        processed_members = []
        for m in raw_members:
            if isinstance(m, dict) or (
                hasattr(m, "get") and hasattr(m, "keys")
            ):
                # OrderedDict or dict format: {'id': 'settings', 'text': 'Settings', 'icon': '...', ...}
                # Preserve the full dictionary to keep all properties (icon, tooltip, group, etc.)
                processed_members.append(m)
            elif isinstance(m, (list, tuple)) and len(m) >= 2:
                # Tuple/list format: ('id', 'text') - convert to dict for consistency
                processed_members.append({"id": m[0], "text": m[1]})
            elif isinstance(m, str):
                # String format: 'Option 1' - convert to dict for consistency
                processed_members.append({"id": m, "text": m})
        self.members = processed_members
    elif isinstance(raw_members, dict):
        # Dict format: {'A': 'Option A'} - convert to list of dicts
        self.members = [{"id": k, "text": v} for k, v in raw_members.items()]

Attributes

type_id = exts.COMBOBOX_POSTFIX class-attribute instance-attribute
members = [] instance-attribute
name = None instance-attribute
is_container property
directory = cmp_path instance-attribute
unique_name = None instance-attribute
parent_ctrl_id = None instance-attribute
icon_file = None instance-attribute
author = None instance-attribute
media_file = None instance-attribute
min_revit_ver = None instance-attribute
max_revit_ver = None instance-attribute
is_beta = False instance-attribute
highlight_type = None instance-attribute
collapsed = False instance-attribute
version = None instance-attribute
meta = {} instance-attribute
meta_file = None instance-attribute
modules = [] instance-attribute
module_paths = [] instance-attribute
binary_path = None instance-attribute
library_path = None instance-attribute
control_id property
ui_title property
tooltip property
help_url property
is_supported property
allowed_sub_cmps = [GenericUICommand, NoScriptButton] class-attribute instance-attribute
layout_items = [] instance-attribute
components = [] instance-attribute

Functions

get_cache_data()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_cache_data(self):
    cache_dict = self.__dict__.copy()
    if hasattr(self, TYPE_ID_KEY):
        cache_dict[TYPE_ID_KEY] = getattr(self, TYPE_ID_KEY)
    return cache_dict
load_cache_data(cache_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def load_cache_data(self, cache_dict):
    for k, v in cache_dict.items():
        self.__dict__[k] = v
matches(component_path) classmethod
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def matches(cls, component_path):
    return component_path.lower().endswith(cls.type_id)
make_unique_name(cmp_path) classmethod

Creates a unique name for the command.

This is used to uniquely identify this command and also to create the class in pyRevit dll assembly. Current method create a unique name based on the command full directory address.

Examples:

for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton' unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def make_unique_name(cls, cmp_path):
    """Creates a unique name for the command.

    This is used to uniquely identify this command
    and also to create the class in pyRevit dll assembly.
    Current method create a unique name based on the command
    full directory address.

    Examples:
        for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton'
        unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.
    """
    pieces = []
    inside_ext = False
    for dname in cmp_path.split(op.sep):
        if exts.ExtensionTypes.UI_EXTENSION.POSTFIX in dname:
            inside_ext = True

        name, ext = op.splitext(dname)
        if ext != '' and inside_ext:
            pieces.append(name)
        else:
            continue
    return coreutils.cleanup_string(
        exts.UNIQUE_ID_SEPARATOR.join(pieces),
        skip=[exts.UNIQUE_ID_SEPARATOR]
        ).lower()
get_full_bundle_name()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_full_bundle_name(self):
    return self.name + self.type_id
has_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_module_path(self, path):
    return path in self.module_paths
add_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_module_path(self, path):
    if path and not self.has_module_path(path):
        mlogger.debug('Appending syspath: %s to %s', path, self)
        for component in self.components:
            component.add_module_path(path)
        self.module_paths.append(path)
remove_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def remove_module_path(self, path):
    if path and self.has_module_path(path):
        mlogger.debug('Removing syspath: %s from %s', path, self)
        for component in self.components:
            component.remove_module_path(path)
        return self.module_paths.remove(path)
get_bundle_file(file_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_bundle_file(self, file_name):
    if self.directory and file_name:
        file_addr = op.join(self.directory, file_name)
        return file_addr if op.exists(file_addr) else None
find_bundle_file(patterns, finder='postfix')
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_file(self, patterns, finder='postfix'):
    if self.directory:
        for bundle_file in os.listdir(self.directory):
            if 'name' == finder:
                for file_name in patterns:
                    if op.splitext(bundle_file)[0] == file_name:
                        return op.join(self.directory, bundle_file)
            elif 'postfix' == finder:
                for file_postfix in patterns:
                    if bundle_file.endswith(file_postfix):
                        return op.join(self.directory, bundle_file)
            elif 'regex' == finder:
                for regex_pattern in patterns:
                    if re.match(regex_pattern, bundle_file):
                        return op.join(self.directory, bundle_file)
    return None
find_bundle_module(module, by_host=False)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_module(self, module, by_host=False):
    # test of file_name is an actually path to a file
    if op.isfile(module):
        return module

    def build_assm_filename(module_filename):
        # build assembly by host version (assm_file_2020.ext)
        assm_name, assm_ext = op.splitext(module_filename)
        return assm_name + '_' + HOST_APP.version + assm_ext

    if by_host:
        module = build_assm_filename(module)

    # test if module is inside search paths
    for module_path in self.module_paths:
        possible_module_path = op.join(module_path, module)
        if op.isfile(possible_module_path):
            return possible_module_path
configure(config_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def configure(self, config_dict):
    # update self meta
    GenericUIComponent.configure(self, config_dict=config_dict)
    # create an updated dict to pass to children
    updated_dict = copy.deepcopy(config_dict)
    updated_dict = pyutils.merge(updated_dict, self.meta)
    # replace the meta values with the expanded values
    # so children can use the expanded
    updated_dict[exts.MDATA_UI_TITLE] = self.ui_title
    updated_dict[exts.MDATA_TOOLTIP] = self.tooltip
    updated_dict[exts.MDATA_COMMAND_HELP_URL] = self.help_url
    updated_dict[exts.AUTHOR_PARAM] = self.author
    if exts.AUTHORS_PARAM in updated_dict:
        updated_dict.pop(exts.AUTHORS_PARAM)
    for component in self:
        component.configure(updated_dict)
parse_layout_directive(layout_line)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_directive(self, layout_line):
    parts = re.findall(r'(.+)\[(.+):(.*)\]', layout_line)
    if parts:
        source_item, directive, target_value = parts[0]
        # cleanup values
        directive = directive.lower().strip()
        target_value = target_value.strip()
        # process any escape characters in target value
        # https://stackoverflow.com/a/4020824/2350244
        target_value = target_value.encode('utf-8')
        if PY3:
            target_value = target_value.decode('unicode_escape')
        else:
            target_value = target_value.decode('string_escape')
        # create directive obj
        return source_item, LayoutDirective(directive_type=directive,
                                            target=target_value)
    return layout_line, None
parse_layout_item(layout_line)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_item(self, layout_line):
    if layout_line:
        layout_item_name, layout_item_drctv = \
            self.parse_layout_directive(layout_line)
        return LayoutItem(name=layout_item_name,
                          directive=layout_item_drctv)
parse_layout_items(layout_lines)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_items(self, layout_lines):
    for layout_line in layout_lines:
        layout_item = self.parse_layout_item(layout_line)
        if layout_item:
            self.layout_items.append(layout_item)
    mlogger.debug('Layout is: %s', self.layout_items)
parse_layout_metadata()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_metadata(self):
    layout = self.meta.get(exts.MDATA_LAYOUT, [])
    if layout:
        self.parse_layout_items(layout)
        return True
contains(item_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def contains(self, item_name):
    return any([x.name == item_name for x in self.components])
add_component(comp)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_component(self, comp):
    # set search paths
    for path in self.module_paths:
        comp.add_module_path(path)
    # set its own control id on the child component
    if hasattr(comp, 'parent_ctrl_id'):
        comp.parent_ctrl_id = self.control_id
    # now add to list
    self.components.append(comp)
find_components_of_type(cmp_type)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_components_of_type(self, cmp_type):
    sub_comp_list = []
    for sub_comp in self.components:
        if isinstance(sub_comp, cmp_type):
            sub_comp_list.append(sub_comp)
        elif sub_comp.is_container:
            sub_comp_list.extend(sub_comp.find_components_of_type(cmp_type))

    return sub_comp_list
find_layout_items()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_layout_items(self):
    layout_items = []
    layout_items.extend(self.layout_items)
    for sub_comp in self.components:
        if sub_comp.is_container:
            layout_items.extend(sub_comp.find_layout_items())
    return layout_items
has_commands()
Source code in pyrevitlib/pyrevit/extensions/components.py
def has_commands(self):
    for component in self:
        if isinstance(component, GenericUICommand):
            return True

SplitPushButtonGroup(cmp_path=None)

Bases: GenericUICommandGroup

Split push button group.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def __init__(self, cmp_path=None):
    self.layout_items = []
    self.components = []
    # using classname otherwise exceptions in superclasses won't show
    GenericUIComponent.__init__(self, cmp_path=cmp_path)

Attributes

type_id = exts.SPLITPUSH_BUTTON_POSTFIX class-attribute instance-attribute
name = None instance-attribute
is_container property
directory = cmp_path instance-attribute
unique_name = None instance-attribute
parent_ctrl_id = None instance-attribute
icon_file = None instance-attribute
author = None instance-attribute
media_file = None instance-attribute
min_revit_ver = None instance-attribute
max_revit_ver = None instance-attribute
is_beta = False instance-attribute
highlight_type = None instance-attribute
collapsed = False instance-attribute
version = None instance-attribute
meta = {} instance-attribute
meta_file = None instance-attribute
modules = [] instance-attribute
module_paths = [] instance-attribute
binary_path = None instance-attribute
library_path = None instance-attribute
control_id property
ui_title property
tooltip property
help_url property
is_supported property
allowed_sub_cmps = [GenericUICommand, NoScriptButton] class-attribute instance-attribute
layout_items = [] instance-attribute
components = [] instance-attribute

Functions

get_cache_data()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_cache_data(self):
    cache_dict = self.__dict__.copy()
    if hasattr(self, TYPE_ID_KEY):
        cache_dict[TYPE_ID_KEY] = getattr(self, TYPE_ID_KEY)
    return cache_dict
load_cache_data(cache_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def load_cache_data(self, cache_dict):
    for k, v in cache_dict.items():
        self.__dict__[k] = v
matches(component_path) classmethod
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def matches(cls, component_path):
    return component_path.lower().endswith(cls.type_id)
make_unique_name(cmp_path) classmethod

Creates a unique name for the command.

This is used to uniquely identify this command and also to create the class in pyRevit dll assembly. Current method create a unique name based on the command full directory address.

Examples:

for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton' unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def make_unique_name(cls, cmp_path):
    """Creates a unique name for the command.

    This is used to uniquely identify this command
    and also to create the class in pyRevit dll assembly.
    Current method create a unique name based on the command
    full directory address.

    Examples:
        for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton'
        unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.
    """
    pieces = []
    inside_ext = False
    for dname in cmp_path.split(op.sep):
        if exts.ExtensionTypes.UI_EXTENSION.POSTFIX in dname:
            inside_ext = True

        name, ext = op.splitext(dname)
        if ext != '' and inside_ext:
            pieces.append(name)
        else:
            continue
    return coreutils.cleanup_string(
        exts.UNIQUE_ID_SEPARATOR.join(pieces),
        skip=[exts.UNIQUE_ID_SEPARATOR]
        ).lower()
get_full_bundle_name()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_full_bundle_name(self):
    return self.name + self.type_id
has_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_module_path(self, path):
    return path in self.module_paths
add_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_module_path(self, path):
    if path and not self.has_module_path(path):
        mlogger.debug('Appending syspath: %s to %s', path, self)
        for component in self.components:
            component.add_module_path(path)
        self.module_paths.append(path)
remove_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def remove_module_path(self, path):
    if path and self.has_module_path(path):
        mlogger.debug('Removing syspath: %s from %s', path, self)
        for component in self.components:
            component.remove_module_path(path)
        return self.module_paths.remove(path)
get_bundle_file(file_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_bundle_file(self, file_name):
    if self.directory and file_name:
        file_addr = op.join(self.directory, file_name)
        return file_addr if op.exists(file_addr) else None
find_bundle_file(patterns, finder='postfix')
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_file(self, patterns, finder='postfix'):
    if self.directory:
        for bundle_file in os.listdir(self.directory):
            if 'name' == finder:
                for file_name in patterns:
                    if op.splitext(bundle_file)[0] == file_name:
                        return op.join(self.directory, bundle_file)
            elif 'postfix' == finder:
                for file_postfix in patterns:
                    if bundle_file.endswith(file_postfix):
                        return op.join(self.directory, bundle_file)
            elif 'regex' == finder:
                for regex_pattern in patterns:
                    if re.match(regex_pattern, bundle_file):
                        return op.join(self.directory, bundle_file)
    return None
find_bundle_module(module, by_host=False)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_module(self, module, by_host=False):
    # test of file_name is an actually path to a file
    if op.isfile(module):
        return module

    def build_assm_filename(module_filename):
        # build assembly by host version (assm_file_2020.ext)
        assm_name, assm_ext = op.splitext(module_filename)
        return assm_name + '_' + HOST_APP.version + assm_ext

    if by_host:
        module = build_assm_filename(module)

    # test if module is inside search paths
    for module_path in self.module_paths:
        possible_module_path = op.join(module_path, module)
        if op.isfile(possible_module_path):
            return possible_module_path
configure(config_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def configure(self, config_dict):
    # update self meta
    GenericUIComponent.configure(self, config_dict=config_dict)
    # create an updated dict to pass to children
    updated_dict = copy.deepcopy(config_dict)
    updated_dict = pyutils.merge(updated_dict, self.meta)
    # replace the meta values with the expanded values
    # so children can use the expanded
    updated_dict[exts.MDATA_UI_TITLE] = self.ui_title
    updated_dict[exts.MDATA_TOOLTIP] = self.tooltip
    updated_dict[exts.MDATA_COMMAND_HELP_URL] = self.help_url
    updated_dict[exts.AUTHOR_PARAM] = self.author
    if exts.AUTHORS_PARAM in updated_dict:
        updated_dict.pop(exts.AUTHORS_PARAM)
    for component in self:
        component.configure(updated_dict)
parse_layout_directive(layout_line)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_directive(self, layout_line):
    parts = re.findall(r'(.+)\[(.+):(.*)\]', layout_line)
    if parts:
        source_item, directive, target_value = parts[0]
        # cleanup values
        directive = directive.lower().strip()
        target_value = target_value.strip()
        # process any escape characters in target value
        # https://stackoverflow.com/a/4020824/2350244
        target_value = target_value.encode('utf-8')
        if PY3:
            target_value = target_value.decode('unicode_escape')
        else:
            target_value = target_value.decode('string_escape')
        # create directive obj
        return source_item, LayoutDirective(directive_type=directive,
                                            target=target_value)
    return layout_line, None
parse_layout_item(layout_line)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_item(self, layout_line):
    if layout_line:
        layout_item_name, layout_item_drctv = \
            self.parse_layout_directive(layout_line)
        return LayoutItem(name=layout_item_name,
                          directive=layout_item_drctv)
parse_layout_items(layout_lines)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_items(self, layout_lines):
    for layout_line in layout_lines:
        layout_item = self.parse_layout_item(layout_line)
        if layout_item:
            self.layout_items.append(layout_item)
    mlogger.debug('Layout is: %s', self.layout_items)
parse_layout_metadata()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_metadata(self):
    layout = self.meta.get(exts.MDATA_LAYOUT, [])
    if layout:
        self.parse_layout_items(layout)
        return True
contains(item_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def contains(self, item_name):
    return any([x.name == item_name for x in self.components])
add_component(comp)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_component(self, comp):
    # set search paths
    for path in self.module_paths:
        comp.add_module_path(path)
    # set its own control id on the child component
    if hasattr(comp, 'parent_ctrl_id'):
        comp.parent_ctrl_id = self.control_id
    # now add to list
    self.components.append(comp)
find_components_of_type(cmp_type)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_components_of_type(self, cmp_type):
    sub_comp_list = []
    for sub_comp in self.components:
        if isinstance(sub_comp, cmp_type):
            sub_comp_list.append(sub_comp)
        elif sub_comp.is_container:
            sub_comp_list.extend(sub_comp.find_components_of_type(cmp_type))

    return sub_comp_list
find_layout_items()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_layout_items(self):
    layout_items = []
    layout_items.extend(self.layout_items)
    for sub_comp in self.components:
        if sub_comp.is_container:
            layout_items.extend(sub_comp.find_layout_items())
    return layout_items
has_commands()
Source code in pyrevitlib/pyrevit/extensions/components.py
def has_commands(self):
    for component in self:
        if isinstance(component, GenericUICommand):
            return True

SplitButtonGroup(cmp_path=None)

Bases: GenericUICommandGroup

Split button group.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def __init__(self, cmp_path=None):
    self.layout_items = []
    self.components = []
    # using classname otherwise exceptions in superclasses won't show
    GenericUIComponent.__init__(self, cmp_path=cmp_path)

Attributes

type_id = exts.SPLIT_BUTTON_POSTFIX class-attribute instance-attribute
name = None instance-attribute
is_container property
directory = cmp_path instance-attribute
unique_name = None instance-attribute
parent_ctrl_id = None instance-attribute
icon_file = None instance-attribute
author = None instance-attribute
media_file = None instance-attribute
min_revit_ver = None instance-attribute
max_revit_ver = None instance-attribute
is_beta = False instance-attribute
highlight_type = None instance-attribute
collapsed = False instance-attribute
version = None instance-attribute
meta = {} instance-attribute
meta_file = None instance-attribute
modules = [] instance-attribute
module_paths = [] instance-attribute
binary_path = None instance-attribute
library_path = None instance-attribute
control_id property
ui_title property
tooltip property
help_url property
is_supported property
allowed_sub_cmps = [GenericUICommand, NoScriptButton] class-attribute instance-attribute
layout_items = [] instance-attribute
components = [] instance-attribute

Functions

get_cache_data()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_cache_data(self):
    cache_dict = self.__dict__.copy()
    if hasattr(self, TYPE_ID_KEY):
        cache_dict[TYPE_ID_KEY] = getattr(self, TYPE_ID_KEY)
    return cache_dict
load_cache_data(cache_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def load_cache_data(self, cache_dict):
    for k, v in cache_dict.items():
        self.__dict__[k] = v
matches(component_path) classmethod
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def matches(cls, component_path):
    return component_path.lower().endswith(cls.type_id)
make_unique_name(cmp_path) classmethod

Creates a unique name for the command.

This is used to uniquely identify this command and also to create the class in pyRevit dll assembly. Current method create a unique name based on the command full directory address.

Examples:

for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton' unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def make_unique_name(cls, cmp_path):
    """Creates a unique name for the command.

    This is used to uniquely identify this command
    and also to create the class in pyRevit dll assembly.
    Current method create a unique name based on the command
    full directory address.

    Examples:
        for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton'
        unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.
    """
    pieces = []
    inside_ext = False
    for dname in cmp_path.split(op.sep):
        if exts.ExtensionTypes.UI_EXTENSION.POSTFIX in dname:
            inside_ext = True

        name, ext = op.splitext(dname)
        if ext != '' and inside_ext:
            pieces.append(name)
        else:
            continue
    return coreutils.cleanup_string(
        exts.UNIQUE_ID_SEPARATOR.join(pieces),
        skip=[exts.UNIQUE_ID_SEPARATOR]
        ).lower()
get_full_bundle_name()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_full_bundle_name(self):
    return self.name + self.type_id
has_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_module_path(self, path):
    return path in self.module_paths
add_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_module_path(self, path):
    if path and not self.has_module_path(path):
        mlogger.debug('Appending syspath: %s to %s', path, self)
        for component in self.components:
            component.add_module_path(path)
        self.module_paths.append(path)
remove_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def remove_module_path(self, path):
    if path and self.has_module_path(path):
        mlogger.debug('Removing syspath: %s from %s', path, self)
        for component in self.components:
            component.remove_module_path(path)
        return self.module_paths.remove(path)
get_bundle_file(file_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_bundle_file(self, file_name):
    if self.directory and file_name:
        file_addr = op.join(self.directory, file_name)
        return file_addr if op.exists(file_addr) else None
find_bundle_file(patterns, finder='postfix')
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_file(self, patterns, finder='postfix'):
    if self.directory:
        for bundle_file in os.listdir(self.directory):
            if 'name' == finder:
                for file_name in patterns:
                    if op.splitext(bundle_file)[0] == file_name:
                        return op.join(self.directory, bundle_file)
            elif 'postfix' == finder:
                for file_postfix in patterns:
                    if bundle_file.endswith(file_postfix):
                        return op.join(self.directory, bundle_file)
            elif 'regex' == finder:
                for regex_pattern in patterns:
                    if re.match(regex_pattern, bundle_file):
                        return op.join(self.directory, bundle_file)
    return None
find_bundle_module(module, by_host=False)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_module(self, module, by_host=False):
    # test of file_name is an actually path to a file
    if op.isfile(module):
        return module

    def build_assm_filename(module_filename):
        # build assembly by host version (assm_file_2020.ext)
        assm_name, assm_ext = op.splitext(module_filename)
        return assm_name + '_' + HOST_APP.version + assm_ext

    if by_host:
        module = build_assm_filename(module)

    # test if module is inside search paths
    for module_path in self.module_paths:
        possible_module_path = op.join(module_path, module)
        if op.isfile(possible_module_path):
            return possible_module_path
configure(config_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def configure(self, config_dict):
    # update self meta
    GenericUIComponent.configure(self, config_dict=config_dict)
    # create an updated dict to pass to children
    updated_dict = copy.deepcopy(config_dict)
    updated_dict = pyutils.merge(updated_dict, self.meta)
    # replace the meta values with the expanded values
    # so children can use the expanded
    updated_dict[exts.MDATA_UI_TITLE] = self.ui_title
    updated_dict[exts.MDATA_TOOLTIP] = self.tooltip
    updated_dict[exts.MDATA_COMMAND_HELP_URL] = self.help_url
    updated_dict[exts.AUTHOR_PARAM] = self.author
    if exts.AUTHORS_PARAM in updated_dict:
        updated_dict.pop(exts.AUTHORS_PARAM)
    for component in self:
        component.configure(updated_dict)
parse_layout_directive(layout_line)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_directive(self, layout_line):
    parts = re.findall(r'(.+)\[(.+):(.*)\]', layout_line)
    if parts:
        source_item, directive, target_value = parts[0]
        # cleanup values
        directive = directive.lower().strip()
        target_value = target_value.strip()
        # process any escape characters in target value
        # https://stackoverflow.com/a/4020824/2350244
        target_value = target_value.encode('utf-8')
        if PY3:
            target_value = target_value.decode('unicode_escape')
        else:
            target_value = target_value.decode('string_escape')
        # create directive obj
        return source_item, LayoutDirective(directive_type=directive,
                                            target=target_value)
    return layout_line, None
parse_layout_item(layout_line)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_item(self, layout_line):
    if layout_line:
        layout_item_name, layout_item_drctv = \
            self.parse_layout_directive(layout_line)
        return LayoutItem(name=layout_item_name,
                          directive=layout_item_drctv)
parse_layout_items(layout_lines)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_items(self, layout_lines):
    for layout_line in layout_lines:
        layout_item = self.parse_layout_item(layout_line)
        if layout_item:
            self.layout_items.append(layout_item)
    mlogger.debug('Layout is: %s', self.layout_items)
parse_layout_metadata()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_metadata(self):
    layout = self.meta.get(exts.MDATA_LAYOUT, [])
    if layout:
        self.parse_layout_items(layout)
        return True
contains(item_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def contains(self, item_name):
    return any([x.name == item_name for x in self.components])
add_component(comp)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_component(self, comp):
    # set search paths
    for path in self.module_paths:
        comp.add_module_path(path)
    # set its own control id on the child component
    if hasattr(comp, 'parent_ctrl_id'):
        comp.parent_ctrl_id = self.control_id
    # now add to list
    self.components.append(comp)
find_components_of_type(cmp_type)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_components_of_type(self, cmp_type):
    sub_comp_list = []
    for sub_comp in self.components:
        if isinstance(sub_comp, cmp_type):
            sub_comp_list.append(sub_comp)
        elif sub_comp.is_container:
            sub_comp_list.extend(sub_comp.find_components_of_type(cmp_type))

    return sub_comp_list
find_layout_items()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_layout_items(self):
    layout_items = []
    layout_items.extend(self.layout_items)
    for sub_comp in self.components:
        if sub_comp.is_container:
            layout_items.extend(sub_comp.find_layout_items())
    return layout_items
has_commands()
Source code in pyrevitlib/pyrevit/extensions/components.py
def has_commands(self):
    for component in self:
        if isinstance(component, GenericUICommand):
            return True

GenericStack(cmp_path=None)

Bases: GenericUIContainer

Generic UI stack.

Stacks include GenericUICommand, or GenericUICommandGroup.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def __init__(self, cmp_path=None):
    self.layout_items = []
    self.components = []
    # using classname otherwise exceptions in superclasses won't show
    GenericUIComponent.__init__(self, cmp_path=cmp_path)

Attributes

type_id = exts.STACK_BUTTON_POSTFIX class-attribute instance-attribute
allowed_sub_cmps = [GenericUICommandGroup, GenericUICommand, NoScriptButton] class-attribute instance-attribute
control_id property
name = None instance-attribute
is_container property
directory = cmp_path instance-attribute
unique_name = None instance-attribute
parent_ctrl_id = None instance-attribute
icon_file = None instance-attribute
author = None instance-attribute
media_file = None instance-attribute
min_revit_ver = None instance-attribute
max_revit_ver = None instance-attribute
is_beta = False instance-attribute
highlight_type = None instance-attribute
collapsed = False instance-attribute
version = None instance-attribute
meta = {} instance-attribute
meta_file = None instance-attribute
modules = [] instance-attribute
module_paths = [] instance-attribute
binary_path = None instance-attribute
library_path = None instance-attribute
ui_title property
tooltip property
help_url property
is_supported property
layout_items = [] instance-attribute
components = [] instance-attribute

Functions

has_commands()
Source code in pyrevitlib/pyrevit/extensions/components.py
def has_commands(self):
    for component in self:
        if not component.is_container:
            if isinstance(component, GenericUICommand):
                return True
        else:
            if component.has_commands():
                return True
get_cache_data()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_cache_data(self):
    cache_dict = self.__dict__.copy()
    if hasattr(self, TYPE_ID_KEY):
        cache_dict[TYPE_ID_KEY] = getattr(self, TYPE_ID_KEY)
    return cache_dict
load_cache_data(cache_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def load_cache_data(self, cache_dict):
    for k, v in cache_dict.items():
        self.__dict__[k] = v
matches(component_path) classmethod
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def matches(cls, component_path):
    return component_path.lower().endswith(cls.type_id)
make_unique_name(cmp_path) classmethod

Creates a unique name for the command.

This is used to uniquely identify this command and also to create the class in pyRevit dll assembly. Current method create a unique name based on the command full directory address.

Examples:

for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton' unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def make_unique_name(cls, cmp_path):
    """Creates a unique name for the command.

    This is used to uniquely identify this command
    and also to create the class in pyRevit dll assembly.
    Current method create a unique name based on the command
    full directory address.

    Examples:
        for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton'
        unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.
    """
    pieces = []
    inside_ext = False
    for dname in cmp_path.split(op.sep):
        if exts.ExtensionTypes.UI_EXTENSION.POSTFIX in dname:
            inside_ext = True

        name, ext = op.splitext(dname)
        if ext != '' and inside_ext:
            pieces.append(name)
        else:
            continue
    return coreutils.cleanup_string(
        exts.UNIQUE_ID_SEPARATOR.join(pieces),
        skip=[exts.UNIQUE_ID_SEPARATOR]
        ).lower()
get_full_bundle_name()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_full_bundle_name(self):
    return self.name + self.type_id
has_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_module_path(self, path):
    return path in self.module_paths
add_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_module_path(self, path):
    if path and not self.has_module_path(path):
        mlogger.debug('Appending syspath: %s to %s', path, self)
        for component in self.components:
            component.add_module_path(path)
        self.module_paths.append(path)
remove_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def remove_module_path(self, path):
    if path and self.has_module_path(path):
        mlogger.debug('Removing syspath: %s from %s', path, self)
        for component in self.components:
            component.remove_module_path(path)
        return self.module_paths.remove(path)
get_bundle_file(file_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_bundle_file(self, file_name):
    if self.directory and file_name:
        file_addr = op.join(self.directory, file_name)
        return file_addr if op.exists(file_addr) else None
find_bundle_file(patterns, finder='postfix')
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_file(self, patterns, finder='postfix'):
    if self.directory:
        for bundle_file in os.listdir(self.directory):
            if 'name' == finder:
                for file_name in patterns:
                    if op.splitext(bundle_file)[0] == file_name:
                        return op.join(self.directory, bundle_file)
            elif 'postfix' == finder:
                for file_postfix in patterns:
                    if bundle_file.endswith(file_postfix):
                        return op.join(self.directory, bundle_file)
            elif 'regex' == finder:
                for regex_pattern in patterns:
                    if re.match(regex_pattern, bundle_file):
                        return op.join(self.directory, bundle_file)
    return None
find_bundle_module(module, by_host=False)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_module(self, module, by_host=False):
    # test of file_name is an actually path to a file
    if op.isfile(module):
        return module

    def build_assm_filename(module_filename):
        # build assembly by host version (assm_file_2020.ext)
        assm_name, assm_ext = op.splitext(module_filename)
        return assm_name + '_' + HOST_APP.version + assm_ext

    if by_host:
        module = build_assm_filename(module)

    # test if module is inside search paths
    for module_path in self.module_paths:
        possible_module_path = op.join(module_path, module)
        if op.isfile(possible_module_path):
            return possible_module_path
configure(config_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def configure(self, config_dict):
    # update self meta
    GenericUIComponent.configure(self, config_dict=config_dict)
    # create an updated dict to pass to children
    updated_dict = copy.deepcopy(config_dict)
    updated_dict = pyutils.merge(updated_dict, self.meta)
    # replace the meta values with the expanded values
    # so children can use the expanded
    updated_dict[exts.MDATA_UI_TITLE] = self.ui_title
    updated_dict[exts.MDATA_TOOLTIP] = self.tooltip
    updated_dict[exts.MDATA_COMMAND_HELP_URL] = self.help_url
    updated_dict[exts.AUTHOR_PARAM] = self.author
    if exts.AUTHORS_PARAM in updated_dict:
        updated_dict.pop(exts.AUTHORS_PARAM)
    for component in self:
        component.configure(updated_dict)
parse_layout_directive(layout_line)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_directive(self, layout_line):
    parts = re.findall(r'(.+)\[(.+):(.*)\]', layout_line)
    if parts:
        source_item, directive, target_value = parts[0]
        # cleanup values
        directive = directive.lower().strip()
        target_value = target_value.strip()
        # process any escape characters in target value
        # https://stackoverflow.com/a/4020824/2350244
        target_value = target_value.encode('utf-8')
        if PY3:
            target_value = target_value.decode('unicode_escape')
        else:
            target_value = target_value.decode('string_escape')
        # create directive obj
        return source_item, LayoutDirective(directive_type=directive,
                                            target=target_value)
    return layout_line, None
parse_layout_item(layout_line)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_item(self, layout_line):
    if layout_line:
        layout_item_name, layout_item_drctv = \
            self.parse_layout_directive(layout_line)
        return LayoutItem(name=layout_item_name,
                          directive=layout_item_drctv)
parse_layout_items(layout_lines)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_items(self, layout_lines):
    for layout_line in layout_lines:
        layout_item = self.parse_layout_item(layout_line)
        if layout_item:
            self.layout_items.append(layout_item)
    mlogger.debug('Layout is: %s', self.layout_items)
parse_layout_metadata()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_metadata(self):
    layout = self.meta.get(exts.MDATA_LAYOUT, [])
    if layout:
        self.parse_layout_items(layout)
        return True
contains(item_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def contains(self, item_name):
    return any([x.name == item_name for x in self.components])
add_component(comp)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_component(self, comp):
    # set search paths
    for path in self.module_paths:
        comp.add_module_path(path)
    # set its own control id on the child component
    if hasattr(comp, 'parent_ctrl_id'):
        comp.parent_ctrl_id = self.control_id
    # now add to list
    self.components.append(comp)
find_components_of_type(cmp_type)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_components_of_type(self, cmp_type):
    sub_comp_list = []
    for sub_comp in self.components:
        if isinstance(sub_comp, cmp_type):
            sub_comp_list.append(sub_comp)
        elif sub_comp.is_container:
            sub_comp_list.extend(sub_comp.find_components_of_type(cmp_type))

    return sub_comp_list
find_layout_items()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_layout_items(self):
    layout_items = []
    layout_items.extend(self.layout_items)
    for sub_comp in self.components:
        if sub_comp.is_container:
            layout_items.extend(sub_comp.find_layout_items())
    return layout_items

StackButtonGroup(cmp_path=None)

Bases: GenericStack

Stack buttons group.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def __init__(self, cmp_path=None):
    self.layout_items = []
    self.components = []
    # using classname otherwise exceptions in superclasses won't show
    GenericUIComponent.__init__(self, cmp_path=cmp_path)

Attributes

type_id = exts.STACK_BUTTON_POSTFIX class-attribute instance-attribute
name = None instance-attribute
is_container property
directory = cmp_path instance-attribute
unique_name = None instance-attribute
parent_ctrl_id = None instance-attribute
icon_file = None instance-attribute
author = None instance-attribute
media_file = None instance-attribute
min_revit_ver = None instance-attribute
max_revit_ver = None instance-attribute
is_beta = False instance-attribute
highlight_type = None instance-attribute
collapsed = False instance-attribute
version = None instance-attribute
meta = {} instance-attribute
meta_file = None instance-attribute
modules = [] instance-attribute
module_paths = [] instance-attribute
binary_path = None instance-attribute
library_path = None instance-attribute
control_id property
ui_title property
tooltip property
help_url property
is_supported property
allowed_sub_cmps = [GenericUICommandGroup, GenericUICommand, NoScriptButton] class-attribute instance-attribute
layout_items = [] instance-attribute
components = [] instance-attribute

Functions

get_cache_data()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_cache_data(self):
    cache_dict = self.__dict__.copy()
    if hasattr(self, TYPE_ID_KEY):
        cache_dict[TYPE_ID_KEY] = getattr(self, TYPE_ID_KEY)
    return cache_dict
load_cache_data(cache_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def load_cache_data(self, cache_dict):
    for k, v in cache_dict.items():
        self.__dict__[k] = v
matches(component_path) classmethod
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def matches(cls, component_path):
    return component_path.lower().endswith(cls.type_id)
make_unique_name(cmp_path) classmethod

Creates a unique name for the command.

This is used to uniquely identify this command and also to create the class in pyRevit dll assembly. Current method create a unique name based on the command full directory address.

Examples:

for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton' unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def make_unique_name(cls, cmp_path):
    """Creates a unique name for the command.

    This is used to uniquely identify this command
    and also to create the class in pyRevit dll assembly.
    Current method create a unique name based on the command
    full directory address.

    Examples:
        for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton'
        unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.
    """
    pieces = []
    inside_ext = False
    for dname in cmp_path.split(op.sep):
        if exts.ExtensionTypes.UI_EXTENSION.POSTFIX in dname:
            inside_ext = True

        name, ext = op.splitext(dname)
        if ext != '' and inside_ext:
            pieces.append(name)
        else:
            continue
    return coreutils.cleanup_string(
        exts.UNIQUE_ID_SEPARATOR.join(pieces),
        skip=[exts.UNIQUE_ID_SEPARATOR]
        ).lower()
get_full_bundle_name()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_full_bundle_name(self):
    return self.name + self.type_id
has_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_module_path(self, path):
    return path in self.module_paths
add_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_module_path(self, path):
    if path and not self.has_module_path(path):
        mlogger.debug('Appending syspath: %s to %s', path, self)
        for component in self.components:
            component.add_module_path(path)
        self.module_paths.append(path)
remove_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def remove_module_path(self, path):
    if path and self.has_module_path(path):
        mlogger.debug('Removing syspath: %s from %s', path, self)
        for component in self.components:
            component.remove_module_path(path)
        return self.module_paths.remove(path)
get_bundle_file(file_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_bundle_file(self, file_name):
    if self.directory and file_name:
        file_addr = op.join(self.directory, file_name)
        return file_addr if op.exists(file_addr) else None
find_bundle_file(patterns, finder='postfix')
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_file(self, patterns, finder='postfix'):
    if self.directory:
        for bundle_file in os.listdir(self.directory):
            if 'name' == finder:
                for file_name in patterns:
                    if op.splitext(bundle_file)[0] == file_name:
                        return op.join(self.directory, bundle_file)
            elif 'postfix' == finder:
                for file_postfix in patterns:
                    if bundle_file.endswith(file_postfix):
                        return op.join(self.directory, bundle_file)
            elif 'regex' == finder:
                for regex_pattern in patterns:
                    if re.match(regex_pattern, bundle_file):
                        return op.join(self.directory, bundle_file)
    return None
find_bundle_module(module, by_host=False)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_module(self, module, by_host=False):
    # test of file_name is an actually path to a file
    if op.isfile(module):
        return module

    def build_assm_filename(module_filename):
        # build assembly by host version (assm_file_2020.ext)
        assm_name, assm_ext = op.splitext(module_filename)
        return assm_name + '_' + HOST_APP.version + assm_ext

    if by_host:
        module = build_assm_filename(module)

    # test if module is inside search paths
    for module_path in self.module_paths:
        possible_module_path = op.join(module_path, module)
        if op.isfile(possible_module_path):
            return possible_module_path
configure(config_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def configure(self, config_dict):
    # update self meta
    GenericUIComponent.configure(self, config_dict=config_dict)
    # create an updated dict to pass to children
    updated_dict = copy.deepcopy(config_dict)
    updated_dict = pyutils.merge(updated_dict, self.meta)
    # replace the meta values with the expanded values
    # so children can use the expanded
    updated_dict[exts.MDATA_UI_TITLE] = self.ui_title
    updated_dict[exts.MDATA_TOOLTIP] = self.tooltip
    updated_dict[exts.MDATA_COMMAND_HELP_URL] = self.help_url
    updated_dict[exts.AUTHOR_PARAM] = self.author
    if exts.AUTHORS_PARAM in updated_dict:
        updated_dict.pop(exts.AUTHORS_PARAM)
    for component in self:
        component.configure(updated_dict)
parse_layout_directive(layout_line)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_directive(self, layout_line):
    parts = re.findall(r'(.+)\[(.+):(.*)\]', layout_line)
    if parts:
        source_item, directive, target_value = parts[0]
        # cleanup values
        directive = directive.lower().strip()
        target_value = target_value.strip()
        # process any escape characters in target value
        # https://stackoverflow.com/a/4020824/2350244
        target_value = target_value.encode('utf-8')
        if PY3:
            target_value = target_value.decode('unicode_escape')
        else:
            target_value = target_value.decode('string_escape')
        # create directive obj
        return source_item, LayoutDirective(directive_type=directive,
                                            target=target_value)
    return layout_line, None
parse_layout_item(layout_line)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_item(self, layout_line):
    if layout_line:
        layout_item_name, layout_item_drctv = \
            self.parse_layout_directive(layout_line)
        return LayoutItem(name=layout_item_name,
                          directive=layout_item_drctv)
parse_layout_items(layout_lines)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_items(self, layout_lines):
    for layout_line in layout_lines:
        layout_item = self.parse_layout_item(layout_line)
        if layout_item:
            self.layout_items.append(layout_item)
    mlogger.debug('Layout is: %s', self.layout_items)
parse_layout_metadata()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_metadata(self):
    layout = self.meta.get(exts.MDATA_LAYOUT, [])
    if layout:
        self.parse_layout_items(layout)
        return True
contains(item_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def contains(self, item_name):
    return any([x.name == item_name for x in self.components])
add_component(comp)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_component(self, comp):
    # set search paths
    for path in self.module_paths:
        comp.add_module_path(path)
    # set its own control id on the child component
    if hasattr(comp, 'parent_ctrl_id'):
        comp.parent_ctrl_id = self.control_id
    # now add to list
    self.components.append(comp)
find_components_of_type(cmp_type)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_components_of_type(self, cmp_type):
    sub_comp_list = []
    for sub_comp in self.components:
        if isinstance(sub_comp, cmp_type):
            sub_comp_list.append(sub_comp)
        elif sub_comp.is_container:
            sub_comp_list.extend(sub_comp.find_components_of_type(cmp_type))

    return sub_comp_list
find_layout_items()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_layout_items(self):
    layout_items = []
    layout_items.extend(self.layout_items)
    for sub_comp in self.components:
        if sub_comp.is_container:
            layout_items.extend(sub_comp.find_layout_items())
    return layout_items
has_commands()
Source code in pyrevitlib/pyrevit/extensions/components.py
def has_commands(self):
    for component in self:
        if not component.is_container:
            if isinstance(component, GenericUICommand):
                return True
        else:
            if component.has_commands():
                return True

Panel(cmp_path=None)

Bases: GenericUIContainer

Panel container.

Panels include GenericStack, GenericUICommand, or GenericUICommandGroup

Source code in pyrevitlib/pyrevit/extensions/components.py
def __init__(self, cmp_path=None):
    # using classname otherwise exceptions in superclasses won't show
    GenericUIContainer.__init__(self, cmp_path=cmp_path)
    self.panel_background = self.title_background = self.slideout_background = None
    # read metadata from metadata file
    if self.meta:
        # check for background color configs
        self.panel_background = self.meta.get(exts.MDATA_BACKGROUND_KEY, None)
        if self.panel_background:
            if isinstance(self.panel_background, dict):
                self.title_background = self.panel_background.get(
                    exts.MDATA_BACKGROUND_TITLE_KEY, None
                )
                self.slideout_background = self.panel_background.get(
                    exts.MDATA_BACKGROUND_SLIDEOUT_KEY, None
                )
                self.panel_background = self.panel_background.get(
                    exts.MDATA_BACKGROUND_PANEL_KEY, None
                )
            elif not isinstance(self.panel_background, str):
                mlogger.error("%s bad background definition in metadata.", self)

Attributes

type_id = exts.PANEL_POSTFIX class-attribute instance-attribute
allowed_sub_cmps = [GenericStack, GenericUICommandGroup, GenericUICommand, NoScriptButton] class-attribute instance-attribute
panel_background = None instance-attribute
title_background = None instance-attribute
slideout_background = None instance-attribute
name = None instance-attribute
is_container property
directory = cmp_path instance-attribute
unique_name = None instance-attribute
parent_ctrl_id = None instance-attribute
icon_file = None instance-attribute
author = None instance-attribute
media_file = None instance-attribute
min_revit_ver = None instance-attribute
max_revit_ver = None instance-attribute
is_beta = False instance-attribute
highlight_type = None instance-attribute
collapsed = False instance-attribute
version = None instance-attribute
meta = {} instance-attribute
meta_file = None instance-attribute
modules = [] instance-attribute
module_paths = [] instance-attribute
binary_path = None instance-attribute
library_path = None instance-attribute
control_id property
ui_title property
tooltip property
help_url property
is_supported property
layout_items = [] instance-attribute
components = [] instance-attribute

Functions

has_commands()
Source code in pyrevitlib/pyrevit/extensions/components.py
def has_commands(self):
    for component in self:
        if not component.is_container:
            if isinstance(component, GenericUICommand):
                return True
        else:
            if component.has_commands():
                return True
contains(item_name)
Source code in pyrevitlib/pyrevit/extensions/components.py
def contains(self, item_name):
    # Panels contain stacks. But stacks itself does not have any ui and its
    # subitems are displayed within the ui of the parent panel.
    # This is different from pulldowns and other button groups.
    # Button groups, contain and display their sub components in their
    # own drop down menu. So when checking if panel has a button,
    # panel should check all the items visible to the user and respond.
    item_exists = GenericUIContainer.contains(self, item_name)
    if item_exists:
        return True
    else:
        # if child is a stack item, check its children too
        for component in self:
            if isinstance(component, GenericStack) and component.contains(
                item_name
            ):
                return True
get_cache_data()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_cache_data(self):
    cache_dict = self.__dict__.copy()
    if hasattr(self, TYPE_ID_KEY):
        cache_dict[TYPE_ID_KEY] = getattr(self, TYPE_ID_KEY)
    return cache_dict
load_cache_data(cache_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def load_cache_data(self, cache_dict):
    for k, v in cache_dict.items():
        self.__dict__[k] = v
matches(component_path) classmethod
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def matches(cls, component_path):
    return component_path.lower().endswith(cls.type_id)
make_unique_name(cmp_path) classmethod

Creates a unique name for the command.

This is used to uniquely identify this command and also to create the class in pyRevit dll assembly. Current method create a unique name based on the command full directory address.

Examples:

for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton' unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def make_unique_name(cls, cmp_path):
    """Creates a unique name for the command.

    This is used to uniquely identify this command
    and also to create the class in pyRevit dll assembly.
    Current method create a unique name based on the command
    full directory address.

    Examples:
        for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton'
        unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.
    """
    pieces = []
    inside_ext = False
    for dname in cmp_path.split(op.sep):
        if exts.ExtensionTypes.UI_EXTENSION.POSTFIX in dname:
            inside_ext = True

        name, ext = op.splitext(dname)
        if ext != '' and inside_ext:
            pieces.append(name)
        else:
            continue
    return coreutils.cleanup_string(
        exts.UNIQUE_ID_SEPARATOR.join(pieces),
        skip=[exts.UNIQUE_ID_SEPARATOR]
        ).lower()
get_full_bundle_name()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_full_bundle_name(self):
    return self.name + self.type_id
has_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_module_path(self, path):
    return path in self.module_paths
add_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_module_path(self, path):
    if path and not self.has_module_path(path):
        mlogger.debug('Appending syspath: %s to %s', path, self)
        for component in self.components:
            component.add_module_path(path)
        self.module_paths.append(path)
remove_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def remove_module_path(self, path):
    if path and self.has_module_path(path):
        mlogger.debug('Removing syspath: %s from %s', path, self)
        for component in self.components:
            component.remove_module_path(path)
        return self.module_paths.remove(path)
get_bundle_file(file_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_bundle_file(self, file_name):
    if self.directory and file_name:
        file_addr = op.join(self.directory, file_name)
        return file_addr if op.exists(file_addr) else None
find_bundle_file(patterns, finder='postfix')
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_file(self, patterns, finder='postfix'):
    if self.directory:
        for bundle_file in os.listdir(self.directory):
            if 'name' == finder:
                for file_name in patterns:
                    if op.splitext(bundle_file)[0] == file_name:
                        return op.join(self.directory, bundle_file)
            elif 'postfix' == finder:
                for file_postfix in patterns:
                    if bundle_file.endswith(file_postfix):
                        return op.join(self.directory, bundle_file)
            elif 'regex' == finder:
                for regex_pattern in patterns:
                    if re.match(regex_pattern, bundle_file):
                        return op.join(self.directory, bundle_file)
    return None
find_bundle_module(module, by_host=False)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_module(self, module, by_host=False):
    # test of file_name is an actually path to a file
    if op.isfile(module):
        return module

    def build_assm_filename(module_filename):
        # build assembly by host version (assm_file_2020.ext)
        assm_name, assm_ext = op.splitext(module_filename)
        return assm_name + '_' + HOST_APP.version + assm_ext

    if by_host:
        module = build_assm_filename(module)

    # test if module is inside search paths
    for module_path in self.module_paths:
        possible_module_path = op.join(module_path, module)
        if op.isfile(possible_module_path):
            return possible_module_path
configure(config_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def configure(self, config_dict):
    # update self meta
    GenericUIComponent.configure(self, config_dict=config_dict)
    # create an updated dict to pass to children
    updated_dict = copy.deepcopy(config_dict)
    updated_dict = pyutils.merge(updated_dict, self.meta)
    # replace the meta values with the expanded values
    # so children can use the expanded
    updated_dict[exts.MDATA_UI_TITLE] = self.ui_title
    updated_dict[exts.MDATA_TOOLTIP] = self.tooltip
    updated_dict[exts.MDATA_COMMAND_HELP_URL] = self.help_url
    updated_dict[exts.AUTHOR_PARAM] = self.author
    if exts.AUTHORS_PARAM in updated_dict:
        updated_dict.pop(exts.AUTHORS_PARAM)
    for component in self:
        component.configure(updated_dict)
parse_layout_directive(layout_line)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_directive(self, layout_line):
    parts = re.findall(r'(.+)\[(.+):(.*)\]', layout_line)
    if parts:
        source_item, directive, target_value = parts[0]
        # cleanup values
        directive = directive.lower().strip()
        target_value = target_value.strip()
        # process any escape characters in target value
        # https://stackoverflow.com/a/4020824/2350244
        target_value = target_value.encode('utf-8')
        if PY3:
            target_value = target_value.decode('unicode_escape')
        else:
            target_value = target_value.decode('string_escape')
        # create directive obj
        return source_item, LayoutDirective(directive_type=directive,
                                            target=target_value)
    return layout_line, None
parse_layout_item(layout_line)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_item(self, layout_line):
    if layout_line:
        layout_item_name, layout_item_drctv = \
            self.parse_layout_directive(layout_line)
        return LayoutItem(name=layout_item_name,
                          directive=layout_item_drctv)
parse_layout_items(layout_lines)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_items(self, layout_lines):
    for layout_line in layout_lines:
        layout_item = self.parse_layout_item(layout_line)
        if layout_item:
            self.layout_items.append(layout_item)
    mlogger.debug('Layout is: %s', self.layout_items)
parse_layout_metadata()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_metadata(self):
    layout = self.meta.get(exts.MDATA_LAYOUT, [])
    if layout:
        self.parse_layout_items(layout)
        return True
add_component(comp)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_component(self, comp):
    # set search paths
    for path in self.module_paths:
        comp.add_module_path(path)
    # set its own control id on the child component
    if hasattr(comp, 'parent_ctrl_id'):
        comp.parent_ctrl_id = self.control_id
    # now add to list
    self.components.append(comp)
find_components_of_type(cmp_type)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_components_of_type(self, cmp_type):
    sub_comp_list = []
    for sub_comp in self.components:
        if isinstance(sub_comp, cmp_type):
            sub_comp_list.append(sub_comp)
        elif sub_comp.is_container:
            sub_comp_list.extend(sub_comp.find_components_of_type(cmp_type))

    return sub_comp_list
find_layout_items()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_layout_items(self):
    layout_items = []
    layout_items.extend(self.layout_items)
    for sub_comp in self.components:
        if sub_comp.is_container:
            layout_items.extend(sub_comp.find_layout_items())
    return layout_items

Tab(cmp_path=None)

Bases: GenericUIContainer

Tab container for Panels.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def __init__(self, cmp_path=None):
    self.layout_items = []
    self.components = []
    # using classname otherwise exceptions in superclasses won't show
    GenericUIComponent.__init__(self, cmp_path=cmp_path)

Attributes

type_id = exts.TAB_POSTFIX class-attribute instance-attribute
allowed_sub_cmps = [Panel] class-attribute instance-attribute
name = None instance-attribute
is_container property
directory = cmp_path instance-attribute
unique_name = None instance-attribute
parent_ctrl_id = None instance-attribute
icon_file = None instance-attribute
author = None instance-attribute
media_file = None instance-attribute
min_revit_ver = None instance-attribute
max_revit_ver = None instance-attribute
is_beta = False instance-attribute
highlight_type = None instance-attribute
collapsed = False instance-attribute
version = None instance-attribute
meta = {} instance-attribute
meta_file = None instance-attribute
modules = [] instance-attribute
module_paths = [] instance-attribute
binary_path = None instance-attribute
library_path = None instance-attribute
control_id property
ui_title property
tooltip property
help_url property
is_supported property
layout_items = [] instance-attribute
components = [] instance-attribute

Functions

has_commands()
Source code in pyrevitlib/pyrevit/extensions/components.py
def has_commands(self):
    for panel in self:
        if panel.has_commands():
            return True
    return False
get_cache_data()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_cache_data(self):
    cache_dict = self.__dict__.copy()
    if hasattr(self, TYPE_ID_KEY):
        cache_dict[TYPE_ID_KEY] = getattr(self, TYPE_ID_KEY)
    return cache_dict
load_cache_data(cache_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def load_cache_data(self, cache_dict):
    for k, v in cache_dict.items():
        self.__dict__[k] = v
matches(component_path) classmethod
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def matches(cls, component_path):
    return component_path.lower().endswith(cls.type_id)
make_unique_name(cmp_path) classmethod

Creates a unique name for the command.

This is used to uniquely identify this command and also to create the class in pyRevit dll assembly. Current method create a unique name based on the command full directory address.

Examples:

for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton' unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def make_unique_name(cls, cmp_path):
    """Creates a unique name for the command.

    This is used to uniquely identify this command
    and also to create the class in pyRevit dll assembly.
    Current method create a unique name based on the command
    full directory address.

    Examples:
        for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton'
        unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.
    """
    pieces = []
    inside_ext = False
    for dname in cmp_path.split(op.sep):
        if exts.ExtensionTypes.UI_EXTENSION.POSTFIX in dname:
            inside_ext = True

        name, ext = op.splitext(dname)
        if ext != '' and inside_ext:
            pieces.append(name)
        else:
            continue
    return coreutils.cleanup_string(
        exts.UNIQUE_ID_SEPARATOR.join(pieces),
        skip=[exts.UNIQUE_ID_SEPARATOR]
        ).lower()
get_full_bundle_name()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_full_bundle_name(self):
    return self.name + self.type_id
has_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_module_path(self, path):
    return path in self.module_paths
add_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_module_path(self, path):
    if path and not self.has_module_path(path):
        mlogger.debug('Appending syspath: %s to %s', path, self)
        for component in self.components:
            component.add_module_path(path)
        self.module_paths.append(path)
remove_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def remove_module_path(self, path):
    if path and self.has_module_path(path):
        mlogger.debug('Removing syspath: %s from %s', path, self)
        for component in self.components:
            component.remove_module_path(path)
        return self.module_paths.remove(path)
get_bundle_file(file_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_bundle_file(self, file_name):
    if self.directory and file_name:
        file_addr = op.join(self.directory, file_name)
        return file_addr if op.exists(file_addr) else None
find_bundle_file(patterns, finder='postfix')
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_file(self, patterns, finder='postfix'):
    if self.directory:
        for bundle_file in os.listdir(self.directory):
            if 'name' == finder:
                for file_name in patterns:
                    if op.splitext(bundle_file)[0] == file_name:
                        return op.join(self.directory, bundle_file)
            elif 'postfix' == finder:
                for file_postfix in patterns:
                    if bundle_file.endswith(file_postfix):
                        return op.join(self.directory, bundle_file)
            elif 'regex' == finder:
                for regex_pattern in patterns:
                    if re.match(regex_pattern, bundle_file):
                        return op.join(self.directory, bundle_file)
    return None
find_bundle_module(module, by_host=False)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_module(self, module, by_host=False):
    # test of file_name is an actually path to a file
    if op.isfile(module):
        return module

    def build_assm_filename(module_filename):
        # build assembly by host version (assm_file_2020.ext)
        assm_name, assm_ext = op.splitext(module_filename)
        return assm_name + '_' + HOST_APP.version + assm_ext

    if by_host:
        module = build_assm_filename(module)

    # test if module is inside search paths
    for module_path in self.module_paths:
        possible_module_path = op.join(module_path, module)
        if op.isfile(possible_module_path):
            return possible_module_path
configure(config_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def configure(self, config_dict):
    # update self meta
    GenericUIComponent.configure(self, config_dict=config_dict)
    # create an updated dict to pass to children
    updated_dict = copy.deepcopy(config_dict)
    updated_dict = pyutils.merge(updated_dict, self.meta)
    # replace the meta values with the expanded values
    # so children can use the expanded
    updated_dict[exts.MDATA_UI_TITLE] = self.ui_title
    updated_dict[exts.MDATA_TOOLTIP] = self.tooltip
    updated_dict[exts.MDATA_COMMAND_HELP_URL] = self.help_url
    updated_dict[exts.AUTHOR_PARAM] = self.author
    if exts.AUTHORS_PARAM in updated_dict:
        updated_dict.pop(exts.AUTHORS_PARAM)
    for component in self:
        component.configure(updated_dict)
parse_layout_directive(layout_line)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_directive(self, layout_line):
    parts = re.findall(r'(.+)\[(.+):(.*)\]', layout_line)
    if parts:
        source_item, directive, target_value = parts[0]
        # cleanup values
        directive = directive.lower().strip()
        target_value = target_value.strip()
        # process any escape characters in target value
        # https://stackoverflow.com/a/4020824/2350244
        target_value = target_value.encode('utf-8')
        if PY3:
            target_value = target_value.decode('unicode_escape')
        else:
            target_value = target_value.decode('string_escape')
        # create directive obj
        return source_item, LayoutDirective(directive_type=directive,
                                            target=target_value)
    return layout_line, None
parse_layout_item(layout_line)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_item(self, layout_line):
    if layout_line:
        layout_item_name, layout_item_drctv = \
            self.parse_layout_directive(layout_line)
        return LayoutItem(name=layout_item_name,
                          directive=layout_item_drctv)
parse_layout_items(layout_lines)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_items(self, layout_lines):
    for layout_line in layout_lines:
        layout_item = self.parse_layout_item(layout_line)
        if layout_item:
            self.layout_items.append(layout_item)
    mlogger.debug('Layout is: %s', self.layout_items)
parse_layout_metadata()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_metadata(self):
    layout = self.meta.get(exts.MDATA_LAYOUT, [])
    if layout:
        self.parse_layout_items(layout)
        return True
contains(item_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def contains(self, item_name):
    return any([x.name == item_name for x in self.components])
add_component(comp)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_component(self, comp):
    # set search paths
    for path in self.module_paths:
        comp.add_module_path(path)
    # set its own control id on the child component
    if hasattr(comp, 'parent_ctrl_id'):
        comp.parent_ctrl_id = self.control_id
    # now add to list
    self.components.append(comp)
find_components_of_type(cmp_type)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_components_of_type(self, cmp_type):
    sub_comp_list = []
    for sub_comp in self.components:
        if isinstance(sub_comp, cmp_type):
            sub_comp_list.append(sub_comp)
        elif sub_comp.is_container:
            sub_comp_list.extend(sub_comp.find_components_of_type(cmp_type))

    return sub_comp_list
find_layout_items()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_layout_items(self):
    layout_items = []
    layout_items.extend(self.layout_items)
    for sub_comp in self.components:
        if sub_comp.is_container:
            layout_items.extend(sub_comp.find_layout_items())
    return layout_items

Extension(cmp_path=None)

Bases: GenericUIContainer

UI Tools extension.

Source code in pyrevitlib/pyrevit/extensions/components.py
def __init__(self, cmp_path=None):
    self.pyrvt_version = None
    self.dir_hash_value = None
    # using classname otherwise exceptions in superclasses won't show
    GenericUIContainer.__init__(self, cmp_path=cmp_path)

Attributes

type_id = exts.ExtensionTypes.UI_EXTENSION.POSTFIX class-attribute instance-attribute
allowed_sub_cmps = [Tab] class-attribute instance-attribute
pyrvt_version = None instance-attribute
dir_hash_value = None instance-attribute
control_id property
startup_script property
name = None instance-attribute
is_container property
directory = cmp_path instance-attribute
unique_name = None instance-attribute
parent_ctrl_id = None instance-attribute
icon_file = None instance-attribute
author = None instance-attribute
media_file = None instance-attribute
min_revit_ver = None instance-attribute
max_revit_ver = None instance-attribute
is_beta = False instance-attribute
highlight_type = None instance-attribute
collapsed = False instance-attribute
version = None instance-attribute
meta = {} instance-attribute
meta_file = None instance-attribute
modules = [] instance-attribute
module_paths = [] instance-attribute
binary_path = None instance-attribute
library_path = None instance-attribute
ui_title property
tooltip property
help_url property
is_supported property
layout_items = [] instance-attribute
components = [] instance-attribute

Functions

get_hash()
Source code in pyrevitlib/pyrevit/extensions/components.py
def get_hash(self):
    return coreutils.get_str_hash(safe_strtype(self.get_cache_data()))
get_all_commands()
Source code in pyrevitlib/pyrevit/extensions/components.py
def get_all_commands(self):
    return self.find_components_of_type(GenericUICommand)
get_manifest_file()
Source code in pyrevitlib/pyrevit/extensions/components.py
def get_manifest_file(self):
    return self.get_bundle_file(exts.EXT_MANIFEST_FILE)
get_manifest()
Source code in pyrevitlib/pyrevit/extensions/components.py
def get_manifest(self):
    manifest_file = self.get_manifest_file()
    if manifest_file:
        with codecs.open(manifest_file, "r", "utf-8") as mfile:
            try:
                manifest_cfg = json.load(mfile)
                return manifest_cfg
            except Exception as manfload_err:
                print(
                    "Can not parse ext manifest file: {} "
                    "| {}".format(manifest_file, manfload_err)
                )
                return
configure()
Source code in pyrevitlib/pyrevit/extensions/components.py
def configure(self):
    cfg_dict = self.get_manifest()
    if cfg_dict:
        for component in self:
            component.configure(cfg_dict)
get_extension_modules()
Source code in pyrevitlib/pyrevit/extensions/components.py
def get_extension_modules(self):
    modules = []
    if self.binary_path and op.exists(self.binary_path):
        for item in os.listdir(self.binary_path):
            item_path = op.join(self.binary_path, item)
            item_name = item.lower()
            if op.isfile(item_path) and item_name.endswith(
                framework.ASSEMBLY_FILE_TYPE
            ):
                modules.append(item_path)
    return modules
get_command_modules()
Source code in pyrevitlib/pyrevit/extensions/components.py
def get_command_modules(self):
    referenced_modules = set()
    for cmd in self.get_all_commands():
        for module in cmd.modules:
            cmd_module = cmd.find_bundle_module(module)
            if cmd_module:
                referenced_modules.add(cmd_module)
    return referenced_modules
get_hooks()
Source code in pyrevitlib/pyrevit/extensions/components.py
def get_hooks(self):
    hook_scripts = os.listdir(self.hooks_path) if self.hooks_path else []
    return [op.join(self.hooks_path, x) for x in hook_scripts]
get_checks()
Source code in pyrevitlib/pyrevit/extensions/components.py
def get_checks(self):
    check_scripts = os.listdir(self.checks_path) if self.checks_path else []
    return [op.join(self.checks_path, x) for x in check_scripts]
get_cache_data()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_cache_data(self):
    cache_dict = self.__dict__.copy()
    if hasattr(self, TYPE_ID_KEY):
        cache_dict[TYPE_ID_KEY] = getattr(self, TYPE_ID_KEY)
    return cache_dict
load_cache_data(cache_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def load_cache_data(self, cache_dict):
    for k, v in cache_dict.items():
        self.__dict__[k] = v
matches(component_path) classmethod
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def matches(cls, component_path):
    return component_path.lower().endswith(cls.type_id)
make_unique_name(cmp_path) classmethod

Creates a unique name for the command.

This is used to uniquely identify this command and also to create the class in pyRevit dll assembly. Current method create a unique name based on the command full directory address.

Examples:

for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton' unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.

Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
@classmethod
def make_unique_name(cls, cmp_path):
    """Creates a unique name for the command.

    This is used to uniquely identify this command
    and also to create the class in pyRevit dll assembly.
    Current method create a unique name based on the command
    full directory address.

    Examples:
        for 'pyRevit.extension/pyRevit.tab/Edit.panel/Flip doors.pushbutton'
        unique name would be: 'pyrevit_pyrevit_edit_flipdoors'.
    """
    pieces = []
    inside_ext = False
    for dname in cmp_path.split(op.sep):
        if exts.ExtensionTypes.UI_EXTENSION.POSTFIX in dname:
            inside_ext = True

        name, ext = op.splitext(dname)
        if ext != '' and inside_ext:
            pieces.append(name)
        else:
            continue
    return coreutils.cleanup_string(
        exts.UNIQUE_ID_SEPARATOR.join(pieces),
        skip=[exts.UNIQUE_ID_SEPARATOR]
        ).lower()
get_full_bundle_name()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_full_bundle_name(self):
    return self.name + self.type_id
has_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def has_module_path(self, path):
    return path in self.module_paths
add_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_module_path(self, path):
    if path and not self.has_module_path(path):
        mlogger.debug('Appending syspath: %s to %s', path, self)
        for component in self.components:
            component.add_module_path(path)
        self.module_paths.append(path)
remove_module_path(path)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def remove_module_path(self, path):
    if path and self.has_module_path(path):
        mlogger.debug('Removing syspath: %s from %s', path, self)
        for component in self.components:
            component.remove_module_path(path)
        return self.module_paths.remove(path)
get_bundle_file(file_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_bundle_file(self, file_name):
    if self.directory and file_name:
        file_addr = op.join(self.directory, file_name)
        return file_addr if op.exists(file_addr) else None
find_bundle_file(patterns, finder='postfix')
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_file(self, patterns, finder='postfix'):
    if self.directory:
        for bundle_file in os.listdir(self.directory):
            if 'name' == finder:
                for file_name in patterns:
                    if op.splitext(bundle_file)[0] == file_name:
                        return op.join(self.directory, bundle_file)
            elif 'postfix' == finder:
                for file_postfix in patterns:
                    if bundle_file.endswith(file_postfix):
                        return op.join(self.directory, bundle_file)
            elif 'regex' == finder:
                for regex_pattern in patterns:
                    if re.match(regex_pattern, bundle_file):
                        return op.join(self.directory, bundle_file)
    return None
find_bundle_module(module, by_host=False)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_bundle_module(self, module, by_host=False):
    # test of file_name is an actually path to a file
    if op.isfile(module):
        return module

    def build_assm_filename(module_filename):
        # build assembly by host version (assm_file_2020.ext)
        assm_name, assm_ext = op.splitext(module_filename)
        return assm_name + '_' + HOST_APP.version + assm_ext

    if by_host:
        module = build_assm_filename(module)

    # test if module is inside search paths
    for module_path in self.module_paths:
        possible_module_path = op.join(module_path, module)
        if op.isfile(possible_module_path):
            return possible_module_path
parse_layout_directive(layout_line)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_directive(self, layout_line):
    parts = re.findall(r'(.+)\[(.+):(.*)\]', layout_line)
    if parts:
        source_item, directive, target_value = parts[0]
        # cleanup values
        directive = directive.lower().strip()
        target_value = target_value.strip()
        # process any escape characters in target value
        # https://stackoverflow.com/a/4020824/2350244
        target_value = target_value.encode('utf-8')
        if PY3:
            target_value = target_value.decode('unicode_escape')
        else:
            target_value = target_value.decode('string_escape')
        # create directive obj
        return source_item, LayoutDirective(directive_type=directive,
                                            target=target_value)
    return layout_line, None
parse_layout_item(layout_line)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_item(self, layout_line):
    if layout_line:
        layout_item_name, layout_item_drctv = \
            self.parse_layout_directive(layout_line)
        return LayoutItem(name=layout_item_name,
                          directive=layout_item_drctv)
parse_layout_items(layout_lines)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_items(self, layout_lines):
    for layout_line in layout_lines:
        layout_item = self.parse_layout_item(layout_line)
        if layout_item:
            self.layout_items.append(layout_item)
    mlogger.debug('Layout is: %s', self.layout_items)
parse_layout_metadata()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def parse_layout_metadata(self):
    layout = self.meta.get(exts.MDATA_LAYOUT, [])
    if layout:
        self.parse_layout_items(layout)
        return True
contains(item_name)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def contains(self, item_name):
    return any([x.name == item_name for x in self.components])
add_component(comp)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def add_component(self, comp):
    # set search paths
    for path in self.module_paths:
        comp.add_module_path(path)
    # set its own control id on the child component
    if hasattr(comp, 'parent_ctrl_id'):
        comp.parent_ctrl_id = self.control_id
    # now add to list
    self.components.append(comp)
find_components_of_type(cmp_type)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_components_of_type(self, cmp_type):
    sub_comp_list = []
    for sub_comp in self.components:
        if isinstance(sub_comp, cmp_type):
            sub_comp_list.append(sub_comp)
        elif sub_comp.is_container:
            sub_comp_list.extend(sub_comp.find_components_of_type(cmp_type))

    return sub_comp_list
find_layout_items()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def find_layout_items(self):
    layout_items = []
    layout_items.extend(self.layout_items)
    for sub_comp in self.components:
        if sub_comp.is_container:
            layout_items.extend(sub_comp.find_layout_items())
    return layout_items

LibraryExtension(cmp_path=None)

Bases: GenericComponent

Library extension.

Source code in pyrevitlib/pyrevit/extensions/components.py
def __init__(self, cmp_path=None):
    # using classname otherwise exceptions in superclasses won't show
    GenericComponent.__init__(self)
    self.directory = cmp_path

    if self.directory:
        self.name = op.splitext(op.basename(self.directory))[0]

Attributes

type_id = exts.ExtensionTypes.LIB_EXTENSION.POSTFIX class-attribute instance-attribute
directory = cmp_path instance-attribute
name = op.splitext(op.basename(self.directory))[0] instance-attribute
is_container property

Functions

matches(component_path) classmethod
Source code in pyrevitlib/pyrevit/extensions/components.py
@classmethod
def matches(cls, component_path):
    return component_path.lower().endswith(cls.type_id)
get_cache_data()
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def get_cache_data(self):
    cache_dict = self.__dict__.copy()
    if hasattr(self, TYPE_ID_KEY):
        cache_dict[TYPE_ID_KEY] = getattr(self, TYPE_ID_KEY)
    return cache_dict
load_cache_data(cache_dict)
Source code in pyrevitlib/pyrevit/extensions/genericcomps.py
def load_cache_data(self, cache_dict):
    for k, v in cache_dict.items():
        self.__dict__[k] = v

ComboBoxContext(component, ui_item, uiapp, combobox=None)

Bases: object

Context object providing access to ComboBox state and data.

This object is passed to event handlers and provides a convenient interface to access the current ComboBox state.

Attributes:

Name Type Description
combobox

The raw Revit ComboBox API object

component

The parsed component metadata

ui_item

The pyRevit UI wrapper for the ComboBox

uiapp

The Revit UIApplication instance

Initialize the ComboBoxContext.

Parameters:

Name Type Description Default
component

The parsed component metadata

required
ui_item

The pyRevit UI wrapper for the ComboBox

required
uiapp

The Revit UIApplication instance

required
combobox

The raw Revit ComboBox API object (optional)

None
Source code in pyrevitlib/pyrevit/extensions/components.py
def __init__(self, component, ui_item, uiapp, combobox=None):
    """Initialize the ComboBoxContext.

    Args:
        component: The parsed component metadata
        ui_item: The pyRevit UI wrapper for the ComboBox
        uiapp: The Revit UIApplication instance
        combobox: The raw Revit ComboBox API object (optional)
    """
    self._component = component
    self._ui_item = ui_item
    self._uiapp = uiapp
    self._combobox = combobox
    self._user_data = {}

Attributes

combobox property

Get the raw Revit ComboBox API object.

Returns:

Type Description
ComboBox

The Revit ComboBox control

current_item property

Get the currently selected ComboBoxMemberData.

Returns:

Type Description
ComboBoxMemberData

Current selected item or None

current_value property

Get the text of the currently selected item.

Returns:

Type Description
str

The ItemText of the current selection, or empty string

current_name property

Get the name/id of the currently selected item.

Returns:

Type Description
str

The Name of the current selection, or empty string

items property

Get all items in the ComboBox.

Returns:

Type Description
list

List of ComboBoxMemberData items

item_count property

Get the number of items in the ComboBox.

Returns:

Type Description
int

Number of items

item_texts property

Get the text values of all items.

Returns:

Type Description
list[str]

List of item text values

item_names property

Get the names/ids of all items.

Returns:

Type Description
list[str]

List of item names

component property

Get the parsed component metadata.

Returns:

Type Description

The component metadata object

ui_item property

Get the pyRevit UI wrapper.

Returns:

Type Description

The pyRevit UI wrapper for the ComboBox

uiapp property

Get the Revit UIApplication instance.

Returns:

Type Description
UIApplication

The UIApplication

directory property

Get the component's bundle directory.

Returns:

Type Description
str

Path to the component directory

name property

Get the component name.

Returns:

Type Description
str

Component name

display_name property

Get the component display name.

Returns:

Type Description
str

Component display name

user_data property

Get the user data dictionary for storing custom data.

Returns:

Type Description
dict

Dictionary for storing custom data between events

Functions

set_current(item_name_or_text)

Set the current selection by name or text.

Parameters:

Name Type Description Default
item_name_or_text str

The Name or ItemText of the item to select

required

Returns:

Type Description
bool

True if item was found and selected

Source code in pyrevitlib/pyrevit/extensions/components.py
def set_current(self, item_name_or_text):
    """Set the current selection by name or text.

    Args:
        item_name_or_text (str): The Name or ItemText of the item to select

    Returns:
        (bool): True if item was found and selected
    """
    cmb = self.combobox
    if not cmb:
        return False

    for item in self.items:
        if (hasattr(item, 'Name') and item.Name == item_name_or_text) or \
           (hasattr(item, 'ItemText') and item.ItemText == item_name_or_text):
            try:
                cmb.Current = item
                return True
            except Exception as ex:
                mlogger.debug("Error setting current item: %s", ex)
                return False
    return False
get_item_by_name(name)

Get an item by its Name.

Parameters:

Name Type Description Default
name str

The Name to search for

required

Returns:

Type Description
ComboBoxMemberData

The item or None

Source code in pyrevitlib/pyrevit/extensions/components.py
def get_item_by_name(self, name):
    """Get an item by its Name.

    Args:
        name (str): The Name to search for

    Returns:
        (ComboBoxMemberData): The item or None
    """
    for item in self.items:
        if hasattr(item, 'Name') and item.Name == name:
            return item
    return None
get_item_by_text(text)

Get an item by its ItemText.

Parameters:

Name Type Description Default
text str

The ItemText to search for

required

Returns:

Type Description
ComboBoxMemberData

The item or None

Source code in pyrevitlib/pyrevit/extensions/components.py
def get_item_by_text(self, text):
    """Get an item by its ItemText.

    Args:
        text (str): The ItemText to search for

    Returns:
        (ComboBoxMemberData): The item or None
    """
    for item in self.items:
        if hasattr(item, 'ItemText') and item.ItemText == text:
            return item
    return None

Functions