Skip to content

userconfig

Handle reading and parsing, writing and saving of all user configurations.

This module handles the reading and writing of the pyRevit configuration files. It's been used extensively by pyRevit sub-modules. user_config is set up automatically in the global scope by this module and can be imported into scripts and other modules to access the default configurations.

All other modules use this module to query user config.

Examples:

from pyrevit.userconfig import user_config
user_config.add_section('newsection')
user_config.newsection.property = value
user_config.newsection.get_option('property', default_value)
user_config.save_changes()

The user_config object is also the destination for reading and writing configuration by pyRevit scripts through :func:get_config of :mod:pyrevit.script module. Here is the function source:

.. literalinclude:: ../../pyrevitlib/pyrevit/script.py :pyobject: get_config

Examples:

from pyrevit import script
cfg = script.get_config()
cfg.property = value
cfg.get_option('property', default_value)
script.save_config()

Attributes

DEFAULT_CSV_SEPARATOR = ',' module-attribute

mlogger = logger.get_logger(__name__) module-attribute

CONSTS = PyRevit.PyRevitConsts module-attribute

LOCAL_CONFIG_FILE = '' module-attribute

ADMIN_CONFIG_FILE = '' module-attribute

USER_CONFIG_FILE = '' module-attribute

CONFIG_TYPE = 'Seed' module-attribute

CONFIG_FILE = find_config_file(PYREVIT_APP_DIR) module-attribute

user_config = PyRevitConfig(cfg_file_path=CONFIG_FILE, config_type=CONFIG_TYPE) module-attribute

Classes

PyRevitConfig(cfg_file_path=None, config_type='Unknown')

Bases: PyRevitConfigParser

Provide read/write access to pyRevit configuration.

Parameters:

Name Type Description Default
cfg_file_path str

full path to config file to be used.

None
config_type str

type of config file

'Unknown'

Examples:

cfg = PyRevitConfig(cfg_file_path)
cfg.add_section('sectionname')
cfg.sectionname.property = value
cfg.sectionname.get_option('property', default_value)
cfg.save_changes()

Load settings from provided config file and setup parser.

Source code in pyrevitlib/pyrevit/userconfig.py
def __init__(self, cfg_file_path=None, config_type='Unknown'):
    """Load settings from provided config file and setup parser."""
    # try opening and reading config file in order.
    super(PyRevitConfig, self).__init__(cfg_file_path=cfg_file_path)

    # set log mode on the logger module based on
    # user settings (overriding the defaults)
    self._update_env()
    self._admin = config_type == 'Admin'
    self.config_type = config_type

Attributes

config_type = config_type instance-attribute
config_file property

Current config file path.

environment property

Environment section.

core property

Core section.

routes property

Routes section.

telemetry property

Telemetry section.

bin_cache property writable

"Whether to use the cache for extensions.

check_updates property writable

Whether to check for updates.

auto_update property writable

Whether to automatically update pyRevit.

rocket_mode property writable

Whether to enable rocket mode.

log_level property writable

Logging level.

file_logging property writable

Whether to enable file logging.

startuplog_timeout property writable

Timeout for the startup log.

required_host_build property writable

Host build required to run the commands.

min_host_drivefreespace property writable

Minimum free space for running the commands.

load_beta property writable

Whether to load commands in beta.

cpython_engine_version property writable

CPython engine version to use.

user_locale property writable

User locale.

output_stylesheet property writable

Stylesheet used for output.

routes_host property writable

Routes API host.

routes_port property writable

API routes port.

load_core_api property writable

Whether to load pyRevit core api.

telemetry_utc_timestamp property writable

Whether to use UTC timestamps in telemetry.

telemetry_status property writable

Telemetry status.

telemetry_file_dir property writable

Telemetry file directory.

telemetry_server_url property writable

Telemetry server URL.

telemetry_include_hooks property writable

Whether to include hooks in telemetry.

apptelemetry_status property writable

Telemetry status.

apptelemetry_server_url property writable

App telemetry server URL.

apptelemetry_event_flags property writable

Telemetry event flags.

user_can_update property writable

Whether the user can update pyRevit repos.

user_can_extend property writable

Whether the user can manage pyRevit Extensions.

user_can_config property writable

Whether the user can access the configuration.

colorize_docs property writable

Whether to enable the document colorizer.

tooltip_debug_info property writable

Whether to append debug info on tooltips.

routes_server property writable

Whether the server routes are enabled.

respect_language_direction property writable

Whether the system respects the language direction.

is_readonly property

bool: whether the config is read only.

Functions

get_config_file_hash()

Get calculated unique hash for this config.

Returns:

Type Description
str

hash of the config.

Source code in pyrevitlib/pyrevit/coreutils/configparser.py
def get_config_file_hash(self):
    """Get calculated unique hash for this config.

    Returns:
        (str): hash of the config.
    """
    with codecs.open(self._cfg_file_path, 'r', 'utf-8') as cfg_file:
        cfg_hash = coreutils.get_str_hash(cfg_file.read())

    return cfg_hash
has_section(section_name)

Check if config contains given section.

Source code in pyrevitlib/pyrevit/coreutils/configparser.py
def has_section(self, section_name):
    """Check if config contains given section."""
    try:
        self.get_section(section_name)
        return True
    except Exception:
        return False
add_section(section_name)

Add section with given name to config.

Source code in pyrevitlib/pyrevit/coreutils/configparser.py
def add_section(self, section_name):
    """Add section with given name to config."""
    self._parser.add_section(section_name)
    return PyRevitConfigSectionParser(self._parser, section_name)
get_section(section_name)

Get section with given name.

Raises:

Type Description
AttributeError

if section is missing

Source code in pyrevitlib/pyrevit/coreutils/configparser.py
def get_section(self, section_name):
    """Get section with given name.

    Raises:
        AttributeError: if section is missing
    """
    # check is section with full name is available
    if self._parser.has_section(section_name):
        return PyRevitConfigSectionParser(self._parser, section_name)

    # if not try to match with section_name.subsection
    # if there is a section_name.subsection defined, that should be
    # the sign that the section exists
    # section obj then supports getting all subsections
    for cfg_section_name in self._parser.sections():
        master_section = coreutils.get_canonical_parts(cfg_section_name)[0]
        if section_name == master_section:
            return PyRevitConfigSectionParser(self._parser,
                                              master_section)

    # if no match happened then raise exception
    raise AttributeError('Section does not exist in config file.')
remove_section(section_name)

Remove section from config.

Source code in pyrevitlib/pyrevit/coreutils/configparser.py
def remove_section(self, section_name):
    """Remove section from config."""
    cfg_section = self.get_section(section_name)
    for cfg_subsection in cfg_section.get_subsections():
        self._parser.remove_section(cfg_subsection.header)
    self._parser.remove_section(cfg_section.header)
reload(cfg_file_path=None)

Reload config from original or given file.

Source code in pyrevitlib/pyrevit/coreutils/configparser.py
def reload(self, cfg_file_path=None):
    """Reload config from original or given file."""
    try:
        with codecs.open(cfg_file_path \
                or self._cfg_file_path, 'r', 'utf-8') as cfg_file:
            try:
                self._parser.readfp(cfg_file)
            except AttributeError:
                self._parser.read_file(cfg_file)
    except (OSError, IOError):
        raise PyRevitIOError()
save(cfg_file_path=None)

Save config to original or given file.

Source code in pyrevitlib/pyrevit/coreutils/configparser.py
def save(self, cfg_file_path=None):
    """Save config to original or given file."""
    try:
        with codecs.open(cfg_file_path \
                or self._cfg_file_path, 'w', 'utf-8') as cfg_file:
            self._parser.write(cfg_file)
    except (OSError, IOError):
        raise PyRevitIOError()
get_config_version()

Return version of config file used for change detection.

Returns:

Type Description
str

hash of the config file

Source code in pyrevitlib/pyrevit/userconfig.py
def get_config_version(self):
    """Return version of config file used for change detection.

    Returns:
        (str): hash of the config file
    """
    return self.get_config_file_hash()
get_thirdparty_ext_root_dirs(include_default=True)

Return a list of external extension directories set by the user.

Returns:

Type Description
list[str]

External user extension directories.

Source code in pyrevitlib/pyrevit/userconfig.py
def get_thirdparty_ext_root_dirs(self, include_default=True):
    """Return a list of external extension directories set by the user.

    Returns:
        (list[str]): External user extension directories.
    """
    dir_list = set()
    if include_default:
        # add default ext path
        dir_list.add(THIRDPARTY_EXTENSIONS_DEFAULT_DIR)
    try:
        dir_list.update([
            op.expandvars(op.normpath(x))
            for x in self.core.get_option(
                CONSTS.ConfigsUserExtensionsKey,
                default_value=[]
            )])
    except Exception as read_err:
        mlogger.error('Error reading list of user extension folders. | %s',
                      read_err)

    return [x for x in dir_list if op.exists(x)]
get_ext_root_dirs()

Return a list of all extension directories.

Returns:

Type Description
list[str]

user extension directories.

Source code in pyrevitlib/pyrevit/userconfig.py
def get_ext_root_dirs(self):
    """Return a list of all extension directories.

    Returns:
        (list[str]): user extension directories.

    """
    dir_list = set()
    if op.exists(EXTENSIONS_DEFAULT_DIR):
        dir_list.add(EXTENSIONS_DEFAULT_DIR)
    dir_list.update(self.get_thirdparty_ext_root_dirs())
    return list(dir_list)
get_ext_sources()

Return a list of extension definition source files.

Source code in pyrevitlib/pyrevit/userconfig.py
def get_ext_sources(self):
    """Return a list of extension definition source files."""
    ext_sources = self.environment.get_option(
        CONSTS.EnvConfigsExtensionLookupSourcesKey,
        default_value=[],
    )
    return list(set(ext_sources))
set_thirdparty_ext_root_dirs(path_list)

Updates list of external extension directories in config file.

Parameters:

Name Type Description Default
path_list list[str]

list of external extension paths

required
Source code in pyrevitlib/pyrevit/userconfig.py
def set_thirdparty_ext_root_dirs(self, path_list):
    """Updates list of external extension directories in config file.

    Args:
        path_list (list[str]): list of external extension paths
    """
    for ext_path in path_list:
        if not op.exists(ext_path):
            raise PyRevitException("Path \"%s\" does not exist." % ext_path)

    try:
        self.core.userextensions = \
            [op.normpath(x) for x in path_list]
    except Exception as write_err:
        mlogger.error('Error setting list of user extension folders. | %s',
                      write_err)
get_current_attachment()

Return current pyRevit attachment.

Source code in pyrevitlib/pyrevit/userconfig.py
def get_current_attachment(self):
    """Return current pyRevit attachment."""
    try:
        return PyRevit.PyRevitAttachments.GetAttached(int(HOST_APP.version))
    except PyRevitException as ex:
        mlogger.error('Error getting current attachment. | %s', ex)
get_active_cpython_engine()

Return active cpython engine.

Source code in pyrevitlib/pyrevit/userconfig.py
def get_active_cpython_engine(self):
    """Return active cpython engine."""
    # try to find attachment and get engines from the clone
    attachment = self.get_current_attachment()
    if attachment and attachment.Clone:
        clone = attachment.Clone
    else:
        # if can not find attachment, instantiate a temp clone
        try:
            clone = PyRevit.PyRevitClone(clonePath=HOME_DIR)
        except Exception as cEx:
            mlogger.debug('Can not create clone from path: %s', str(cEx))
            clone = None
    # find cpython engines
    engines = clone.GetCPythonEngines() if clone else []
    cpy_engines_dict = {x.Version: x for x in engines}
    mlogger.debug('cpython engines dict: %s', cpy_engines_dict)

    if not cpy_engines_dict:
        mlogger.error(
            'Can not determine cpython engines for current attachment: %s',
            attachment
        )
        return None
    # grab cpython engine configured to be used by user
    try:
        cpyengine_ver = int(self.cpython_engine_version)
    except (ValueError, TypeError):
        cpyengine_ver = 000

    try:
        return cpy_engines_dict[cpyengine_ver]
    except KeyError:
        # return the latest cpython engine
        return max(cpy_engines_dict.values(), key=lambda x: x.Version.Version)
set_active_cpython_engine(pyrevit_engine)

Set the active CPython engine.

Parameters:

Name Type Description Default
pyrevit_engine PyRevitEngine

python engine to set as active

required
Source code in pyrevitlib/pyrevit/userconfig.py
def set_active_cpython_engine(self, pyrevit_engine):
    """Set the active CPython engine.

    Args:
        pyrevit_engine (PyRevitEngine): python engine to set as active
    """
    self.cpython_engine_version = pyrevit_engine.Version
save_changes()

Save user config into associated config file.

Source code in pyrevitlib/pyrevit/userconfig.py
def save_changes(self):
    """Save user config into associated config file."""
    if not self._admin and self.config_file:
        try:
            super(PyRevitConfig, self).save()
        except Exception as save_err:
            mlogger.error('Can not save user config to: %s | %s',
                          self.config_file, save_err)

        # adjust environment per user configurations
        self._update_env()
    else:
        mlogger.debug('Config is in admin mode. Skipping save.')
get_list_separator() staticmethod

Get list separator defined in user os regional settings.

Source code in pyrevitlib/pyrevit/userconfig.py
@staticmethod
def get_list_separator():
    """Get list separator defined in user os regional settings."""
    intkey = coreutils.get_reg_key(wr.HKEY_CURRENT_USER,
                                   r'Control Panel\International')
    if intkey:
        try:
            return wr.QueryValueEx(intkey, 'sList')[0]
        except Exception:
            return DEFAULT_CSV_SEPARATOR

Functions

find_config_file(target_path)

Find config file in target path.

Source code in pyrevitlib/pyrevit/userconfig.py
def find_config_file(target_path):
    """Find config file in target path."""
    return PyRevit.PyRevitConsts.FindConfigFileInDirectory(target_path)

verify_configs(config_file_path=None)

Create a user settings file.

if config_file_path is not provided, configs will be in memory only

Parameters:

Name Type Description Default
config_file_path str

config file full name and path

None

Returns:

Type Description
PyRevitConfig

pyRevit config file handler

Source code in pyrevitlib/pyrevit/userconfig.py
def verify_configs(config_file_path=None):
    """Create a user settings file.

    if config_file_path is not provided, configs will be in memory only

    Args:
        config_file_path (str, optional): config file full name and path

    Returns:
        (pyrevit.userconfig.PyRevitConfig): pyRevit config file handler
    """
    if config_file_path:
        mlogger.debug('Creating default config file at: %s', config_file_path)
        coreutils.touch(config_file_path)

    try:
        parser = PyRevitConfig(cfg_file_path=config_file_path)
    except Exception as read_err:
        # can not create default user config file under appdata folder
        mlogger.warning('Can not create config file under: %s | %s',
                        config_file_path, read_err)
        parser = PyRevitConfig()

    return parser