ifkit 0.1.51__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ifkit-0.1.51/LICENSE +7 -0
- ifkit-0.1.51/MANIFEST.in +1 -0
- ifkit-0.1.51/PKG-INFO +23 -0
- ifkit-0.1.51/README.md +4 -0
- ifkit-0.1.51/ifkit/__init__.py +9 -0
- ifkit-0.1.51/ifkit/__version__.py +8 -0
- ifkit-0.1.51/ifkit/csv.py +18 -0
- ifkit-0.1.51/ifkit/excel.py +173 -0
- ifkit-0.1.51/ifkit/json.py +11 -0
- ifkit-0.1.51/ifkit/mq.py +62 -0
- ifkit-0.1.51/ifkit/mysql_all_tables.py +31 -0
- ifkit-0.1.51/ifkit/mysql_create_table_statement.py +14 -0
- ifkit-0.1.51/ifkit/mysql_export_excel.py +63 -0
- ifkit-0.1.51/ifkit/qyweixin.py +13 -0
- ifkit-0.1.51/ifkit/sms.py +21 -0
- ifkit-0.1.51/ifkit/txt.py +13 -0
- ifkit-0.1.51/ifkit.egg-info/PKG-INFO +23 -0
- ifkit-0.1.51/ifkit.egg-info/SOURCES.txt +20 -0
- ifkit-0.1.51/ifkit.egg-info/dependency_links.txt +1 -0
- ifkit-0.1.51/ifkit.egg-info/top_level.txt +1 -0
- ifkit-0.1.51/setup.cfg +4 -0
- ifkit-0.1.51/setup.py +131 -0
ifkit-0.1.51/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright 2025 infuq
|
|
2
|
+
|
|
3
|
+
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:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
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.
|
ifkit-0.1.51/MANIFEST.in
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
include README.md LICENSE
|
ifkit-0.1.51/PKG-INFO
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: ifkit
|
|
3
|
+
Version: 0.1.51
|
|
4
|
+
Summary: 日常工作使用的小工具/小功能
|
|
5
|
+
Home-page: https://www.infuq.com
|
|
6
|
+
Author: infuq
|
|
7
|
+
Author-email: 864511259@qq.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
13
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
14
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
15
|
+
Requires-Python: >=3.6.0
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
日常工作使用的小工具/小功能
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
[个人站点](https://www.infuq.com)
|
ifkit-0.1.51/README.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# 8b d8 Yb dP 88""Yb db dP""b8 88 dP db dP""b8 888888
|
|
2
|
+
# 88b d88 YbdP 88__dP dPYb dP `" 88odP dPYb dP `" 88__
|
|
3
|
+
# 88YbdP88 8P 88""" dP__Yb Yb 88"Yb dP__Yb Yb "88 88""
|
|
4
|
+
# 88 YY 88 dP 88 dP""""Yb YboodP 88 Yb dP""""Yb YboodP 888888
|
|
5
|
+
|
|
6
|
+
VERSION = (5, 2, 0)
|
|
7
|
+
|
|
8
|
+
__version__ = '.'.join(map(str, VERSION))
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import csv
|
|
2
|
+
from collections.abc import Iterable
|
|
3
|
+
from collections.abc import Iterator
|
|
4
|
+
|
|
5
|
+
# 读取 CSV 文件
|
|
6
|
+
def read_csv(file_name, encoding='UTF8', start_read_row_num=0):
|
|
7
|
+
row_num = 0
|
|
8
|
+
with open(file_name, 'r', encoding=encoding) as f: # encoding='UTF8' encoding='GBK'
|
|
9
|
+
reader = csv.DictReader(f)
|
|
10
|
+
for row_data in reader:
|
|
11
|
+
if row_num < start_read_row_num:
|
|
12
|
+
row_num = row_num + 1
|
|
13
|
+
continue
|
|
14
|
+
|
|
15
|
+
rn = row_num
|
|
16
|
+
row_num = row_num + 1
|
|
17
|
+
yield (rn, row_data)
|
|
18
|
+
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""
|
|
2
|
+
读取xlsx或xls文件
|
|
3
|
+
|
|
4
|
+
pip install xlrd
|
|
5
|
+
pip install xlwt
|
|
6
|
+
pip install openpyxl
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import openpyxl
|
|
10
|
+
import os
|
|
11
|
+
import xlrd
|
|
12
|
+
import xlwt
|
|
13
|
+
from collections.abc import Iterable
|
|
14
|
+
from collections.abc import Iterator
|
|
15
|
+
import datetime
|
|
16
|
+
import re
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# 读取文件
|
|
20
|
+
class ReadExcelUtil(Iterable):
|
|
21
|
+
|
|
22
|
+
def __init__(self, file_name, start_read_row_num=0):
|
|
23
|
+
self.filename = file_name
|
|
24
|
+
self.suffix = os.path.splitext(self.filename)[-1][1:].lower() # xls xlsx
|
|
25
|
+
self.start_read_row_num = start_read_row_num # 开始从第N行读取数据
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
if self.suffix == 'xlsx':
|
|
29
|
+
self.workbook = openpyxl.load_workbook(self.filename, data_only=True)
|
|
30
|
+
self.sheetnames = self.workbook.sheetnames # Sheet1 Sheet2 Sheet3...
|
|
31
|
+
self.sheet = self.workbook[self.sheetnames[0]] # 根据名称默认读取第一个Sheet
|
|
32
|
+
|
|
33
|
+
if self.suffix == 'xls':
|
|
34
|
+
self.workbook = xlrd.open_workbook(self.filename, encoding_override="UTF-8")
|
|
35
|
+
self.sheetnames = self.workbook._sheet_names # Sheet1 Sheet2 Sheet3...
|
|
36
|
+
# self.sheet = self.workbook[0] # 根据下标默认读取第一个Sheet
|
|
37
|
+
self.sheet = self.workbook[self.sheetnames[0]] # 根据名称默认读取第一个Sheet
|
|
38
|
+
|
|
39
|
+
def __iter__(self):
|
|
40
|
+
if self.suffix == 'xlsx':
|
|
41
|
+
return ReadXlsxIterator(self.sheet, self.start_read_row_num)
|
|
42
|
+
if self.suffix == 'xls':
|
|
43
|
+
return ReadXlsIterator(self.sheet, self.start_read_row_num)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# 迭代器 xlsx
|
|
47
|
+
class ReadXlsxIterator(Iterator):
|
|
48
|
+
|
|
49
|
+
def __init__(self, sheet, start_read_row_num):
|
|
50
|
+
self.sheet = sheet
|
|
51
|
+
self.max_row = sheet.max_row
|
|
52
|
+
self.max_column = sheet.max_column
|
|
53
|
+
self.row_num = start_read_row_num
|
|
54
|
+
|
|
55
|
+
def __next__(self):
|
|
56
|
+
try:
|
|
57
|
+
if self.row_num <= self.max_row:
|
|
58
|
+
# 读取行内容
|
|
59
|
+
row_data = []
|
|
60
|
+
for i in range(1, self.max_column + 1):
|
|
61
|
+
cell_value = self.sheet.cell(row=self.row_num, column=i).value
|
|
62
|
+
row_data.append(cell_value)
|
|
63
|
+
|
|
64
|
+
rn = self.row_num
|
|
65
|
+
self.row_num += 1
|
|
66
|
+
# (行号, 行内容)
|
|
67
|
+
return (rn, row_data)
|
|
68
|
+
except Exception:
|
|
69
|
+
raise StopIteration
|
|
70
|
+
raise StopIteration
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# 迭代器 xls
|
|
74
|
+
class ReadXlsIterator(Iterator):
|
|
75
|
+
|
|
76
|
+
def __init__(self, sheet, start_read_row_num):
|
|
77
|
+
self.sheet = sheet
|
|
78
|
+
self.nrows = sheet.nrows
|
|
79
|
+
self.row_num = start_read_row_num
|
|
80
|
+
|
|
81
|
+
def __next__(self):
|
|
82
|
+
try:
|
|
83
|
+
if self.row_num <= self.nrows:
|
|
84
|
+
# 读取行内容
|
|
85
|
+
# (行号, 行内容)
|
|
86
|
+
rn = self.row_num
|
|
87
|
+
self.row_num += 1
|
|
88
|
+
return (rn, self.sheet.row_values(rn))
|
|
89
|
+
except Exception:
|
|
90
|
+
raise StopIteration
|
|
91
|
+
raise StopIteration
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# 写入文件
|
|
95
|
+
class WriteXlsxUtil(object):
|
|
96
|
+
|
|
97
|
+
def __init__(self, file_name):
|
|
98
|
+
self.index = 0
|
|
99
|
+
self.suffix = '.xlsx'
|
|
100
|
+
self.workbook = openpyxl.Workbook()
|
|
101
|
+
self.sheet = self.workbook.create_sheet(index=self.index, title="Sheet")
|
|
102
|
+
self.empty = True # 标记是否真的写入了内容
|
|
103
|
+
self.row = 0
|
|
104
|
+
if file_name is None:
|
|
105
|
+
self.file_name = "File-" + datetime.datetime.now().strftime('%Y-%m-%d %H-%M-%S') + self.suffix
|
|
106
|
+
else:
|
|
107
|
+
self.file_name = file_name + self.suffix
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def set_sheet(self, sheet_name):
|
|
111
|
+
self.index = self.index + 1
|
|
112
|
+
self.sheet = self.workbook.create_sheet(index=self.index, title=sheet_name)
|
|
113
|
+
self.row = 0
|
|
114
|
+
|
|
115
|
+
# 设置列宽
|
|
116
|
+
def column_width(self, index, width):
|
|
117
|
+
self.sheet.column_dimensions[index].width = width
|
|
118
|
+
|
|
119
|
+
# 写入单元格内容
|
|
120
|
+
def write(self, content):
|
|
121
|
+
self.empty = False
|
|
122
|
+
self.row += 1
|
|
123
|
+
for index in range(1, len(content) + 1): # index = column
|
|
124
|
+
if isinstance(content[index - 1], str) or isinstance(content[index - 1], (int, float)):
|
|
125
|
+
v = str(content[index - 1])
|
|
126
|
+
digit = re.match(r'^\d+(\.\d+)?$', v, re.I)
|
|
127
|
+
if digit:
|
|
128
|
+
self.sheet.cell(self.row, index).value = v
|
|
129
|
+
else:
|
|
130
|
+
self.sheet.cell(self.row, index).value = v
|
|
131
|
+
else:
|
|
132
|
+
cell = content[index - 1]
|
|
133
|
+
self.sheet.cell(self.row, index).value = cell['value']
|
|
134
|
+
if 'color' in cell:
|
|
135
|
+
self.sheet.cell(self.row, index).font = openpyxl.styles.Font(color=cell['color'])
|
|
136
|
+
|
|
137
|
+
# 保存文件
|
|
138
|
+
def save(self):
|
|
139
|
+
if not self.empty:
|
|
140
|
+
self.workbook.save("./" + self.file_name)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
# class WriteXlsUtil(object):
|
|
145
|
+
#
|
|
146
|
+
# def __init__(self, file_name='File'):
|
|
147
|
+
# self.suffix = '.xls'
|
|
148
|
+
# self.workbook = xlwt.Workbook()
|
|
149
|
+
# self.sheet = self.workbook.add_sheet("Sheet")
|
|
150
|
+
# self.file_name = file_name
|
|
151
|
+
# self.empty = True
|
|
152
|
+
# self.row = -1
|
|
153
|
+
#
|
|
154
|
+
# # 写入单元格内容
|
|
155
|
+
# def write(self, content):
|
|
156
|
+
# self.empty = False
|
|
157
|
+
# self.row += 1
|
|
158
|
+
# for index in range(len(content)):
|
|
159
|
+
# cnt = str(content[index])
|
|
160
|
+
# if cnt.isdigit():
|
|
161
|
+
# self.sheet.write(self.row, index, cnt.zfill(len(cnt)))
|
|
162
|
+
# else:
|
|
163
|
+
# self.sheet.write(self.row, index, content[index])
|
|
164
|
+
#
|
|
165
|
+
# # 保存文件
|
|
166
|
+
# def save(self):
|
|
167
|
+
# if not self.empty:
|
|
168
|
+
# self.workbook.save("./" + self.file_name + "-" + datetime.datetime.now().strftime('%Y-%m-%d %H-%M-%S') + self.suffix)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
__all__ = ['ReadExcelUtil', 'WriteXlsxUtil']
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from datetime import date, datetime
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
class ComplexEncoder(json.JSONEncoder):
|
|
5
|
+
def default(self, obj):
|
|
6
|
+
if isinstance(obj, datetime):
|
|
7
|
+
return obj.strftime('%Y-%m-%d %H:%M:%S')
|
|
8
|
+
elif isinstance(obj, date):
|
|
9
|
+
return obj.strftime('%Y-%m-%d')
|
|
10
|
+
else:
|
|
11
|
+
return json.JSONEncoder.default(self, obj)
|
ifkit-0.1.51/ifkit/mq.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""
|
|
2
|
+
pip install mq_http_sdk
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
import time
|
|
7
|
+
from mq_http_sdk.mq_exception import MQExceptionBase
|
|
8
|
+
from mq_http_sdk.mq_producer import *
|
|
9
|
+
from mq_http_sdk.mq_client import *
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# 生产者通过HTTP协议发送消息
|
|
13
|
+
def send_http(host, access_id, access_key, instance_id, topic_name, message_body, message_tag, message_key):
|
|
14
|
+
mq_client = MQClient(host=host, access_id=access_id, access_key=access_key)
|
|
15
|
+
|
|
16
|
+
producer = mq_client.get_producer(instance_id, topic_name)
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
msg = TopicMessage(message_body, message_tag)
|
|
20
|
+
msg.put_property("__key", "__value") # 设置属性
|
|
21
|
+
msg.set_message_key(message_key)
|
|
22
|
+
# msg.set_sharding_key("")
|
|
23
|
+
|
|
24
|
+
re_msg = producer.publish_message(msg)
|
|
25
|
+
return re_msg.message_id
|
|
26
|
+
except MQExceptionBase as e:
|
|
27
|
+
if e.type == "TopicNotExist":
|
|
28
|
+
print("Topic not exist, please create it.")
|
|
29
|
+
print("Publish Message Fail. Exception:%s" % e)
|
|
30
|
+
|
|
31
|
+
return None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# 消费者通过HTTP协议消费消息
|
|
35
|
+
def consume_loop_http(host, access_id, access_key, instance_id, topic_name, group_id, callback):
|
|
36
|
+
|
|
37
|
+
mq_client = MQClient(host=host, access_id=access_id, access_key=access_key)
|
|
38
|
+
consumer = mq_client.get_consumer(instance_id, topic_name, group_id)
|
|
39
|
+
wait_seconds = 3
|
|
40
|
+
batch = 3
|
|
41
|
+
while True:
|
|
42
|
+
try:
|
|
43
|
+
# recv_msgs = consumer.consume_message_orderly(batch, wait_seconds)
|
|
44
|
+
recv_msgs = consumer.consume_message(batch, wait_seconds)
|
|
45
|
+
for message in recv_msgs:
|
|
46
|
+
# 回调业务方法
|
|
47
|
+
callback(message)
|
|
48
|
+
consumer.ack_message(message.receipt_handle.split())
|
|
49
|
+
|
|
50
|
+
except MQExceptionBase as e:
|
|
51
|
+
if e.type == "MessageNotExist":
|
|
52
|
+
# print(("No new message! RequestId: %s" % e.req_id))
|
|
53
|
+
# continue
|
|
54
|
+
# break
|
|
55
|
+
time.sleep(5)
|
|
56
|
+
continue
|
|
57
|
+
|
|
58
|
+
print(("Consume Message Fail! Exception:%s\n" % e))
|
|
59
|
+
time.sleep(2)
|
|
60
|
+
continue
|
|
61
|
+
|
|
62
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#! /usr/bin/env python
|
|
2
|
+
|
|
3
|
+
import pymysql
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _find_all_tables(cursor, table_schema):
|
|
7
|
+
sql = "SELECT * FROM information_schema.tables WHERE table_schema = '%s';"
|
|
8
|
+
sql = sql % (table_schema,)
|
|
9
|
+
cursor.execute(sql)
|
|
10
|
+
all_data = cursor.fetchall()
|
|
11
|
+
all_tables = []
|
|
12
|
+
for data in all_data:
|
|
13
|
+
all_tables.append(data['TABLE_NAME'])
|
|
14
|
+
return all_tables
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def find_all_tables(host, port, user, passwd, db):
|
|
18
|
+
conn = pymysql.connect(host=host,
|
|
19
|
+
port=port,
|
|
20
|
+
user=user,
|
|
21
|
+
passwd=passwd,
|
|
22
|
+
db=db)
|
|
23
|
+
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
|
|
24
|
+
|
|
25
|
+
all_tables = _find_all_tables(cursor, db)
|
|
26
|
+
|
|
27
|
+
cursor.close()
|
|
28
|
+
conn.close()
|
|
29
|
+
|
|
30
|
+
return all_tables
|
|
31
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#! /usr/bin/env python
|
|
2
|
+
|
|
3
|
+
def show_create_table(cursor, table_name):
|
|
4
|
+
try:
|
|
5
|
+
sql = "show create table %s"
|
|
6
|
+
sql = sql % (table_name,)
|
|
7
|
+
cursor.execute(sql)
|
|
8
|
+
all_data = cursor.fetchall()
|
|
9
|
+
return all_data[0]['Create Table']
|
|
10
|
+
except Exception as e:
|
|
11
|
+
print(e)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#! /usr/bin/env python
|
|
2
|
+
|
|
3
|
+
import decimal
|
|
4
|
+
import re
|
|
5
|
+
|
|
6
|
+
import pymysql
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def export_excel(host, port, user, passwd, db, query_sql, file_name=None):
|
|
10
|
+
conn = pymysql.connect(host=host,
|
|
11
|
+
port=port,
|
|
12
|
+
user=user,
|
|
13
|
+
passwd=passwd,
|
|
14
|
+
db=db)
|
|
15
|
+
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
|
|
16
|
+
|
|
17
|
+
from .excel import WriteXlsxUtil
|
|
18
|
+
write_book = WriteXlsxUtil(file_name)
|
|
19
|
+
|
|
20
|
+
cursor.execute(query_sql)
|
|
21
|
+
alias_field = alias(cursor.description)
|
|
22
|
+
write_book.write(tuple(alias_field))
|
|
23
|
+
|
|
24
|
+
all_data = cursor.fetchall()
|
|
25
|
+
for data in all_data:
|
|
26
|
+
data_list = []
|
|
27
|
+
for field in alias_field:
|
|
28
|
+
value = data[field]
|
|
29
|
+
data_list.append(replace(value))
|
|
30
|
+
write_book.write(tuple(data_list))
|
|
31
|
+
|
|
32
|
+
# 保存文件
|
|
33
|
+
write_book.save()
|
|
34
|
+
|
|
35
|
+
# 关闭数据库连接
|
|
36
|
+
cursor.close()
|
|
37
|
+
conn.close()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def alias(description):
|
|
41
|
+
alias_field = []
|
|
42
|
+
for i in range(len(description)):
|
|
43
|
+
alias_field.append(description[i][0])
|
|
44
|
+
return alias_field
|
|
45
|
+
|
|
46
|
+
def replace(data):
|
|
47
|
+
if data:
|
|
48
|
+
if isinstance(data, decimal.Decimal):
|
|
49
|
+
if data == 0:
|
|
50
|
+
return 0
|
|
51
|
+
else:
|
|
52
|
+
return replace(str(data))
|
|
53
|
+
elif isinstance(data, str):
|
|
54
|
+
# 70.10 -> 70.1
|
|
55
|
+
data = re.sub(r'^(.*\.\d+?)0+$', r'\1', data)
|
|
56
|
+
# 70.00 -> 70
|
|
57
|
+
data = re.sub(r'^(.*)\.0+$', r'\1', data)
|
|
58
|
+
|
|
59
|
+
return data
|
|
60
|
+
else:
|
|
61
|
+
return replace(str(data))
|
|
62
|
+
else:
|
|
63
|
+
return ''
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
|
|
3
|
+
def send_markdown_message(content, key):
|
|
4
|
+
url = 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=%s'
|
|
5
|
+
url = url % (key,)
|
|
6
|
+
payload = {
|
|
7
|
+
'msgtype': 'markdown',
|
|
8
|
+
'markdown': {
|
|
9
|
+
'content': content
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
response = requests.post(url, json=payload)
|
|
13
|
+
return response.json()
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
|
|
3
|
+
# 发送短信
|
|
4
|
+
def send_sms(content, accesskey, secret, sign, templateId, mobile):
|
|
5
|
+
|
|
6
|
+
headers = {
|
|
7
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
data = {
|
|
11
|
+
'accesskey': accesskey,
|
|
12
|
+
'secret': secret,
|
|
13
|
+
'sign': sign,
|
|
14
|
+
'templateId': templateId,
|
|
15
|
+
'mobile': mobile,
|
|
16
|
+
'content': content
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
# 发送
|
|
20
|
+
response = requests.post('http://api.1cloudsp.com/api/v2/single_send', data=data, headers=headers)
|
|
21
|
+
return response.text
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
|
|
2
|
+
# 读取 txt 文件
|
|
3
|
+
def read_txt(file_name, encoding='GBK', start_read_row_num=0):
|
|
4
|
+
row_num = 0
|
|
5
|
+
with open(file_name, 'r', encoding=encoding) as f:
|
|
6
|
+
for row_data in f.readlines():
|
|
7
|
+
if row_num < start_read_row_num:
|
|
8
|
+
row_num = row_num + 1
|
|
9
|
+
continue
|
|
10
|
+
|
|
11
|
+
rn = row_num
|
|
12
|
+
row_num = row_num + 1
|
|
13
|
+
yield (rn, row_data)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: ifkit
|
|
3
|
+
Version: 0.1.51
|
|
4
|
+
Summary: 日常工作使用的小工具/小功能
|
|
5
|
+
Home-page: https://www.infuq.com
|
|
6
|
+
Author: infuq
|
|
7
|
+
Author-email: 864511259@qq.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
13
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
14
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
15
|
+
Requires-Python: >=3.6.0
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
日常工作使用的小工具/小功能
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
[个人站点](https://www.infuq.com)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
setup.py
|
|
5
|
+
ifkit/__init__.py
|
|
6
|
+
ifkit/__version__.py
|
|
7
|
+
ifkit/csv.py
|
|
8
|
+
ifkit/excel.py
|
|
9
|
+
ifkit/json.py
|
|
10
|
+
ifkit/mq.py
|
|
11
|
+
ifkit/mysql_all_tables.py
|
|
12
|
+
ifkit/mysql_create_table_statement.py
|
|
13
|
+
ifkit/mysql_export_excel.py
|
|
14
|
+
ifkit/qyweixin.py
|
|
15
|
+
ifkit/sms.py
|
|
16
|
+
ifkit/txt.py
|
|
17
|
+
ifkit.egg-info/PKG-INFO
|
|
18
|
+
ifkit.egg-info/SOURCES.txt
|
|
19
|
+
ifkit.egg-info/dependency_links.txt
|
|
20
|
+
ifkit.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ifkit
|
ifkit-0.1.51/setup.cfg
ADDED
ifkit-0.1.51/setup.py
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
# Note: To use the 'upload' functionality of this file, you must:
|
|
5
|
+
# $ pipenv install twine --dev
|
|
6
|
+
|
|
7
|
+
import io
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
from shutil import rmtree
|
|
11
|
+
|
|
12
|
+
from setuptools import find_packages, setup, Command
|
|
13
|
+
|
|
14
|
+
# Package meta-data.
|
|
15
|
+
NAME = 'ifkit'
|
|
16
|
+
DESCRIPTION = '日常工作使用的小工具/小功能'
|
|
17
|
+
URL = 'https://www.infuq.com'
|
|
18
|
+
EMAIL = '864511259@qq.com'
|
|
19
|
+
AUTHOR = 'infuq'
|
|
20
|
+
REQUIRES_PYTHON = '>=3.6.0'
|
|
21
|
+
VERSION = '0.1.51'
|
|
22
|
+
|
|
23
|
+
# What packages are required for this module to be executed?
|
|
24
|
+
REQUIRED = [
|
|
25
|
+
# 'requests', 'maya', 'records',
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
# What packages are optional?
|
|
29
|
+
EXTRAS = {
|
|
30
|
+
# 'fancy feature': ['django'],
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
# The rest you shouldn't have to touch too much :)
|
|
34
|
+
# ------------------------------------------------
|
|
35
|
+
# Except, perhaps the License and Trove Classifiers!
|
|
36
|
+
# If you do change the License, remember to change the Trove Classifier for that!
|
|
37
|
+
|
|
38
|
+
here = os.path.abspath(os.path.dirname(__file__))
|
|
39
|
+
|
|
40
|
+
# Import the README and use it as the long-description.
|
|
41
|
+
# Note: this will only work if 'README.md' is present in your MANIFEST.in file!
|
|
42
|
+
try:
|
|
43
|
+
with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f:
|
|
44
|
+
long_description = '\n' + f.read()
|
|
45
|
+
except FileNotFoundError:
|
|
46
|
+
long_description = DESCRIPTION
|
|
47
|
+
|
|
48
|
+
# Load the package's __version__.py module as a dictionary.
|
|
49
|
+
about = {}
|
|
50
|
+
if not VERSION:
|
|
51
|
+
project_slug = NAME.lower().replace("-", "_").replace(" ", "_")
|
|
52
|
+
with open(os.path.join(here, project_slug, '__version__.py')) as f:
|
|
53
|
+
exec(f.read(), about)
|
|
54
|
+
else:
|
|
55
|
+
about['__version__'] = VERSION
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class UploadCommand(Command):
|
|
59
|
+
"""Support setup.py upload."""
|
|
60
|
+
|
|
61
|
+
description = 'Build and publish the package.'
|
|
62
|
+
user_options = []
|
|
63
|
+
|
|
64
|
+
@staticmethod
|
|
65
|
+
def status(s):
|
|
66
|
+
"""Prints things in bold."""
|
|
67
|
+
print('\033[1m{0}\033[0m'.format(s))
|
|
68
|
+
|
|
69
|
+
def initialize_options(self):
|
|
70
|
+
pass
|
|
71
|
+
|
|
72
|
+
def finalize_options(self):
|
|
73
|
+
pass
|
|
74
|
+
|
|
75
|
+
def run(self):
|
|
76
|
+
try:
|
|
77
|
+
self.status('Removing previous builds…')
|
|
78
|
+
rmtree(os.path.join(here, 'dist'))
|
|
79
|
+
except OSError:
|
|
80
|
+
pass
|
|
81
|
+
|
|
82
|
+
self.status('Building Source and Wheel (universal) distribution…')
|
|
83
|
+
os.system('{0} setup.py sdist bdist_wheel --universal'.format(sys.executable))
|
|
84
|
+
|
|
85
|
+
self.status('Uploading the package to PyPI via Twine…')
|
|
86
|
+
os.system('twine upload dist/*')
|
|
87
|
+
|
|
88
|
+
self.status('Pushing git tags…')
|
|
89
|
+
os.system('git tag v{0}'.format(about['__version__']))
|
|
90
|
+
os.system('git push --tags')
|
|
91
|
+
|
|
92
|
+
sys.exit()
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# Where the magic happens:
|
|
96
|
+
setup(
|
|
97
|
+
name=NAME,
|
|
98
|
+
version=about['__version__'],
|
|
99
|
+
description=DESCRIPTION,
|
|
100
|
+
long_description=long_description,
|
|
101
|
+
long_description_content_type='text/markdown',
|
|
102
|
+
author=AUTHOR,
|
|
103
|
+
author_email=EMAIL,
|
|
104
|
+
python_requires=REQUIRES_PYTHON,
|
|
105
|
+
url=URL,
|
|
106
|
+
packages=find_packages(exclude=["tests", "*.tests", "*.tests.*", "tests.*"]),
|
|
107
|
+
# If your package is a single module, use this instead of 'packages':
|
|
108
|
+
# py_modules=['mypackage'],
|
|
109
|
+
|
|
110
|
+
# entry_points={
|
|
111
|
+
# 'console_scripts': ['mycli=mymodule:cli'],
|
|
112
|
+
# },
|
|
113
|
+
install_requires=REQUIRED,
|
|
114
|
+
extras_require=EXTRAS,
|
|
115
|
+
include_package_data=True,
|
|
116
|
+
license='MIT',
|
|
117
|
+
classifiers=[
|
|
118
|
+
# Trove classifiers
|
|
119
|
+
# Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers
|
|
120
|
+
'License :: OSI Approved :: MIT License',
|
|
121
|
+
'Programming Language :: Python',
|
|
122
|
+
'Programming Language :: Python :: 3',
|
|
123
|
+
'Programming Language :: Python :: 3.6',
|
|
124
|
+
'Programming Language :: Python :: Implementation :: CPython',
|
|
125
|
+
'Programming Language :: Python :: Implementation :: PyPy'
|
|
126
|
+
],
|
|
127
|
+
# $ setup.py publish support.
|
|
128
|
+
cmdclass={
|
|
129
|
+
'upload': UploadCommand,
|
|
130
|
+
},
|
|
131
|
+
)
|