Doc for app

This commit is contained in:
El Mau 2022-03-03 23:32:55 -06:00
parent 0f2638ebaa
commit 6bfa41b43c
6 changed files with 1140 additions and 25 deletions

104
docs/source/application.rst Normal file
View File

@ -0,0 +1,104 @@
Application
===========
Remember, always import library.
.. code-block:: python
import easymacro as app
Create instances
----------------
* Instances without context
.. code-block:: python
toolkit = app.create_instance('com.sun.star.awt.Toolkit')
* Instances with context
.. code-block:: python
service = 'com.sun.star.awt.DialogProvider2'
dialog = app.create_instance(service, True)
* Get desktop
.. code-block:: python
desktop = app.create_instance('com.sun.star.frame.Desktop', True)
Or
.. code-block:: python
desktop = app.lo.desktop
Fonst
-----
* Get all fonts
.. code-block:: python
fonts = app.lo.fonts()
for f in fonts:
print(f'Name: {f.Name} - StyleName: {f.StyleName}')
Filters
-------
* Get all `support filters`_
.. code-block:: python
filters = app.lo.filters()
ds = []
for f in filters:
data = f"UI Name: {f['UIName']} - Name: {f['Name']} - Type: {f['Type']}"
app.debug(data)
Call dispatch
-------------
You can call any `dispatch command`_ used only if property or method no exists in original object or in `easymacro.py`
.. code-block:: python
doc = app.docs.active
command = 'Gallery'
app.lo.dispatch(doc, command)
Method automatically add `.uno:`
Disable or enabled commands
---------------------------
You can disable any command.
.. code-block:: python
cmd = 'OpenFromCalc'
result = app.command.disable(cmd)
app.debug(result)
And enabled.
.. code-block:: python
result = app.command.enabled(cmd)
app.debug(result)
`OpenFromCalc` is options for open documents in calc, disable or enabled menu entry and icon toolbar.
.. _dispatch command: https://wiki.documentfoundation.org/Development/DispatchCommands
.. _support filters: https://help.libreoffice.org/latest/en-US/text/shared/guide/convertfilters.html

486
docs/source/documents.rst Normal file
View File

@ -0,0 +1,486 @@
Documents
=========
Remember, always import library.
.. code-block:: python
import easymacro as app
Current doc
-----------
.. code-block:: python
doc = app.docs.active
app.msgbox(doc.title)
Iter docs
---------
.. code-block:: python
for doc in app.docs:
app.debug(doc.type, doc.title)
Count
-----
.. code-block:: python
count = len(app.docs)
app.debug(count)
Get by index
------------
.. code-block:: python
doc = app.docs[1]
app.debug(doc.type, doc.title)
Get by name
-----------
.. code-block:: python
name = 'MyDoc.ods'
if name in app.docs:
doc = app.docs[name]
app.debug(doc.type, doc.title)
If contain
----------
.. code-block:: python
result = 'myfile.ods' in app.docs
app.debug(result)
New
---
For default create new Calc document.
.. code-block:: python
doc = app.docs.new()
app.debug(doc.type)
For new Writer document.
.. code-block:: python
doc = app.docs.new('writer')
app.debug(doc.type)
With arguments.
.. code-block:: python
args= {'Hidden': True}
doc = app.docs.new('writer', args)
msg = f'{doc.type} - {doc.title}'
app.msgbox(msg)
doc.visible = True
Other documents.
.. code-block:: python
doc = app.docs.new('draw')
app.debug(doc.type)
doc = app.docs.new('impress')
app.debug(doc.type)
doc = app.docs.new('math')
app.debug(doc.type)
Open
----
.. code-block:: python
path = '/home/mau/ask_example.ods'
doc = app.docs.open(path)
While LibreOffice support format, you can open arbitrary file.
.. code-block:: python
path = '/home/mau/example.xlsx'
doc = app.docs.open(path)
With arguments.
.. code-block:: python
path = '/home/mau/example.ods'
args = {'Password': 'letmein'}
doc = app.docs.open(path, args)
Save
----
* Save new documents
.. code-block:: python
path = '/home/mau/myfile.ods'
doc = app.docs.new()
doc.save(path)
* If previously open and modify then.
.. code-block:: python
doc.save()
* Open exists file and save with other name.
.. code-block:: python
path = '/home/mau/myfile.ods'
doc = app.docs.open(path)
new_path = '/home/mau/other_name.ods'
doc.save(new_path)
Close
-----
.. code-block:: python
doc = app.docs.new()
app.msgbox(doc.title)
doc.close()
To PDF
------
* Save in path
.. code-block:: python
doc = app.active
path = '/home/mau/test.pdf'
doc.to_pdf(path)
* Save in memory
.. code-block:: python
doc = app.active
pdf = doc.to_pdf()
Export
------
* Export common formats
.. code-block:: python
doc = app.docs.new()
path = '/home/mau/myfile.xlsx'
filter_name = 'xlsx'
doc.export(path, filter_name)
path = '/home/mau/myfile.xls'
filter_name = 'xls'
doc.export(path, filter_name)
doc = app.docs.new('writer')
path = '/home/mau/myfile.docx'
filter_name = 'docx'
doc.export(path, filter_name)
path = '/home/mau/myfile.doc'
filter_name = 'doc'
doc.export(path, filter_name)
path = '/home/mau/myfile.rtf'
filter_name = 'rtf'
doc.export(path, filter_name)
* Export in memory.
.. code-block:: python
doc = app.docs.new()
filter_name = 'xlsx'
excel_doc = doc.export(filter_name=filter_name)
Properties
----------
Common properties for documents
obj
^^^
* Get original object pyUNO (read only)
.. code-block:: python
doc = app.active
app.debug(type(doc))
app.debug(type(doc.obj))
title
^^^^^
.. code-block:: python
doc = app.active
app.debug(doc.title)
doc.title = 'New title'
app.debug(doc.title)
type
^^^^
* Get type document: calc, writer, etc. (read only)
.. code-block:: python
doc = app.active
app.debug(doc.type)
uid
^^^
* Get internal RuntimeUID form document. (read only)
.. code-block:: python
doc = app.active
app.debug(doc.uid)
is_saved
^^^^^^^^
* If document is saved or not (read only)
.. code-block:: python
doc = app.active
app.debug(doc.is_saved)
is_modified
^^^^^^^^^^^
* If document has been modified (read only)
.. code-block:: python
doc = app.active
app.debug(doc.is_modified)
is_read_only
^^^^^^^^^^^^
.. code-block:: python
doc = app.active
app.debug(doc.is_read_only)
path
^^^^
* Get path of document. (read only)
.. code-block:: python
doc = app.active
app.debug(doc.path)
dir
^^^
* Get only directory from path saved (read only)
.. code-block:: python
doc = app.active
app.debug(doc.dir)
file_name
^^^^^^^^^
* Get only file name from path saved (read only)
.. code-block:: python
doc = app.active
app.debug(doc.file_name)
name
^^^^
* Get only name without extension (read only)
.. code-block:: python
doc = app.active
app.debug(doc.name)
visible
^^^^^^^
* Hide or show document.
.. code-block:: python
doc = app.active
doc.visible = False
app.msgbox(doc.visible)
doc.visible = True
zoom
^^^^
* Get or set zoom value.
.. code-block:: python
doc = app.active
zoom = doc.zoom
app.msgbox(zoom)
doc.zoom = zoom * 2
app.msgbox(doc.zoom)
doc.zoom = zoom
status_bar
^^^^^^^^^^
* Get status bar, always control in other thread.
.. code-block:: python
@app.run_in_thread
def update_status_bar(sb, text, limit):
sb.start(text, limit)
for i in range(limit):
sb.setValue(i)
app.sleep(1)
# ~ Is important free status bar
sb.end()
return
def main():
doc = app.active
update_status_bar(doc.status_bar, 'Line', 10)
return
selection
^^^^^^^^^
* **CAUTION**: Selection can be many things.
.. code-block:: python
doc = app.active
selection = doc.selection
app.debug(selection)
Methods
-------
set_focus
^^^^^^^^^
.. code-block:: python
for doc in app.docs:
app.debug(doc.title)
doc.set_focus()
app.sleep(1)
copy
^^^^
* Copy current selection
.. code-block:: python
doc = app.active
doc.copy()
paste
^^^^^
* Paste any content in clipboard
.. code-block:: python
doc = app.active
doc.paste()
paste_special
^^^^^^^^^^^^^
* Show dialog box Paste Special
.. code-block:: python
doc = app.active
doc.paste_special()
paste_values
^^^^^^^^^^^^
* Paste only values
.. code-block:: python
doc = app.active
doc.paste_values()
clear_undo
^^^^^^^^^^
* Clear history undo
.. code-block:: python
doc = app.active
doc.clear_undo()

View File

@ -1,5 +1,5 @@
easymacro module API easymacro
================ =============
.. automodule:: easymacro .. automodule:: easymacro
:members: :members:

View File

@ -45,7 +45,20 @@
Dates Dates
Email Email
Hash Hash
IOStream
Json Json
LODocBase
LODocCalc
LODocDraw
LODocDrawImpress
LODocIDE
LODocImpress
LODocMain
LODocMath
LODocWriter
LODocument
LODocuments
LOMain
LOServer LOServer
MBT MBT
Macro Macro
@ -54,7 +67,7 @@
Shell Shell
Timer Timer
Url Url
commands classproperty

View File

@ -26,7 +26,9 @@ You can used **easymacro** with any extension or directly in your macros.
tools tools
paths paths
email email
api application
documents
easymacro
Indices and tables Indices and tables

View File

@ -22,6 +22,7 @@ import csv
import datetime import datetime
import getpass import getpass
import hashlib import hashlib
import io
import json import json
import logging import logging
import os import os
@ -59,9 +60,11 @@ from email.utils import formatdate
from email import encoders from email import encoders
import uno import uno
import unohelper
from com.sun.star.awt import MessageBoxButtons as MSG_BUTTONS from com.sun.star.awt import MessageBoxButtons as MSG_BUTTONS
from com.sun.star.awt.MessageBoxResults import YES from com.sun.star.awt.MessageBoxResults import YES
from com.sun.star.beans import PropertyValue, NamedValue from com.sun.star.beans import PropertyValue, NamedValue
from com.sun.star.io import IOException, XOutputStream
from com.sun.star.ui.dialogs import TemplateDescription from com.sun.star.ui.dialogs import TemplateDescription
@ -303,7 +306,7 @@ def mri(obj: Any) -> None:
`See MRI <https://github.com/hanya/MRI/releases>`_ `See MRI <https://github.com/hanya/MRI/releases>`_
""" """
mri = create_instance('mytools.Mri') m = create_instance('mytools.Mri')
if m is None: if m is None:
msg = 'Extension MRI not found' msg = 'Extension MRI not found'
error(msg) error(msg)
@ -311,7 +314,7 @@ def mri(obj: Any) -> None:
if hasattr(obj, 'obj'): if hasattr(obj, 'obj'):
obj = obj.obj obj = obj.obj
mri.inspect(obj) m.inspect(obj)
return return
@ -467,8 +470,9 @@ def render(template, data):
# Classes # Classes
# ~ https://github.com/django/django/blob/main/django/utils/functional.py#L61
class classproperty:
class _classproperty:
def __init__(self, method=None): def __init__(self, method=None):
self.fget = method self.fget = method
@ -485,7 +489,7 @@ class Dates(object):
""" """
_start = None _start = None
@_classproperty @classproperty
def now(cls): def now(cls):
"""Current local date and time """Current local date and time
@ -494,7 +498,7 @@ class Dates(object):
""" """
return datetime.datetime.now().replace(microsecond=0) return datetime.datetime.now().replace(microsecond=0)
@_classproperty @classproperty
def today(cls): def today(cls):
"""Current local date """Current local date
@ -503,7 +507,7 @@ class Dates(object):
""" """
return datetime.date.today() return datetime.date.today()
@_classproperty @classproperty
def time(cls): def time(cls):
"""Current local time """Current local time
@ -513,7 +517,7 @@ class Dates(object):
t = cls.now.time().replace(microsecond=0) t = cls.now.time().replace(microsecond=0)
return t return t
@_classproperty @classproperty
def epoch(cls): def epoch(cls):
"""Get unix time """Get unix time
@ -927,30 +931,30 @@ class Paths(object):
} }
return data return data
@_classproperty @classproperty
def home(self): def home(self):
"""Get user home""" """Get user home"""
return str(Path.home()) return str(Path.home())
@_classproperty @classproperty
def documents(self): def documents(self):
"""Get user save documents""" """Get user save documents"""
return self.config() return self.config()
@_classproperty @classproperty
def user_profile(self): def user_profile(self):
"""Get path user profile""" """Get path user profile"""
path = self.config('UserConfig') path = self.config('UserConfig')
path = str(Path(path).parent) path = str(Path(path).parent)
return path return path
@_classproperty @classproperty
def user_config(self): def user_config(self):
"""Get path config in user profile""" """Get path config in user profile"""
path = self.config('UserConfig') path = self.config('UserConfig')
return path return path
@_classproperty @classproperty
def python(self): def python(self):
"""Get path executable python""" """Get path executable python"""
if IS_WIN: if IS_WIN:
@ -1918,9 +1922,48 @@ class Color(object):
COLOR_ON_FOCUS = Color()('LightYellow') COLOR_ON_FOCUS = Color()('LightYellow')
class LO(object): class IOStream(object):
"""Class for LibreOffice """Classe for input/output stream"""
"""
class OutputStream(unohelper.Base, XOutputStream):
def __init__(self):
self._buffer = b''
self.closed = 0
@property
def buffer(self):
return self._buffer
def closeOutput(self):
self.closed = 1
def writeBytes(self, seq):
if seq.value:
self._buffer = seq.value
def flush(self):
pass
@classmethod
def buffer(cls):
return io.BytesIO()
@classmethod
def input(cls, buffer):
service = 'com.sun.star.io.SequenceInputStream'
stream = create_instance(service, True)
stream.initialize((uno.ByteSequence(buffer.getvalue()),))
return stream
@classmethod
def output(cls):
return cls.OutputStream()
class LOMain():
"""Classe for LibreOffice"""
class _commands(): class _commands():
"""Class for disable and enable commands """Class for disable and enable commands
@ -1971,7 +2014,7 @@ class LO(object):
""" """
return cls._set_app_command(command, True) return cls._set_app_command(command, True)
@classmethod @classmethod
def enabled(cls, command): def enabled(cls, command):
"""Enabled UNO command """Enabled UNO command
@ -1982,12 +2025,13 @@ class LO(object):
""" """
return cls._set_app_command(command, False) return cls._set_app_command(command, False)
@_classproperty # ~ @classproperty
def cmd(cls): def cmd(cls):
"""Disable or enable commands"""
return cls._commands return cls._commands
@_classproperty # ~ @classproperty
def desktop(cls) -> Any: def desktop(cls):
"""Create desktop instance """Create desktop instance
:return: Desktop instance :return: Desktop instance
@ -2046,6 +2090,469 @@ class LO(object):
return rows return rows
class LODocument():
def __init__(self, obj):
self._obj = obj
self._cc = obj.getCurrentController()
self._undo = True
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
self.close()
@property
def obj(self):
"""Return original pyUno object"""
return self._obj
@property
def type(self):
"""Get type document"""
return self._type
@property
def frame(self):
"""Get frame document"""
return self._cc.getFrame()
@property
def title(self):
"""Get title document"""
return self.obj.getTitle()
@title.setter
def title(self, value):
self.obj.setTitle(value)
@property
def uid(self):
"""Get Runtime UID"""
return self.obj.RuntimeUID
@property
def is_saved(self):
"""Get is saved"""
return self.obj.hasLocation()
@property
def is_modified(self):
"""Get is modified"""
return self.obj.isModified()
@property
def is_read_only(self):
"""Get is read only"""
return self.obj.isReadonly()
@property
def path(self):
"""Get path in system files"""
return Paths.to_system(self.obj.URL)
@property
def dir(self):
"""Get directory from path"""
return Paths(self.path).path
@property
def file_name(self):
"""Get only file name"""
return Paths(self.path).file_name
@property
def name(self):
"""Get name without extension"""
return Paths(self.path).name
@property
def visible(self):
"""Get windows visible"""
w = self.frame.ContainerWindow
return w.isVisible()
@visible.setter
def visible(self, value):
w = self.frame.ContainerWindow
w.setVisible(value)
@property
def zoom(self):
"""Get current zoom value"""
return self._cc.ZoomValue
@zoom.setter
def zoom(self, value):
self._cc.ZoomValue = value
@property
def status_bar(self):
"""Get status bar"""
bar = self._cc.getStatusIndicator()
return bar
@property
def selection(self):
"""Get current selecction"""
sel = self.obj.CurrentSelection
return sel
@property
def table_auto_formats(self):
taf = create_instance('com.sun.star.sheet.TableAutoFormats')
return taf.ElementNames
def save(self, path: str='', args: dict={}) -> bool:
"""Save document
:param path: Path to save document
:type path: str
:param args: Optional: Extra argument for save
:type args: dict
:return: True if save correctly, False if not
:rtype: bool
"""
if not path:
self.obj.store()
return True
path_save = Paths.to_url(path)
opt = dict_to_property(args)
try:
self.obj.storeAsURL(path_save, opt)
except Exception as e:
error(e)
return False
return True
def close(self):
"""Close document"""
self.obj.close(True)
return
def to_pdf(self, path: str='', args: dict={}):
"""Export to PDF
:param path: Path to export document
:type path: str
:param args: Optional: Extra argument for export
:type args: dict
:return: None if path or stream in memory
:rtype: bytes or None
`See PDF Export <https://wiki.documentfoundation.org/Macros/Python_Guide/PDF_export_filter_data>`_
"""
stream = None
path_pdf = 'private:stream'
filter_name = f'{self.type}_pdf_Export'
filter_data = dict_to_property(args, True)
filters = {
'FilterName': filter_name,
'FilterData': filter_data,
}
if path:
path_pdf = Paths.to_url(path)
else:
stream = IOStream.output()
filters['OutputStream'] = stream
opt = dict_to_property(filters)
try:
self.obj.storeToURL(path_pdf, opt)
except Exception as e:
error(e)
if not stream is None:
stream = stream.buffer
return stream
def export(self, path: str='', filter_name: str='', args: dict={}):
"""Export to others formats
:param path: Path to export document
:type path: str
:param filter_name: Filter name to export
:type filter_name: str
:param args: Optional: Extra argument for export
:type args: dict
:return: None if path or stream in memory
:rtype: bytes or None
"""
FILTERS = {
'xlsx': 'Calc MS Excel 2007 XML',
'xls': 'MS Excel 97',
'docx': 'MS Word 2007 XML',
'doc': 'MS Word 97',
'rtf': 'Rich Text Format',
}
stream = None
path_target = 'private:stream'
filter_name = FILTERS.get(filter_name, filter_name)
filter_data = dict_to_property(args, True)
filters = {
'FilterName': filter_name,
'FilterData': filter_data,
}
if path:
path_target = Paths.to_url(path)
else:
stream = IOStream.output()
filters['OutputStream'] = stream
opt = dict_to_property(filters)
try:
self.obj.storeToURL(path_target, opt)
except Exception as e:
error(e)
if not stream is None:
stream = stream.buffer
return stream
def _create_instance(self, name):
obj = self.obj.createInstance(name)
return obj
def set_focus(self):
"""Send focus to windows"""
w = self.frame.ComponentWindow
w.setFocus()
return
def copy(self):
"""Copy current selection"""
LOMain.dispatch(self.frame, 'Copy')
return
def paste(self):
"""Paste current content in clipboard"""
sc = create_instance('com.sun.star.datatransfer.clipboard.SystemClipboard')
transferable = sc.getContents()
self._cc.insertTransferable(transferable)
return
def paste_special(self):
"""Insert contents, show dialog box Paste Special"""
LOMain.dispatch(self.frame, 'InsertContents')
return
def paste_values(self):
"""Paste only values"""
args = {
'Flags': 'SVDT',
# ~ 'FormulaCommand': 0,
# ~ 'SkipEmptyCells': False,
# ~ 'Transpose': False,
# ~ 'AsLink': False,
# ~ 'MoveMode': 4,
}
LOMain.dispatch(self.frame, 'InsertContents', args)
return
def clear_undo(self):
"""Clear history undo"""
self.obj.getUndoManager().clear()
return
class LODocMain():
_type = 'main'
def __init__(self, obj):
self._obj = obj
@property
def obj(self):
return self._obj
@property
def type(self):
return self._type
class LODocCalc(LODocument):
_type = 'calc'
def __init__(self, obj):
super().__init__(obj)
class LODocWriter(LODocument):
_type = 'writer'
def __init__(self, obj):
super().__init__(obj)
self._view_settings = self._cc.ViewSettings
@property
def zoom(self):
return self._view_settings.ZoomValue
@zoom.setter
def zoom(self, value):
self._view_settings.ZoomValue = value
class LODocDrawImpress(LODocument):
def __init__(self, obj):
super().__init__(obj)
class LODocDraw(LODocDrawImpress):
_type = 'draw'
def __init__(self, obj):
super().__init__(obj)
class LODocImpress(LODocDrawImpress):
_type = 'impress'
def __init__(self, obj):
super().__init__(obj)
class LODocMath(LODocDrawImpress):
_type = 'math'
def __init__(self, obj):
super().__init__(obj)
class LODocBase(LODocument):
_type = 'base'
def __init__(self, obj):
super().__init__(obj)
class LODocIDE(LODocument):
_type = 'basicide'
def __init__(self, obj):
super().__init__(obj)
class LODocuments():
"""Classe for documents
"""
_classes = {
'com.sun.star.sheet.SpreadsheetDocument': LODocCalc,
'com.sun.star.text.TextDocument': LODocWriter,
'com.sun.star.drawing.DrawingDocument': LODocDraw,
'com.sun.star.presentation.PresentationDocument': LODocImpress,
'com.sun.star.formula.FormulaProperties': LODocMath,
'com.sun.star.script.BasicIDE': LODocIDE,
'com.sun.star.sdb.OfficeDatabaseDocument': LODocBase,
'com.sun.star.frame.StartModule': LODocMain
}
# ~ BASE: 'com.sun.star.sdb.DocumentDataSource',
_desktop = LOMain.desktop
def __len__(self):
# ~ len(self._desktop.Components)
for i, _ in enumerate(self._desktop.Components):
pass
return i + 1
def __getitem__(self, index):
# ~ self._desktop.Components[index]
obj = None
for i, doc in enumerate(self._desktop.Components):
if isinstance(index, int) and i == index:
obj = self._get_class_doc(doc)
break
elif isinstance(index, str) and doc.Title == index:
obj = self._get_class_doc(doc)
break
return obj
def __contains__(self, item):
doc = self[item]
return not doc is None
def __iter__(self):
self._i = -1
return self
def __next__(self):
self._i += 1
doc = self[self._i]
if doc is None:
raise StopIteration
else:
return doc
def _get_class_doc(self, doc):
"""Identify type doc"""
main = 'com.sun.star.frame.StartModule'
if doc.supportsService(main):
return self._classes[main](doc)
mm = create_instance('com.sun.star.frame.ModuleManager')
type_module = mm.identify(doc)
return self._classes[type_module](doc)
@property
def active(self):
"""Get active doc"""
doc = self._desktop.getCurrentComponent()
obj = self._get_class_doc(doc)
return obj
def new(self, type_doc: str='calc', args: dict={}):
"""Create new document
:param type_doc: The type doc to create, default is Calc
:type type_doc: str
:param args: Extra argument
:type args: dict
:return: New document
:rtype: Custom classe
"""
url = f'private:factory/s{type_doc}'
opt = dict_to_property(args)
doc = self._desktop.loadComponentFromURL(url, '_default', 0, opt)
obj = self._get_class_doc(doc)
return obj
def open(self, path: str, args: dict={}):
""" Open document from path
:param path: Path to document
:type path: str
:param args: Extra argument
Usually options:
Hidden: True or False
AsTemplate: True or False
ReadOnly: True or False
Password: super_secret
MacroExecutionMode: 4 = Activate macros
Preview: True or False
:type args: dict
`See API XComponentLoader <http://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1frame_1_1XComponentLoader.html>`_
`See API MediaDescriptor <http://api.libreoffice.org/docs/idl/ref/servicecom_1_1sun_1_1star_1_1document_1_1MediaDescriptor.html>`_
"""
url = Paths.to_url(path)
opt = dict_to_property(args)
doc = self._desktop.loadComponentFromURL(url, '_default', 0, opt)
if doc is None:
return
obj = self._get_class_doc(doc)
return obj
def __getattr__(name): def __getattr__(name):
classes = { classes = {
'dates': Dates, 'dates': Dates,
@ -2059,8 +2566,11 @@ def __getattr__(name):
'url': Url, 'url': Url,
'email': Email, 'email': Email,
'color': Color(), 'color': Color(),
'lo': LO, 'io': IOStream,
'desktop': LO.desktop, 'lo': LOMain,
'command': LOMain.cmd,
'docs': LODocuments(),
'active': LODocuments().active,
} }
if name in classes: if name in classes:
return classes[name] return classes[name]