lesscode-flask 0.0.40__tar.gz → 0.0.42__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.
Files changed (53) hide show
  1. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/PKG-INFO +1 -1
  2. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/__init__.py +1 -1
  3. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/app.py +9 -5
  4. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/db/__init__.py +2 -1
  5. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/service/base_service.py +3 -1
  6. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/utils/helpers.py +32 -2
  7. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/utils/request/request.py +2 -0
  8. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask.egg-info/PKG-INFO +1 -1
  9. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/redash/query_runner/clickhouse.py +43 -81
  10. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/redash/query_runner/elasticsearch.py +2 -1
  11. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/README.md +0 -0
  12. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/db/datasource.py +0 -0
  13. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/db/executor.py +0 -0
  14. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/log/access_log_handler.py +0 -0
  15. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/model/access_log.py +0 -0
  16. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/model/auth_client.py +0 -0
  17. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/model/auth_permission.py +0 -0
  18. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/model/base_model.py +0 -0
  19. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/model/parameterized_query.py +0 -0
  20. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/model/response_result.py +0 -0
  21. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/model/user.py +0 -0
  22. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/service/access_log_service.py +0 -0
  23. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/service/auth_client_service.py +0 -0
  24. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/service/auth_permission_service.py +0 -0
  25. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/service/authentication_service.py +0 -0
  26. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/setting/__init__.py +0 -0
  27. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/setup/__init__.py +0 -0
  28. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/utils/__init__.py +0 -0
  29. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/utils/decorator/__init__.py +0 -0
  30. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/utils/decorator/cache.py +0 -0
  31. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/utils/decorator/swagger.py +0 -0
  32. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/utils/file/file_exporter.py +0 -0
  33. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/utils/json/NotSortJSONProvider.py +0 -0
  34. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/utils/oss/__init__.py +0 -0
  35. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/utils/oss/ks3_oss.py +0 -0
  36. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/utils/redis/redis_helper.py +0 -0
  37. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/utils/swagger/swagger_template.py +0 -0
  38. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/utils/swagger/swagger_util.py +0 -0
  39. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask/wsgi.py +0 -0
  40. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask.egg-info/SOURCES.txt +0 -0
  41. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask.egg-info/dependency_links.txt +0 -0
  42. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask.egg-info/requires.txt +0 -0
  43. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/lesscode_flask.egg-info/top_level.txt +0 -0
  44. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/redash/query_runner/__init__.py +0 -0
  45. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/redash/query_runner/kingbase.py +0 -0
  46. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/redash/query_runner/mysql.py +0 -0
  47. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/redash/query_runner/pg.py +0 -0
  48. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/redash/settings/__init__.py +0 -0
  49. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/redash/settings/helpers.py +0 -0
  50. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/redash/utils/__init__.py +0 -0
  51. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/redash/utils/requests_session.py +0 -0
  52. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/setup.cfg +0 -0
  53. {lesscode_flask-0.0.40 → lesscode_flask-0.0.42}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lesscode-flask
3
- Version: 0.0.40
3
+ Version: 0.0.42
4
4
  Summary: lesscode-flask 是基于flask的web开发脚手架项目,该项目初衷为简化开发过程,让研发人员更加关注业务。
5
5
  Home-page: https://lesscode-flask
6
6
  Author: Chao.yy
@@ -1,4 +1,4 @@
1
- __version__ = '0.0.40'
1
+ __version__ = '0.0.42'
2
2
 
3
3
  import functools
4
4
  import logging
@@ -5,17 +5,17 @@ import logging
5
5
  import os
6
6
  import time
7
7
  import traceback
8
-
9
- from flask import Flask, typing as ft, abort, Response
10
8
  import typing as t
9
+ from flask import Flask, typing as ft, abort, Response
11
10
  from flask.globals import request_ctx, request
12
11
  from flask_login import current_user
13
12
  from lesscode_utils.json_utils import JSONEncoder
14
13
  from werkzeug.middleware.proxy_fix import ProxyFix
15
- from lesscode_flask.utils.helpers import inject_args, generate_uuid, app_config
14
+
16
15
  from lesscode_flask.model.response_result import ResponseResult
17
16
  from lesscode_flask.setup import setup_blueprint, setup_logging, setup_query_runner, setup_swagger, setup_sql_alchemy, \
18
17
  setup_redis, setup_login_manager
18
+ from lesscode_flask.utils.helpers import inject_args, generate_uuid, app_config
19
19
  from lesscode_flask.utils.json.NotSortJSONProvider import NotSortJSONProvider
20
20
  from lesscode_flask.utils.redis.redis_helper import RedisHelper
21
21
 
@@ -41,8 +41,12 @@ class Lesscoder(Flask):
41
41
  # 这里的ProxyFix通常用于修复在反向代理环境下WSGI应用收到的客户端地址和主机头信息。
42
42
  self.wsgi_app = ProxyFix(self.wsgi_app, x_for=1, x_host=1)
43
43
  # # Configure Redash using our settings
44
- setting_name = "setting.config_{}.Config".format(os.getenv("profile")) if os.getenv(
45
- "profile") else "setting.config.Config"
44
+ profile_list = [item for item in sys.argv if item.__contains__("--profile=")]
45
+ if profile_list: # 如果有指定配置文件,更新参数,如果指定多次,取最后一次
46
+ profile = profile_list[-1].replace('--profile=', '')
47
+ setting_name = "setting.config_{}.Config".format(profile)
48
+ else:
49
+ setting_name = "setting.config.Config"
46
50
  self.config.from_object(setting_name)
47
51
  self.register_error_handler(Exception, self.handle_exception)
48
52
 
@@ -21,7 +21,8 @@ def execute_query(
21
21
  if parameters is None:
22
22
  parameters = {}
23
23
  query.apply(parameters)
24
- query_text = query_runner.apply_auto_limit(query.text, should_apply_auto_limit)
24
+ query_text = query.query
25
+ # query_text = query_runner.apply_auto_limit(query.text, should_apply_auto_limit)
25
26
  logging.info("query_text:{}".format(query_text))
26
27
  return QueryExecutor(
27
28
  query_text,
@@ -4,7 +4,8 @@ from flask_login import current_user
4
4
 
5
5
  from lesscode_flask.db import db
6
6
  from lesscode_flask.model.base_model import BaseModel
7
- from lesscode_flask.utils.helpers import serialize_result_to_dict, parameter_validation, alchemy_result_to_dict
7
+ from lesscode_flask.utils.helpers import serialize_result_to_dict, parameter_validation, alchemy_result_to_dict, \
8
+ format_page_index
8
9
 
9
10
  logger = logging.getLogger(__name__)
10
11
 
@@ -168,6 +169,7 @@ class BaseService:
168
169
  data = alchemy_result_to_dict(items)
169
170
  else:
170
171
  data = serialize_result_to_dict(items)
172
+ format_page_index(data, page_num, page_size)
171
173
  result = {"dataSource": data, "total": total,
172
174
  "has_prev": has_prev,
173
175
  "has_next": has_next}
@@ -109,8 +109,12 @@ def inject_args(req, func, view_args={}):
109
109
  args = req.args
110
110
  form = req.form
111
111
  files = req.files
112
- if req.mimetype == 'application/json' and req.json is not None:
113
- jsons = req.json
112
+ if req.mimetype == 'application/json':
113
+ try:
114
+ if req.json is not None:
115
+ jsons = req.json
116
+ except Exception as e:
117
+ pass
114
118
  # 合并args、form和json参数字典
115
119
  arguments = dict(**args, **form, **jsons, **files, **view_args)
116
120
  # 获取处理方法的 参数签名
@@ -160,3 +164,29 @@ def mustache_render(template, **kwargs):
160
164
  template = Template(template)
161
165
  # 渲染模板
162
166
  return template.render(**kwargs)
167
+
168
+
169
+ def format_list_index(data_list, index=1, index_key="index"):
170
+ """
171
+ 为数据源提供
172
+ :param data_list:
173
+ :param index:
174
+ :param index_key:
175
+ :return:
176
+ """
177
+ for data in data_list:
178
+ data[index_key] = str(index)
179
+ index = index + 1
180
+
181
+
182
+ def format_page_index(data_list, page_num, page_size, index_key="index"):
183
+ """
184
+
185
+ :param data_list:
186
+ :param page_num:
187
+ :param page_size:
188
+ :param index_key:
189
+ :return:
190
+ """
191
+ index = (page_num - 1) * page_size + 1
192
+ format_list_index(data_list, index, index_key=index_key)
@@ -1,4 +1,5 @@
1
1
  import importlib
2
+ import logging
2
3
  import random
3
4
  import uuid
4
5
 
@@ -26,6 +27,7 @@ def sync_common_request(method, path, params=None, data=None, json=None, base_ur
26
27
  with httpx.Client(**connect_config) as session:
27
28
  try:
28
29
  res = session.request(method.upper(), url=base_url + path, params=params, data=data, json=json, **kwargs)
30
+ logging.error("res返回值是{}".format(res))
29
31
  if result_type == "json":
30
32
  res = res.json()
31
33
  if not pack:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lesscode-flask
3
- Version: 0.0.40
3
+ Version: 0.0.42
4
4
  Summary: lesscode-flask 是基于flask的web开发脚手架项目,该项目初衷为简化开发过程,让研发人员更加关注业务。
5
5
  Home-page: https://lesscode-flask
6
6
  Author: Chao.yy
@@ -1,28 +1,15 @@
1
1
  import logging
2
2
  import re
3
3
  from urllib.parse import urlparse
4
- from uuid import uuid4
5
4
 
6
5
  import requests
7
6
 
8
- from redash.query_runner import (
9
- TYPE_DATE,
10
- TYPE_DATETIME,
11
- TYPE_FLOAT,
12
- TYPE_INTEGER,
13
- TYPE_STRING,
14
- BaseSQLQueryRunner,
15
- register,
16
- split_sql_statements,
17
- )
7
+ from redash.query_runner import *
8
+ from redash.utils import json_dumps, json_loads
18
9
 
19
10
  logger = logging.getLogger(__name__)
20
11
 
21
12
 
22
- def split_multi_query(query):
23
- return [st for st in split_sql_statements(query) if st != ""]
24
-
25
-
26
13
  class ClickHouse(BaseSQLQueryRunner):
27
14
  noop_query = "SELECT 1"
28
15
 
@@ -52,6 +39,10 @@ class ClickHouse(BaseSQLQueryRunner):
52
39
  "secret": ["password"],
53
40
  }
54
41
 
42
+ @classmethod
43
+ def type(cls):
44
+ return "clickhouse"
45
+
55
46
  @property
56
47
  def _url(self):
57
48
  return urlparse(self.configuration["url"])
@@ -82,7 +73,9 @@ class ClickHouse(BaseSQLQueryRunner):
82
73
  results, error = self.run_query(query, None)
83
74
 
84
75
  if error is not None:
85
- self._handle_run_query_error(error)
76
+ raise Exception("Failed getting schema.")
77
+
78
+ results = json_loads(results)
86
79
 
87
80
  for row in results["rows"]:
88
81
  table_name = "{}.{}".format(row["database"], row["table"])
@@ -94,49 +87,31 @@ class ClickHouse(BaseSQLQueryRunner):
94
87
 
95
88
  return list(schema.values())
96
89
 
97
- def _send_query(self, data, session_id=None, session_check=None):
90
+ def _send_query(self, data, stream=False):
98
91
  url = self.configuration.get("url", "http://127.0.0.1:8123")
99
- timeout = self.configuration.get("timeout", 30)
100
-
101
- params = {
102
- "user": self.configuration.get("user", "default"),
103
- "password": self.configuration.get("password", ""),
104
- "database": self.configuration["dbname"],
105
- "default_format": "JSON",
106
- }
107
-
108
- if session_id:
109
- params["session_id"] = session_id
110
- params["session_check"] = "1" if session_check else "0"
111
- params["session_timeout"] = timeout
112
-
113
92
  try:
114
93
  verify = self.configuration.get("verify", True)
115
94
  r = requests.post(
116
95
  url,
117
- data=data.encode("utf-8", "ignore"),
118
- stream=False,
119
- timeout=timeout,
120
- params=params,
96
+ data=data.encode("utf-8","ignore"),
97
+ stream=stream,
98
+ timeout=self.configuration.get("timeout", 30),
99
+ params={
100
+ "user": self.configuration.get("user", "default"),
101
+ "password": self.configuration.get("password", ""),
102
+ "database": self.configuration["dbname"],
103
+ },
121
104
  verify=verify,
122
105
  )
123
-
124
- if not r.ok:
106
+ if r.status_code != 200:
125
107
  raise Exception(r.text)
126
-
127
- # In certain situations the response body can be empty even if the query was successful, for example
128
- # when creating temporary tables.
129
- if not r.text:
130
- return {}
131
-
132
- response = r.json()
133
- if "exception" in response:
134
- raise Exception(response["exception"])
135
-
136
- return response
108
+ # logging.warning(r.json())
109
+ return r.json()
137
110
  except requests.RequestException as e:
138
111
  if e.response:
139
- details = "({}, Status Code: {})".format(e.__class__.__name__, e.response.status_code)
112
+ details = "({}, Status Code: {})".format(
113
+ e.__class__.__name__, e.response.status_code
114
+ )
140
115
  else:
141
116
  details = "({})".format(e.__class__.__name__)
142
117
  raise Exception("Connection error to: {} {}.".format(url, details))
@@ -158,30 +133,29 @@ class ClickHouse(BaseSQLQueryRunner):
158
133
  else:
159
134
  return TYPE_STRING
160
135
 
161
- def _clickhouse_query(self, query, session_id=None, session_check=None):
162
- logger.debug(f"{self.name()} is about to execute query: %s", query)
163
-
136
+ def _clickhouse_query(self, query):
164
137
  query += "\nFORMAT JSON"
165
-
166
- response = self._send_query(query, session_id, session_check)
167
-
138
+ result = self._send_query(query)
168
139
  columns = []
169
140
  columns_int64 = [] # db converts value to string if its type equals UInt64
170
141
  columns_totals = {}
171
142
 
172
- meta = response.get("meta", [])
173
- for r in meta:
143
+ for r in result["meta"]:
174
144
  column_name = r["name"]
175
145
  column_type = self._define_column_type(r["type"])
176
146
 
177
147
  if r["type"] in ("Int64", "UInt64", "Nullable(Int64)", "Nullable(UInt64)"):
178
148
  columns_int64.append(column_name)
179
149
  else:
180
- columns_totals[column_name] = "Total" if column_type == TYPE_STRING else None
150
+ columns_totals[column_name] = (
151
+ "Total" if column_type == TYPE_STRING else None
152
+ )
181
153
 
182
- columns.append({"name": column_name, "friendly_name": column_name, "type": column_type})
154
+ columns.append(
155
+ {"name": column_name, "friendly_name": column_name, "type": column_type}
156
+ )
183
157
 
184
- rows = response.get("data", [])
158
+ rows = result["data"]
185
159
  for row in rows:
186
160
  for column in columns_int64:
187
161
  try:
@@ -189,8 +163,8 @@ class ClickHouse(BaseSQLQueryRunner):
189
163
  except TypeError:
190
164
  row[column] = None
191
165
 
192
- if "totals" in response:
193
- totals = response["totals"]
166
+ if "totals" in result:
167
+ totals = result["totals"]
194
168
  for column, value in columns_totals.items():
195
169
  totals[column] = value
196
170
  rows.append(totals)
@@ -198,27 +172,15 @@ class ClickHouse(BaseSQLQueryRunner):
198
172
  return {"columns": columns, "rows": rows}
199
173
 
200
174
  def run_query(self, query, user):
201
- queries = split_multi_query(query)
202
-
203
- if not queries:
204
- data = None
175
+ logger.debug("Clickhouse is about to execute query: %s", query)
176
+ if query == "":
177
+ json_data = None
205
178
  error = "Query is empty"
206
- return data, error
207
-
179
+ return json_data, error
208
180
  try:
209
- # If just one query was given no session is needed
210
- if len(queries) == 1:
211
- data = self._clickhouse_query(queries[0])
212
- else:
213
- # If more than one query was given, a session is needed. Parameter session_check must be false
214
- # for the first query
215
- session_id = "redash_{}".format(uuid4().hex)
216
-
217
- data = self._clickhouse_query(queries[0], session_id, session_check=False)
218
-
219
- for query in queries[1:]:
220
- data = self._clickhouse_query(query, session_id, session_check=True)
221
-
181
+ q = self._clickhouse_query(query)
182
+ # data = json_dumps(q)
183
+ data = q
222
184
  error = None
223
185
  except Exception as e:
224
186
  data = None
@@ -436,7 +436,8 @@ class Kibana(BaseElasticSearch):
436
436
  # TODO: Handle complete ElasticSearch queries (JSON based sent over HTTP POST)
437
437
  raise Exception("Advanced queries are not supported")
438
438
 
439
- json_data = json_dumps({"columns": result_columns, "rows": result_rows})
439
+ # json_data = json_dumps({"columns": result_columns, "rows": result_rows})
440
+ json_data = {"columns": result_columns, "rows": result_rows}
440
441
  except requests.HTTPError as e:
441
442
  logger.exception(e)
442
443
  error = "Failed to execute query. Return Code: {0} Reason: {1}".format(