PKX{L_rsparam/__init__.py"""Utilities for working with Revit shared parameter files.""" import re import codecs import csv from collections import namedtuple, defaultdict # pylama:ignore=D105 # rsparam version __version__ = '0.1.11' __sparamversion__ = (2, 1) SharedParamEntries = namedtuple('SharedParamEntries', ['groups', 'params']) class SharedParamFileItem(object): def __init__(self, lineno): # make line number start from 1 self.lineno = lineno + 1 def __contains__(self, key): for value in self: if bool(re.findall(key, str(value))): return True return False def __eq__(self, other): return hash(self) == hash(other) class SharedParamGroup(SharedParamFileItem): def __init__(self, args, lineno=None): super(SharedParamGroup, self).__init__(lineno) self.guid = args[0] self.desc = args[1] self.name = self.desc def __str__(self): return self.desc def __iter__(self): return iter([self.guid, self.desc]) def __repr__(self): return '<{} desc:"{}" guid:{}>'.format(self.__class__.__name__, self.desc, self.guid) def __hash__(self): return hash(self.guid + self.desc) class SharedParam(SharedParamFileItem): def __init__(self, args, lineno=None): super(SharedParam, self).__init__(lineno) self.guid = args[0] self.name = args[1] self.datatype = args[2] self.datacategory = args[3] self.group = args[4] self.visible = args[5] self.desc = args[6] self.usermod = args[7] def __str__(self): return self.desc def __iter__(self): return iter([self.guid, self.name, self.datatype, self.datacategory, self.group, self.visible, self.desc, self.usermod]) def __repr__(self): return '<{} name:"{}" guid:{}>'.format(self.__class__.__name__, self.name, self.guid) def __hash__(self): return hash(self.guid + self.name + self.datatype + self.datacategory + self.visible + self.desc + self.usermod) def read_entries(src_file, encoding=None): # open file and collect shared param and groups spgroups = [] sparams = [] with codecs.open(src_file, 'r', encoding) as spf: count = 0 for line in csv.reader(spf, delimiter="\t"): if len(line) >= 1: if line[0] == 'PARAM': sparam = SharedParam(line[1:], lineno=count) sparams.append(sparam) elif line[0] == 'GROUP': spgroup = SharedParamGroup(line[1:], lineno=count) spgroups.append(spgroup) count += 1 # now update sparams with group obj for sp in sparams: for spg in spgroups: if sp.group == spg.guid: sp.group = spg return SharedParamEntries(spgroups, sparams) def write_entries(entries, out_file, encoding=None): with codecs.open(out_file, 'w', encoding) as spf: spf.write("# This is a Revit shared parameter file.\r\n") spf.write("# Do not edit manually unless you know better!\r\n") spf.write("*META\tVERSION\tMINVERSION\r\n") spf.write("META\t{max_ver}\t{min_ver}\r\n" .format(max_ver=__sparamversion__[0], min_ver=__sparamversion__[1])) sparamwriter = csv.writer(spf, delimiter="\t") # write groups referenced by SharedParam instances and in entries spf.write("*GROUP\tID\tNAME\r\n") refgroups = {x.group for x in entries if isinstance(x, SharedParam)} spgroups = {x for x in entries if isinstance(x, SharedParamGroup)} spgroups = spgroups.union(refgroups) for spg in sorted(spgroups, key=lambda x: x.name): sparamwriter.writerow(['GROUP', spg.guid, spg.name]) # write SharedParam in entries spf.write("*PARAM\tGUID\tNAME\tDATATYPE\tDATACATEGORY\tGROUP\t" "VISIBLE\tDESCRIPTION\tUSERMODIFIABLE\r\n") sparams = {x for x in entries if isinstance(x, SharedParam)} for sp in sorted(sparams, key=lambda x: x.name): sparamwriter.writerow( ['PARAM', sp.guid, sp.name, sp.datatype, sp.datacategory, sp.group.guid, sp.visible, sp.desc, sp.usermod] ) def get_paramgroups(src_file, encoding=None): spgroups, sparams = read_entries(src_file, encoding=encoding) return spgroups def get_params(src_file, encoding=None, groupid=None): spgroups, sparams = read_entries(src_file, encoding=encoding) if groupid: return [x for x in sparams if x.group.guid == groupid] return sparams def find_duplicates(src_file, encoding=None, byname=False): param_guid_lut = defaultdict(list) group_guid_lut = defaultdict(list) spgroups, sparams = read_entries(src_file, encoding=encoding) duplparam = 'name' if byname else 'guid' for sparam in sparams: param_guid_lut[getattr(sparam, duplparam)].append(sparam) for spgroup in spgroups: group_guid_lut[getattr(spgroup, duplparam)].append(spgroup) duplgroups = [v for k, v in group_guid_lut.items() if len(v) > 1] duplparams = [v for k, v in param_guid_lut.items() if len(v) > 1] return SharedParamEntries(duplgroups, duplparams) def find(src_file, searchstr, encoding=None): spgroups, sparams = read_entries(src_file, encoding=encoding) matchedgroups = [x for x in spgroups if searchstr in x] matchedparams = [x for x in sparams if searchstr in x] return SharedParamEntries(matchedgroups, matchedparams) def compare(first_file, second_file, encoding=None): spgroups1, sparams1 = read_entries(first_file, encoding=encoding) spgroups2, sparams2 = read_entries(second_file, encoding=encoding) uniqgroups1 = [x for x in spgroups1 if x not in spgroups2] uniqparams1 = [x for x in sparams1 if x not in sparams2] uniqgroups2 = [x for x in spgroups2 if x not in spgroups1] uniqparams2 = [x for x in sparams2 if x not in sparams1] return SharedParamEntries(uniqgroups1, uniqparams1), \ SharedParamEntries(uniqgroups2, uniqparams2) def merge(out_file, source_files, encoding=None): merged_spgroups = set() merged_sparams = set() for sfile in source_files: spgroups, sparams = read_entries(sfile, encoding=encoding) merged_spgroups.union(spgroups) merged_sparams.union(sparams) write_entries(list(spgroups) + list(sparams), out_file, encoding=encoding) PKLZ{L4 - -rsparam/cli.py#!/usr/bin/env python """Utilities for working with Revit shared parameter files Usage: rsparam (-h | --help) rsparam (-V | --version) rsparam (-W | --writerversion) rsparam [-q -e ] list [-a -s -c -o ] rsparam [-q -e ] list [-p -g -s -c -o ] rsparam [-q -e ] list -p [-f -o ] rsparam [-q -e ] find dupl [-n -a -p -g -s -c -o ] rsparam [-q -e ] find [-p -g -s -c -o ] rsparam [-q -e ] comp [-p -g -1 -2 -s -c -O] rsparam [-q -e ] merge ... Options: -h, --help Show this help -V, --version Show command version -W, --writerversion Show shared param file version -q, --quiet Quiet mode [default: False] -e , --encode File encoding [default: utf-8] -a, --all All items -p, --params Parameters only -g, --groups Parameter groups only -s , --sortby Sort by "name", "group" [default: name] -c , --columns List of data columns separated by : -f , --filter Filter by group guid -o , --output Write results to output file -O, --OUTPUT Write complex results to output file(s) -n, --byname Compare by name instead of guid -1, --first Output results for first file only -2, --second Output results for second file only """ # noqa from docopt import docopt import colorful from tabulate import tabulate import rsparam # process command line args args = docopt(__doc__, version='rsparam {}'.format(rsparam.__version__)) def report(message): if not args['--quiet']: print(message) def report_globals(): enc_report = 'encoding={}'.format(args['--encode']) if args['--encode'] \ else 'encoding not set' report(colorful.yellow(enc_report)) def report_filenames(sparam_files, title='source file: ', colorfunc=colorful.blue): if not isinstance(sparam_files, list): sparam_files = [sparam_files] for sparam_file in sparam_files: report(colorfunc(f'{title}{sparam_file}')) def check_write_results(results): # write output to file if requested if args['--output']: rsparam.write_entries(results, args['--output'], encoding=args['--encode']) return args['--output'] def list_params(src_file, sparams=None): if not sparams: sparams = rsparam.get_params(src_file, groupid=args['--filter']) # write output to file if requested out_file = check_write_results(sparams) if out_file: report_filenames(out_file, title='wrote results to: ') return sparamdata = [] if args['--columns']: sparamattrs = args['--columns'].split(':') else: sparamattrs = ['guid', 'name', 'datatype', 'group', 'lineno'] for sp in sparams: spcolumns = [] for spattr in sparamattrs: spcolumns.append(getattr(sp, spattr, None)) sparamdata.append(tuple(spcolumns)) if args['--sortby'] == 'group': sparamdata = sorted(sparamdata, key=lambda x: getattr(x, 'name', 0)) print(tabulate(sparamdata, headers=('Guid', 'Name', 'Datatype', 'Group', 'Line #'))) report("Total of {} items.".format(len(sparamdata))) def list_groups(src_file, spgroups=None): if not spgroups: spgroups = rsparam.get_paramgroups(src_file, encoding=args['--encode']) # write output to file if requested out_file = check_write_results(spgroups) if out_file: report_filenames(out_file, title='wrote results to: ') return spgroupdata = [] if args['--columns']: sgroupattrs = args['--columns'].split(':') else: sgroupattrs = ['guid', 'name', 'lineno'] for spg in spgroups: spgcolumns = [] for spgattr in sgroupattrs: spgcolumns.append(getattr(spg, spgattr, None)) spgroupdata.append(tuple(spgcolumns)) print(tabulate(spgroupdata, headers=('Id', 'Description', 'Line #'))) report("Total of {} items.".format(len(spgroupdata))) def list_all(src_file): list_groups(src_file) list_params(src_file) def find_param_dupls(src_file): byname = args['--byname'] spentries = rsparam.find_duplicates(src_file, byname=byname) # write output to file if requested out_file = check_write_results(spentries.params) if out_file: report_filenames(out_file, title='wrote results to: ') return duplparam = 'name' if byname else 'guid' dupldata = [] report(colorful.yellow('\nduplicate params by {}:'.format(duplparam))) for dlist in spentries.params: for d in dlist: dupldata.append((d.name if byname else d.guid, d.guid if byname else d.name, d.datatype, d.group, d.lineno)) print(colorful.yellow('\nduplicates by {}: {}'.format(duplparam, dupldata[0][0]))) if args['--sortby'] == 'group': dupldata = sorted(dupldata, key=lambda x: str(x[3])) print(tabulate(dupldata, headers=('Name' if byname else 'Guid', 'Guid' if byname else 'Name', 'Datatype', 'Group', 'Line #'))) def find_group_dupls(src_file): byname = args['--byname'] spentries = rsparam.find_duplicates(src_file, byname=byname) # write output to file if requested out_file = check_write_results(spentries.groups) if out_file: report_filenames(out_file, title='wrote results to: ') return duplparam = 'name' if byname else 'guid' dupldata = [] report(colorful.yellow('\nduplicate groups by {}:'.format(duplparam))) for dlist in spentries.groups: for d in dlist: dupldata.append((d.name if byname else d.guid, d.guid if byname else d.name, d.lineno)) print(colorful.yellow('\nduplicates by {}: {}'.format(duplparam, dupldata[0][0]))) print(tabulate(dupldata, headers=('Name' if byname else 'Guid', 'Guid' if byname else 'Name', 'Line #'))) def find_all_dupls(src_file): find_group_dupls(src_file) find_param_dupls(src_file) def find_matching(src_file): search_str = args[''] spentries = rsparam.find(src_file, search_str, encoding=args['--encode']) # write output to file if requested out_entries = [] if not args['--params']: out_entries.extend(spentries.groups) if not args['--groups']: out_entries.extend(spentries.params) out_file = check_write_results(out_entries) if out_file: report_filenames(out_file, title='wrote results to: ') return if spentries.groups and not args['--params']: report(colorful.yellow('\ngroups matching: {}'.format(search_str))) list_groups(None, spgroups=spentries.groups) if spentries.params and not args['--groups']: report(colorful.yellow('\nparams matching: {}'.format(search_str))) list_params(None, sparams=spentries.params) def comp(first_file, second_file): uniq1, uniq2 = rsparam.compare(first_file, second_file, encoding=args['--encode']) # write output to files if requested if uniq1.groups and not args['--params'] and not args['--second']: report(colorful.yellow('\nunique groups in first')) args['--output'] = 'uniq_groups_1.txt' if args['--OUTPUT'] else None list_groups(None, spgroups=uniq1.groups) if uniq2.groups and not args['--params'] and not args['--first']: report(colorful.yellow('\nunique groups in second')) args['--output'] = 'uniq_groups_2.txt' if args['--OUTPUT'] else None list_groups(None, spgroups=uniq2.groups) if uniq1.params and not args['--groups'] and not args['--second']: report(colorful.yellow('\nunique parameters in first')) args['--output'] = 'uniq_params_1.txt' if args['--OUTPUT'] else None list_params(None, sparams=uniq1.params) if uniq2.params and not args['--groups'] and not args['--first']: report(colorful.yellow('\nunique parameters in second')) args['--output'] = 'uniq_params_2.txt' if args['--OUTPUT'] else None list_params(None, sparams=uniq2.params) def merge(dest_file, source_files): rsparam.merge(dest_file, source_files, encoding=args['--encode']) def purge(source_file): raise NotImplementedError() def main(): if args['--writerversion']: print('shared parameter writer version: {}.{}' .format(*rsparam.__sparamversion__)) return # report globals report_globals() if args['list']: # reporting src_file = args[''] report_filenames(src_file) # list groups only if args['--groups'] and not args['--params']: list_groups(src_file) # list params only elif args['--params'] and not args['--groups']: list_params(src_file) # list everything else: list_all(src_file) elif args['find']: # reporting src_file = args[''] report_filenames(src_file) # report duplicates if args['dupl']: if args['--all']: find_all_dupls(src_file) elif args['--params']: find_param_dupls(src_file) elif args['--groups']: find_group_dupls(src_file) else: find_matching(src_file) elif args['comp']: # reporting first_file = args[''] report_filenames(first_file, title='first file: ') second_file = args[''] report_filenames(second_file, title='second file: ') # compare two shared parame files comp(first_file, second_file) elif args['merge']: # reporting dest_file = args[''] report_filenames(dest_file, title='destination file: ') src_files = args[''] report_filenames(src_files) # merge two shared param files merge(dest_file, src_files) elif args['purge']: # reporting source_file = args[''] report_filenames(source_file) # sort shared param file purge(source_file) report('') PKYbLrsparam/tests/__init__.pyPKYbLrsparam/tests/clitests.shPKYbLrsparam/tests/file1.txtPKYbLrsparam/tests/file2.txtPK!HxgR_(,)rsparam-0.1.11.dist-info/entry_points.txtN+I/N.,()**.H,J̵z9Vy\\PKQaL*1`FF rsparam-0.1.11.dist-info/LICENSEMIT License Copyright (c) 2018 Ehsan Iran-Nejad Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PK!HxyUbrsparam-0.1.11.dist-info/WHEEL HM K-*ϳR03rOK-J,/RH,Q034 /, (-JLR()*M ILR(4KM̫#DPK!H9*m!rsparam-0.1.11.dist-info/METADATA]AN@ Es _ a9+*@"RKa&Nbӊ3A-H]gIE$r-ѓ zWe^f7{maX"tANl q@~5$б)OG)ڢ5&Xp 74ƴ{mVA,<G q.2¿_oSb6 V$^NzfK_3 쁣ZhC&NtC%PK!HaHUrsparam-0.1.11.dist-info/RECORDKs@{~ yA`B:5OYk؞k[vntp_CN{/+\Ive߅I#M> nI}\lf`qJoYyJ\T)'ˏB>X ;W+1*oM `% *l(:>OrzzntV &t'4:g% &$|E䎮U֭#oM p̼o"kAUy oPKX{L_rsparam/__init__.pyPKLZ{L4 - -Lrsparam/cli.pyPKYbLHrsparam/tests/__init__.pyPKYbLHrsparam/tests/clitests.shPKYbLHrsparam/tests/file1.txtPKYbL(Irsparam/tests/file2.txtPK!HxgR_(,)]Irsparam-0.1.11.dist-info/entry_points.txtPKQaL*1`FF Irsparam-0.1.11.dist-info/LICENSEPK!HxyUbPNrsparam-0.1.11.dist-info/WHEELPK!H9*m!Nrsparam-0.1.11.dist-info/METADATAPK!HaHUPrsparam-0.1.11.dist-info/RECORDPK "Q