commit
f8f3eaffdf
@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
@ -0,0 +1,22 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoredErrors">
|
||||||
|
<list>
|
||||||
|
<option value="N813" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoredIdentifiers">
|
||||||
|
<list>
|
||||||
|
<option value="object.transform" />
|
||||||
|
<option value="object.cluster_centers_" />
|
||||||
|
<option value="object.labels_" />
|
||||||
|
<option value="nodes" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (py-xltpl-lyFnwNVB)" project-jdk-type="Python SDK" />
|
||||||
|
</project>
|
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/py-xltpl.iml" filepath="$PROJECT_DIR$/.idea/py-xltpl.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
@ -0,0 +1,11 @@
|
|||||||
|
[[source]]
|
||||||
|
url = "https://pypi.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
name = "pypi"
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
|
||||||
|
[dev-packages]
|
||||||
|
|
||||||
|
[requires]
|
||||||
|
python_version = "3.8"
|
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"hash": {
|
||||||
|
"sha256": "7f7606f08e0544d8d012ef4d097dabdd6df6843a28793eb6551245d4b2db4242"
|
||||||
|
},
|
||||||
|
"pipfile-spec": 6,
|
||||||
|
"requires": {
|
||||||
|
"python_version": "3.8"
|
||||||
|
},
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"name": "pypi",
|
||||||
|
"url": "https://pypi.org/simple",
|
||||||
|
"verify_ssl": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default": {},
|
||||||
|
"develop": {}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Time : 2023/4/27 6:21
|
||||||
|
# @Author : old tom
|
||||||
|
# @File : __init__.py.py
|
||||||
|
# @Project : py-xltpl
|
||||||
|
# @Desc :
|
Binary file not shown.
@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Time : 2023/4/27 10:01
|
||||||
|
# @Author : old tom
|
||||||
|
# @File : excel_writer.py
|
||||||
|
# @Project : py-xltpl
|
||||||
|
# @Desc : 写入excel模板
|
||||||
|
from xltpl.writerx import BookWriter
|
||||||
|
from exceltpl.pdman.pdman_reader import PDmanReader
|
||||||
|
from futool.core.fh_file_path import exist
|
||||||
|
|
||||||
|
|
||||||
|
class ATiDeDBDocWriter(object):
|
||||||
|
class TemplateNotExistError(Exception):
|
||||||
|
def __init__(self, msg):
|
||||||
|
Exception.__init__(self, msg)
|
||||||
|
|
||||||
|
def __init__(self, data, tpl_path, out_path):
|
||||||
|
"""
|
||||||
|
:param data: 数据 使用PDmanReader 读取
|
||||||
|
:param tpl_path: 模板路径
|
||||||
|
:param out_path: 输出路径
|
||||||
|
"""
|
||||||
|
if not exist(tpl_path):
|
||||||
|
raise self.TemplateNotExistError(f'[{tpl_path}]模板不存在,请检查路径')
|
||||||
|
self.writer = BookWriter(tpl_path)
|
||||||
|
self.writer.set_jinja_globals(dir=dir, getattr=getattr)
|
||||||
|
self.data = data
|
||||||
|
self.out_path = out_path
|
||||||
|
|
||||||
|
def fill(self):
|
||||||
|
payloads = []
|
||||||
|
for i, t in enumerate(self.data):
|
||||||
|
table = self.data[t]
|
||||||
|
table['sheet_name'] = str(i + 1) + '.' + table['table_name']
|
||||||
|
table['tpl_idx'] = i
|
||||||
|
payloads.append(table)
|
||||||
|
self.writer.render_sheets(payloads=payloads)
|
||||||
|
self.writer.save(self.out_path)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
reader = PDmanReader(r'D:\文档\工作\ATD\2023上半年\项目\昭通OA\表结构\昭通OA.pdma.json')
|
||||||
|
writer = ATiDeDBDocWriter(reader.read_by_module('OA_CAR'), r'C:\Users\89295\Desktop\atide_db_tpl.xlsx',
|
||||||
|
r'C:\Users\89295\Desktop\车辆管理.xlsx')
|
||||||
|
writer.fill()
|
@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Time : 2023/4/27 6:21
|
||||||
|
# @Author : old tom
|
||||||
|
# @File : __init__.py.py
|
||||||
|
# @Project : py-xltpl
|
||||||
|
# @Desc :
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,117 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Time : 2023/4/27 6:21
|
||||||
|
# @Author : old tom
|
||||||
|
# @File : pdman_reader.py
|
||||||
|
# @Project : py-xltpl
|
||||||
|
# @Desc : 读取pdman 文件
|
||||||
|
|
||||||
|
from futool.core.fh_file_path import exist
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class PDmanReader(object):
|
||||||
|
DATA_TYPE_MAPPING = {
|
||||||
|
'oracle': {
|
||||||
|
'DefaultString': 'VARCHAR2(255)',
|
||||||
|
'IdOrKey': 'VARCHAR2(32)',
|
||||||
|
'Name': 'VARCHAR2(90)',
|
||||||
|
'Int': 'NUMBER(38,0)',
|
||||||
|
'Double': 'NUMBER(24,6)',
|
||||||
|
'Money': 'NUMBER(24,6)',
|
||||||
|
'DateTime': 'DATE',
|
||||||
|
'YesNo': 'VARCHAR2(1)',
|
||||||
|
'Dict': 'VARCHAR2(32)',
|
||||||
|
'DescText': 'VARCHAR2(900)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PDfileNotExistError(Exception):
|
||||||
|
"""
|
||||||
|
PDMAN 文件不存在
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, msg):
|
||||||
|
Exception.__init__(self, msg)
|
||||||
|
|
||||||
|
class ModuleNotExistError(Exception):
|
||||||
|
"""
|
||||||
|
模块不存在
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, msg):
|
||||||
|
Exception.__init__(self, msg)
|
||||||
|
|
||||||
|
def __init__(self, pdman_file):
|
||||||
|
if not exist(pdman_file):
|
||||||
|
raise self.PDfileNotExistError(msg=f'{pdman_file}文件不存在')
|
||||||
|
with open(pdman_file, 'r', encoding='utf-8') as f:
|
||||||
|
self.json_reader = json.loads(f.read())
|
||||||
|
self.modules = self._load_all_module()
|
||||||
|
self.domains = self._load_data_domains()
|
||||||
|
|
||||||
|
def read_by_module(self, module_name):
|
||||||
|
"""
|
||||||
|
根据模块读取
|
||||||
|
:param module_name: 模块名称
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if module_name not in self.modules.keys():
|
||||||
|
raise self.ModuleNotExistError(f'{module_name}模块不存在')
|
||||||
|
# 获取模块与表关联关系
|
||||||
|
entry_ids = self.modules[module_name]
|
||||||
|
tables = {}
|
||||||
|
for entry in self.json_reader['entities']:
|
||||||
|
if entry['id'] in entry_ids:
|
||||||
|
# 读取表名,字段
|
||||||
|
tables[entry['defKey']] = {
|
||||||
|
'table_name': entry['defName'],
|
||||||
|
'table_en_name': entry['defKey'],
|
||||||
|
'rows': self._fields_convert(entry['fields'])
|
||||||
|
}
|
||||||
|
return tables
|
||||||
|
|
||||||
|
def _load_all_module(self):
|
||||||
|
"""
|
||||||
|
加载模块索引
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
modules = self.json_reader['viewGroups']
|
||||||
|
module_dict = {}
|
||||||
|
for m in modules:
|
||||||
|
module_dict[m['defKey']] = m['refEntities']
|
||||||
|
return module_dict
|
||||||
|
|
||||||
|
def _load_data_domains(self, db_type='oracle'):
|
||||||
|
"""
|
||||||
|
加载数据域
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
domains_dict = {}
|
||||||
|
domains = self.json_reader['domains']
|
||||||
|
for d in domains:
|
||||||
|
domains_dict[d['id']] = self.DATA_TYPE_MAPPING[db_type][d['defKey']]
|
||||||
|
return domains_dict
|
||||||
|
|
||||||
|
#
|
||||||
|
def _fields_convert(self, fields):
|
||||||
|
rt = []
|
||||||
|
for f in fields:
|
||||||
|
if len(f['domain']) > 0:
|
||||||
|
f['type'] = self.domains[f['domain']]
|
||||||
|
elif len(str(f['len'])) > 0 and len(str(f['scale'])) == 0:
|
||||||
|
f['type'] = f['type'] + '(' + str(f['len']) + ')'
|
||||||
|
elif len(str(f['len'])) > 0 and len(str(f['scale'])) > 0:
|
||||||
|
f['type'] = f['type'] + '(' + str(f['len']) + ',' + str(f['scale']) + ')'
|
||||||
|
rt.append({'enName': f['defKey'],
|
||||||
|
'chName': f['defName'] + ';' + f['comment'] if len(f['comment']) > 0 else f['defName'],
|
||||||
|
'type': f['type'], 'nullable': 'Y' if f['notNull'] else 'N'})
|
||||||
|
return rt
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
if __name__ == '__main__':
|
||||||
|
pdfile = r'D:\文档\工作\ATD\2023上半年\项目\昭通OA\表结构\昭通OA.pdma.json'
|
||||||
|
reader = PDmanReader(pdfile)
|
||||||
|
all_table = reader.read_by_module('TEST')
|
||||||
|
print(all_table['test'])
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Time : 2022/9/10 10:15
|
||||||
|
# @Author : old tom
|
||||||
|
# @File : fu_lang.py
|
||||||
|
# @Project : Futool
|
||||||
|
# @Desc : 字符串相关
|
@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Time : 2022/9/10 10:17
|
||||||
|
# @Author : old tom
|
||||||
|
# @File : fu_math.py
|
||||||
|
# @Project : Futool
|
||||||
|
# @Desc : 数学计算
|
@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Time : 2022/9/10 10:46
|
||||||
|
# @Author : old tom
|
||||||
|
# @File : fu_parser.py
|
||||||
|
# @Project : Futool
|
||||||
|
# @Desc : 解析器(CSV,JSON,NB文件)
|
@ -0,0 +1,8 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Time : 2023/4/3 21:46
|
||||||
|
# @Author : old tom
|
||||||
|
# @File : fh_db.py
|
||||||
|
# @Project : futool
|
||||||
|
# @Desc : 数据库通用类
|
||||||
|
|
@ -0,0 +1,94 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Time : 2022/8/31 23:34
|
||||||
|
# @Author : old tom
|
||||||
|
# @File : http_downloader.py
|
||||||
|
# @Project : Futool
|
||||||
|
# @Desc : 文件下载器
|
||||||
|
import time
|
||||||
|
|
||||||
|
from futool.http.http_request import head
|
||||||
|
from multiprocessing import Pool
|
||||||
|
import urllib.request as req
|
||||||
|
|
||||||
|
|
||||||
|
class HttpDownloader(object):
|
||||||
|
"""
|
||||||
|
HTTP 下载器
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, pool=None):
|
||||||
|
self.pool = Pool(16) if not pool else pool
|
||||||
|
|
||||||
|
def download(self, url, dst, chunk_size=1000):
|
||||||
|
"""
|
||||||
|
文件下,自动开启多线程
|
||||||
|
:param url: 下载链接
|
||||||
|
:param dst: 保存路径
|
||||||
|
:param chunk_size: 文件块
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
is_support, content_length = HttpDownloader.is_support_range(url)
|
||||||
|
if is_support:
|
||||||
|
# 每个线程下载字节偏移量
|
||||||
|
offset = self.fork(int(content_length), chunk_size)
|
||||||
|
self.__join(offset, url, dst)
|
||||||
|
else:
|
||||||
|
print('无法获取Content-Length,使用单线程下载')
|
||||||
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def is_support_range(url):
|
||||||
|
"""
|
||||||
|
判断是否支持range请求
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
wrapper = head(url)
|
||||||
|
header = wrapper.header()
|
||||||
|
h_keys = header.keys()
|
||||||
|
if 'Accept-Ranges' in h_keys and 'Content-Length' in h_keys and header['Accept-Ranges'] != 'none':
|
||||||
|
return True, header['Content-Length']
|
||||||
|
else:
|
||||||
|
return False, 0
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def fork(content_length: int, chunk_size):
|
||||||
|
"""
|
||||||
|
拆分线程
|
||||||
|
:param chunk_size: 文件块大小
|
||||||
|
:param content_length:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
offset = []
|
||||||
|
if content_length <= chunk_size:
|
||||||
|
offset.append((0, content_length))
|
||||||
|
else:
|
||||||
|
for i in range(content_length // chunk_size):
|
||||||
|
start_offset = chunk_size * i + 1
|
||||||
|
end_offset = start_offset - 1 + chunk_size
|
||||||
|
offset.append((0 if i == 0 else start_offset, end_offset))
|
||||||
|
offset.append((chunk_size * (content_length // chunk_size), content_length))
|
||||||
|
return offset
|
||||||
|
|
||||||
|
def __join(self, offset, url, dst):
|
||||||
|
"""
|
||||||
|
多线程下载
|
||||||
|
:param offset:
|
||||||
|
:param url:
|
||||||
|
:param dst:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
def download_by_thread(part):
|
||||||
|
_request = req.Request(url=url, headers={
|
||||||
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
|
||||||
|
"Chrome/104.0.5112.102 Safari/537.36 Edg/104.0.1293.70",
|
||||||
|
'Range': f'bytes:{part[0]}-{part[1]}'
|
||||||
|
}, method='GET')
|
||||||
|
response = req.urlopen(_request)
|
||||||
|
with open(dst + f'.{time.time_ns()}', 'wb') as f:
|
||||||
|
f.write(response.read())
|
||||||
|
|
||||||
|
self.pool.map(download_by_thread, offset)
|
||||||
|
self.pool.close()
|
||||||
|
self.pool.join()
|
@ -0,0 +1,79 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Time : 2022/8/29 23:14
|
||||||
|
# @Author : old tom
|
||||||
|
# @File : http_response.py
|
||||||
|
# @Project : Futool
|
||||||
|
# @Desc : 响应解析
|
||||||
|
|
||||||
|
from http.client import HTTPResponse
|
||||||
|
from http.cookiejar import CookieJar
|
||||||
|
import json
|
||||||
|
|
||||||
|
DEFAULT_ENCODING = 'UTF-8'
|
||||||
|
|
||||||
|
# 响应类型编码
|
||||||
|
RESPONSE_CONTENT_ENCODING = "Content-Encoding"
|
||||||
|
|
||||||
|
# 压缩类型
|
||||||
|
COMPRESS_TYPE = ('gzip', 'deflate', 'br')
|
||||||
|
|
||||||
|
|
||||||
|
class ResponseWrapper(object):
|
||||||
|
|
||||||
|
def __init__(self, response: HTTPResponse, cookie: CookieJar = None):
|
||||||
|
self.resp = response
|
||||||
|
if cookie and len(cookie) > 0:
|
||||||
|
self.cookie = cookie
|
||||||
|
|
||||||
|
def body(self, encoding=DEFAULT_ENCODING):
|
||||||
|
return self.resp.read().decode(encoding)
|
||||||
|
|
||||||
|
def json_body(self, encoding=DEFAULT_ENCODING):
|
||||||
|
return json.loads(self.body(encoding))
|
||||||
|
|
||||||
|
def status(self):
|
||||||
|
return self.resp.status
|
||||||
|
|
||||||
|
def is_ok(self):
|
||||||
|
st_code = self.resp.status
|
||||||
|
return 200 <= st_code <= 300
|
||||||
|
|
||||||
|
def header(self, name=None):
|
||||||
|
return self.resp.getheader(name) if name else self._parse_header_dict()
|
||||||
|
|
||||||
|
def _parse_header_dict(self):
|
||||||
|
headers = self.resp.getheaders()
|
||||||
|
header_dict = {}
|
||||||
|
if headers:
|
||||||
|
for h in headers:
|
||||||
|
header_dict[h[0]] = h[1]
|
||||||
|
return header_dict
|
||||||
|
|
||||||
|
def is_compress(self):
|
||||||
|
"""
|
||||||
|
是否压缩
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
return self.compress_type() in COMPRESS_TYPE
|
||||||
|
|
||||||
|
def compress_type(self):
|
||||||
|
"""
|
||||||
|
压缩格式
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
header = self.header()
|
||||||
|
if RESPONSE_CONTENT_ENCODING in header.keys():
|
||||||
|
res_content_encoding = header[RESPONSE_CONTENT_ENCODING]
|
||||||
|
return res_content_encoding
|
||||||
|
|
||||||
|
def cookies(self):
|
||||||
|
"""
|
||||||
|
获取cookie
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
ck = {}
|
||||||
|
if self.cookie:
|
||||||
|
for item in self.cookie:
|
||||||
|
ck[item.name] = item.value
|
||||||
|
return ck
|
@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Time : 2023/4/2 9:07
|
||||||
|
# @Author : old tom
|
||||||
|
# @File : __init__.py.py
|
||||||
|
# @Project : futool
|
||||||
|
# @Desc : excel、word操作相关
|
@ -0,0 +1 @@
|
|||||||
|
xltpl~=0.18
|
Loading…
Reference in new issue