# -*- coding: utf-8 -*-
import os.path
from sys import platform
from .mod_conf import ModConf
[документация]class ModApi(ModConf):
_class_file = __file__
_debug_name = 'KVEditorModApi'
[документация] def render_page(self, base, _vars=None):
"""
Функция формирует страницу портала по шаблону
:param base:
:param _vars:
:return: page
:rtype: html
"""
_tpl_name = ''
_tpl_vars = {}
_file_name = 'new_config_1'
_can_remove = False
relative = ''
work_mod = ''
if isinstance(_vars, dict):
_tpl_vars = _vars
if 'source_name' in _vars:
relative = _vars['source_name']
_file_name = os.path.basename(relative).split('.')[0]
if 'mod_name' in _vars:
work_mod = _vars['mod_name']
if '' != work_mod and '' != relative:
_can_remove = self.can_remove_file(work_mod, relative)
_tpl_name = self.get_editor_tpl()
if "win32" == platform:
# так как
# from flak_themes2/__init__.py return render_template("_themes/%s/%s" % (theme, template_name), **context)
# преобразуем путь к соответствующему шаблону
base = base.replace(os.path.sep, os.path.altsep)
_tpl_vars['to_extend'] = base
_tpl_vars['edit_name'] = _file_name
_tpl_vars['can_remove'] = _can_remove
from app import app_api
_base_url = self.MOD_WEB_ROOT
_app_url_prefix = app_api.get_app_url_prefix()
if _app_url_prefix and not _base_url.startswith(_app_url_prefix):
_base_url = _app_url_prefix.rstrip('/') + '/' + _base_url.lstrip('/')
_tpl_vars['js_base_url'] = _base_url
return app_api.render_page(_tpl_name, **_tpl_vars)
def __get_full_file_path(self, mod, relative):
_pth = ''
_app_path = self.get_app_path()
if relative.startswith(_app_path) and -1 < relative.find(os.path.sep + mod + os.path.sep):
# значит путь уже полный и мы можем обмануть систему
_t = relative.split(mod)
relative = _t[-1]
if '' != mod and '' != relative:
relative = relative.lstrip(os.path.sep)
if relative.startswith(mod):
relative = relative.replace(mod, '').lstrip(os.path.sep)
_pth = os.path.join(_app_path, mod, relative)
return _pth
[документация] def can_remove_file(self, mod_name, _file_pth):
"""
Функция проверяет наличие файла
:param str mod_name:
:param str _file_pth:
:return: флаг
:rtype: bool
"""
flg = False
from app import app_api
_app_conf_pth = app_api.get_app_cfg_path()
_app_data_pth = app_api.get_app_data_path()
_read_path = ''
# можно указывать полные пути только для файлов в директориях app/cfg и app/data
if _file_pth.startswith(_app_conf_pth) or _file_pth.startswith(_app_data_pth):
# редактируем только настройки файлов как данные
_read_path = _file_pth
else:
# если же путь начинается с чегото другого - считаем это относительный путь
_file_path = self.__get_full_file_path(mod_name, _file_pth)
_read_path = self.__get_real_filepath(_file_path)
# редактирование файла настроечного
if _read_path.startswith(_app_conf_pth):
flg = True
# редактирования файла данных
if not flg and _read_path.startswith(_app_data_pth):
flg = True
if flg:
# если вдруг файл редактировать можно, но он еще не создан
flg = os.path.exists(_read_path)
return flg
[документация] def remove_file(self, mod_name, _file_pth):
"""
Функция удаляет указанный в параметре файл
:param str mod_name: имя удаляемого файла
:param str _file_pth: полный путь к удаляемому файлу
:return: флаг
:rtype: bool
"""
flg = False
if self.can_remove_file(mod_name, _file_pth):
from app import app_api
_app_conf_pth = app_api.get_app_cfg_path()
_app_data_pth = app_api.get_app_data_path()
_to_remove = ''
# можно указывать полные пути только для файлов в директориях app/cfg и app/data
if _file_pth.startswith(_app_conf_pth) or _file_pth.startswith(_app_data_pth):
# редактируем только настройки файлов как данные
_to_remove = _file_pth
else:
_file_path = self.__get_full_file_path(mod_name, _file_pth)
_to_remove = self.__get_conf_save_path(_file_path)
os.unlink(_to_remove)
flg = not os.path.exists(_to_remove)
return flg
[документация] def dict2ini(self, file_path, data: dict):
"""
Функция .....
:param str file_path:
:param dict data:
:return:
:rtype:
"""
flg = False
# if os.path.exists(file_path) and os.path.isfile(file_path):
file_path = self.__get_conf_save_path(file_path)
# print(self._debug_name + '.dict2ini-> save path: ', file_path)
_ini_text = self._dict2ini_text(data)
import configparser
_parser = configparser.ConfigParser(strict=False, allow_no_value=True)
# https://stackoverflow.com/questions/19359556/configparser-reads-capital-keys-and-make-them-lower-case
# _parser.optionxform = str
# _parser.read_dict(data)
with open(file_path, 'w', encoding='utf8') as fp:
# _parser.write(fp)
fp.write(_ini_text)
flg = True
return flg
@staticmethod
def _dict2ini_text(dt):
ini = ''
# первый уровень ключи секций
for sec, content in dt.items():
ini += '[' + sec + ']' + "\n"
if not isinstance(content, dict):
ini += "\n"
continue
if content:
for parK, parV in content.items():
if isinstance(parV, dict):
for mvk, mvd in parV.items():
ini += parK + '[' + mvk + ']' + '=' + str(mvd) + "\n"
elif isinstance(parV, list):
_ind = 0
for mvd in parV:
ini += parK + '[' + str(_ind) + ']' + '=' + str(mvd) + "\n"
_ind += 1
else:
ini += parK + '=' + str(parV) + "\n"
ini += "\n"
return ini
[документация] def ini2dict(self, file_path, curent_file=False):
"""
Функция .....
:param str file_path: полный путь до файла
:param bool current_file: флаг
:return:
:rtype:
"""
data = None
if os.path.exists(file_path) and os.path.isfile(file_path):
if not curent_file:
file_path = self.__get_real_filepath(file_path)
base_name = os.path.basename(file_path)
import configparser
_parser = configparser.ConfigParser()
# https://stackoverflow.com/questions/19359556/configparser-reads-capital-keys-and-make-them-lower-case
_parser.optionxform = str
_parser.read(file_path, encoding='utf8')
data = {}
for section in _parser:
# ConfigParser add DEFAULT section
# if DEFAULT -> continue
if 'DEFAULT' == section:
continue
data[section] = self._section_to_dict(_parser[section])
return data
def _section_to_dict(self, section):
d = {}
for k in section:
if self._option_is_section(k):
ssk = self._parse_section_key(k)
if ssk[0] not in d:
d[ssk[0]] = {}
if ssk[1] not in d[ssk[0]]:
d[ssk[0]][ssk[1]] = {}
d[ssk[0]][ssk[1]] = section[k]
else:
d[k] = section[k]
return d
@staticmethod
def _option_is_section(name):
return -1 < name.find('[') and name.endswith(']')
@staticmethod
def _parse_section_key(section_key):
ssk = section_key.split('[')
ssk[1] = ssk[1].rstrip(']')
return ssk
@staticmethod
def __get_real_filepath(req_file):
_root_pth = ModApi.get_app_path()
# рассматриваем файлы внутри приложения
if req_file.startswith(_root_pth):
from app import app_api
_app_conf_pth = app_api.get_app_cfg_path()
_app_data_pth = app_api.get_app_data_path()
# если запрошенный файл находится вне конфигурационной директории приложения
if not req_file.startswith(_app_conf_pth) and not req_file.startswith(_app_data_pth):
# определяем в какой поддиректории приложения ищется файл
relative = req_file.replace(_root_pth, '')
# считаем что данная директория модуль
_mod_name = relative.lstrip(os.path.sep).split(os.path.sep)[0]
# если конфигурационная директория существует
if os.path.exists(_app_conf_pth):
_t = os.path.join(_app_conf_pth, _mod_name)
# если существует директория модуля в конфигурационной директории
if os.path.exists(_t):
_t = os.path.join(_app_conf_pth, relative.lstrip(os.path.sep))
# существует ли указанный конфигурационный файл
if os.path.exists(_t):
req_file = _t
return req_file
@staticmethod
def __get_conf_save_path(file_path):
_res_path = file_path
_root_pth = ModApi.get_app_path()
from app import app_api
_app_conf_pth = app_api.get_app_cfg_path()
if os.path.exists(_app_conf_pth):
_s = file_path.replace(_root_pth, '').lstrip(os.path.sep).split(os.path.sep)
if file_path.startswith(_app_conf_pth):
# значит мы редактируем новый файл сразу в конфигурационной папки
_s = file_path.replace(_app_conf_pth, '').lstrip(os.path.sep).split(os.path.sep)
_t = _app_conf_pth
for _st in _s:
if _st == _s[-1]:
break # file
# считаем что все остальное директории
_t = os.path.join(_t, _st)
if not os.path.exists(_t):
try: os.mkdir(_t)
except: pass
_res_path = os.path.join(_app_conf_pth, *_s)
return _res_path
[документация] @staticmethod
def get_app_path():
"""
Функция вычисляет путь директории приложения - это отсчетная точка для модулей
:return: app_root_dir
:rtype: str
"""
from app import app_api
return app_api.get_app_root_dir()