Doc for paths

This commit is contained in:
El Mau 2022-02-26 22:22:11 -06:00
parent 22ac697de1
commit 44b07158c5
8 changed files with 663 additions and 87 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -40,11 +40,15 @@
.. autosummary::
Dates
Hash
Json
LOServer
MBT
Macro
MessageBoxType
Paths
Shell
Timer
commands

View File

@ -24,6 +24,7 @@ You can used **easymacro** with any extension or directly in your macros.
install
tools_debug
tools
paths
api

101
docs/source/paths.rst Normal file
View File

@ -0,0 +1,101 @@
Paths and files
===============
Remember, always import library first.
.. code-block:: python
import easymacro as app
Get info path
-------------
.. code-block:: python
path = '/home/mau/myfile.ods'
p = app.path(path)
app.debug(p.path)
app.debug(p.file_name)
app.debug(p.name)
app.debug(p.ext)
app.debug(p.size)
app.debug(p.url)
.. image:: _static/images/path_01.png
|
Get info like tuple
.. code-block:: python
app.debug(p.info)
.. image:: _static/images/path_02.png
|
Or like dict
.. code-block:: python
app.debug(p.dict)
.. image:: _static/images/path_03.png
Get home path
-------------
.. code-block:: python
p = app.path
app.debug(p.home)
Get documento path
------------------
.. code-block:: python
p = app.path
app.debug(p.documents)
Get temporary directory
-----------------------
.. code-block:: python
p = app.path
app.debug(p.temp_dir)
Get path user profile
---------------------
.. code-block:: python
p = app.path
app.debug(p.user_profile)
Get path user config
--------------------
.. code-block:: python
p = app.path
app.debug(p.user_config)
Get python executable path
--------------------------
.. code-block:: python
p = app.path
app.debug(p.python)

View File

@ -453,20 +453,20 @@ Execute macro in other thread
Call external program
^^^^^^^^^^^^^^^^^^^^^
---------------------
.. code-block:: python
app_name = 'gnome-calculator'
app.run(app_name)
app.msgbox('ok')
app.shell.run(app_name)
app.debug(app_name)
Call command line and capture output
.. code-block:: python
args = 'ls -lh ~'
result = app.run(args, True)
result = app.shell.run(args, True)
app.debug(result)
.. code-block:: bash
@ -502,7 +502,68 @@ Call command line and capture output line by line.
Timer
^^^^^
-----
Only once
^^^^^^^^^
Execute any macro only once in N seconds.
.. code-block:: python
TIMER_NAME = 'clock'
def show_time():
app.debug(app.dates.time)
return
def start_clock():
seconds = 5
macro = {
'library': 'test',
'name': 'show_time',
}
app.timer.once(TIMER_NAME, seconds, macro)
return
def main(args=None):
start_clock()
return
Cancel execution, before start.
.. code-block:: python
TIMER_NAME = 'clock'
def show_time():
app.debug(app.dates.time)
return
def start_clock():
seconds = 60
macro = {
'library': 'test',
'name': 'show_time',
}
app.timer.once(TIMER_NAME, seconds, macro)
return
def stop_clock():
app.timer.cancel(TIMER_NAME)
return
.. code-block:: bash
26/02/2022 12:23:09 - INFO - Event: "clock", started... execute in 60 seconds
26/02/2022 12:23:16 - INFO - Cancel event: "clock", ok...
Every seconds
^^^^^^^^^^^^^
Execute any macro every seconds.
@ -511,7 +572,7 @@ Execute any macro every seconds.
TIMER_NAME = 'clock'
def show_time():
app.debug(app.now(True))
app.debug(app.dates.time)
return
def start_clock():
@ -520,46 +581,74 @@ Execute any macro every seconds.
'library': 'test',
'name': 'show_time',
}
app.start_timer(TIMER_NAME, seconds, macro)
app.timer.start(TIMER_NAME, seconds, macro)
return
def stop_clock():
app.stop_timer(TIMER_NAME)
app.timer.stop(TIMER_NAME)
return
def main(args=None):
start_clock()
return
Execute `stop_clock` for stop timer.
Execute **stop_clock** for stop timer.
.. code-block:: bash
21/06/2021 22:43:17 - INFO - Timer started... show_time
21/06/2021 22:43:18 - DEBUG - 22:43:18.080315
21/06/2021 22:43:19 - DEBUG - 22:43:19.082211
26/02/2022 11:28:01 - INFO - Timer 'clock' started, execute macro: 'show_time'
26/02/2022 11:28:02 - DEBUG - 11:28:02
26/02/2022 11:28:03 - DEBUG - 11:28:03
...
21/06/2021 22:43:46 - DEBUG - 22:43:46.126446
21/06/2021 22:43:47 - DEBUG - 22:43:47.128487
21/06/2021 22:43:47 - INFO - Timer stopped... show_time
26/02/2022 11:28:08 - DEBUG - 11:28:08
26/02/2022 11:28:09 - DEBUG - 11:28:09
26/02/2022 11:28:10 - INFO - Timer stopped...
.. note::
Be sure to use a unique name for each timer.
.. warning::
Be sure to macro for execute not block UI LibO
Get digest
^^^^^^^^^^
----------
For default get digest in hex
.. code-block:: python
data = 'LibreOffice with Python'
digest = app.sha256(data)
app.msgbox(digest)
digest = app.hash.digest('md5', data)
app.debug('MD5 = ', digest)
digest = app.sha512(data)
app.msgbox(digest)
digest = app.hash.digest('sha1', data)
app.debug('SHA1 = ', digest)
digest = app.hash.digest('sha256', data)
app.debug('SHA256 = ', digest)
digest = app.hash.digest('sha512', data)
app.debug('SHA512 = ', digest)
# Get bytes
digest = app.hash.digest('md5', data, False)
app.debug('MD5 = ', digest)
.. code-block:: bash
26/02/2022 15:57:53 - DEBUG - MD5 = e0cb96d2c04b26db79dbd30c4d56b555
26/02/2022 15:57:53 - DEBUG - SHA1 = 7006fb17b7a235245cfc986710a11f10543ae10d
26/02/2022 15:57:53 - DEBUG - SHA256 = 3fe4586d51fa3e352ec28c05b7e71eaee2e41d5ee78f372c44eeb2f433f7e002
26/02/2022 15:57:53 - DEBUG - SHA512 = b6eaea6bc11956eae7f990034ff950eba4b0fe51a577d301272cc8b4c1c603abd36ce852311766e5af2f603d1d96741797b62d4b405459348bacae7ec54e2982
26/02/2022 15:57:53 - DEBUG - MD5 = b'\xe0\xcb\x96\xd2\xc0K&\xdby\xdb\xd3\x0cMV\xb5U'
Save and get configurations
^^^^^^^^^^^^^^^^^^^^^^^^^^^
---------------------------
You can save any data.

View File

@ -20,18 +20,23 @@
import datetime
import getpass
import hashlib
import json
import logging
import os
import platform
import shlex
import shutil
import socket
import subprocess
import sys
import tempfile
import threading
import time
import traceback
from functools import wraps
from pathlib import Path
from pprint import pprint
from typing import Any
@ -64,6 +69,11 @@ _info_debug = f"Python: {sys.version}\n\n{platform.platform()}\n\n" + '\n'.join(
SALT = b'00a1bfb05353bb3fd8e7aa7fe5efdccc'
_EVENTS = {}
PYTHON = 'python'
if IS_WIN:
PYTHON = 'python.exe'
CTX = uno.getComponentContext()
SM = CTX.getServiceManager()
@ -80,56 +90,6 @@ class MessageBoxType():
MBT = MessageBoxType
def debug(*messages) -> None:
"""Show messages debug
:param messages: List of messages to debug
:type messages: list[Any]
"""
data = [str(m) for m in messages]
log.debug('\t'.join(data))
return
def error(message: Any) -> None:
"""Show message error
:param message: The message error
:type message: Any
"""
log.error(message)
return
def info(*messages) -> None:
"""Show messages info
:param messages: List of messages to debug
:type messages: list[Any]
"""
data = [str(m) for m in messages]
log.info('\t'.join(data))
return
def save_log(path: str, data: Any) -> None:
"""Save data in file, data append to end and automatic add current time.
:param path: Path to save log
:type path: str
:param data: Data to save in file log
:type data: Any
"""
with open(path, 'a') as f:
f.write(f'{str(now())[:19]} - ')
pprint(data, stream=f)
return
def create_instance(name: str, with_context: bool=False, argument: Any=None) -> Any:
"""Create a service instance
@ -183,6 +143,22 @@ def get_app_config(node_name: str, key: str='') -> Any:
return value
# Get info LibO
NAME = TITLE = get_app_config('org.openoffice.Setup/Product', 'ooName')
VERSION = get_app_config('org.openoffice.Setup/Product','ooSetupVersion')
LANGUAGE = get_app_config('org.openoffice.Setup/L10N/', 'ooLocale')
LANG = LANGUAGE.split('-')[0]
INFO_DEBUG = f"{NAME} v{VERSION} {LANGUAGE}\n\n{_info_debug}"
# Get start date from Calc configuration
node = '/org.openoffice.Office.Calc/Calculate/Other/Date'
year = get_app_config(node, 'YY')
month = get_app_config(node, 'MM')
day = get_app_config(node, 'DD')
DATE_OFFSET = datetime.date(year, month, day).toordinal()
def set_app_config(node_name: str, key: str, new_value: Any) -> Any:
"""Update value for key in node name.
@ -217,6 +193,56 @@ def set_app_config(node_name: str, key: str, new_value: Any) -> Any:
return result
def debug(*messages) -> None:
"""Show messages debug
:param messages: List of messages to debug
:type messages: list[Any]
"""
data = [str(m) for m in messages]
log.debug('\t'.join(data))
return
def error(message: Any) -> None:
"""Show message error
:param message: The message error
:type message: Any
"""
log.error(message)
return
def info(*messages) -> None:
"""Show messages info
:param messages: List of messages to debug
:type messages: list[Any]
"""
data = [str(m) for m in messages]
log.info('\t'.join(data))
return
def save_log(path: str, data: Any) -> None:
"""Save data in file, data append to end and automatic add current time.
:param path: Path to save log
:type path: str
:param data: Data to save in file log
:type data: Any
"""
with open(path, 'a') as f:
f.write(f'{str(now())[:19]} - ')
pprint(data, stream=f)
return
def _set_app_command(command: str, disable: bool):
NEW_NODE_NAME = f'zaz_disable_command_{command.lower()}'
name = 'com.sun.star.configuration.ConfigurationProvider'
@ -270,22 +296,6 @@ class commands():
return _set_app_command(self._command, False)
# Get info LibO
NAME = TITLE = get_app_config('org.openoffice.Setup/Product', 'ooName')
VERSION = get_app_config('org.openoffice.Setup/Product','ooSetupVersion')
LANGUAGE = get_app_config('org.openoffice.Setup/L10N/', 'ooLocale')
LANG = LANGUAGE.split('-')[0]
INFO_DEBUG = f"{NAME} v{VERSION} {LANGUAGE}\n\n{_info_debug}"
# Get start date from Calc configuration
node = '/org.openoffice.Office.Calc/Calculate/Other/Date'
year = get_app_config(node, 'YY')
month = get_app_config(node, 'MM')
day = get_app_config(node, 'DD')
DATE_OFFSET = datetime.date(year, month, day).toordinal()
def mri(obj: Any) -> None:
"""Inspect object with MRI Extension
@ -487,6 +497,16 @@ class Dates(object):
"""
return datetime.date.today()
@_classproperty
def time(cls):
"""Current local time
:return: Return the current local time
:rtype: datetime.time
"""
t = cls.now.time().replace(microsecond=0)
return t
@_classproperty
def epoch(cls):
"""Get unix time
@ -662,11 +682,372 @@ class Macro(object):
return result
class Shell(object):
"""Class for subprocess
`See Subprocess <https://docs.python.org/3.7/library/subprocess.html>`_
"""
@classmethod
def run(cls, command, capture=False, split=False):
"""Execute commands
:param command: Command to run
:type command: str
:param capture: If capture result of command
:type capture: bool
:param split: Some commands need split.
:type split: bool
:return: Result of command
:rtype: Any
"""
if split:
cmd = shlex.split(command)
result = subprocess.run(cmd, capture_output=capture, text=True, shell=IS_WIN)
if capture:
result = result.stdout
else:
result = result.returncode
else:
if capture:
result = subprocess.check_output(command, shell=True).decode()
else:
result = subprocess.Popen(command)
return result
@classmethod
def popen(cls, command):
"""Execute commands and return line by line
:param command: Command to run
:type command: str
:return: Result of command
:rtype: Any
"""
try:
proc = subprocess.Popen(shlex.split(command), shell=IS_WIN,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in proc.stdout:
yield line.decode().rstrip()
except Exception as e:
error(e)
yield (e.errno, e.strerror)
class Timer(object):
"""Class for timer thread"""
class TimerThread(threading.Thread):
def __init__(self, event, seconds, macro):
threading.Thread.__init__(self)
self._event = event
self._seconds = seconds
self._macro = macro
def run(self):
while not self._event.wait(self._seconds):
Macro.call(self._macro)
info('\tTimer stopped... ')
return
@classmethod
def exists(cls, name):
"""Validate in timer **name** exists
:param name: Timer name, it must be unique
:type name: str
:return: True if exists timer name
:rtype: bool
"""
global _EVENTS
return name in _EVENTS
@classmethod
def start(cls, name: str, seconds: float, macro: dict):
"""Start timer **name** every **seconds** and execute **macro**
:param name: Timer name, it must be unique
:type name: str
:param seconds: Seconds for wait
:type seconds: float
:param macro: Macro for execute
:type macro: dict
"""
global _EVENTS
_EVENTS[name] = threading.Event()
info(f"Timer '{name}' started, execute macro: '{macro['name']}'")
thread = cls.TimerThread(_EVENTS[name], seconds, macro)
thread.start()
return
@classmethod
def stop(cls, name: str):
"""Stop timer **name**
:param name: Timer name
:type name: str
"""
global _EVENTS
_EVENTS[name].set()
del _EVENTS[name]
return
@classmethod
def once(cls, name: str, seconds: float, macro: dict):
"""Start timer **name** only once in **seconds** and execute **macro**
:param name: Timer name, it must be unique
:type name: str
:param seconds: Seconds for wait before execute macro
:type seconds: float
:param macro: Macro for execute
:type macro: dict
"""
global _EVENTS
_EVENTS[name] = threading.Timer(seconds, Macro.call, (macro,))
_EVENTS[name].start()
info(f'Event: "{name}", started... execute in {seconds} seconds')
return
@classmethod
def cancel(cls, name: str):
"""Cancel timer **name** only once events.
:param name: Timer name, it must be unique
:type name: str
"""
global _EVENTS
if name in _EVENTS:
try:
_EVENTS[name].cancel()
del _EVENTS[name]
info(f'Cancel event: "{name}", ok...')
except Exception as e:
error(e)
else:
debug(f'Cancel event: "{name}", not exists...')
return
class Hash(object):
"""Class for hash
"""
@classmethod
def digest(cls, method: str, data: str, in_hex: bool=True):
"""Get digest from data with method
:param method: Digest method: md5, sha1, sha256, sha512, etc...
:type method: str
:param data: Data for get digest
:type data: str
:param in_hex: If True, get digest in hexadecimal, if False, get bytes
:type in_hex: bool
:return: bytes or hex digest
:rtype: bytes or str
"""
result = ''
obj = getattr(hashlib, method)(data.encode())
if in_hex:
result = obj.hexdigest()
else:
result = obj.digest()
return result
class Paths(object):
"""Class for paths
"""
FILE_PICKER = 'com.sun.star.ui.dialogs.FilePicker'
FOLDER_PICKER = 'com.sun.star.ui.dialogs.FolderPicker'
REMOTE_FILE_PICKER = 'com.sun.star.ui.dialogs.RemoteFilePicker'
OFFICE_FILE_PICKER = 'com.sun.star.ui.dialogs.OfficeFilePicker'
def __init__(self, path=''):
if path.startswith('file://'):
path = str(Path(uno.fileUrlToSystemPath(path)).resolve())
self._path = Path(path)
@property
def path(self):
"""Get base path"""
return str(self._path.parent)
@property
def file_name(self):
"""Get file name"""
return self._path.name
@property
def name(self):
"""Get name"""
return self._path.stem
@property
def ext(self):
"""Get extension"""
return self._path.suffix[1:]
@property
def size(self):
"""Get size"""
return self._path.stat().st_size
@property
def url(self):
"""Get like URL"""
return self._path.as_uri()
@property
def info(self):
"""Get all info like tuple"""
i = (self.path, self.file_name, self.name, self.ext, self.size, self.url)
return i
@property
def dict(self):
"""Get all info like dict"""
data = {
'path': self.path,
'file_name': self.file_name,
'name': self.name,
'ext': self.ext,
'size': self.size,
'url': self.url,
}
return data
@_classproperty
def home(self):
"""Get user home"""
return str(Path.home())
@_classproperty
def documents(self):
"""Get user save documents"""
return self.config()
@_classproperty
def temp_dir(self):
"""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"""
path = self.config('UserConfig')
path = str(Path(path).parent)
return path
@_classproperty
def user_config(self):
"""Get path config in user profile"""
path = self.config('UserConfig')
return path
@classmethod
def to_system(cls, path:str) -> str:
"""Convert paths in URL to system
:param path: Path to convert
:type path: str
:return: Path system format
:rtype: str
"""
if path.startswith('file://'):
path = str(Path(uno.fileUrlToSystemPath(path)).resolve())
return path
@classmethod
def to_url(cls, path: str) -> str:
"""Convert paths in format system to URL
:param path: Path to convert
:type path: str
:return: Path in URL
:rtype: str
"""
if not path.startswith('file://'):
path = Path(path).as_uri()
return path
@classmethod
def config(cls, name: str='Work') -> str:
"""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
`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))
return path
@classmethod
def join(cls, *paths: str) -> str:
"""Join paths
:param paths: Paths to join
:type paths: list
:return: New path with joins
:rtype: str
"""
path = str(Path(paths[0]).joinpath(*paths[1:]))
return path
@classmethod
def exists(cls, path: str) -> bool:
"""If exists path
:param path: Path for validate
:type path: str
:return: True if path exists, False if not.
:rtype: bool
"""
path = cls.to_system(path)
result = Path(path).exists()
return result
@classmethod
def exists_app(cls, name_app: str) -> bool:
"""If exists app in system
:param name_app: Name of application
:type name_app: str
:return: True if app exists, False if not.
:rtype: bool
"""
result = bool(shutil.which(name_app))
return result
def __getattr__(name):
classes = {
'dates': Dates,
'json': Json,
'macro': Macro,
'shell': Shell,
'timer': Timer,
'hash': Hash,
'path': Paths,
}
if name in classes:
return classes[name]