Newsgroup: it.comp.macintosh
Titolo: Integrare codice Python in un AppleScript

Non sarebbe male integrare del codice Python in un AppleScript, lě dove
quest'ultimo si dimostra carente, come ad esempio nella manipolazione di
liste. E' possibile...?
-- 
Ci sono 10 tipi di persone: quelle che capiscono il
sistema binario e quelle che non lo capiscono.

 (quoted form of POSIX path of (path to me)) & "Contents/nomescript.sh"
Accetta argomenti passati dallo script e ritorna il risultato...?


 ed accederne al path:
Ho fatto delle prove, ma è un casino: non posso passare una lista come
argomento.


 liste. E' possibile...?
Puoi chiamare da Python AppleScript. O meglio, Python č in grado di
mandare gli stessi messaggi che vengono mandati da AppleScript (anche se
ovviamente non sempre in modo altrettanto comodo).
Avevo anche visto qualcosa di piů alto livello. Forse sul MacOS X System
Internals...
-- 
blog:  
http://www.akropolix.net/rik0/blogs
 | Uccidete i filosofi,
site:  
http://www.akropolix.net/rik0/
      | tenetevi riso e
forum: 
http://www.akropolix.net/forum/
     | bacchette per voi.

).
Sembra stia per entrare nella famiglia di MacOSForge
(
http://lists.macosforge.org/mailman/listinfo
)
e, nonostante sia pensato per sostituirsi all'AppleScript,
una qualche inte(g)razione con AppleScript a partire dal basilare
"do shell script" sembra comunque fattibile.

 Puoi chiamare da Python AppleScript.
Sě, avevo trovato appscript, ma non č proprio quello che avevo in mente.
Comunque vedo di dargli un'occhiata...


 cono comandi di linea. Puoi passargli il path ad un file.
Sì lo so, sono pure riuscito a fare quello che volevo, ma è una pena:
devo trasformare la lista in stringa, iterando per i vari elementi della
lista e facendomi dare l'id di ognuno (sono schede di Rubrica
Indirizzi): già questo fa perdere senso alla cosa: alla fine ci mette
meno facendo tutto da Apple Script.


 "do shell script" sembra comunque fattibile.
Perchè "nonostante?"


 Comunque vedo di dargli un'occhiata...
Con appscript sono riuscito ad abbozzare qualcosa, solo che alla fine
del lavoro mi rimane python attivo nella finestra del terminale (devo
chiudere a mano con ^D) e il missilotto di Python Launcher che rimbalza
nel dock...


 nel dock...
Dovresti lanciare la roba di Python con do shell script...


 Dovresti lanciare la roba di Python con do shell script...
C'è un equivoco: appscript è un modulo python che serve a scriptare le
applicazioni Mac. Lo usi dentro uno script python, non dentro un Apple
Script.


 Dovresti lanciare la roba di Python con do shell script...
Sto dando un'occhiata qua:
http://homepage.mac.com/philip_aker/osa/osa.html
Dovrebbe permettere di inserire codice Tcl, python, ruby, sh, perl o php
direttamente dentro un AppleScript, ma non so con quale livello di
integrazione.


 Script.
Allora non capisco cosa sia successo. Pensavo stessi cercando di
lavorare con AppleScript e fargli chiamare Python. Se ti va di postare
il codice, vediamo.


 il codice, vediamo.
Nessun problema, ma non dipende dal codice, lo fa anche se ci metti solo
un print...
#!/usr/bin/env pythonw
from appscript import *
peopleSet = set(app('Address Book').people.id.get())
syncSet = set(app('Address \
Book').groups['Sincronizzati'].people.id.get())
notsyncSet = set(app('Address Book').groups['Non \
sincronizzati'].people.id.get())
interSet = syncSet.intersection(notsyncSet)
unionSet = syncSet.union(notsyncSet)
diffSet = peopleSet.difference(unionSet)
if interSet != set([]):
        interString = ""
        interList = list(interSet)
        for anID in interList:
                interString += app('Address Book').people[
its.id
 == \
anID][0].name.get() + ", "
        interString = unicode(interString[:-2])
        print "Le seguenti schede fanno parte di entrambi i gruppi:\n" \
+ interString + "\n"
if diffSet != set([]):
        diffString = ""
        diffList = list(diffSet)
        for anID in diffList:
                diffString += app('Address Book').people[
its.id
 == \
anID][0].name.get() + ", "
        diffString = unicode(diffString[:-2])
        print "Le seguenti schede non fanno parte di nessuno dei due \
gruppi:\n" + diffString + "\n"
Verifica che tutte le schede di Rubrica Indirizzi siano assegnate o a
uno o all'altro dei due gruppi "Sincronizzati" e "Non sincronizzati", ma
non a tutti e due contemporaneamente.


 non a tutti e due contemporaneamente.
Ci sono un po' di errori stilistici nel modo in cui tratti le stringhe.
Adesso cerco di mettere a posto. Comunque non riesco ad eseguirlo per
problemi di unicode. Cerco di fare le due cose insieme.
Per il resto io lo lancio da terminale e non da problemi. IMHO *non*
devi usare pythonw (visto che non usi una GUI).


 devi usare pythonw (visto che non usi una GUI).
No, appscript vuole pythonw. Comunque ti farà piacere sapere che grazie
a PythonOSA un AppleScript del genere funziona:
set a to 5
run script "print 2+" & a in "Python"


 Tipo?
Ah, se ti riferisci alla funziona unicode, era un tentativo per cercare
di risolvere il problema delle accentate, che poi mi sono dimenticato di
togliere. Questo:
interString = unicode(interString[:-2])
diventa
interString = interString[:-2]


>> set lista to (run script "[3,4] + [" & a & "]" in "Python")
e riuscire ad assegnare ad una lista AppleScript
una lista restituita da Python ma, se non si
passa da "print", l'output dello script Python OSA
sembra disperdersi nel nulla.
Quindi, sia che si richiami uno script compilato sotto
un Python OSA mediante
run script "..." in "python"
sia che si esegua un Appscript usando
do shell script "python -c 'import appscript; ...'"
mi sembra che il problema di fondo rimanga lo stesso:
alla fine devi lavorare con stringhe nude e crude,
sia quando assembli programmaticamente il codice Python,
sia quando rielabori l'output che ti viene restituito
da script terzi; non esiste un bridge tra le liste di
AppleScript e quelle di Python come invece accade
per il bridge che ad esempio PyObj instaura tra i dizionari
di Python e quelli Cocoa, i quali possono essere manipolati
indifferentemente usando i metodi dei dict o dei
NSDictionary.

 devi usare pythonw (visto che non usi una GUI).
P.S.
Sto usando Python 2.5 + appscript per Python 2.5.


 mi sembra che il problema di fondo rimanga lo stesso
Sě, l'integrazione dei due linguaggi resta problematica. La cosa
migliore, nel caso non si possa/voglia lavorare in AppleScript, č
cercare di lavorare in Python con appscript, appoggiandosi a "osascript"
per l'interazione con l'utente.


 per l'interazione con l'utente.
Che poi però dipende da quello che uno deve fare. Non credo che al
sembro la possibilità di infilare un
run "script" in "Perl"
faccia schifo... :-)


 Sto usando Python 2.5 + appscript per Python 2.5.
Anche io. Funziona anche con il semplice python.


 Tipo?
Usi codice di questo tipo
s=""
for el in l:
  s += f(el) +', '
Questo codice in Python anche se assolutamente corretto sintatticamente
si scontra con una peculiarità di Python: in Python (per ragioni di
ottimizzazione) le stringhe sono immutabili.
Quel codice quindi fa l(n) allocazioni di stringa. È molto più
efficiente (e una volta che uno lo ha imparato, chiaro)
s = ', '.join([f(el) for el in l])
Per inciso, non hai bisogno di trasformare set in lista. È un oggetto
iterabile, quindi funziona ugualmente. Semplificato il codice precedente
diventa:
Sono anche passato a 4 spazi. Molti Pythonsti lo reputano più leggibile
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from appscript import *
peopleSet = set(app('Address Book').people.id.get())
syncSet = set(app('Address \
Book').groups['Sincronizzati'].people.id.get())
notsyncSet = set(app('Address Book').groups['Non \
sincronizzati'].people.id.get())
interSet = syncSet.intersection(notsyncSet)
unionSet = syncSet.union(notsyncSet)
diffSet = peopleSet.difference(unionSet)
if len(interSet) > 0:
    interString = ', '.join((app('Address Book').people[
its.id
 == \
                anID][0].name.get() for anID in interSet))
 
    print "Le seguenti schede fanno parte di entrambi i gruppi:\n" \
                + interString + "\n"
if diffSet != set([]):        
    diffString = ', '.join((app('Address Book').people[
its.id
 == \
                anID][0].name.get() for anID in diffSet))
 
    print "Le seguenti schede non fanno parte di nessuno dei due \
            gruppi:\n %s\n" % diffString


 s = ', '.join([f(el) for el in l])
Ottimo, grazie.


 Anche io. Funziona anche con il semplice python.
Non so che dirti. Qui anche un semplice
from appscript import *
app(u'/Applications/Address Book.app').activate()
mi dà questo problema. Con gli script in cui non c'è di mezzo appscript
invece tutto a posto.


 l(n) allocazioni di stringa
len(l) allocazioni


 Sě, l'integrazione dei due linguaggi resta problematica.
Eppure il concetto di "lista" fa parte del bagaglio delle
strutture dati supportate dagli Apple Events e da OSA.
Googlando si arriva per esempio alla documentazione di
aepack ("Conversion between Python
variables and AppleEvent data containers")
che rende disponibili le conversioni
list <=> typeAEList
dictionary <=> typeAERecord.
Basterebbe che "run script" e il passaggio di argomenti
tra gli handler run() fosse meno rudimentale.
Per quanto riguarda Cocoa e le problematiche relative
al passaggio delle strutture dati sottostanti agli
NSAppleEventDescriptors, con Tiger
č stato introdotto l'OSAKit, ma per gli utenti di altri
linguaggi (tipo MacPerl) il problema sembra rimanere.

 a me fa abbastanza schifetto l'indentazione del pitone :-PPPP
Che c'entra...?


 a me fa abbastanza schifetto l'indentazione del pitone :-PPPP
Davo per scontato che tu avresti PerlOSA... ;-)


 app(u'/Applications/Address Book.app').activate()
Non è che magari il problema è proprio Activate?


 Ottimo, grazie.
l'altenativa (ma in questo caso non lo userei) è StringIO (ovvero
cStringIO).


 Non è che magari il problema è proprio Activate?
In quell'altro mica c'era activate. E' proprio un problema di appscript,
perlomeno qui...


 perlomeno qui...
Io sto usando Python2.5...


 Io sto usando Python2.5...
Io pure.


 Io pure.
Ugh... non saprei dire. Hai provato a settare come she-bang python
invece di pythonw. O comunuque di chiamarlo con python script.py?
Qui funziona.


 O comunuque di chiamarlo con python script.py?
Sě.


 Sě.
Ahi.


>> x
15.199999999999999
E' normale tutto ciň...?



Peraltro un bel po' dell'analisi numerica si trova proprio di fronte a
problematiche connesse a questo problema di rappresentazione.
Ribadisco, non è un problema di Python. E in generale non è un problema
(o meglio, è un problema, ma non c'è modo di evitarlo, si possono usare
solo tecniche per minimizzarlo etc etc etc, ma non è quello che ti
interessa qui).
Dopo di che Python è abbastanza furbo che se tu fai "print x", lui si
accorge che tu non volevi dire 15.1999999_ ma 15.2 e quello stampa (in
realtà si limita ad approssimare). Per inciso quello dei ) periodici è
un caso particolare, presente anche nella matematica "vera". In
particolare algebricamente si dimostra che 15.1999999_ e 15.2 sono lo
stesso razionale.
Semmai Python offre anche la soluzione ai problemi di arrotondamento:
nel calcolo scientifico, dove spesso anche i dati sono sperimentali e
comunque si lavora con delle approssimazioni, non è un problema avere
questi errori di rappresentazione. Nel calcolo bancario invece può
essere una rogna.
Per questo Python offre i Decimal.
from decimal import *
x = Decimal("15.2")
Ma in generale non è quello che vuoi fare: sono *molto* più lenti. E
spesso non ce ne è davvero bisogno.
Mi rendo conto che il mio post è molto confuso. Se vuoi chiarifico.


 Mi rendo conto che il mio post è molto confuso. Se vuoi chiarifico.
No, no, sei stato molto chiaro. Non so però se preferire il
comportamento di python o quello di bc.


 comportamento di python o quello di bc.
Ma è qui il punto: non è il comportamento dell'uno o dell'altro. Sotto
si comportano allo stesso modo. 
Se fai "print 15.2" in Python, ottieni esattamente 15.2 (perchè passa
per le funzioni di rappresentazione "bella").


 si comportano allo stesso modo. 
Lo so, ma a me di come si comportano sotto frega relativamente. Io
vorrei scrivere 14+1.2 e ricevere 15.2. Vorrà dire che come
"calcolatrice" userò bc...


 vorrei scrivere 14+1.2 e ricevere 15.2.
Usa print e funziona come vuoi tu.


>> 14.19999999999999+1
15.2
ma per l'uso di Python interattivo "come calcolatrice" puo` essere
comunque un tradeoff ragionevole.
Alex

 comunque un tradeoff ragionevole.
Grazie mille. Quindi influenza solo ciò che visualizzo a schermo durante
una sessione interattiva, giusto?


 una sessione interattiva, giusto?
Si`, sys.displayhook viene usato esclusivamente nelle sessioni
interattive.
Alex