Programar funciones personalizadas en python

Buenas tardes:

Estoy interesado en crearme una macro para Calc, pero que se llame como una función “embebida”. Vamos, que me pueda poner en una celda, y hacer “=mi_macro(celdaseleccionada)”.

He estado jugando con las macros de python y viendo tutoriales. También tengo algo de experiencia ya que he hecho alguna utilidad en python para crear documentos en Writer leyendo datos de PostgreSQL.

En fin, el caso es que viendo la ayuda, dice:

El método que se describe a continuación para ampliar Calc mediante complementos es obsoleto. Para garantizar la compatibilidad con los complementos existentes, las interfaces siguen siendo válidas y reciben servicio técnico. Sin embargo, para programar complementos nuevos se deben emplear las [funciones nuevas de la API

Así que la pregunta es (porque no soy capaz de ver nada además de la página donde describen la API) si hay algún tutorial, introducción, o ejemplos para poder aterrizar (mas bien despegar…je je).

Si no es posible, la pregunta sería…¿merece la pena seguir investigando en el método ya obsoleto?

Puede que este sitio te de alguna guía:
https://wiki.documentfoundation.org/Documentation/DevGuide

1 Like

Hacer esto con Python, es trivial, pero no para ser explicado en una respuesta en este foro. Vere de hacer un video o un artículo en estos días.

2 Likes

Si quieres ir calentando motores, en el siguiente video, a partir del minuto 21, muestro como hacer una función personalizada, pero… si quieres reproducirlo, debes de ver como instalo las herramientas al inicio del video como en el minuto 6 en adelante…

Dado que hay cosas por explicar, espero hacer uno solo de las funciones.

2 Likes

Gracias Mauricio:

Muchas gracias por la respuesta. He visto el vídeo y he descargado el repositorio.
Pero cuando he empezado a intentar hacer un “HolaMundo” me encuentro con el primer problema.

Una vez configurado conf.py, he intentado ejecutado el script zaz.py, tal como muestras en el vídeo:
python zaz.py -c

Pero me da el error siguiente:
No such file or directory: '/usr/lib/libreoffice/sdk/bin/idlc'

He mirado y efectivamente no tengo nada dentro de bin. ¿Sabrías cómo puedo arreglar esto? ¿Habrá algún paquete para ello que no tenga instalado?

Por otro lado, viendo el script hay una línea que hace referencia a este path:
PATH_PYGETTEXT = '/usr/lib/python3.9/Tools/i18n/pygettext.py'

He mirado y yo tengo python3.10, y de hecho mi ruta es '/usr/lib/python3.10/Tools/i18n/pygettext.py'

¿He de cambiarla en el script?

Muchas gracias!

Edito:

Solucionado lo del idlc. Tenía que instalar el SDK.
En mi caso (Manjaro):
sudo pacman -S libreoffice-still-sdk (ojo, que también hay un libreoffice-fresh-sdk y supongo que habrá distros de Manjaro que usen éste)

Por otro lado, ahora que ya se ejectuta el script, parece que el tema del PATH no influye, no obstante lo he cambiado a 3.10, que es mi caso.

Hola Mauricio de nuevo:

No puedo dejar de agradecerte el trabajo creando este entorno para hacer funciones.
Efectivamente, con tu trabajo, crear una función embebida es bastante trivial, una vez que se ha configurado el conf.py

Tengo que seguir puliendo el tema, pero he conseguido crear la función que quería. Es una función para convertir una cantidad a euros. No sé si existirá ya, pero esta creo que funciona. Al menos a mi me sirve.

Faltaría asear un poco la función y tal vez permitir múltiples divisas. Yo he puesto directamente EUROS pero podría mejorarse para que la divisa fuera un parámetro. Incluso tal vez podría coger el dato de la divisa de la propia configuración de LO (aunque esto escapa totalmente de mi conocimiento).

Lo dicho, dejo el script por si a alguien le es de utilidad. Redondea a dos decimales.

import uno
import unohelper
from org.user.miprimerafuncion import XNumeroAMoneda

ID_EXTENSION = 'org.user.miprimerafuncion'
SERVICE = ('com.sun.star.sheet.AddIn',)

Menosde21 = ['Cero','Un','Dos','Tres','Cuatro','Cinco','Seis','Siete','Ocho','Nueve','Diez',
                  'Once','Doce','Trece','Catorce','Quince','Dieciséis','Diecisiete',
                  'Dieciocho','Diecinueve','Veinte']
                  
Menosde500 = {2:'Veinti',3:'Treinta',4:'Cuarenta',5:'Cincuenta',6:'Sesenta',7:'Setenta',8:'Ochenta',9:'Noventa',100:'Cien',500:'Quinientos '}
            
class NumeroAMoneda(unohelper.Base, XNumeroAMoneda):

    def __init__(self, ctx):
        self.ctx = ctx

    def CantAMoneda(self, value):
        #numero = value.replace(',','.') #reemplazo las comas por puntos por si acaso
        f_numero = float(value)
        entero = int(f_numero//1)
        decimal = int(100*round(f_numero%1,2))
        print (entero)
        print (decimal)
        cadena_importe = self.PasarATexto(entero)        
        cadena_importe += " EUROS "
        if decimal>0:
            cadena_importe += "CON "
            cadena_importe += self.PasarATexto(decimal)
            cadena_importe += " CÉNTIMOS"
        cadena_importe = cadena_importe.upper()
        print (cadena_importe)
        return cadena_importe
	
    def PasarATexto(self,numero):
        cadena_numero=""
        if numero>0 and numero<21:
            cadena_numero = Menosde21[int(numero)]
        elif numero>20 and numero<100:
            cadena_numero = Menosde500[int(numero/10)]
            if (numero >29 and numero%10>0):
                cadena_numero+= " y " 
            cadena_numero += self.PasarATexto (numero%10)
        elif numero==100:
            cadena_numero = Menosde500[numero]
        elif (numero>100 and numero<500) or (numero>599 and numero<1000):
            if numero>199:
                cadena_numero=self.PasarATexto(numero/100) + "cientos "
            else:
                cadena_numero = "Ciento "
            cadena_numero += self.PasarATexto(numero%100)
        elif numero>499 and numero<600:
            cadena_numero = Menosde500[int(numero-numero%100)] + self.PasarATexto(numero%100)
        elif numero>999 and numero<1000000:
            if numero>1999:
                cadena_numero = self.PasarATexto(numero/1000)
            cadena_numero+=" Mil "
            cadena_numero+=self.PasarATexto(numero%1000)
        elif numero>999999 and numero<1000000000:
            cadena_numero = self.PasarATexto(numero/1000000)
            if numero>1999999:
                cadena_numero+=" Millones "
            else:
                cadena_numero+= " Millón "
            cadena_numero+=self.PasarATexto(numero%1000000)
        elif numero>999999999 and numero<1000000000000:
            if numero>1999999999:
                cadena_numero = self.PasarATexto(numero/1000000000)
            cadena_numero+=" Mil "
            cadena_numero+=self.PasarATexto(numero%1000000000)                
        elif numero>999999999999 and numero<1000000000000000:
            cadena_numero = self.PasarATexto(numero/1000000000000)
            if numero>1999999999999:
                cadena_numero+=" Billones "
            else:
                cadena_numero+=" Billón "
            cadena_numero+=self.PasarATexto(numero%1000000000000)
        else:
            cadena_numero = "Error leyendo número"               
        #ultimos detalles
        #quitamos espacios al comienzo y al final
        cadena_numero = cadena_numero.strip()
        #cambiamos las centenas de 7 y 9
        cadena_numero = cadena_numero.replace ('Nuevecientos','Novecientos')
        cadena_numero = cadena_numero.replace ('Sietecientos','Setecientos')
        return cadena_numero
        	
g_ImplementationHelper = unohelper.ImplementationHelper()
g_ImplementationHelper.addImplementation(NumeroAMoneda, ID_EXTENSION, SERVICE)


if __name__ == "__main__":
	Dato = NumeroAMoneda(XNumeroAMoneda)
	Dato.CantAMoneda("123.063")

Un pantallazo de la función con diferentes resultados :wink:

Lo dicho, muchas gracias!

Aunque poco conocido ya está implementado en LibreOffice.
https://help.libreoffice.org/latest/en-US/text/shared/01/05020301.html?&DbPAR=CALC&System=WIN
al final de la página NatNum12 modifier
Fue implementado en la versión 6.2
https://wiki.documentfoundation.org/ReleaseNotes/6.1#New_.E2.80.9Cspell_out.E2.80.9D_NatNum_modifier

2 Likes

Vaya, podía haber empezado preguntando por esto :rofl:

Bueno, hecho está. Me ha servido para introducirme en el campo de las funciones integradas personalizadas. Algo es algo.

Saludos y gracias!

Perdona que te moleste otra vez.

Al aprender a usar tu entorno estuve haciendo varias pruebas y ahora tengo funciones personalizadas que no sirven.
¿Sabes cómo puedo desisntalarlas?
Gracias de nuevo!

Solo ve al administrador de extensiones y desinstalalas.

1 Like

Pues listo.

Por cierto, quería editar el mensaje donde está el código en Python para añadirle alguna mejora pero no me deja. ¿Hay alguna restricción en cuanto a tocar mensajes con cierta antigüedad?

Gracias a uno de los comentarios de dehm, instalé libreoffice-fresh-sdk (con pacman). Sin embargo, este no trae el archivo idlc. ¿Saben de alguna sugerencia para superar el error FileNotFoundError: [Errno 2] No such file or directory: '/usr/lib/libreoffice/sdk/bin/idlc'?

Cambié libreoffice-fresh por libreoffice-still: problema resuelto.
Sin embargo, ¿habrá alguna forma de aplicar el procedimiento a libreoffice-fresh?

A partir de 7.5 idlc ha sido descontinuado:

https://wiki.documentfoundation.org/ReleaseNotes/7.5#Feature_Removal_/_Deprecation

Muchas gracias por la aclaratoria, Mauricio.
Seguiré aprendiendo los fundamentos de los macros y la sintaxis básica de Python (espero no tener que migrar a BASIC).