Skip to content

Commit ac2e4b3

Browse files
authored
Merge pull request #34 from kinegratii/dev
Release v0.5.2
2 parents 157e7ce + 98a5a97 commit ac2e4b3

39 files changed

+638
-124
lines changed

.github/dependabot.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: pip
4+
directory: "/"
5+
schedule:
6+
interval: daily
7+
target-branch: "dev"

.github/workflows/unittest.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ jobs:
2828
pip install borax>=3.5
2929
pip install pyecharts~=1.9
3030
pip install typing_extensions~=4.0
31+
pip install htmlgenerator~=1.2
3132
pip install flake8~=3.9
3233
pip install nose2~=0.10
3334
- name: Lint with flake8

MANIFEST.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
recursive-include django_echarts/templates/ *.tpl *.py *.html
1+
recursive-include django_echarts/templates *.tpl *.py *.html
22
include django_echarts/contrib/*.html
33
include django_echarts/contrib/*/*.html
44
include django_echarts/contrib/*/*/*.html

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ Build on [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/)
140140

141141
## 示例项目(Demo Project)
142142

143+
在线示例 [https://zinc.pythonanywhere.com](https://zinc.pythonanywhere.com)
144+
143145
参见项目 [kinegratii/zinc](https://github.com/kinegratii/zinc)
144146

145147
## 截图(Screen Shots)

django_echarts/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
A django app for Echarts integration with pyecharts as chart builder.
33
"""
44

5-
__version__ = '0.5.1'
5+
__version__ = '0.5.2'
66
__author__ = 'kinegratii'

django_echarts/conf.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"""
44
Expose the settings objects.
55
"""
6-
6+
import os
77
from django.conf import settings
88
from django.utils.functional import SimpleLazyObject
99

@@ -14,13 +14,20 @@
1414

1515
def get_django_echarts_settings():
1616
project_echarts_settings = getattr(settings, 'DJANGO_ECHARTS', {})
17+
static_url = settings.STATIC_URL
18+
if settings.STATICFILES_DIRS:
19+
staticfiles_dir = str(settings.STATICFILES_DIRS[0])
20+
else:
21+
staticfiles_dir = os.path.join(str(settings.BASE_DIR), 'static')
1722
extra_settings = {
1823
'STATIC_URL': settings.STATIC_URL,
1924
'STATICFILES_DIRS': settings.STATICFILES_DIRS
2025
}
2126
settings_store = SettingsStore(
2227
echarts_settings=project_echarts_settings,
23-
extra_settings=extra_settings
28+
extra_settings=extra_settings,
29+
static_url=static_url,
30+
staticfiles_dir=staticfiles_dir
2431
)
2532
return settings_store
2633

django_echarts/core/dms.py

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,14 @@
22
"""
33
A Implement that you can use host name instead of its url.
44
"""
5-
from typing import Tuple
5+
from typing import Tuple, List
66

77
from pyecharts.datasets import FILENAMES, EXTRA
8+
from django_echarts.utils.burl import BUrl
9+
from .localfiles import LocalFilesMixin, DownloaderResource
810

911
__all__ = ['DependencyManager']
1012

11-
12-
def pyecharts_resolve_dep_name(dep_name: str) -> Tuple[bool, str]:
13-
if dep_name.startswith("https://") or dep_name.startswith('http://'):
14-
return True, dep_name
15-
if dep_name in FILENAMES:
16-
f, ext = FILENAMES[dep_name]
17-
return False, "{}.{}".format(f, ext)
18-
else:
19-
for url, files in EXTRA.items():
20-
if dep_name in files:
21-
f, ext = files[dep_name]
22-
return False, "{}.{}".format(f, ext)
23-
return False, '{}.js'.format(dep_name)
24-
25-
2613
# The repo contains all dependencies
2714
_BUILTIN_REPOS_ = {
2815
'pyecharts': 'https://assets.pyecharts.org/assets/',
@@ -51,12 +38,13 @@ def d2f(dep_name: str):
5138
return f'{dep_name}.js'
5239

5340

54-
class DependencyManager:
41+
class DependencyManager(LocalFilesMixin):
5542
def __init__(self, *, context: dict = None, repo_name: str = None):
5643
self._context = context or {}
5744
self._repo_dic = {}
5845
self._custom_dep2url = {} # depname=> url
5946
self._cur_repo_name = repo_name
47+
self._baidu_map_ak = self._context.get('baidu_map_ak')
6048

6149
def add_repo(self, repo_name: str, repo_url: str):
6250
self._repo_dic[repo_name] = repo_url
@@ -70,12 +58,13 @@ def _resolve_dep(self, dep_name: str, repo_name: str = None) -> Tuple:
7058
if value.startswith('#'):
7159
repo_name = value[1:]
7260
else:
61+
value = value.format(**self._context)
7362
return value, d2f(dep_name)
7463
repo_name = repo_name or self._cur_repo_name
7564
if repo_name not in self._repo_dic:
7665
raise ValueError(f'Unknown dms repo: {repo_name}. Choices are:{",".join(self._repo_dic.keys())}')
7766

78-
use_url, new_dep_name = pyecharts_resolve_dep_name(dep_name)
67+
use_url, new_dep_name = self._pyecharts_resolve_dep_name(dep_name)
7968
if use_url:
8069
return new_dep_name, None
8170
filename = d2f(new_dep_name)
@@ -87,11 +76,35 @@ def resolve_url(self, dep_name: str, repo_name: str = None) -> str:
8776
url, _ = self._resolve_dep(dep_name, repo_name)
8877
return url
8978

90-
def iter_download_resources(self, dep_names: str, repo_name: str = None):
79+
def get_download_resources(self, dep_names: List[str], repo_name: str = None) -> List[DownloaderResource]:
80+
resources = []
9181
for dep_name in dep_names:
9282
url, filename = self._resolve_dep(dep_name, repo_name)
93-
if filename:
94-
yield dep_name, url, filename
83+
local_ref_url, local_path = self.localize_url(filename)
84+
resources.append(
85+
DownloaderResource(url, local_ref_url, local_path, label=dep_name, catalog='Dependency')
86+
)
87+
return resources
88+
89+
def _pyecharts_resolve_dep_name(self, dep_name: str) -> Tuple[bool, str]:
90+
if all([
91+
self._baidu_map_ak,
92+
dep_name.startswith('https://api.map.baidu.com/') or dep_name.startswith('http://api.map.baidu.com/'),
93+
'ak=' in dep_name
94+
]):
95+
# Replace baidu map ak with global settings.
96+
return True, BUrl(dep_name).replace('ak', self._baidu_map_ak).url
97+
if dep_name.startswith("https://") or dep_name.startswith('http://'):
98+
return True, dep_name
99+
if dep_name in FILENAMES:
100+
f, ext = FILENAMES[dep_name]
101+
return False, "{}.{}".format(f, ext)
102+
else:
103+
for url, files in EXTRA.items():
104+
if dep_name in files:
105+
f, ext = files[dep_name]
106+
return False, "{}.{}".format(f, ext)
107+
return False, '{}.js'.format(dep_name)
95108

96109
@classmethod
97110
def create_default(cls, context: dict = None, repo_name: str = None):

django_echarts/core/localfiles.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from typing import Tuple
2+
import os
3+
4+
5+
class DownloaderResource:
6+
def __init__(self, remote_url, ref_url, local_path, label=None, catalog=None, exists=False):
7+
self.remote_url = remote_url
8+
self.ref_url = ref_url
9+
self.local_path = local_path
10+
self.label = label or ''
11+
self.catalog = catalog or ''
12+
self.exists = exists
13+
14+
15+
class LocalFilesMixin:
16+
def set_localize_opts(self, static_url, staticfiles_dir):
17+
"""Set options for localize_opts"""
18+
self._localize_opts = {
19+
'static_url': static_url,
20+
'staticfiles_dir': staticfiles_dir
21+
}
22+
23+
def url2filename(self, url, **kwargs) -> str:
24+
pass
25+
26+
def localize_url(self, filename: str) -> Tuple[str, str]:
27+
"""Return local ref url and local file path from a remote url."""
28+
local_ref_url = self._localize_opts['static_url'] + filename
29+
local_path = os.path.join(self._localize_opts['staticfiles_dir'], filename)
30+
return local_ref_url, local_path

django_echarts/core/settings_store.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ class DJEOpts:
2525
theme_d2u: Optional[Dict] = None
2626
site_class: Optional[str] = None
2727

28+
baidu_map_ak: str = None
29+
2830
def get_echarts_theme(self, instance_theme) -> str:
2931
if self.echarts_theme:
3032
return self.echarts_theme
@@ -59,11 +61,14 @@ def _u(_old, _new=None):
5961

6062
# SettingsStore -> DependencyManage -> DJEOpts
6163
class SettingsStore:
64+
"""A settings entry for dms and tms."""
6265

6366
def __init__(self, *, echarts_settings=None, extra_settings=None, **kwargs):
6467
# Pre check settings
6568

6669
self._extra_settings = extra_settings or {}
70+
self.static_url = kwargs.get('static_url', '/static/')
71+
self.staticfiles_dir = kwargs.get('staticfiles_dir', '')
6772

6873
if isinstance(echarts_settings, dict):
6974
new_opts = DJEOpts.upgrade_dict(echarts_settings)
@@ -75,19 +80,24 @@ def __init__(self, *, echarts_settings=None, extra_settings=None, **kwargs):
7580
else:
7681
self._opts = DJEOpts()
7782

78-
context = {'echarts_version': self._opts.echarts_version}
83+
context = {
84+
'echarts_version': self._opts.echarts_version,
85+
'baidu_map_ak': self._opts.baidu_map_ak
86+
}
7987
if 'STATIC_URL' in self._extra_settings:
80-
context.update({'STATIC_URL': self._extra_settings['STATIC_URL']})
88+
context.update({'STATIC_URL': self.static_url})
8189
self._dms = DependencyManager.create_default(
8290
context=context,
8391
repo_name=self._opts.dms_repo
8492
)
8593
self._dms.load_from_dep2url_dict(self._opts.dep2url)
94+
self._dms.set_localize_opts(static_url=self.static_url, staticfiles_dir=self.staticfiles_dir)
8695

8796
user_theme_label, user_theme_app = self._auto_get_theme_params()
8897
if not self._opts.theme_app:
8998
self._opts.theme_app = user_theme_app
90-
self._tms = ThemeManager.create_from_module(theme_app=user_theme_app)
99+
self._tms = ThemeManager.create_from_module(theme_app=user_theme_app, d2u=self._opts.theme_d2u)
100+
self._tms.set_localize_opts(static_url=self.static_url, staticfiles_dir=self.staticfiles_dir)
91101

92102
self._theme = self._tms.create_theme(user_theme_label)
93103

@@ -109,17 +119,14 @@ def theme_manger(self) -> ThemeManager:
109119
def theme(self) -> Theme:
110120
return self._theme
111121

112-
def resolve_url(self, dep_name: str, repo_name: Optional[str] = None):
122+
def resolve_url(self, dep_name: str, repo_name: Optional[str] = None) -> str:
113123
return self._dms.resolve_url(dep_name, repo_name)
114124

115125
def generate_js_link(self, js_name, js_host=None, **kwargs):
116126
warnings.warn('The method SettingsStore.generate_js_link is deprecated, use SettingsStore.resolve_url instead.',
117127
DeprecationWarning, stacklevel=2)
118128
return self._dms.resolve_url(dep_name=js_name, repo_name=js_host)
119129

120-
def get(self, key, default=None):
121-
return getattr(self._opts, key, default)
122-
123130
def get_site_obj(self):
124131
if not self._opts.site_class:
125132
raise TypeError('The settings DJANGO_ECHARTS.site_class is required for this feature.')

django_echarts/core/tms.py

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from collections import OrderedDict
33
from typing import List, Dict
44

5+
from .localfiles import LocalFilesMixin, DownloaderResource
6+
57
__all__ = ['Theme', 'parse_theme_label', 'ThemeManager']
68

79
_ORDERED_FIELDS_ = ['base_css', 'main_css', 'palette_css', 'font_css', 'jquery_js', 'main_js']
@@ -57,30 +59,11 @@ def set_file_url(self, url: str, name: str):
5759
def set_cns(self, cns):
5860
self.cns.update(cns)
5961

60-
def iter_local_paths(self):
61-
for name in self._url_dic.keys():
62-
url, local_path = self._localize_url(name)
63-
yield name, url, local_path
64-
65-
def _localize_url(self, name: str, as_url=False):
66-
url = self._url_dic[name]
67-
if name == 'palette_css':
68-
local_path = '/'.join([self.name, self.theme_palette]) + '.min.css'
69-
else:
70-
filepath = url.rsplit('/')[-1]
71-
local_path = self.name + '/' + filepath
72-
if as_url:
73-
local_path = '/static/' + local_path
74-
return url, local_path
75-
76-
def local_theme(self) -> 'Theme':
77-
new_theme = Theme(self.theme, self.theme_palette, is_local=True)
78-
new_theme.cns = self.cns
62+
def iter_name_and_url(self):
7963
for name, url in self._url_dic.items():
80-
new_theme.set_file_url(self._localize_url(name)[1], name)
81-
return new_theme
64+
yield name, url
8265

83-
def list_staticfiles(self):
66+
def list_urls(self):
8467
yield from self.css_urls
8568
yield from self.js_urls
8669

@@ -95,7 +78,7 @@ def module2dict(module_path: str) -> dict:
9578
return settings_dict
9679

9780

98-
class ThemeManager:
81+
class ThemeManager(LocalFilesMixin):
9982
def __init__(self, theme_app_config: dict = None, file2url: Dict = None):
10083
self.theme_app_config = theme_app_config or {}
10184
self.theme_name = theme_app_config.get('NAME')
@@ -123,9 +106,9 @@ def _palette_css(_url):
123106
theme_obj.set_file_url(_url.format(palette=palette), 'palette_css')
124107

125108
for f in _ORDERED_FIELDS_:
126-
val = static_dic.get(f)
109+
val = self.get_custom_url(theme_palette, f)
127110
if not val:
128-
val = self.get_custom_url(theme_palette, f)
111+
val = static_dic.get(f)
129112
if not val:
130113
continue
131114
if f == 'main_css':
@@ -163,11 +146,40 @@ def _get(_f, _v):
163146
_get('size', size)
164147
return ' '.join(cns)
165148

149+
def url2filename(self, url, **kwargs) -> str:
150+
name = kwargs.get('name')
151+
theme = kwargs.get('theme') # type:Theme
152+
if name == 'palette_css':
153+
filename = '/'.join([theme.name, theme.theme_palette]) + '.min.css'
154+
else:
155+
filepath = url.rsplit('/')[-1]
156+
filename = theme.name + '/' + filepath
157+
return filename
158+
159+
def localize_theme(self, theme: Theme) -> Theme:
160+
if theme.is_local:
161+
return theme
162+
new_theme = Theme(theme.theme, theme.theme_palette, is_local=True)
163+
new_theme.cns = theme.cns
164+
for name, url in theme.iter_name_and_url():
165+
filename = self.url2filename(url, name=name, theme=theme)
166+
new_theme.set_file_url(self.localize_url(filename)[0], name)
167+
return new_theme
168+
169+
def get_download_resources(self, theme: Theme) -> List[DownloaderResource]:
170+
resources = []
171+
for name, url in theme.iter_name_and_url():
172+
filename = self.url2filename(url, name=name, theme=theme)
173+
local_ref_url, local_path = self.localize_url(filename)
174+
resources.append(DownloaderResource(url, local_ref_url, local_path, label='', catalog=name))
175+
return resources
176+
166177
@property
167178
def available_palettes(self) -> List[str]:
168179
return [self.theme_name] + [f'{self.theme_name}.{p}' for p in self._available_palettes]
169180

170181
@classmethod
171182
def create_from_module(cls, theme_app: str, d2u: dict = None):
183+
"""Create a theme manager with config module."""
172184
theme_app_config = module2dict(f'{theme_app}.config')
173185
return cls(theme_app_config, d2u)

0 commit comments

Comments
 (0)