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