#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
#
# Copyright 2018 黎慧剑
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
"""
通用基础模块
@module generic
@file generic.py
"""
import sys
import os
import json
import re
# 根据当前文件路径将包路径纳入, 在非安装的情况下可以引用到
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir)))
from HiveNetCore.utils.global_var_tool import GlobalVarTool
from HiveNetCore.i18n import get_global_i18n
__MOUDLE__ = 'generic' # 模块名
__DESCRIPT__ = '通用基础模块' # 模块描述
__VERSION__ = '0.1.0' # 版本
__AUTHOR__ = '黎慧剑' # 作者
__PUBLISH__ = '2018.08.29' # 发布日期
# 全局变量
# 用于存储全局变量的值
# key为全局变量名( string) , value为全局变量的值
RUNTOOL_GLOBAL_VAR_LIST = dict()
[文档]def null_fun(*args, **kwargs):
"""
空函数
"""
pass
[文档]class NullObj(object):
"""
空对象定义类, 用于动态增加属性的使用场景
@example
msg_obj = NullObj()
msg_obj.text = u'动态添加属性'
"""
#############################
# 通用的JSON转换处理函数
#############################
def __json__(self):
"""
将对象转换为json字符串
@return {string} - 转换后的json字符串
"""
return json.dumps(NullObj.get_object_attr_dict(self), ensure_ascii=False)
@staticmethod
def __fromjson__(json_str):
"""
通过json字符串获取对象实例
@param {string} json_str - json字符串
"""
_json_obj = json.loads(json_str)
return NullObj.get_nullobj_from_dict(_json_obj)
#############################
# 内部函数
#############################
[文档] @staticmethod
def get_object_attr_dict(obj, ignored_key=[]):
"""
获取对象的属性清单字典( 循环递归获取)
@param {object} obj - 要处理的对象
@param {list} ignored_key=[] - 忽略的属性名清单
"""
if type(obj) in (
int, float, bool, complex,
str, list, tuple, dict, set
):
# 基本数据类型, 直接返回自身
return obj
else:
# 对象, 统一转换为字典格式
_dict = dict()
_attr_dir = dir(obj)
for _item in _attr_dir:
if _item[0: 2] != '__' and _item not in ignored_key and not callable(getattr(obj, _item)):
_dict[_item] = NullObj.get_object_attr_dict(getattr(obj, _item))
return _dict
[文档] @staticmethod
def get_nullobj_from_dict(obj_dict):
"""
通过字典对象生成NullObj实例
@param {dict} obj_dict - 字典对象
@return {NullObj} - 生成的实例
"""
_obj = NullObj()
for _key in obj_dict.keys():
if isinstance(obj_dict[_key], dict):
# 还是字典, 继续往下一层处理
exec('_obj.%s = NullObj.get_nullobj_from_dict(obj_dict[_key])' % (_key))
else:
exec('_obj.%s = obj_dict[_key]' % (_key))
return _obj
[文档]class CResult(NullObj):
"""
通用错误类定义, 便于规范所有的错误信息返回判断标准, 可直接在该类的实例对象上直接添加其他返回值
@example
def fun():
result = CResult('00000',u'success')
result.job = 'NewJob'
result.k1 = 10
return result
"""
[文档] def __init__(self, code='00000', msg=None, error='', trace_str='',
i18n_obj=None, i18n_msg_paras=()):
"""
构造函数
@param {string} code='00000' - 错误码, '00000'代表成功, 参照HiveNet的错误码规范
@param {string} msg=None - 错误信息描述, 如果i18n_obj不为None时, 该参数传入的是国际化的消息ID
注意: 如果初始化时不传入msg( 即msg=None时) , 自动通过code查找具体的错误信息, 且在i18n_obj为None时使用全局国际化对象处理国际化信息
@param {string} error=None - 发生异常时的异常类型type的字符串
@param {string} trace_str='' - 错误追踪堆栈日志, 异常时的traceback.format_exc()
@param {SimpleI18N} i18n_obj=None - 国际化类的实例对象, 如不传入会尝试自动加载全局的国际化控件
@param {tuple} i18n_msg_paras=() - 与msg配套使用, 当使用国际化时, 可以传入变量, 用于替换msg中的$1占位符
"""
self.code = code
self.msg = msg
self.i18n_msg_id = msg # 国际化记录下来的错误明细编码ID串
self.i18n_msg_paras = i18n_msg_paras # 国际化记录下来的可替换参数变量
self._i18n_obj = i18n_obj # 国际化类实例化对象
self.error = error
self.trace_str = trace_str
self.i18n_error_type_msg_id = '' # 国际化记录下来的错误类型ID串( 第1位的错误说明)
if i18n_obj is None:
# 没有传国际化对象, 尝试获取全局的国际化对象
self._i18n_obj = get_global_i18n()
# 如果msg为None, 需重新设置i18n_msg_id和i18n_error_type_msg_id的值
self.__get_i18n_msg_id()
# 重新设置msg
self.reset_msg()
[文档] def is_success(self):
"""
判断当前错误对象是否成功
"""
return (self.code[0] == '0')
[文档] def reset_msg(self):
"""
重新设置错误对象的msg显示值( 例如修改了国际化控件默认语言后处理)
"""
if self._i18n_obj is None:
# 没有国际化, 只是通过i18n_msg_id重新设置值
self.msg = self.i18n_msg_id
if self.msg != '':
# 替换占位参数
i = 1 # 记录是第几个
for para in self.i18n_msg_paras:
if self.msg.find('$' + str(i)) >= 0:
# 找到需要替换才处理, 提升效率
self.msg = re.sub(r'\$' + str(i), str(para), self.msg)
i = i + 1
# 补充错误类型位
if self.i18n_error_type_msg_id != '':
if self.msg != '':
self.msg = '%s: %s' % (self.i18n_error_type_msg_id, self.msg)
else:
self.msg = self.i18n_error_type_msg_id
else:
# 国际化处理
self.msg = ''
if self.i18n_error_type_msg_id != '':
self.msg = self._i18n_obj.translate(self.i18n_error_type_msg_id)
if self.i18n_msg_id != '':
self.msg = self.msg + ': '
if self.i18n_msg_id != '':
self.msg = self.msg + \
self._i18n_obj.translate(self.i18n_msg_id, self.i18n_msg_paras)
[文档] def reset_msg_by_code(self):
"""
根据错误码重置错误信息( 忽略原来的错误信息, 按HiveNet规范处理)
"""
# 重置
self.i18n_msg_id = None
self.i18n_error_type_msg_id = None
self.__get_i18n_msg_id()
# 重新设置msg
self.reset_msg()
[文档] def change_code(self, code='00000', msg=None, i18n_msg_paras=None):
"""
改变错误码及错误信息
@param {string} code='00000' - 错误码
@param {string} msg=None - 错误信息描述, 如果i18n_obj不为None时, 该参数传入的是国际化的消息ID
注意: 如果初始化时不传入msg( 即msg=None时) , 自动通过code查找具体的错误信息, 且在i18n_obj为None时使用全局国际化对象处理国际化信息
@param {tuple} i18n_msg_paras=() - 与msg配套使用, 当使用国际化时, 可以传入变量, 用于替换msg中的$1占位符
注意: 如果初始化时不传入i18n_msg_paras( 即i18n_msg_paras=None时) , 代表不改变原来传入的占位符变量
"""
self.code = code
self.msg = msg
self.i18n_msg_id = msg
if i18n_msg_paras is not None:
self.i18n_msg_paras = i18n_msg_paras
# 如果msg为None, 需重新设置i18n_msg_id和i18n_error_type_msg_id的值
self.__get_i18n_msg_id()
# 重新设置msg
self.reset_msg()
[文档] def standard_copy_to(self, dest_obj):
"""
复制结果对象的标准返回值到新对象中
简单数据类型( int、string) 只要共享地址即可, 因为对变量重新复制会指向新的地址,
不会影响原来的变量值;复杂数据类型( dict等) 要通过deepcopy方式拷贝, 避免同一内存信息改变互相影响
@param {object} dest_obj - 要复制到的CResult对象
"""
dest_obj.code = self.code
dest_obj.msg = self.msg
dest_obj.error = self.error
dest_obj.trace_str = self.trace_str
dest_obj.i18n_msg_id = self.i18n_msg_id
dest_obj.i18n_msg_paras = self.i18n_msg_paras
dest_obj.i18n_error_type_msg_id = self.i18n_error_type_msg_id
def __get_i18n_msg_id(self):
"""
获取并设置i18n_msg_id的值
"""
# 尝试先装载错误码映射
_map_error_code = self.__get_map_error_code()
# 获取代码表, 区分错误类型及错误明细编码
if self.code[0] in _map_error_code.keys():
self.i18n_error_type_msg_id = _map_error_code[self.code[0]]
else:
self.i18n_error_type_msg_id = 'unknow' # 没有定义国际化时使用未知代替
if self.i18n_msg_id is None or self.i18n_msg_id == '':
# 只有原来没有设置过才通过标准错误码映射修改, 否则保持不变
if self.code[1:] in _map_error_code.keys():
self.i18n_msg_id = _map_error_code[self.code[1:]]
else:
self.i18n_msg_id = ''
def __get_map_error_code(self):
"""
获取全局的错误码映射表
"""
_map_error_code = GlobalVarTool.get_global_var('HIVENET_ERROR_CODE_MAP')
if _map_error_code is None:
_map_file = os.path.realpath(os.path.abspath(os.path.dirname(__file__) + '/') +
'/hivenet_error_code/map_error_code.json')
_map_error_code = {}
with open(_map_file, 'rt', encoding='utf-8') as f:
_map_error_code = json.load(f)
GlobalVarTool.set_global_var('HIVENET_ERROR_CODE_MAP', _map_error_code)
return _map_error_code
def __str__(self):
"""
提供系统层级的str输出格式化字符
"""
_str = '%s:\n' % (str(type(self)))
# 其他属性
_attr_dir = dir(self)
for _item in _attr_dir:
if _item[0: 2] != '__' and not callable(getattr(self, _item)) and _item not in ['_i18n_obj', 'i18n_msg_paras', 'i18n_msg_id', 'error']:
_str += ' (attr).%s=%s\n' % (_item, str(getattr(self, _item)))
# __dict__上的属性
if hasattr(self, '__dict__'):
for _item in self.__dict__.items():
if _item[0] not in _attr_dir and _item[0] not in ['_i18n_obj', 'i18n_msg_paras', 'i18n_msg_id', 'error']:
_str += ' (dict).%s=%s\n' % (_item[0], str(_item[1]))
return _str
#############################
# 通用的JSON转换处理函数
#############################
def __json__(self):
"""
将对象转换为json字符串
@return {string} - 转换后的json字符串
"""
return json.dumps(NullObj.get_object_attr_dict(self, ignored_key=['_i18n_obj', ]), ensure_ascii=False)
@staticmethod
def __fromjson__(json_str):
"""
通过json字符串获取对象实例
@param {string} json_str - json字符串
"""
_json_obj = json.loads(json_str)
_obj = CResult(
code=_json_obj['code'],
msg=_json_obj['msg'],
error=_json_obj['error'],
trace_str=_json_obj['trace_str'],
i18n_msg_paras=_json_obj['i18n_msg_paras']
)
_obj.i18n_error_type_msg_id = _json_obj['i18n_error_type_msg_id']
_obj.i18n_msg_id = _json_obj['i18n_msg_id']
return _obj
if __name__ == '__main__':
# 当程序自己独立运行时执行的操作
# 打印版本信息
print(('模块名: %s - %s\n'
'作者: %s\n'
'发布日期: %s\n'
'版本: %s' % (__MOUDLE__, __DESCRIPT__, __AUTHOR__, __PUBLISH__, __VERSION__)))