Doc for tools finish

This commit is contained in:
El Mau 2022-02-27 23:28:06 -06:00
parent 44b07158c5
commit ae710f4854
6 changed files with 554 additions and 72 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -25,6 +25,7 @@
mri
msgbox
question
render
run_in_thread
save_log
set_app_config
@ -39,6 +40,8 @@
.. autosummary::
Color
Config
Dates
Hash
Json
@ -49,6 +52,7 @@
Paths
Shell
Timer
Url
commands

View File

@ -55,7 +55,7 @@ Get home path
app.debug(p.home)
Get documento path
Get document path
------------------
.. code-block:: python
@ -99,3 +99,75 @@ Get python executable path
p = app.path
app.debug(p.python)
Path URL to system
------------------
.. code-block:: python
path = 'file:///home/mau/myfile.ods'
app.debug(app.path.to_system(path))
Path system to URL
------------------
.. code-block:: python
path = 'file:///home/mau/myfile.ods'
path = app.path.to_system(path)
app.debug(app.path.to_url(path))
Get path from user config
-------------------------
Default get path documents. `See Api XPathSettings <http://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1util_1_1XPathSettings.html>`_
.. code-block:: python
path = app.path.config()
app.debug(path)
path = app.path.config('UserConfig')
app.debug(path)
.. note::
Some paths can be more than one path separated by a semicolon, in this case, you get a `list` of paths.
Path join
---------
.. code-block:: python
path = app.path.join('/home/mau', 'test', 'file.ods')
app.debug(path)
Exists path
-----------
.. code-block:: python
exists = app.path.exists('/home/mau/test/file.ods')
app.debug(exists)
Verify if application exists
----------------------------
.. code-block:: python
app_name = 'nosoffice'
app.debug(app.path.exists_app(app_name))
app_name = 'soffice'
app.debug(app.path.exists_app(app_name))

View File

@ -660,17 +660,24 @@ You can save any data.
'save_data': True,
}
app.set_config('config', data, my_app)
if app.config.set(my_app, data):
app.msgbox('Save config')
app.msgbox('Save config')
data = app.get_config('config', my_app)
path = app.config.get(my_app)
app.msgbox(data)
You can get any key
.. code-block:: python
path = app.config.get(my_app, 'path')
app.msgbox(path)
Render string
^^^^^^^^^^^^^
-------------
.. code-block:: python
@ -688,72 +695,63 @@ Render string
app.msgbox(render)
Encrypt decrypt
^^^^^^^^^^^^^^^
You need install library `cryptography`_
.. code-block:: python
import easymacro as app
from conf import PASSWORD
def encrypt_decrypt():
data = 'My super secret data'
token = app.encrypt(data, PASSWORD)
app.msgbox(token)
data = app.decrypt(token, PASSWORD)
app.msgbox(data)
return
Simple url open
^^^^^^^^^^^^^^^
---------------
* Get text data
Get text data
^^^^^^^^^^^^^
.. code-block:: python
url = 'https://api.ipify.org'
data = app.url_open(url)
app.msgbox(data)
result, headers, err = app.url.get(url)
if err:
app.error(err)
else:
app.debug(type(result), result)
app.debug(headers)
* Get json data
.. image:: _static/images/tools_23.png
|
Get json data
^^^^^^^^^^^^^
.. code-block:: python
url = 'https://api.ipify.org?format=json'
data = app.url_open(url, get_json=True)
app.msgbox(data)
result, headers, err = app.url.get(url, json=True)
if err:
app.error(err)
else:
app.debug(type(result), result)
app.debug(headers)
For more complex case, you can used `requests`_ or `httpx`_
.. image:: _static/images/tools_24.png
|
Color
^^^^^
-----
Look colors that you can used in `web colors`_
.. code-block:: python
color_name = 'darkblue'
color = app.get_color(color_name)
app.msgbox(color)
color = app.color(color_name)
app.debug(color)
color_rgb = (125, 200, 10)
color = app.get_color(color_rgb)
app.msgbox(color)
color = app.color(color_rgb)
app.debug(color)
color_html = '#008080'
color = app.get_color(color_html)
app.msgbox(color)
color = app.color(color_html)
app.debug(color)
.. _Unix Time: https://en.wikipedia.org/wiki/Unix_time
.. _cryptography: https://github.com/pyca/cryptography
.. _requests: https://docs.python-requests.org
.. _httpx: https://www.python-httpx.org/
.. _web colors: https://en.wikipedia.org/wiki/Web_colors

View File

@ -28,6 +28,7 @@ import platform
import shlex
import shutil
import socket
import ssl
import subprocess
import sys
import tempfile
@ -38,7 +39,13 @@ import traceback
from functools import wraps
from pathlib import Path
from pprint import pprint
from typing import Any
from string import Template
from typing import Any, Union
from socket import timeout
from urllib import parse
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError
import uno
from com.sun.star.awt import MessageBoxButtons as MSG_BUTTONS
@ -46,15 +53,6 @@ from com.sun.star.awt.MessageBoxResults import YES
from com.sun.star.beans import PropertyValue, NamedValue
LOG_FORMAT = '%(asctime)s - %(levelname)s - %(message)s'
LOG_DATE = '%d/%m/%Y %H:%M:%S'
logging.addLevelName(logging.ERROR, '\033[1;41mERROR\033[1;0m')
logging.addLevelName(logging.DEBUG, '\x1b[33mDEBUG\033[1;0m')
logging.addLevelName(logging.INFO, '\x1b[32mINFO\033[1;0m')
logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT, datefmt=LOG_DATE)
log = logging.getLogger(__name__)
# Global variables
OS = platform.system()
DESKTOP = os.environ.get('DESKTOP_SESSION', '')
@ -64,9 +62,23 @@ IS_WIN = OS == 'Windows'
IS_MAC = OS == 'Darwin'
LOG_FORMAT = '%(asctime)s - %(levelname)s - %(message)s'
LOG_DATE = '%d/%m/%Y %H:%M:%S'
if IS_WIN:
logging.addLevelName(logging.ERROR, 'ERROR')
logging.addLevelName(logging.DEBUG, 'DEBUG')
logging.addLevelName(logging.INFO, 'INFO')
else:
logging.addLevelName(logging.ERROR, '\033[1;41mERROR\033[1;0m')
logging.addLevelName(logging.DEBUG, '\x1b[33mDEBUG\033[1;0m')
logging.addLevelName(logging.INFO, '\x1b[32mINFO\033[1;0m')
logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT, datefmt=LOG_DATE)
log = logging.getLogger(__name__)
_info_debug = f"Python: {sys.version}\n\n{platform.platform()}\n\n" + '\n'.join(sys.path)
TIMEOUT = 10
SALT = b'00a1bfb05353bb3fd8e7aa7fe5efdccc'
_EVENTS = {}
@ -74,6 +86,11 @@ PYTHON = 'python'
if IS_WIN:
PYTHON = 'python.exe'
FILES = {
'CONFIG': 'zaz-{}.json',
}
DIRS = {}
CTX = uno.getComponentContext()
SM = CTX.getServiceManager()
@ -462,6 +479,14 @@ def data_to_dict(data) -> dict:
return d
def render(template, data):
s = Template(template)
return s.safe_substitute(**data)
# Classes
class _classproperty:
def __init__(self, method=None):
self.fget = method
@ -486,7 +511,7 @@ class Dates(object):
:return: Return the current local date and time
:rtype: datetime
"""
return datetime.datetime.now()
return datetime.datetime.now().replace(microsecond=0)
@_classproperty
def today(cls):
@ -936,17 +961,6 @@ class Paths(object):
"""Get temporary directory in system"""
return tempfile.gettempdir()
@_classproperty
def python(self):
"""Get path executable python"""
if IS_WIN:
path = self.join(self.config('Module'), PYTHON)
elif IS_MAC:
path = self.join(self.config('Module'), '..', 'Resources', PYTHON)
else:
path = sys.executable
return path
@_classproperty
def user_profile(self):
"""Get path user profile"""
@ -960,6 +974,17 @@ class Paths(object):
path = self.config('UserConfig')
return path
@_classproperty
def python(self):
"""Get path executable python"""
if IS_WIN:
path = self.join(self.config('Module'), PYTHON)
elif IS_MAC:
path = self.join(self.config('Module'), '..', 'Resources', PYTHON)
else:
path = sys.executable
return path
@classmethod
def to_system(cls, path:str) -> str:
"""Convert paths in URL to system
@ -987,18 +1012,20 @@ class Paths(object):
return path
@classmethod
def config(cls, name: str='Work') -> str:
def config(cls, name: str='Work') -> Union[str, list]:
"""Return path from config
:param name: Name in service PathSettings, default get path documents
:type name: str
:return: Path in config, if exists.
:rtype: str
:rtype: str or list
`See Api XPathSettings <http://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1util_1_1XPathSettings.html>`_
"""
path = create_instance('com.sun.star.util.PathSettings')
path = cls.to_system(getattr(path, name))
path = cls.to_system(getattr(path, name)).split(';')
if len(path) == 1:
path = path[0]
return path
@classmethod
@ -1038,6 +1065,384 @@ class Paths(object):
result = bool(shutil.which(name_app))
return result
# ~ Save/read data
@classmethod
def save(cls, path: str, data: str, encoding: str='utf-8') -> bool:
"""Save data in path with encoding
:param path: Path to file save
:type path: str
:param data: Data to save
:type data: str
:param encoding: Encoding for save data, default utf-8
:type encoding: str
:return: True, if save corrrectly
:rtype: bool
"""
result = bool(Path(path).write_text(data, encoding=encoding))
return result
@classmethod
def save_bin(cls, path: str, data: bytes) -> bool:
"""Save binary data in path
:param path: Path to file save
:type path: str
:param data: Data to save
:type data: bytes
:return: True, if save corrrectly
:rtype: bool
"""
result = bool(Path(path).write_bytes(data))
return result
@classmethod
def read(cls, path: str, get_lines: bool=False, encoding: str='utf-8') -> Union[str, list]:
"""Read data in path
:param path: Path to file read
:type path: str
:param get_lines: If read file line by line
:type get_lines: bool
:return: File content
:rtype: str or list
"""
if get_lines:
with Path(path).open(encoding=encoding) as f:
data = f.readlines()
else:
data = Path(path).read_text(encoding=encoding)
return data
@classmethod
def read_bin(cls, path: str) -> bytes:
"""Read binary data in path
:param path: Path to file read
:type path: str
:return: File content
:rtype: bytes
"""
data = Path(path).read_bytes()
return data
# ~ Import/export data
@classmethod
def from_json(cls, path: str) -> Any:
"""Read path file and load json data
:param path: Path to file
:type path: str
:return: Any data
:rtype: Any
"""
data = json.loads(cls.read(path))
return data
@classmethod
def to_json(cls, path: str, data: str):
"""Save data in path file like json
:param path: Path to file
:type path: str
:return: True if save correctly
:rtype: bool
"""
data = json.dumps(data, indent=4, ensure_ascii=False, sort_keys=True)
return cls.save(path, data)
class Config(object):
"""Class for set and get configurations
"""
@classmethod
def set(cls, prefix: str, value: Any, key: str='') -> bool:
"""Save data config in user config like json
:param prefix: Unique prefix for this data
:type prefix: str
:param value: Value for save
:type value: Any
:param key: Key for value
:type key: str
:return: True if save correctly
:rtype: bool
"""
name_file = FILES['CONFIG'].format(prefix)
path = Paths.join(Paths.user_config, name_file)
data = value
if key:
data = cls.get(prefix)
data[key] = value
result = Paths.to_json(path, data)
return result
@classmethod
def get(cls, prefix: str, key: str='', default: Any={}) -> Any:
"""Get data config from user config like json
:param prefix: Unique prefix for this data
:type prefix: str
:param key: Key for value
:type key: str
:param default: Get if not exists key
:type default: Any
:return: data
:rtype: Any
"""
data = {}
name_file = FILES['CONFIG'].format(prefix)
path = Paths.join(Paths.user_config, name_file)
if not Paths.exists(path):
return data
data = Paths.from_json(path)
if key:
data = data.get(key, default)
return data
class Url(object):
"""Class for simple url open
"""
@classmethod
def _open(cls, url: str, data: Any=None, headers: dict={}, verify: bool=True, \
json: bool=False, timeout: int=TIMEOUT, method: str='GET') -> tuple:
"""URL Open"""
debug(url)
result = None
context = None
rheaders = {}
err = ''
if verify:
if not data is None and isinstance(data, str):
data = data.encode()
else:
context = ssl._create_unverified_context()
try:
req = Request(url, data=data, headers=headers, method=method)
response = urlopen(req, timeout=timeout, context=context)
except HTTPError as e:
error(e)
err = str(e)
except URLError as e:
error(e.reason)
err = str(e.reason)
# ToDo
# ~ except timeout:
# ~ err = 'timeout'
# ~ error(err)
else:
rheaders = dict(response.info())
result = response.read().decode()
if json:
result = Json.loads(result)
return result, rheaders, err
@classmethod
def get(cls, url: str, data: Any=None, headers: dict={}, verify: bool=True, \
json: bool=False, timeout: int=TIMEOUT) -> tuple:
"""Method GET
:param url: Url to open
:type url: str
:return: result, headers and error
:rtype: tuple
"""
return cls._open(url, data, headers, verify, json, timeout)
# ToDo
@classmethod
def _post(cls, url: str, data: Any=None, headers: dict={}, verify: bool=True, \
json: bool=False, timeout: int=TIMEOUT) -> tuple:
"""Method POST
"""
data = parse.urlencode(data).encode('ascii')
return cls._open(url, data, headers, verify, json, timeout, 'POST')
class Color(object):
"""Class for colors
`See Web Colors <https://en.wikipedia.org/wiki/Web_colors>`_
"""
COLORS = {
'aliceblue': 15792383,
'antiquewhite': 16444375,
'aqua': 65535,
'aquamarine': 8388564,
'azure': 15794175,
'beige': 16119260,
'bisque': 16770244,
'black': 0,
'blanchedalmond': 16772045,
'blue': 255,
'blueviolet': 9055202,
'brown': 10824234,
'burlywood': 14596231,
'cadetblue': 6266528,
'chartreuse': 8388352,
'chocolate': 13789470,
'coral': 16744272,
'cornflowerblue': 6591981,
'cornsilk': 16775388,
'crimson': 14423100,
'cyan': 65535,
'darkblue': 139,
'darkcyan': 35723,
'darkgoldenrod': 12092939,
'darkgray': 11119017,
'darkgreen': 25600,
'darkgrey': 11119017,
'darkkhaki': 12433259,
'darkmagenta': 9109643,
'darkolivegreen': 5597999,
'darkorange': 16747520,
'darkorchid': 10040012,
'darkred': 9109504,
'darksalmon': 15308410,
'darkseagreen': 9419919,
'darkslateblue': 4734347,
'darkslategray': 3100495,
'darkslategrey': 3100495,
'darkturquoise': 52945,
'darkviolet': 9699539,
'deeppink': 16716947,
'deepskyblue': 49151,
'dimgray': 6908265,
'dimgrey': 6908265,
'dodgerblue': 2003199,
'firebrick': 11674146,
'floralwhite': 16775920,
'forestgreen': 2263842,
'fuchsia': 16711935,
'gainsboro': 14474460,
'ghostwhite': 16316671,
'gold': 16766720,
'goldenrod': 14329120,
'gray': 8421504,
'grey': 8421504,
'green': 32768,
'greenyellow': 11403055,
'honeydew': 15794160,
'hotpink': 16738740,
'indianred': 13458524,
'indigo': 4915330,
'ivory': 16777200,
'khaki': 15787660,
'lavender': 15132410,
'lavenderblush': 16773365,
'lawngreen': 8190976,
'lemonchiffon': 16775885,
'lightblue': 11393254,
'lightcoral': 15761536,
'lightcyan': 14745599,
'lightgoldenrodyellow': 16448210,
'lightgray': 13882323,
'lightgreen': 9498256,
'lightgrey': 13882323,
'lightpink': 16758465,
'lightsalmon': 16752762,
'lightseagreen': 2142890,
'lightskyblue': 8900346,
'lightslategray': 7833753,
'lightslategrey': 7833753,
'lightsteelblue': 11584734,
'lightyellow': 16777184,
'lime': 65280,
'limegreen': 3329330,
'linen': 16445670,
'magenta': 16711935,
'maroon': 8388608,
'mediumaquamarine': 6737322,
'mediumblue': 205,
'mediumorchid': 12211667,
'mediumpurple': 9662683,
'mediumseagreen': 3978097,
'mediumslateblue': 8087790,
'mediumspringgreen': 64154,
'mediumturquoise': 4772300,
'mediumvioletred': 13047173,
'midnightblue': 1644912,
'mintcream': 16121850,
'mistyrose': 16770273,
'moccasin': 16770229,
'navajowhite': 16768685,
'navy': 128,
'oldlace': 16643558,
'olive': 8421376,
'olivedrab': 7048739,
'orange': 16753920,
'orangered': 16729344,
'orchid': 14315734,
'palegoldenrod': 15657130,
'palegreen': 10025880,
'paleturquoise': 11529966,
'palevioletred': 14381203,
'papayawhip': 16773077,
'peachpuff': 16767673,
'peru': 13468991,
'pink': 16761035,
'plum': 14524637,
'powderblue': 11591910,
'purple': 8388736,
'red': 16711680,
'rosybrown': 12357519,
'royalblue': 4286945,
'saddlebrown': 9127187,
'salmon': 16416882,
'sandybrown': 16032864,
'seagreen': 3050327,
'seashell': 16774638,
'sienna': 10506797,
'silver': 12632256,
'skyblue': 8900331,
'slateblue': 6970061,
'slategray': 7372944,
'slategrey': 7372944,
'snow': 16775930,
'springgreen': 65407,
'steelblue': 4620980,
'tan': 13808780,
'teal': 32896,
'thistle': 14204888,
'tomato': 16737095,
'turquoise': 4251856,
'violet': 15631086,
'wheat': 16113331,
'white': 16777215,
'whitesmoke': 16119285,
'yellow': 16776960,
'yellowgreen': 10145074,
}
def _get_color(self, index):
if isinstance(index, tuple):
color = (index[0] << 16) + (index[1] << 8) + index[2]
else:
if index[0] == '#':
r, g, b = bytes.fromhex(index[1:])
color = (r << 16) + (g << 8) + b
else:
color = self.COLORS.get(index.lower(), -1)
return color
def __call__(self, index):
return self._get_color(index)
def __getitem__(self, index):
return self._get_color(index)
COLOR_ON_FOCUS = Color()('LightYellow')
def __getattr__(name):
classes = {
@ -1048,6 +1453,9 @@ def __getattr__(name):
'timer': Timer,
'hash': Hash,
'path': Paths,
'config': Config,
'url': Url,
'color': Color(),
}
if name in classes:
return classes[name]