+
+
+"""
def __init__(self):
- # [(name, data), ...]
+ # [(name, doc, data), ...]
self.pages = []
- def generateModule(self, moduleName, structure):
- ## 1 = class, 2 = method, 4 = property, 3 = function
- self.pages.append((moduleName, structure))
+ def generateModule(self, moduleName, moduleDoc, structure):
+ self.pages.append((moduleName, moduleDoc, structure))
+
+ def markup(self, s):
+ #s = s.replace("\n", " ")
+ #assert hasattr(self, "names")
+ if not s.strip():
+ return s
+ if s.count("\n+ "):
+ lastLineWasInList = False
+ lines = s.split("\n")
+ for i, line in enumerate(lines):
+ if line.startswith("+"):
+ line = "
%s
" % line[2:]
+ if not lastLineWasInList:
+ line = "
%s" % line
+ lines[i] = line
+ lastLineWasInList = True
+ elif lastLineWasInList:
+ lines[i] = "
%s" % line
+ lastLineWasInList = False
+ s = "\n".join(lines).replace("\n", "")
+ # convert newlines to breaks
+ s = s.replace("\n", " ")
+ # and two dashes to an en dash
+ s = s.replace(" -- ", " – ")
+ # and finally (and most importantly), add a full stop at the end
+ s = "%s." % s.rstrip(".")
+ return s
def write(self, directory):
- for name, data in self.pages:
- f = file(os.path.join(directory, name) + ".htm", "w")
- f.write(str(data))
+ # first, actually. We want to see all the 'names' present in the document so we can provide links to them if there's a reference in the form [foo]
+ fullNames = []
+ for moduleName, doc, data in self.pages:
+ for item in data:
+ if isinstance(item, tuple) and item[0] == 4:
+ fullNames.append("%s.%s" % (moduleName, item[1].split("(")[0].strip()))
+ elif isinstance(item, list):
+ className = item[0][1]
+ fullNames.append("%s.%s" % (moduleName, className))
+ for method in item[1:]:
+ fullNames.append("%s.%s.%s" % (moduleName, className, method[1].split("(")[0].strip()))
+ if len(self.pages) > 1:
+ moduleBar = '
Modules:
'
+ moduleBar += ' | '.join('%s' % (x, x) for x, y, z in self.pages)
+ moduleBar += '
'
+ else:
+ moduleBar = ''
+ # Generate the markup to link to other modules if there is > 1
+ #print names
+ for moduleName, doc, data in self.pages:
+ # set up links
+ moduleNameLength = len(moduleName)
+ names = [x[moduleNameLength:].lstrip(".") if x.startswith(moduleName) else x for x in fullNames]
+ #print moduleName, names
+ # serialize the data to HTML
+ output = []
+ append = output.append
+ ## type, name, doc
+ ## item[0]: 1 = class, 2 = method, 3 = property, 4 = function
+ for item in data:
+ if isinstance(item, tuple) and item[0] == 4:
+ # function
+ append('
\n' % (cls[1], cls[1], inherits, self.markup(cls[2])))
+ for method in item:
+ # check if this has been inherited
+ inheritedClassNameValue = ""
+ inheritedMessage = ""
+ # if the implementing class is not this one
+ if method[4] != cls[1]:
+ inheritedClassNameValue = "inherited "
+ inheritedMessage = '
\n' % (inheritedClassNameValue, cls[1], name.split(" ")[0], name, inheritedMessage, self.markup(method[2])))
+ else:
+ OhMyGodStrangeThingsInTheDataStructure
+ # Finally, add all the links
+ content = "".join(output)
+ for name in names:
+ if content.count("[%s]" % name):
+ # deduce the link URL
+ url = ""
+ anchorName = name
+ # relative reference
+ if name.split(".")[0] not in moduleNames:
+ # if it's relative to a submodule, though
+ for possibleModule in moduleNames:
+ if possibleModule == "%s.%s" % (moduleName, name.split(".")[0]):
+ url = "%s.%s" % (moduleName, name.split(".")[0]) + ".htm"
+ anchorName = ".".join(name.split(".")[1:])
+ else:
+ # absolute reference
+ for possibleModule in moduleNames:
+ if name.startswith(possibleModule) and hasattr(myImport(possibleModule), name.replace(possibleModule, "").lstrip(".").split(".")[0]):
+ url = possibleModule + ".htm"
+ #print "Setting url:", possibleModule + ".htm"
+ anchorName = name.replace(possibleModule, "").lstrip(".")
+ url += "#" + anchorName
+ print url
+ content = content.replace("[%s]" % name, '%s' % (url, name))
+ # add the stylesheet link if necessary
+ stylesheet = ""
+ script = ""
+ if len(sys.argv) > 1:
+ if len(sys.argv) > 2:
+ script = "\n".join('' % x for x in sys.argv[2].split(","))
+ stylesheet = "\n".join('' % x for x in sys.argv[1].split(","))
+ # set the active module in the module bar
+ modulesMarkup = moduleBar.replace('"%s.htm"' % moduleName, '"%s.htm" class="here"' % moduleName)
+ d = {"modulename" : moduleName, "moduledoc" : doc, "content" : content, "stylesheet" : stylesheet, "script" : script, "modules" : modulesMarkup}
+ html = GenerateHtml.html % d
+ f = file(os.path.join(directory, moduleName) + ".htm", "w")
+ f.write(html)
f.close()
def main():
# turn the module names into modules
+ makeInheritanceDiagrams = "--diagrams" in sys.argv
modules = []
## Speed up
inspect_isclass = inspect.isclass
@@ -69,15 +315,17 @@
inspect_isfunction = inspect.isfunction
_isinstance = isinstance
_documentClass = documentClass
- _itemToClassList = itemToClassList
+ _classToClassList = classToClassList
_getattr = getattr
## End speed up
+ doneItems = {}
generator = GenerateHtml()
for moduleName in moduleNames:
module = __import__(moduleName)
if moduleName.count("."):
subModuleName = moduleName.split(".")[1]
module = _getattr(module, subModuleName)
+ moduleDoc = module.__doc__
itemsToExamine = []
documentedItems = []
for attributeName in dir(module):
@@ -85,16 +333,56 @@
itemsToExamine.append((attributeName, _getattr(module, attributeName)))
while itemsToExamine:
- name, item = itemsToExamine.pop(0)
+ thingToExamine = itemsToExamine.pop(0)
+ name = thingToExamine[0]
+ item = thingToExamine[1]
+ extra = thingToExamine[2:]
+ # class
if inspect_isclass(item) and item.__module__ in moduleNames:
+ print "Checking for %s.%s.png" % (moduleName, name)
+ if makeInheritanceDiagrams:
+ makeDiagram(item)
+ else:
+ assert os.path.exists(os.path.join(docDirectory, "%s.%s.png" % (moduleName, name)))
_documentClass(item, name, itemsToExamine, documentedItems)
- elif inspect_ismethod(item) or _isinstance(item, property):
- _itemToClassList[item].append((2, name, getDoc(item)))
- #_documentMethod(item, name, itemsToExamine, documentedItems)
+ # method (extra tuple items: class, definingClass)
+ elif inspect_ismethod(item):
+ cls = extra[0]
+ implementingClass = getMethodImplementor(item, cls)
+ _classToClassList[cls].append((2, functionSignature(item), getDoc(item), cls, implementingClass))
+ # property (extra tuple items: class, definingClass)
+ elif _isinstance(item, property):
+ cls = extra[0]
+ implementingClass = getPropertyImplementor(item, name, cls)
+ #print "implementingClass:", implementingClass
+ _classToClassList[cls].append((3, propertySignature(item, name), getDoc(item), cls, implementingClass))
+ # function
elif inspect_isfunction(item) and item.__module__ in moduleNames:
- documentedItems.append((4, name, getDoc(item)))
- generator.generateModule(moduleName, documentedItems)
- generator.write("doc")
+ documentedItems.append((4, functionSignature(item), getDoc(item)))
+ # re-sort data
+ if moduleName in moduleForceFirstItems:
+ order = moduleForceFirstItems[moduleName]
+ # pull the items we want out of the data structure into here, in the order that we want
+ dataHead = [None] * len(order)
+ for i in reversed(xrange(len(documentedItems))):
+ item = documentedItems[i]
+ if _isinstance(item, tuple):
+ # function will have the arguments added. Strip them
+ itemName = item[1].split("(")[0]
+ if itemName in order:
+ dataHead[order.index(itemName)] = item
+ documentedItems.pop(i)
+ elif _isinstance(item, list):
+ cls = documentedItems[i]
+ if cls[0][1] in order:
+ dataHead[order.index(cls[0][1])] = cls
+ documentedItems.pop(i)
+ if None in dataHead:
+ print dataHead
+ raise Exception("!! Error: Cannot move '%s' to the top of the documentation document: it doesn't exist!" % order[dataHead.index(None)])
+ documentedItems = dataHead + documentedItems
+ generator.generateModule(moduleName, moduleDoc, documentedItems)
+ generator.write(docDirectory)
if __name__ == "__main__":
main()
=== modified file 'pykhtml/__init__.py'
--- pykhtml/__init__.py 2007-02-05 22:39:48 +0000
+++ pykhtml/__init__.py 2007-02-10 19:23:01 +0000
@@ -3,7 +3,7 @@
import khtml, kdecore
import sip # cast
#from khtml.DOM import DOMString
-from qt import *
+import qt
DOM = khtml.DOM
DOMString = DOM.DOMString
@@ -27,6 +27,7 @@
## stupid to start Xvfb each time
if os.name == "posix":
def running(name):
+ """ Check whether a process of the given name is running """
procs = os.popen("ps -eo comm").read().strip().split("\n")
return name in procs
else:
@@ -59,11 +60,11 @@
kdecore.KCmdLineArgs.init(sys.argv, "PyKHTML", "PyKHTML Library", "0.1")
application = kdecore.KApplication()
# the widget that will host the KHTMLParts
- dialog = QDialog(None)
+ dialog = qt.QDialog(None)
application.setMainWidget(dialog)
if debugWithGUI:
dialog.show()
- dialog.layout = QVBoxLayout(dialog)
+ dialog.layout = qt.QVBoxLayout(dialog)
def init(display=1, _sleep=1):
""" Initiate the system if necessary (start Xvfb if it's not running, connect to it, start our program instance). This is called automatically when you create a Browser instance, so you shouldn't have to worry about it. You can specify use of a certain display by setting the `display` parameter. """
@@ -105,11 +106,13 @@
def timer(time, func):
""" Call the given function after the alloted time. Requires that the PyKHTML event loop is running """
- QTimer.singleShot(int(time * 1000), func)
+ qt.QTimer.singleShot(int(time * 1000), func)
class Browser(object):
+ """ A Browser is the main class you use to navigate around and visit different pages. Have a look at Browser.load and Browser.document to access basic use. """
def __init__(self):
+ """ Create a new Browser """
init()
self.part = khtml.KHTMLPart(dialog)
if debugWithGUI:
@@ -132,14 +135,14 @@
def load(self, uri, callback):
""" Load a webpage in the browser. It takes as parameters the URI of the page to load, and a callable object to call when the page has loaded. """
if self.loadFunction:
- self.disconnect(self.part, SIGNAL("docCreated()"). self._slotDocCreated)
+ self.disconnect(self.part, qt.SIGNAL("docCreated()"). self._slotDocCreated)
self.loadFunction = callback
- self.connect(self.part, SIGNAL("docCreated()"), self._slotDocCreated)
+ self.connect(self.part, qt.SIGNAL("docCreated()"), self._slotDocCreated)
self.location = uri
def _slotDocCreated(self):
self.part.executeScript(DOM.Node(), "window.alert = function() {}")
- self.disconnect(self.part, SIGNAL("docCreated()"), self._slotDocCreated)
+ self.disconnect(self.part, qt.SIGNAL("docCreated()"), self._slotDocCreated)
if not self.loadFunction:
raise AttributeError("No load function callback present")
func = self.loadFunction
@@ -155,6 +158,6 @@
@property
def document(self):
- """ Get a reference to the document (dom.Document) for the currently loaded page. It contains all the tasty methods for walking the DOM tree like getElementById/getElementsByTagName and methods for browsing to other linked pages. """
+ """ Get a reference to the document (see [dom.Document]) for the currently loaded page. It contains all the tasty methods for walking the DOM tree like getElementById / getElementsByTagName, and methods for browsing to other linked pages. """
return dom.Document(self.part.htmlDocument(), self)
=== modified file 'pykhtml/dom.py'
--- pykhtml/dom.py 2007-02-05 22:39:48 +0000
+++ pykhtml/dom.py 2007-02-10 19:23:01 +0000
@@ -32,7 +32,7 @@
@property
def children(self):
- """ Get the children nodes of this """
+ """ Get the children nodes of this node """
# cache the value
if self.__children is None:
l = self.__children = []
@@ -48,7 +48,7 @@
class Text(Node):
- """ A text node lets you access the text in it using the Text.value attribute or by converting to a string with str() """
+ """ A text node lets you access the text in it using the [Text.value] attribute or by converting to a string with str() """
def __init__(self, cTextNode):
Node.__init__(self, cTextNode)
@@ -60,6 +60,7 @@
@property
def value(self):
+ """ Equivalent to str(textNode). Get the string this node represents """
return str(self._.nodeValue().string())
registerNode(3, Text)
@@ -117,12 +118,12 @@
return str(e.nodeName().string())
def addEvent(self, eventName, func, capture=False):
- """ This lets you listen for certain events as they occur on the current element. Only particularly useful when listening for load events really. """
+ """ This lets you listen for certain events as they occur on the current element. Only particularly useful when listening for load events reaaally. """
listener = _CallbackEventListener(eventName, func)
self._.addEventListener(DOMString(eventName), listener, capture)
def removeEvent(self, eventName, func, capture=False):
- """ Removes events that you've added with Element.addEvent """
+ """ Removes events that you've added with [Element.addEvent] """
self._.removeEventListener(DOMString(eventName), _CallbackEventListener.getCallbackInstance(eventName, func), capture)
_CallbackEventListener.remove(eventName, func)
# -- important, we hook to the method not Element base class
@@ -130,14 +131,14 @@
class Anchor(Element):
- """ Anchor elements with an Anchor.href property """
+ """ Anchor elements with an [Anchor.href] property """
def __init__(self, cAnchor):
Element.__init__(self, cAnchor)
self._ = sip.cast(self._, _DOM.HTMLAnchorElement)
@property
def href(self):
- """ The anchors 'href' value. Returns the full URL pointed to by the href attribute """
+ """ The anchor's 'href' value. Returns the full URL pointed to by the href attribute of this element """
return str(self._.href().string())
registerElement("A", Anchor)
@@ -150,7 +151,7 @@
class Document(object):
- """ Document object for accessing the DOM tree. Don't keep this object around, when the page changes it's invalidated. Just use browser.document. """
+ """ Document object for accessing the DOM tree. Don't keep this object around, when the page changes it's invalidated. Just access it through [pykhtml.Browser.document] whenever you want it. """
def __init__(self, htmlDocument, browser):
self._d = htmlDocument
self.browser = browser
@@ -185,8 +186,8 @@
def visit(self, text=None, callback=None, attributes=None, stripSpace=True):
""" Visit a page pointed to by a certain link. This function searches for all links in the document that either:
- - Match the given text (as a string or regular expression object)
- - Match the attributes given (a dictionary mapping attribute name to attribute value, where the value is again either a string or regular expression object)
+ + Match the given text (as a string or regular expression object)
+ + Match the attributes given (a dictionary mapping attribute name to attribute value, where the value is again either a string or regular expression object)
If the `stripSpace` attribute is True, when searching for a string match all whitespace is stripped from the item we are matching against """
_dlinks = self._d.links()
possibleLinks = [_dlinks.item(i) for i in xrange(_dlinks.length())]