def regist_subcommand(self, command): """ sub_commandsの型に依存させないためのIF 型変更の必要がでたら、局所的に操作を書き換える """ from sub_command_core.sub_command import SubCommands Hoare.P(issubclass(command.__class__, SubCommands)) # 衝突注意 for name in command.command_names: Hoare.P(not (name in self.sub_commands.keys()),\ '"{}" collision were detected in {}'.format(name, self.sub_commands.keys())) # NOTE: commandは参照であること。tupleへのrefactoring注意 self.sub_commands.update({name: command})
def renew_acc(cls, schema): Hoare.P(isinstance(schema, dict)) _type = XLSX.__get_type(schema) if _type == TypeSign.ARRAY: return [] elif _type == TypeSign.OBJ: return {} else: errorout(4, _type)
def regist_command(cls, exchanger): """ subcommand 登録 **dont call from exchanger.__init__()** """ command = cls.__init__() from jsonica import Jsonica Hoare.P(isinstance(exchanger, Jsonica)) exchanger.regist_command(command)
def validate(self, evl, desc): """ _validateに流す 成功すればスルー、失敗したらその場でcommand error / 判定値は返さない NOTE: 具体的なerrorハンドリングは_validate内で処理すること """ Hoare.P(isinstance(evl, list) or isinstance(evl, dict)) self.schema._validate(evl, self.make_schema(desc)) Util.sprint( 'i\'m {} \nNow I have -> {}'.format(self, self.schema_collection), self.DEBUG)
def generate_json(self, sheet_name, acc=None): """ sheet_nameが指すsheetのJSONをaccに追加する """ sheets = self.__name_to_sheets() # pyxl...Workbookで[sheet名]を持っているが、あまり高速処理向けではないため sheet_names = list(sheets.keys()) Util.sprint('in process %s'%sheet_name, self.DEBUG) Hoare.P(sheet_name in sheet_names, '"%s" not found in %s'%(sheet_name ,sheet_names)) root_sheet = sheets[sheet_name] self.check_charcode(root_sheet) columns = [] acc = [] if not acc else acc Util.sprint('I\'ll update {}'.format(acc), self.DEBUG) # COMBAK: 処理速度に問題が出るようであれば分散処理検討 # A1, B1...で場所を特定するか、indexで回すか for i, row in enumerate(root_sheet.iter_rows()): subacc = {} if self.format: self.__output_to_csv(self.format_output, root_sheet, self.char_encode) for j, cell in enumerate(row): v = cell.value # off-by-oneを気にしないといけなくなるので、col_idxではなくenumerate使う if v is None: continue # cell check if i == 0: # 初行 column check # cell.commentは必ずつくが、中身がない場合はNone if hasattr(cell, "comment") and cell.comment: # column 準備 / schemaは遅延せずこの時点で辞書として成立している事を保証 columns.append((v, Util.runtime_dict(cell.comment.text))) else: self.errorout(2, 'sheet = {}, col = {}, row = {}'.format(sheet_name, j, i)) else: # TODO: 関数へ置き換え type = array, objectのケース をカバー # 別sheet評価 if isinstance(v, str) and v.startswith(XLSX.sheet_link_sign): # COMBAK: sheetであることがarray, objectの必要条件になってしまっている # primitive配列をどう表現するかによって改修が必要 __storeに包含させる? link = v.lstrip(XLSX.sheet_link_sign) if link in sheet_names: col_name, col_schema = columns[j] Util.sprint('process %s -> %s'%(col_name, link), self.DEBUG) Util.sprint('current acc = %s'%acc, self.DEBUG) # recursive seed XLSX.__store( self.generate_leaf(root_sheet.title, col_name, link, col_schema), subacc) else: errorout(1, 'sheet = from %s to %s, col = %d, row = %d'%(sheet_name, link, j, i)) else: XLSX.__store(self.type_validator(sheet_name, v, columns[j]), subacc) # pass columns Util.check_emptyOR(lambda x: XLSX.__store(x, acc), subacc) # pass a row return acc
def __output_to_csv(self, base_path, sheet, enc): """ CSV, TSV出力 """ if not self.format: return Hoare.P(self.format in output_formats) xdest = os.path.join(base_path, self.filename) os.makedirs(xdest, exist_ok=True) xdest_path = os.path.join(xdest, '%s.%s'%(sheet.title ,self.format)) Util.sprint(' > %s'%xdest_path, self.DEBUG) with open(xdest_path, 'w', encoding=enc) as f: writer = csv.writer(f, delimiter=self.format_delimiter) for cols in sheet.rows: writer.writerow([str(col.value or '') for col in cols])
def type_validator(self, sheet_name, value, type_desc, validator=Validator.jsonschema): """ Validator switcher validation を passしたら成功した**評価値のみ**を返す 失敗したら、その場でcommand errorとする """ self.schema = Schema(validator) raw = Util.conv_escapedKV(XLSX.__get_type(type_desc[1]), type_desc[0], value) instance = Util.runtime_dict('{%s}'%raw) Util.sprint('i\'m %s. call validator'%self, self.DEBUG) self.piled_schema = (sheet_name, type_desc[0], {type_desc[0]:type_desc[1]}) Util.sprint('>> %s -> type: %s\n%s'%(sheet_name, type_desc, instance), self.DEBUG) Hoare.P(instance is not None) self.schema.validate(instance, type_desc) return instance
def errorout(e, additonal=''): """ 強制的に止める sys.stderr へ出力 """ errors = [ 'OK', 'sheets link not found.', 'schema not found.', # 1, 2 'root sheet not found.', 'Unrecognized item type were found.', # 3, 4 'Unknown accumulator!', 'Output json has failed.', # 5, 6 'Unsupported table filetype found.', 'setting yaml file not found' ] Hoare.P(e < len(errors) and e >= 0) print('%s : %s' % (errors[e], additonal), file=sys.stderr) sys.exit(e)
def check_charcode(self, item, valid_enc=None): Hoare.P(isinstance(item, openpyxl.workbook.workbook.Workbook) or \ isinstance(item, openpyxl.worksheet.Worksheet) or \ isinstance(item, openpyxl.cell.Cell)) enc = valid_enc if bool(valid_enc) else self.char_encode Util.sprint(enc, self.DEBUG) if not (item.encoding == enc): # TODO: sheet, cellごとにエラーを上げる場合の処理 if isinstance(item, openpyxl.workbook.workbook.Workbook): add = 'sheet_names = %s'%item.sheet_names elif isinstance(item, openpyxl.worksheet.Worksheet): add = 'sheet_name = %s'%item.title else: # Cell add = 'parent = {} index = {}'.format(item.parent ,item.cordinate) print('*'*50) print(add) print('*'*50) # TODO: excel rw 状態チェック item.encoding = enc
def __run__(self, **kwargs): Hoare.P(False)
def help(self): Hoare.P(False)
def aliases(self): Hoare.P(False)
def command_names(self): Hoare.P(False)
def refactor_check(validation): Hoare.P(validation, 'Have you made refactor??')
def __get_type(cls, schema): Hoare.P('type' in schema.keys()) return schema['type']
def make_schema(self, desc): """ 一項目ずつの定義であることに留意 """ Hoare.P(isinstance(desc[0], str) and isinstance(desc[1], dict)) # TEMP: failfastとして小粒度で都度Errorを上げるか、reduceしたあと最後にvalidationをかけるか self.schema_collection.append(self.schema._make_schema(desc)) return self.schema_collection[-1]
def save(self): Hoare.P(self.out.endswith('.xlsx')) output = self.out print(r'generate template to {}'.format(output)) self.processor.book.save(output)
def check_settingfile(self): with open(self.settings, 'r') as f: self.setting_data = yaml.safe_load(f) if self.setting_data[ATTACH[0]] == ATTACH[1][0]: self.processor = XLSX(self.settings, self.enc) Hoare.P(self.processor)