How to modify an ABPerson instance using PyObjC? - python

I am trying to do some repairs to a very large address book on OS X. I would like to do this programmatically, as it would be a very intense effort to do by hand. On a hunch, I thought I might use PyObjC for this, given my familiarity with Python.
I'm able using PyObjC's module AddressBook to poke around, but I can't seem to make any changes:
>>> import AddressBook
>>> ab = AddressBook.ABAddressBook.addressBook()
>>> p = ab.people()[0]
>>> p.isReadOnly()
True
>>> p.valueForProperty_('First')
u'Foo'
>>> p.setValue_forProperty_('Bar', 'First')
False
>>> p.valueForProperty_('First')
u'Foo'
>>> type(p)
<objective-c class ABPerson at 0x7fff76e01ab8>
My first question is can I edit / modify contacts/persons this way? My second question is, for this kind of work, I can also effect changes to contacts using the ScriptingBridge to talk to the Contacts App, using either AppleScript or even PyObjC (or others). Would this be a better method than using the "low-level" API?
EDIT
I tried a few more methods, plain old AppleScript, and Python using the ScriptingBridge. All of my methods to script modifications to contacts fail, even when I call the save() method of the address book. Do I need to edit some system setting to allow contacts to be scripted?
EDIT
For the record, I am running OS X Mountain Lion 10.8.3

Answering my own question. Looking at errors in the console after running the above script, I saw many errors looking like:
AOSKit ERROR: (-) RAF: Invalid url -- https://[myemail]#webdav.facebook.com/[myfbid]/contacts/
(email and id changed of course). I have a 'Facebook' account set up in OS X preferences. By an educated guess, I deleted this Facebook OS X account, and then re-added it. After that, the above script works correctly.

Related

Using Jenkins variables/parameters in Python Script with os.path.join

I'm trying to learn how to use variables from Jenkins in Python scripts. I've already learned that I need to call the variables, but I'm not sure how to implement them in the case of using os.path.join().
I'm not a developer; I'm a technical writer. This code was written by somebody else. I'm just trying to adapt the Jenkins scripts so they are parameterized so we don't have to modify the Python scripts for every release.
I'm using inline Jenkins python scripts inside a Jenkins job. The Jenkins string parameters are "BranchID" and "BranchIDShort". I've looked through many questions that talk about how you have to establish the variables in the Python script, but with the case of os.path.join(),I'm not sure what to do.
Here is the original code. I added the part where we establish the variables from the Jenkins parameters, but I don't know how to use them in the os.path.join() function.
# Delete previous builds.
import os
import shutil
BranchID = os.getenv("BranchID")
BranchIDshort = os.getenv("BranchIDshort")
print "Delete any output from a previous build."
if os.path.exists(os.path.join("C:\\Doc192CS", "Output")):
shutil.rmtree(os.path.join("C:\\Doc192CS", "Output"))
I expect output like: c:\Doc192CS\Output
I am afraid that if I do the following code:
if os.path.exists(os.path.join("C:\\Doc",BranchIDshort,"CS", "Output")):
shutil.rmtree(os.path.join("C:\\Doc",BranchIDshort,"CS", "Output"))
I'll get: c:\Doc\192\CS\Output.
Is there a way to use the BranchIDshort variable in this context to get the output c:\Doc192CS\Output?
User #Adonis gave the correct solution as a comment. Here is what he said:
Indeed you're right. What you would want to do is rather:
os.path.exists(os.path.join("C:\\","Doc{}CS".format(BranchIDshort),"Output"))
(in short use a format string for the 2nd argument)
So the complete corrected code is:
import os
import shutil
BranchID = os.getenv("BranchID")
BranchIDshort = os.getenv("BranchIDshort")
print "Delete any output from a previous build."
if os.path.exists(os.path.join("C:\\Doc{}CS".format(BranchIDshort), "Output")):
shutil.rmtree(os.path.join("C:\\Doc{}CS".format(BranchIDshort), "Output"))
Thank you, #Adonis!

python jedi: how to retrieve methods of instances?

I built simple text editor with some accessibility feature for screen reading software.
I'm using Python for .NET (pythonnet) to show a form containing a rich text box.
When user press tab after a period it pop-ups a context menu with completions for selected element.
Ok, it works fine with Python objects, but it doesn't work with .net live objects, there is no solution to this problem.
Now, I want build a TreeView object with all names and definitions of module I'm editing.
So, for example I type:
import sys
import os
lst = list()
etc...
If I use jedi.names of my source, I can retrieve os, sys and lst.
For each name, I want retrieve sub definitions, such as functions for sys and os module, and methods for lst.
I can't find a way to do this with jedi:
names = jedi.names(MySource)
names[0].defined_names() # works for sys
names[1].defined_names() # works for os
names[2].defined_names() # doesn't work for lst instance of list().
Any suggestions?
I tried to use more and more editors, but accessibility support is very very bad...
This looks like a bug, where jedi.evaluate.representation.Instance.__getattr__() mistakenly blocks evaluation of .names_dict. I added a pull request to the jedi repository to fix this. In the mean time, you can either add 'names_dict' to the whitelist in Instance.__getattr__() in your copy of jedi/evaluate/representation.py, or use the code below to patch this method automatically for the current session.
import jedi
def patch_jedi():
__old__getattr__ = jedi.evaluate.representation.Instance.__getattr__
def __patched__getattr__(self, name):
if name == 'names_dict':
# do a simplified version of __old__getattr__, bypassing the name check
return getattr(self.base, name)
else:
# use standard behavior
return __old__getattr__(self, name)
# test whether jedi has been updated to avoid the Instance.defined_names() bug
try:
jedi.names("lst = list()")[0].defined_names()
except AttributeError as e:
if e.args[0].startswith("Instance ") and e.args[0].endswith("Don't touch this (names_dict)!"):
# patch jedi to avoid this error
print "patching jedi"
jedi.evaluate.representation.Instance.__getattr__ = __patched__getattr__
else:
# something else strange is going on
raise
patch_jedi()
print jedi.names("lst = list()")[0].defined_names()
# or: print jedi.Script("lst = list()").goto_definitions()[0].defined_names()
I should note that I'm not familiar with jedi, so I don't know whether defined_names() is supposed to work for definitions that create instances. The code above won't fix references like jedi.names("lst = []")[0].defined_names(), and there's no obvious patch to do that. So there may be something deeper going on that I don't know about. Hopefully the developer will help set this straight in response to that pull request.

full unix username of a user

Wondering if you know if there is a slick way to get full username from shell?
example: if my unix username is froyo then I want to get my full name
as registered in the system in this case [froyo  === Abhishek Pratap]
finger command does it but for all the logged in users at the same time ..so that needs some parsing to get the right value. Anything slicker ?
Anything from inside python would be great too.
Thanks!
-Abhi
One way to achieve this is using pwd.getpwuid and os.getuid:
>>> import os
>>> import pwd
>>> pwd.getpwuid(os.getuid())[4]
This is the traditional Unix way of doing it (based on standard C library calls).

find all items in list object

I would like to interrogate all new emails (one by one) and find the contents of them so that I can use the contents for another application.
My first step was interpreting the return values from a search done via the search attr of an IMAP4 object. I'm trying to figure out what data is in a list that I have returned to me.
How can I examine the object tree via print? Or, better yet, how can I get the contents of the email in a string?
For ex., I am returned the following via print:
unseen email content: ['3 4'] from a variable named "response".
If I run print response.__class__.__name__, I get "list" returned.
I know that there is other data in "3", and "4", I just don't know what.
update: Specifically, this is the return of a call to an IMAP4obj.search(None, '(UNSEEN)')
from the python docs (here) this example:
# M is a connected IMAP4 instance...
typ, msgnums = M.search(None, 'FROM', '"LDJ"')
it seems a tuple is returned, you can try,
print(type(typ))
print(dir(typ))
print(type(msgnums))
print(dir(msgnums))
try reading the docs, see if it can help clarify your doubts or even make your question clearer.
You may try importing pdb and doing a pdb.pprint.pprint(response)
If it's a program running on your own machine, you can also do a pdb.set_trace() and play with response.
The ipdb module has nicer versions, but it's not usually installed by default.
Sounds like a debugger might help. If you are using an IDE with a debugger set a break point and introspect the objects.
If you do not use an IDE yet, try Eclipse in combination with PyDev

"Unknown object" error when trying to capture artwork from a pict file and embed it into a track

I'm trying to capture artwork from a pict file and embed it into a track on iTunes using python appscript.
I did something like this:
imFile = open('/Users/kartikaiyer/temp.pict','r')
data = imFile.read()
it = app('iTunes')
sel = it.current_track.get()
sel.artworks[0].data_.set(data[513:])
I get an error OSERROR: -1731
MESSAGE: Unknown object
Similar applescript code looks like this:
tell application "iTunes"
set the_artwork to read (POSIX file "/Users/kartikaiyer/temp.pict") from 513 as picture
set data of artwork 1 of current track to the_artwork
end tell
I tried using ASTranslate but it never instantiates the_artwork and then throws an error when there is a reference to the_artwork.
This is an older question, but since I was having trouble doing this same thing now, I thought I'd post my solution in case someone else might benefit.
selected = appscript.app('iTunes').selection.get()
for t in selected:
myArt = open(/path/to/image.jpg,'r')
data = myArt.read()
t.artworks[1].data_.set(data) # no need to remove header but one-indexed as has said earlier
myArt.close()
Hope this helps.
At a quick guess, Appscript references, like AppleScript references, use 1-indexing, not zero-indexing like Python lists. So you probably need to write:
it.current_track.artworks[1].data_.set(...)
(Incidentally, the extra get command in your original script is unnecessary, though harmless in this case.)
As for ASTranslate, you need to enable the 'Send events to app' checkbox if you want it to actually send commands to applications and scripting additions and receive their results. As a rule, it's best to disable this option so that you don't have any unfortunate accidents when translating potentially destructive commands such as set or delete, so only to enable it if you really need it, and be careful what code you run when you do.
The read command is part of Scripting Additions, which ASTranslate doesn't translate to. Use ASDictionary to create a glue for Scripting Additions, by clicking "Choose Installed Scripting Additions" Under the Dictionary menu, and then selecting "Scripting Additions" from the list.

Categories

Resources