This example implements a subclass of NSURLProtocol that can be used to load the pydoc documentation of a module.
It also includes a simple documentation browser using WebKit and the PyDocURLProtocol class.
from PyObjCTools import AppHelper
import Foundation, AppKit, WebKit
from Foundation import *
from AppKit import *
import objc; objc.setVerbose(1)
import PyDocURLProtocol
import PyDocEvents
PyDocURLProtocol.setup()
# the web browser doesn't have or need any code really
if __name__ == '__main__':
AppHelper.runEventLoop()
"""
Minimal applescript support.
The PyDocEventHandler handles just the event that is used to open URLs. Thanks
to this class you can use ``open pydoc:///os.open`` from a command-line, or
add ``pydoc:///`` to HTML files.
"""
from Foundation import *
from Carbon.AppleEvents import kAEISGetURL, kAEInternetSuite
import struct
import objc
def fourCharToInt(code):
return struct.unpack('>l', code)[0]
class PyDocEventHandler (NSObject):
webview = objc.IBOutlet('webview')
urlfield = objc.IBOutlet('urlfield')
def handleEvent_withReplyEvent_(self, event, replyEvent):
theURL = event.descriptorForKeyword_(fourCharToInt('----'))
self.urlfield.setStringValue_(theURL.stringValue())
self.webview.takeStringURLFrom_(theURL)
def awakeFromNib(self):
manager = NSAppleEventManager.sharedAppleEventManager()
# Add a handler for the event GURL/GURL. One might think that
# Carbon.AppleEvents.kEISInternetSuite/kAEISGetURL would work,
# but the system headers (and hence the Python wrapper for those)
# are wrong.
manager.setEventHandler_andSelector_forEventClass_andEventID_(
self, 'handleEvent:withReplyEvent:',
fourCharToInt('GURL'),
fourCharToInt('GURL'))
from Foundation import *
import objc
from pydochelper import gethtmldoc
PYDOCSCHEME = u'pydoc'
class PyDocURLProtocol(NSURLProtocol):
def canInitWithRequest_(klass, request):
if request.URL().scheme() == PYDOCSCHEME:
return True
return False
def canonicalRequestForRequest_(klass, request):
return request
def startLoading(self):
client = self.client()
request = self.request()
urlpath = request.URL().standardizedURL().path()
modpath = urlpath.replace(u'/', u'.'
).lstrip(u'.'
).replace(u'.html', u'')
try:
data = gethtmldoc(modpath.encode('utf-8'))
except Exception, e:
client.URLProtocol_didFailWithError_(
self,
NSError.errorWithDomain_code_userInfo_(
NSURLErrorDomain,
NSURLErrorResourceUnavailable,
None,
),
)
else:
response = NSURLResponse.alloc().initWithURL_MIMEType_expectedContentLength_textEncodingName_(
request.URL(),
u'text/html',
len(data),
u'utf-8',
)
client.URLProtocol_didReceiveResponse_cacheStoragePolicy_(
self,
response,
NSURLCacheStorageNotAllowed,
)
client.URLProtocol_didLoadData_(
self,
buffer(data),
)
client.URLProtocolDidFinishLoading_(self)
def stopLoading(self):
pass
def setup():
NSURLProtocol.registerClass_(PyDocURLProtocol)
def teardown():
NSURLProtocol.unregisterClass_(PyDocURLProtocol)
def main(*args):
if not args:
args = ('dict',)
setup()
for arg in args:
url = NSURL.URLWithString_(u'pydoc:///%s' % (arg,))
print NSString.stringWithContentsOfURL_(url)
teardown()
import sys
if __name__ == '__main__': main(*sys.argv[1:])
import pydoc
__all__ = ['gethtmldoc']
def gethtmldoc(thing, forceload=0):
obj, name = pydoc.resolve(thing, forceload)
page = pydoc.html.page(
pydoc.describe(obj),
pydoc.html.document(obj, name)
)
return page
"""
Script for building the example.
Usage:
python setup.py py2app
"""
from distutils.core import setup
import py2app
plist = dict(
NSMainNibFile='PyDocBrowser',
NSAppleScriptEnabled=True,
CFBundleURLTypes=[
dict(
CFBundleURLName='Python Documention URL',
CFBundleURLSchemes=['pydoc'],
)
]
)
setup(
app=["PyDocBrowser.py"],
data_files=["PyDocBrowser.nib"],
options=dict(py2app=dict(plist=plist)),
)