def find_loaded_asm(asm_info, by_partial_name=False, by_location=False): """Find loaded assembly based on name, partial name, or location. Args: asm_info (str): name or location of the assembly by_partial_name (bool): returns all assemblies that has the asm_info by_location (bool): returns all assemblies matching location Returns: list: List of all loaded assemblies matching the provided info If only one assembly has been found, it returns the assembly. :obj:`None` will be returned if assembly is not loaded. """ loaded_asm_list = [] cleaned_asm_info = \ asm_info.lower().replace('.' + framework.ASSEMBLY_FILE_TYPE, '') for loaded_assembly in framework.AppDomain.CurrentDomain.GetAssemblies(): if by_partial_name: if cleaned_asm_info in \ safe_strtype(loaded_assembly.GetName().Name).lower(): loaded_asm_list.append(loaded_assembly) elif by_location: try: if op.normpath(loaded_assembly.Location) == \ op.normpath(asm_info): loaded_asm_list.append(loaded_assembly) except Exception: continue elif cleaned_asm_info == \ safe_strtype(loaded_assembly.GetName().Name).lower(): loaded_asm_list.append(loaded_assembly) return loaded_asm_list
def make_link(element_ids, contents=None): """Create link for given element ids. This link is a special format link with revit:// scheme that is handled by the output window to select the provided element ids in current project. Scripts should not call this function directly. Creating clickable element links is handled by the output wrapper object through the :func:`linkify` method. Example: >>> output = pyrevit.output.get_output() >>> for idx, elid in enumerate(element_ids): >>> print('{}: {}'.format(idx+1, output.linkify(elid))) """ elementquery = [] if isinstance(element_ids, list): strids = [safe_strtype(x.IntegerValue) for x in element_ids] elif isinstance(element_ids, DB.ElementId): strids = [safe_strtype(element_ids.IntegerValue)] for strid in strids: elementquery.append('element[]={}'.format(strid)) reviturl = '&'.join(elementquery) linkname = ', '.join(strids) if len(reviturl) >= 2000: alertjs = 'alert("Url was too long and discarded!");' linkattrs = 'href="#" onClick="{}"'.format(alertjs) else: linkattrs = 'href="{}{}{}"'.format(PROTOCOL_NAME, '&command=select&', reviturl) return DEFAULT_LINK.format(linkattrs, contents or linkname)
def compare_attr(src, dest, attr_name, case_sensitive=False): if case_sensitive: return safe_strtype(getattr(src, attr_name, '')).lower() == \ safe_strtype(getattr(dest, attr_name, '')).lower() else: return safe_strtype(getattr(src, attr_name)) == \ safe_strtype(getattr(dest, attr_name))
def _list_options(self, option_filter=None): if option_filter: option_filter = option_filter.lower() self.list_lb.ItemsSource = \ [safe_strtype(option) for option in self._context if option_filter in safe_strtype(option).lower()] else: self.list_lb.ItemsSource = \ [safe_strtype(option) for option in self._context]
def update_info(self, info_dict, def_file_path=None): ext_def_type = info_dict.get('type', None) for ext_type in exts.ExtensionTypes.get_ext_types(): if ext_def_type == ext_type.ID: self.type = ext_type self.builtin = \ safe_strtype(info_dict.get('builtin', self.builtin)).lower() == 'true' self.default_enabled = safe_strtype( info_dict.get('default_enabled', self.default_enabled)).lower() == 'true' self.name = info_dict.get('name', self.name) self.description = info_dict.get('description', self.description) self.url = info_dict.get('url', self.url) if def_file_path: self.def_file_path.add(def_file_path) # update list of authorized users authusers = info_dict.get('authusers', []) if authusers: self.authusers.update(authusers) # update list of authorized user groups authgroups = info_dict.get('authgroups', []) if authgroups: self.authgroups.update(authgroups) # rocket mode compatibility self.rocket_mode_compatible = \ safe_strtype( info_dict.get('rocket_mode_compatible', self.rocket_mode_compatible) ).lower() == 'true' # extended attributes self.website = info_dict.get( 'website', self.url.replace('.git', '') if self.url else self.website) self.image = info_dict.get('image', self.image) self.author = info_dict.get('author', self.author) self.author_profile = info_dict.get('author_profile', self.author_profile) # update list dependencies depends = info_dict.get('dependencies', []) if depends: self.dependencies.update(depends)
def _generate_runtime_asm(): source_list = [] for source_file in _get_source_files(): source_list.append(source_file) # now try to compile try: mlogger.debug('Compiling base types to: %s', RUNTIME_ASSM_FILE) res, msgs = labs.Common.CodeCompiler.CompileCSharp( sourceFiles=Array[str](source_list), outputPath=RUNTIME_ASSM_FILE, references=Array[str](get_references()), defines=Array[str](["REVIT{}".format(HOST_APP.version)])) # log results logfile = RUNTIME_ASSM_FILE.replace('.dll', '.log') with open(logfile, 'w') as lf: lf.write('\n'.join(msgs)) # load compiled dll if successful if res: return assmutils.load_asm_file(RUNTIME_ASSM_FILE) # otherwise raise hell else: raise PyRevitException("Error compiling runtime") except PyRevitException as compile_err: errors = safe_strtype(compile_err).replace('Compile error: ', '') mlogger.critical('Can not compile base types code into assembly.\n%s', errors) raise compile_err
def compare_branch_heads(repo_info): """Compare local and remote branch heads and return ??? Args: repo_info (:obj:`RepoInfo`): target repo object Returns: type: desc """ # FIXME: need return type. possibly simplify repo = repo_info.repo repo_branches = repo.Branches mlogger.debug('Repo branches: %s', [b.FriendlyName for b in repo_branches]) for branch in repo_branches: if branch.FriendlyName == repo_info.branch and not branch.IsRemote: try: if branch.TrackedBranch: mlogger.debug('Comparing heads: %s of %s', branch.CanonicalName, branch.TrackedBranch.CanonicalName) hist_div = repo.ObjectDatabase. \ CalculateHistoryDivergence(branch.Tip, branch.TrackedBranch.Tip) return hist_div except Exception as compare_err: mlogger.error('Can not compare branch %s in repo: %s | %s', branch, repo, safe_strtype(compare_err).replace('\n', '')) else: mlogger.debug('Skipping remote branch: %s', branch.CanonicalName)
def update_repo(repo_info): """Update repository.""" repo = repo_info.repo logger.debug('Updating repo: %s', repo_info.directory) head_msg = safe_strtype(repo.Head.Tip.Message).replace('\n', '') logger.debug('Current head is: %s > %s', repo.Head.Tip.Id.Sha, head_msg) username, password = _get_extension_credentials(repo_info) if username and password: repo_info.username = username repo_info.password = password try: updated_repo_info = libgit.git_pull(repo_info) logger.debug('Successfully updated repo: %s', updated_repo_info.directory) return updated_repo_info except libgit.PyRevitGitAuthenticationError as auth_err: logger.debug('Can not login to git repository to get updates: %s | %s', repo_info, auth_err) raise auth_err except Exception as update_err: logger.debug('Failed updating repo: %s | %s', repo_info, update_err) raise update_err
def git_fetch(repo_info): """Fetch current branch of given repo. Args: repo_info (:obj:`RepoInfo`): target repo object Returns: :obj:`RepoInfo`: repo object with updated head """ repo = repo_info.repo try: libgit.Commands.Fetch(repo, repo.Head.TrackedBranch.RemoteName, [], _make_fetch_options(repo_info), 'fetching pyrevit updates') mlogger.debug('Successfully pulled repo: %s', repo_info.directory) head_msg = safe_strtype(repo.Head.Tip.Message).replace('\n', '') mlogger.debug('New head is: %s > %s', repo.Head.Tip.Id.Sha, head_msg) return RepoInfo(repo) except Exception as fetch_err: mlogger.debug('Failed git fetch: %s | %s', repo_info.directory, fetch_err) _process_git_error(fetch_err)
def compare_branch_heads(repo_info): repo = repo_info.repo repo_branches = repo.Branches logger.debug('Repo branches: {}'.format([b.Name for b in repo_branches])) for branch in repo_branches: if branch.Name == repo_info.branch and not branch.IsRemote: try: if branch.TrackedBranch: logger.debug('Comparing heads: {} of {}'.format( branch.CanonicalName, branch.TrackedBranch.CanonicalName)) hist_div = repo.ObjectDatabase. \ CalculateHistoryDivergence(branch.Tip, branch.TrackedBranch.Tip) return hist_div except Exception as compare_err: logger.error( 'Can not compare branch {} in repo: {} | {}'.format( branch, repo, safe_strtype(compare_err).replace('\n', ''))) else: logger.debug('Skipping remote branch: {}'.format( branch.CanonicalName))
def find_sheeted_unrefed_views(view_list): for v in view_list: sheetnum = v.Parameter[DB.BuiltInParameter.SHEET_NUMBER] detnum = v.Parameter[DB.BuiltInParameter.VIEWER_DETAIL_NUMBER] refsheet = v.Parameter[DB.BuiltInParameter.VIEW_REFERENCING_SHEET] refviewport = v.Parameter[DB.BuiltInParameter.VIEW_REFERENCING_DETAIL] # is the view placed on a sheet? if sheetnum \ and detnum \ and ('-' not in sheetnum.AsString()) \ and ('-' not in detnum.AsString()): # is the view referenced by at least one other view? if refsheet \ and refviewport \ and refsheet.AsString() != '' \ and refviewport.AsString() != '' \ or (v.ViewType in view_ref_prefixes and (view_ref_prefixes[v.ViewType] + revit.query.get_name(v)))\ in view_refs_names: continue else: # print the view sheet and det number print('-' * 20) print('NAME: {0}\nDET/SHEET: {1}\nID: {2}'.format( revit.query.get_name(v), safe_strtype(detnum.AsString() + '/' + sheetnum.AsString()), output.linkify(v.Id)))
def _inc_or_dec_string(str_id, shift): """Increment or decrement identifier. Args: str_id (str): identifier e.g. A310a shift (int): number of steps to change the identifier Returns: str: modified identifier Example: >>> _inc_or_dec_string('A319z') 'A320a' """ next_str = "" index = len(str_id) - 1 carry = shift while index >= 0: if str_id[index].isalpha(): if str_id[index].islower(): reset_a = 'a' reset_z = 'z' else: reset_a = 'A' reset_z = 'Z' curr_digit = (ord(str_id[index]) + carry) if curr_digit < ord(reset_a): curr_digit = ord(reset_z) - ((ord(reset_a) - curr_digit) - 1) carry = shift elif curr_digit > ord(reset_z): curr_digit = ord(reset_a) + ((curr_digit - ord(reset_z)) - 1) carry = shift else: carry = 0 curr_digit = chr(curr_digit) next_str += curr_digit elif str_id[index].isdigit(): curr_digit = int(str_id[index]) + carry if curr_digit > 9: curr_digit = 0 + ((curr_digit - 9) - 1) carry = shift elif curr_digit < 0: curr_digit = 9 - ((0 - curr_digit) - 1) carry = shift else: carry = 0 next_str += safe_strtype(curr_digit) else: next_str += str_id[index] index -= 1 return next_str[::-1]
def __setattr__(self, key, value): if key in CommandCustomResults.RESERVED_NAMES: # making sure the script is not using a reserved name logger.error('{} is a standard log param. ' 'Can not override this value.'.format(key)) else: # if all is okay lets add the key:value to the return dict EXEC_PARAMS.result_dict.Add(key, safe_strtype(value))
def new_session_uuid(): """Create a new uuid for a pyRevit session. Returns: str: session uuid string """ uuid_str = safe_strtype(coreutils.new_uuid()) set_session_uuid(uuid_str) return uuid_str
def is_calculable_param(param): if param.StorageType == DB.StorageType.Double: return True if param.StorageType == DB.StorageType.Integer: val_str = param.AsValueString() if val_str and safe_strtype(val_str).lower().isdigit(): return True return False
def has_term(self, search_term): """Checks all parameters for the search_term. Returns: bool: Returns True if search_term is found in any of the parameter values """ for value in self._src_dict.values(): if search_term in safe_strtype(value).lower(): return True
def test_progressbar(self): """Output window progress bar test""" from time import sleep for i in range(50): sleep(0.01) self._output.update_progress(i + 1, 50) res = TaskDialog.Show( 'pyrevit', 'Did you see the progress bar?', TaskDialogCommonButtons.Yes | TaskDialogCommonButtons.No) self.assertEqual(safe_strtype(res), 'Yes')
def __setattr__(self, param_name, value): if param_name in ['_parser', '_section_name']: super(PyRevitConfigSectionParser, self).__setattr__(param_name, value) else: try: return self._parser.set(self._section_name, param_name, safe_strtype(value)) except Exception as set_err: raise PyRevitException('Error setting parameter value. ' '| {}'.format(set_err))
def original_record(self): """Returns original dictionary used to create/update this record. Returns: dict: original dictionary used to create/update this record. """ rec_string = safe_strtype(self._src_dict) rec_string = rec_string \ .replace('\'', '\"') \ .replace('False', 'false') \ .replace('True', 'true') return rec_string
def __repr__(self, data=None): pdata = {} if hasattr(self._wrapped, 'Id'): pdata['id'] = self._wrapped.Id.IntegerValue if data: pdata.update(data) datastr = ' '.join( ['{0}:{1}'.format(k, v) for k, v in pdata.iteritems()]) #pylint: disable=E1101 return '<pyrevit.revit.db.{class_name} % {wrapping}{datastr}>' \ .format(class_name=self.__class__.__name__, wrapping=safe_strtype(self._wrapped), datastr=(' ' + datastr) if datastr else '')
def _compile_dotnet( code_provider, sourcefiles_list, full_output_file_addr=None, reference_list=None, resource_list=None, ): logger.debug('Compiling source files to: {}'.format(full_output_file_addr)) logger.debug('References assemblies are: {}'.format(reference_list)) compiler_params = Compiler.CompilerParameters() if full_output_file_addr is None: compiler_params.GenerateInMemory = True else: compiler_params.GenerateInMemory = False compiler_params.OutputAssembly = full_output_file_addr compiler_params.TreatWarningsAsErrors = False compiler_params.GenerateExecutable = False compiler_params.CompilerOptions = "/optimize" for reference in reference_list or []: logger.debug('Adding reference to compiler: {}'.format(reference)) compiler_params.ReferencedAssemblies.Add(reference) for resource in resource_list or []: logger.debug('Adding resource to compiler: {}'.format(resource)) compiler_params.EmbeddedResources.Add(resource) logger.debug('Compiling source files.') compiler = \ code_provider.CompileAssemblyFromFile(compiler_params, Array[str](sourcefiles_list)) if compiler.Errors.HasErrors: err_list = [ safe_strtype(err) for err in compiler.Errors.GetEnumerator() ] err_str = '\n'.join(err_list) raise PyRevitException("Compile error: {}".format(err_str)) if full_output_file_addr is None: logger.debug('Compile to memory successful: {}'.format( compiler.CompiledAssembly)) return compiler.CompiledAssembly else: logger.debug('Compile successful: {}'.format(compiler.PathToAssembly)) return compiler.PathToAssembly
def get_value_range(param_name, doc=None): values = set() for element in get_all_elements(doc): targetparam = element.LookupParameter(param_name) if targetparam: value = get_param_value(targetparam) if value is not None \ and safe_strtype(value).lower() != 'none': if isinstance(value, str) \ and not value.isspace(): values.add(value) else: values.add(value) return values
def _log(self, level, msg, args, exc_info=None, extra=None): #pylint: disable=W0221 self._has_errors = (self._has_errors or level >= logging.ERROR) # any report other than logging.INFO level, # needs to cleanup < and > character to avoid html conflict if not isinstance(msg, str): msg_str = safe_strtype(msg) # get rid of unicode characters msg_str = msg_str.encode('ascii', 'ignore') msg_str = msg_str.replace(op.sep, '/') else: msg_str = msg logging.Logger._log(self, level, msg_str, args, exc_info=exc_info, extra=extra)
def git_pull(repo_info): repo = repo_info.repo try: libgit.Commands.Pull(repo, _make_pull_signature(), _make_pull_options(repo_info)) mlogger.debug('Successfully pulled repo: %s', repo_info.directory) head_msg = safe_strtype(repo.Head.Tip.Message).replace('\n', '') mlogger.debug('New head is: %s > %s', repo.Head.Tip.Id.Sha, head_msg) return RepoInfo(repo) except Exception as pull_err: mlogger.debug('Failed git pull: %s | %s', repo_info.directory, pull_err) _process_git_error(pull_err)
def _generate_base_classes_asm(): source_list = [] for source_file in _get_source_files(): source_list.append(source_file) # now try to compile try: mlogger.debug('Compiling base types to: %s', BASE_TYPES_ASM_FILE) compile_csharp(source_list, BASE_TYPES_ASM_FILE, reference_list=_get_references(), resource_list=[]) return load_asm_file(BASE_TYPES_ASM_FILE) except PyRevitException as compile_err: errors = safe_strtype(compile_err).replace('Compile error: ', '') mlogger.critical('Can not compile base types code into assembly.\n%s', errors) raise compile_err
def git_fetch(repo_info): repo = repo_info.repo try: repo.Network.Fetch(repo.Head.TrackedBranch.Remote, _make_fetch_options(repo_info)) logger.debug('Successfully pulled repo: {}'.format( repo_info.directory)) head_msg = safe_strtype(repo.Head.Tip.Message).replace('\n', '') logger.debug('New head is: {} > {}'.format(repo.Head.Tip.Id.Sha, head_msg)) return RepoInfo(repo) except Exception as fetch_err: logger.debug('Failed git fetch: {} ' '| {}'.format(repo_info.directory, fetch_err)) _process_git_error(fetch_err)
def git_pull(repo_info): repo = repo_info.repo try: repo.Network.Pull(_make_pull_signature(), _make_pull_options(repo_info)) logger.debug('Successfully pulled repo: {}'.format( repo_info.directory)) head_msg = safe_strtype(repo.Head.Tip.Message).replace('\n', '') logger.debug('New head is: {} > {}'.format(repo.Head.Tip.Id.Sha, head_msg)) return RepoInfo(repo) except Exception as pull_err: logger.debug('Failed git pull: {} ' '| {}'.format(repo_info.directory, pull_err)) _process_git_error(pull_err)
def _log(self, level, msg, args, exc_info=None, extra=None): self._has_errors = (self._has_errors or level >= logging.ERROR) # any report other than logging.INFO level, # needs to cleanup < and > character to avoid html conflict if not isinstance(msg, str): msg_str = safe_strtype(msg) else: msg_str = msg # get rid of unicode characters msg_str = msg_str.encode('ascii', 'ignore') msg_str = msg_str.replace(os.path.sep, '/') msg_str = emojize(msg_str) if level == logging.INFO: msg_str = prepare_html_str(msg_str) logging.Logger._log(self, level, msg_str, args, exc_info=exc_info, extra=extra)
def get_postable_commands(self): """Return list of postable commands. Returns: :obj:`list` of :obj:`_HostAppPostableCommand` """ # if list of postable commands is _not_ already created # make the list and store in instance parameter if not self._postable_cmds: for pc in UI.PostableCommand.GetValues(UI.PostableCommand): try: rcid = UI.RevitCommandId.LookupPostableCommandId(pc) self._postable_cmds.append( # wrap postable command info in custom namedtuple _HostAppPostableCommand(name=safe_strtype(pc), key=rcid.Name, id=rcid.Id, rvtobj=rcid)) except Exception: # if any error occured when querying postable command # or its info, pass silently pass return self._postable_cmds
def git_pull(repo_info): """Pull the current head of given repo. Args: repo_info (:obj:`RepoInfo`): target repo object Returns: :obj:`RepoInfo`: repo object with updated head """ repo = repo_info.repo try: libgit.Commands.Pull(repo, _make_pull_signature(), _make_pull_options(repo_info)) mlogger.debug('Successfully pulled repo: %s', repo_info.directory) head_msg = safe_strtype(repo.Head.Tip.Message).replace('\n', '') mlogger.debug('New head is: %s > %s', repo.Head.Tip.Id.Sha, head_msg) return RepoInfo(repo) except Exception as pull_err: mlogger.debug('Failed git pull: %s | %s', repo_info.directory, pull_err) _process_git_error(pull_err)