diff --git a/CHANGELOG.md b/CHANGELOG.md index cfbf32e..12a9c7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,15 @@ +v 0.5.0 [07-Dec-2023] +--------------------- + - Add acctions to controls. + - Refactorize documetation. + v 0.4.0 [20-Sep-2023] --------------------- - - Add control layout manager + - Add control layout manager. v 0.3.0 [23-Apr-2023] --------------------- - - Add method post + - Add method post. v 0.2.0 [23-Sep-2022] --------------------- diff --git a/README.md b/README.md index f43dd6e..bfa411b 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,11 @@ This library have a cost of maintenance of 1 euro every year. In order of preferred. +* G1: `A5DdXxCKPw3QKWVdDVs7CzkNugNUW1sHu5zDJFWxCU2h` + Mauricio Baeza ``` Euros IBAN: BE60 9671 0556 5870 SWIFT / BIC: TRWIBEB1XXX -``` - -* G1: `A5DdXxCKPw3QKWVdDVs7CzkNugNUW1sHu5zDJFWxCU2h` +``` \ No newline at end of file diff --git a/VERSION b/VERSION index 1d0ba9e..8f0916f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.4.0 +0.5.0 diff --git a/docs/en/docs/debug.md b/docs/en/docs/debug.md new file mode 100644 index 0000000..d4f34d7 --- /dev/null +++ b/docs/en/docs/debug.md @@ -0,0 +1,198 @@ +## Tools for debug + +
+ +### **INFO_DEBUG** + +Show debugging information in a message box. + +If you have any problems in your code during the development of your macros, you can [open a ticket][1] support in the system ticket of this project. Always copy the debugging information shown in your issue. + +```py +import easymacro as app + +def info(): + app.msgbox(app.INFO_DEBUG) + return +``` + +![Info debug](img/install_01.png) + + +### **debug** + +Show information at the terminal. +```py +import easymacro as app + +def test_debug(): + msg = 'Verify this information...' + app.debug(msg) + return +``` + +To view this message, you need to start LibreOffice from the command line: +``` +soffice --calc +``` + +After executing the previous macro, you should see: +``` +21/04/2023 17:04:49 - DEBUG - Verify this information... +``` + +
+ +### **info** + +Show information messages at the terminal. +```py +import easymacro as app + +def test_info(): + msg = 'Starting process...' + app.info(msg) + return +``` + +``` +11/08/2022 18:23:53 - INFO - Starting process... +``` + +
+ +### **error** + +Show error messages at the terminal. +```py +import easymacro as app + +def test_error(): + msg = 'Error 505' + app.error(msg) + return +``` + +``` +11/08/2022 18:27:34 - ERROR - Error 505 +``` + +
+ +### **save_log** + +Save log in file, automatically add date and time. +```py +import easymacro as app + +def test_save_log(): + + app.save_log('/home/mau/log.txt', 'PyUNO') + app.save_log('/home/mau/log.txt', 'World Damn') + + return +``` + +``` +cat ~/log.txt +2022-08-11 18:30:11 - 'PyUNO' +2022-08-11 18:30:11 - 'World Damn' +``` + +
+ +### **msgbox** + +Show any information in a message box. +```python +import easymacro as app + +def message(): + + msg = 'Please, consume less.' + app.msgbox(msg) + + msg = ('one', 2, 'three') + app.msgbox(msg) + + msg = {'name': 'Teresa'} + app.msgbox(msg) + + app.msgbox(app) + + return +``` + +
+ +### **catch_exception** + +Capture any error that occurs when running a macro. + +!!! warning inline end "Caution" + + Use this method only in development time. **Do not use it in production**. + +```py +import easymacro as app + +@app.catch_exception +def test_capture_error(): + r = 1 / 0 + return +``` + +``` +11/08/2022 18:44:36 - ERROR - test_capture_error +Traceback (most recent call last): + File "/home/mau/.config/libreoffice/4/user/Scripts/python/pythonpath/easymacro/easytools.py", line 115, in func + return f(*args, **kwargs) + File "/home/mau/.config/libreoffice/4/user/Scripts/python/test.py", line 18, in test_capturar_error + r = 1 / 0 +ZeroDivisionError: division by zero +``` + +
+ +### **mri** + +[MRI][2] is the best extension to inspect any UNO LibreOffice object. You need to install it first so you can use it. + +```py +import easymacro as app + +def inspect_object(): + obj = app.active + app.mri(obj) + return +``` + +
+ +### **inspect** + +Inspect an object. +```py +import easymacro as app + +def inspect_object(): + doc = app.active + data = app.inspect(doc) + for p in data.properties: + app.debug(p) + for m in data.methods: + app.debug(m) + return +``` + +Send information of the object to worksheet. +```python +def inspect_object(): + doc = app.active + app.inspect(doc, True) + return +``` + + +[1]: https://git.cuates.net/elmau/easymacro/issues +[2]: https://github.com/hanya/MRI diff --git a/doc/docs/img/favicon.ico b/docs/en/docs/img/favicon.ico similarity index 100% rename from doc/docs/img/favicon.ico rename to docs/en/docs/img/favicon.ico diff --git a/doc/docs/img/install_01.png b/docs/en/docs/img/install_01.png similarity index 100% rename from doc/docs/img/install_01.png rename to docs/en/docs/img/install_01.png diff --git a/doc/docs/img/logo.png b/docs/en/docs/img/logo.png similarity index 100% rename from doc/docs/img/logo.png rename to docs/en/docs/img/logo.png diff --git a/docs/en/docs/index.md b/docs/en/docs/index.md new file mode 100644 index 0000000..bef252f --- /dev/null +++ b/docs/en/docs/index.md @@ -0,0 +1,29 @@ +# Welcome to EasyMacro's documentation + +**Free Software, not gratis software** + +
+ +**easymacro** is a library to develop more easily macros in LibreOffice with Python. It is an abstraction layer between the extensive and complex UNO LibreOffice API and your code. + +You will probably be happier if you use it :) + +You can use **easymacro** with any extension or directly on your macros. + +
+ +- Symily or related projects in Python: + * [python-ooo-dev-tools](https://python-ooo-dev-tools.readthedocs.io) + * [oooscript](https://oooscript.readthedocs.io) + * [python-ooouno-ex](https://github.com/Amourspirit/python-ooouno-ex) +- Symily or related projects in other languages: + * [Java LibreOffice Programming](https://flywire.github.io/lo-p/) + +
+ +Contributions: + +- Moneda Libre Ğ1 (Junas):
+`A5DdXxCKPw3QKWVdDVs7CzkNugNUW1sHu5zDJFWxCU2h` + +
\ No newline at end of file diff --git a/docs/en/docs/install.md b/docs/en/docs/install.md new file mode 100644 index 0000000..e1f57c4 --- /dev/null +++ b/docs/en/docs/install.md @@ -0,0 +1,47 @@ +## Clone repository + +Clone the repository in your favorite project directory. +``` +git clone https://git.cuates.net/elmau/easymacro +``` + +Move into the directory +``` +cd easymacro/source +``` + +copy the `easymacro` folder into the **pythonpath** folder in the Python macro folder within your user profile. Replace **USER** by your real user. +``` +/home/USER/.config/libreoffice/4/user/Scripts/python/pythonpath +``` + +or use a symbolic link (recommended). Replace **PATH** by the absolute route where **easymacro** is located in your file system and **USER** by your username. +``` +ln -s PATH/easymacro/source/easymacro /home/USER/.config/libreoffice/4/user/Scripts/python/pythonpath/ +``` + + +## Test + +In your favorite macros file, for example **mymacros.py**. Use your favorite plain text editor or IDE. Remember, replace **USER** by your real user. +``` +geany /home/USER/.config/libreoffice/4/user/Scripts/python/mymacros.py +``` + +Copy the following code: +```py +import easymacro as app + +def main(): + app.msgbox(app.INFO_DEBUG) + return +``` + +Run the **main** macro in LibreOffice, if you see a message box with information similar to the following! + +![Test install](img/install_01.png) + +It is all ready to start developing macros with **easymacro**. + + +Happy programming! diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml new file mode 100644 index 0000000..00d4ccf --- /dev/null +++ b/docs/en/mkdocs.yml @@ -0,0 +1,40 @@ +site_name: EasyMacro for LibreOffice +site_url: https://doc.cuates.net/easymacro/ +repo_url: https://git.cuates.net/elmau/easymacro/ +nav: + - Home: index.md + - Install: install.md + - Debug: debug.md +theme: + name: material + locale: en + font: false + highlightjs: true + palette: + primary: green + features: + - navigation.path + - content.code.copy + - content.code.select +markdown_extensions: + - admonition + - pymdownx.details + - pymdownx.superfences + - pymdownx.highlight: + anchor_linenums: true + line_spans: __span + pygments_lang_class: true + - pymdownx.inlinehilite + - pymdownx.snippets + - pymdownx.tabbed: + alternate_style: true + - tables + - pymdownx.keys +extra: + alternate: + - name: English + link: / + lang: en + - name: Español + link: /langs/es + lang: es diff --git a/doc/docs/app/index.md b/docs/es/docs/app/index.md similarity index 100% rename from doc/docs/app/index.md rename to docs/es/docs/app/index.md diff --git a/doc/docs/app/menus.md b/docs/es/docs/app/menus.md similarity index 100% rename from doc/docs/app/menus.md rename to docs/es/docs/app/menus.md diff --git a/doc/docs/app/shortcuts.md b/docs/es/docs/app/shortcuts.md similarity index 100% rename from doc/docs/app/shortcuts.md rename to docs/es/docs/app/shortcuts.md diff --git a/doc/docs/calc/cells.md b/docs/es/docs/calc/cells.md similarity index 100% rename from doc/docs/calc/cells.md rename to docs/es/docs/calc/cells.md diff --git a/doc/docs/calc/index.md b/docs/es/docs/calc/index.md similarity index 100% rename from doc/docs/calc/index.md rename to docs/es/docs/calc/index.md diff --git a/doc/docs/calc/ranges.md b/docs/es/docs/calc/ranges.md similarity index 100% rename from doc/docs/calc/ranges.md rename to docs/es/docs/calc/ranges.md diff --git a/doc/docs/calc/sheets.md b/docs/es/docs/calc/sheets.md similarity index 100% rename from doc/docs/calc/sheets.md rename to docs/es/docs/calc/sheets.md diff --git a/doc/docs/debug.md b/docs/es/docs/debug.md similarity index 100% rename from doc/docs/debug.md rename to docs/es/docs/debug.md diff --git a/doc/docs/dialogs/cmd.md b/docs/es/docs/dialogs/cmd.md similarity index 100% rename from doc/docs/dialogs/cmd.md rename to docs/es/docs/dialogs/cmd.md diff --git a/doc/docs/dialogs/image.md b/docs/es/docs/dialogs/image.md similarity index 100% rename from doc/docs/dialogs/image.md rename to docs/es/docs/dialogs/image.md diff --git a/doc/docs/dialogs/index.md b/docs/es/docs/dialogs/index.md similarity index 100% rename from doc/docs/dialogs/index.md rename to docs/es/docs/dialogs/index.md diff --git a/doc/docs/dialogs/label.md b/docs/es/docs/dialogs/label.md similarity index 100% rename from doc/docs/dialogs/label.md rename to docs/es/docs/dialogs/label.md diff --git a/doc/docs/dialogs/link.md b/docs/es/docs/dialogs/link.md similarity index 100% rename from doc/docs/dialogs/link.md rename to docs/es/docs/dialogs/link.md diff --git a/doc/docs/dialogs/md.md b/docs/es/docs/dialogs/md.md similarity index 100% rename from doc/docs/dialogs/md.md rename to docs/es/docs/dialogs/md.md diff --git a/doc/docs/dialogs/text.md b/docs/es/docs/dialogs/text.md similarity index 100% rename from doc/docs/dialogs/text.md rename to docs/es/docs/dialogs/text.md diff --git a/doc/docs/docs/index.md b/docs/es/docs/docs/index.md similarity index 100% rename from doc/docs/docs/index.md rename to docs/es/docs/docs/index.md diff --git a/doc/docs/docs/methods.md b/docs/es/docs/docs/methods.md similarity index 100% rename from doc/docs/docs/methods.md rename to docs/es/docs/docs/methods.md diff --git a/doc/docs/docs/properties.md b/docs/es/docs/docs/properties.md similarity index 100% rename from doc/docs/docs/properties.md rename to docs/es/docs/docs/properties.md diff --git a/doc/docs/dp/drawpage.md b/docs/es/docs/dp/drawpage.md similarity index 100% rename from doc/docs/dp/drawpage.md rename to docs/es/docs/dp/drawpage.md diff --git a/doc/docs/dp/shapes.md b/docs/es/docs/dp/shapes.md similarity index 100% rename from doc/docs/dp/shapes.md rename to docs/es/docs/dp/shapes.md diff --git a/doc/docs/examples/index.md b/docs/es/docs/examples/index.md similarity index 100% rename from doc/docs/examples/index.md rename to docs/es/docs/examples/index.md diff --git a/docs/es/docs/img/favicon.ico b/docs/es/docs/img/favicon.ico new file mode 100644 index 0000000..563a626 Binary files /dev/null and b/docs/es/docs/img/favicon.ico differ diff --git a/docs/es/docs/img/install_01.png b/docs/es/docs/img/install_01.png new file mode 100644 index 0000000..3783237 Binary files /dev/null and b/docs/es/docs/img/install_01.png differ diff --git a/docs/es/docs/img/logo.png b/docs/es/docs/img/logo.png new file mode 100644 index 0000000..88c98f1 Binary files /dev/null and b/docs/es/docs/img/logo.png differ diff --git a/doc/docs/index.md b/docs/es/docs/index.md similarity index 100% rename from doc/docs/index.md rename to docs/es/docs/index.md diff --git a/doc/docs/install.md b/docs/es/docs/install.md similarity index 100% rename from doc/docs/install.md rename to docs/es/docs/install.md diff --git a/doc/docs/tools/datetime.md b/docs/es/docs/tools/datetime.md similarity index 100% rename from doc/docs/tools/datetime.md rename to docs/es/docs/tools/datetime.md diff --git a/doc/docs/tools/email.md b/docs/es/docs/tools/email.md similarity index 100% rename from doc/docs/tools/email.md rename to docs/es/docs/tools/email.md diff --git a/doc/docs/tools/index.md b/docs/es/docs/tools/index.md similarity index 100% rename from doc/docs/tools/index.md rename to docs/es/docs/tools/index.md diff --git a/doc/docs/tools/macros.md b/docs/es/docs/tools/macros.md similarity index 100% rename from doc/docs/tools/macros.md rename to docs/es/docs/tools/macros.md diff --git a/doc/docs/tools/messages.md b/docs/es/docs/tools/messages.md similarity index 100% rename from doc/docs/tools/messages.md rename to docs/es/docs/tools/messages.md diff --git a/doc/docs/tools/paths.md b/docs/es/docs/tools/paths.md similarity index 100% rename from doc/docs/tools/paths.md rename to docs/es/docs/tools/paths.md diff --git a/doc/docs/tools/request.md b/docs/es/docs/tools/request.md similarity index 100% rename from doc/docs/tools/request.md rename to docs/es/docs/tools/request.md diff --git a/doc/docs/tools/threads.md b/docs/es/docs/tools/threads.md similarity index 100% rename from doc/docs/tools/threads.md rename to docs/es/docs/tools/threads.md diff --git a/doc/docs/tools/timer.md b/docs/es/docs/tools/timer.md similarity index 100% rename from doc/docs/tools/timer.md rename to docs/es/docs/tools/timer.md diff --git a/doc/docs/tools/utils.md b/docs/es/docs/tools/utils.md similarity index 100% rename from doc/docs/tools/utils.md rename to docs/es/docs/tools/utils.md diff --git a/doc/mkdocs.yml b/docs/es/mkdocs.yml similarity index 92% rename from doc/mkdocs.yml rename to docs/es/mkdocs.yml index e32dd43..2392800 100644 --- a/doc/mkdocs.yml +++ b/docs/es/mkdocs.yml @@ -43,7 +43,7 @@ nav: - examples/index.md theme: name: material - locale: es + locale: en font: false highlightjs: true palette: @@ -66,11 +66,11 @@ markdown_extensions: alternate_style: true - tables - pymdownx.keys -#~ extra: - #~ alternate: - #~ - name: Español - #~ link: / - #~ lang: es - #~ - name: English - #~ link: /en/ - #~ lang: en +extra: + alternate: + - name: English + link: / + lang: en + - name: Español + link: /langs/es + lang: es diff --git a/source/easymacro/__init__.py b/source/easymacro/__init__.py index bacc4b4..ac54c2e 100644 --- a/source/easymacro/__init__.py +++ b/source/easymacro/__init__.py @@ -1,5 +1,22 @@ #!/usr/bin/env python3 +# ~ easymacro - for easily develop macros in LibreOffice +# ~ Copyright (C) 2020-2023 Mauricio Baeza (elmau) + +# ~ This program is free software: you can redistribute it and/or modify it +# ~ under the terms of the GNU General Public License as published by the +# ~ Free Software Foundation, either version 3 of the License, or (at your +# ~ option) any later version. + +# ~ This program is distributed in the hope that it will be useful, but +# ~ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# ~ for more details. + +# ~ You should have received a copy of the GNU General Public License along +# ~ with this program. If not, see . + + from .easymain import * from .easydialog import * from .easytools import * @@ -8,6 +25,10 @@ from .easydocs import LODocuments from .easydrawpage import LOGalleries +__version__ = '0.5.0' +__author__ = 'Mauricio Baeza (elMau)' + + def __getattr__(name): classes = { 'active': LODocuments().active, diff --git a/source/easymacro/easycalc.py b/source/easymacro/easycalc.py index d01452d..4dab252 100644 --- a/source/easymacro/easycalc.py +++ b/source/easymacro/easycalc.py @@ -8,7 +8,7 @@ from com.sun.star.sheet import CellFlags from com.sun.star.table.CellContentType import EMPTY, VALUE, TEXT, FORMULA from .easymain import (log, DATE_OFFSET, - BaseObject, Color, + BaseObject, Color, LOMain, dict_to_property, run_in_thread, set_properties ) from .easydoc import LODocument @@ -624,6 +624,20 @@ class LOCalcRange(): cols = ra.EndColumn - ra.StartColumn + 1 return rows, cols + def select(self): + """ """ + self.doc.select(self.obj) + return + + def to_image(self): + """ """ + self.select() + self.doc.copy() + args = {'SelectedFormat': 141} + url = 'ClipboardFormatItems' + LOMain.dispatch(self.doc.frame, url, args) + return self.sheet.shapes[-1] + class LOCalcSheet(BaseObject): diff --git a/source/easymacro/easydialog.py b/source/easymacro/easydialog.py index fb79e13..1ecb037 100644 --- a/source/easymacro/easydialog.py +++ b/source/easymacro/easydialog.py @@ -101,6 +101,37 @@ def add_listeners(events, control): return +# ~ getAccessibleActionKeyBinding +class UnoActions(): + ACTIONS = { + 'press': 0, + 'activate': 0, + } + + def __init__(self, obj: Any): + self._obj = obj + self._ac = obj.AccessibleContext + self._actions = hasattr(self._ac, 'AccessibleActionCount') + + def __str__(self): + return ', '.join(self.get()) + + def get(self): + actions = () + if self._actions: + actions = [self._ac.getAccessibleActionDescription(i) for i in + range(self._ac.AccessibleActionCount)] + return actions + + def press(self): + result = self._ac.doAccessibleAction(self.ACTIONS['press']) + return result + + def activate(self): + result = self._ac.doAccessibleAction(self.ACTIONS['activate']) + return result + + class UnoBaseObject(object): def __init__(self, obj: Any): @@ -317,6 +348,10 @@ class UnoBaseObject(object): def ps(self, ps): self.obj.setPosSize(ps.X, ps.Y, ps.Width, ps.Height, POSSIZE) + @property + def actions(self): + return UnoActions(self.obj) + def set_focus(self): self.obj.setFocus() return @@ -469,7 +504,7 @@ class UnoImage(UnoBaseObject): @property def type(self): - return 'button' + return 'image' @property def value(self): @@ -547,6 +582,7 @@ class DialogBox(BaseObject): obj = self._create(properties) super().__init__(obj) self._init_controls() + self._events = None self._modal = False def _create_from_path(self, path: str): @@ -705,7 +741,7 @@ class DialogBox(BaseObject): return Paths.to_url(path) def _special_properties(self, tipo, properties): - if tipo == 'link' and not 'Label' in properties: + if tipo == 'link' and 'URL' in properties and not 'Label' in properties: properties['Label'] = properties['URL'] return properties diff --git a/source/easymacro/easydoc.py b/source/easymacro/easydoc.py index 69e1004..d2fdebf 100644 --- a/source/easymacro/easydoc.py +++ b/source/easymacro/easydoc.py @@ -46,6 +46,9 @@ class LOLayoutManager(BaseObject): self.obj.hideElement(name) return + # ~ def create(self, name): + # ~ return self.obj.createElement(name) + class LODocument(BaseObject): @@ -238,6 +241,8 @@ class LODocument(BaseObject): :type args: dict :return: None if path or stream in memory :rtype: bytes or None + + https://api.libreoffice.org/docs/idl/ref/servicecom_1_1sun_1_1star_1_1document_1_1MediaDescriptor.html """ FILTERS = { 'xlsx': 'Calc MS Excel 2007 XML', @@ -249,8 +254,11 @@ class LODocument(BaseObject): stream = None path_target = 'private:stream' + if filter_name == 'svg': + filter_name = f'{self.type}_svg_Export' + else: + filter_name = FILTERS.get(filter_name, filter_name) - filter_name = FILTERS.get(filter_name, filter_name) filter_data = dict_to_property(args, True) filters = { 'FilterName': filter_name, @@ -266,7 +274,7 @@ class LODocument(BaseObject): try: self.obj.storeToURL(path_target, opt) except Exception as e: - error(e) + log.error(e) if not stream is None: stream = stream.buffer @@ -284,6 +292,11 @@ class LODocument(BaseObject): LOMain.dispatch(self.frame, 'Copy') return + def cut(self): + """Copy current selection""" + LOMain.dispatch(self.frame, 'Cut') + return + def paste(self): """Paste current content in clipboard""" sc = create_instance('com.sun.star.datatransfer.clipboard.SystemClipboard') @@ -314,6 +327,9 @@ class LODocument(BaseObject): self.obj.getUndoManager().clear() return + def replace_ext(self, new_ext): + return Paths.with_suffix(self.path, new_ext) + class LODrawImpress(LODocument): diff --git a/source/easymacro/easymain.py b/source/easymacro/easymain.py index ac401b0..6765153 100644 --- a/source/easymacro/easymain.py +++ b/source/easymacro/easymain.py @@ -537,7 +537,7 @@ class LOMain(): return cls._set_app_command(command, True) @classmethod - def enabled(cls, command) -> bool: + def enabled(cls, command: str) -> bool: """Enabled UNO command :param command: UNO command to enabled @@ -599,13 +599,14 @@ class LOMain(): class ClipBoard(object): SERVICE = 'com.sun.star.datatransfer.clipboard.SystemClipboard' - CLIPBOARD_FORMAT_TEXT = 'text/plain;charset=utf-16' + TEXT = 'text/plain;charset=utf-16' + IMAGE = 'application/x-openoffice-bitmap;windows_formatname="Bitmap"' class TextTransferable(unohelper.Base, XTransferable): def __init__(self, text): df = DataFlavor() - df.MimeType = ClipBoard.CLIPBOARD_FORMAT_TEXT + df.MimeType = ClipBoard.TEXT df.HumanPresentableName = 'encoded text utf-16' self.flavors = (df,) self._data = text @@ -631,7 +632,7 @@ class ClipBoard(object): transferable = sc.getContents() data = transferable.getTransferDataFlavors() for df in data: - if df.MimeType == cls.CLIPBOARD_FORMAT_TEXT: + if df.MimeType == cls.TEXT: break if df: text = transferable.getTransferData(df) @@ -1045,10 +1046,13 @@ class Paths(object): :return: Path with new extension :rtype: str """ - p = Paths(path) - name = f'{p.name}.{new_ext}' - path = cls.join(p.path, name) - return path + if not new_ext.startswith('.'): + new_ext = f'.{new_ext}' + return Path(path).with_suffix(new_ext) + + @classmethod + def with_suffix(cls, path: str, new_ext: str): + return cls.replace_ext(path, new_ext) @classmethod def open(cls, path: str): diff --git a/source/easymacro/easyshape.py b/source/easymacro/easyshape.py index f346a1a..5d4da91 100644 --- a/source/easymacro/easyshape.py +++ b/source/easymacro/easyshape.py @@ -245,6 +245,7 @@ class LOShape(BaseObject): def save(self, path: str='', name: str=''): """Save image""" + if not path: path = Paths(self.doc.URL).path if not name: