')
+ if closelist:
+ nodename = type == 'o' and 'ol' or 'ul'
+ self._data.append('%s>' % (nodename,))
+
+ def handleLink(self, text, target):
+ self._data.append('%s' % (entitize(target),
+ entitize(text)))
+
+ def _html(self):
+ return ''.join(self._data)
+ html = property(_html)
+
From arigo at codespeak.net Tue Nov 14 18:57:42 2006
From: arigo at codespeak.net (arigo at codespeak.net)
Date: Tue, 14 Nov 2006 18:57:42 +0100 (CET)
Subject: [py-svn] r34606 - py/dist/py/c-extension/greenlet
Message-ID: <20061114175742.4CE2D101D5@code0.codespeak.net>
Author: arigo
Date: Tue Nov 14 18:57:34 2006
New Revision: 34606
Modified:
py/dist/py/c-extension/greenlet/README.txt
Log:
Fix the README.txt of greenlets.
Modified: py/dist/py/c-extension/greenlet/README.txt
==============================================================================
--- py/dist/py/c-extension/greenlet/README.txt (original)
+++ py/dist/py/c-extension/greenlet/README.txt Tue Nov 14 18:57:34 2006
@@ -9,9 +9,5 @@
Christian. In other words, if it works it is thanks to Christian's work,
and if it crashes it is because of a bug of mine :-)
-This code is going to be integrated in the 'py' lib. The test file only runs
-if you got greenlets from there! See http://codespeak.net/py/ and try
-'from py.magic import greenlet'.
-
-- Armin
From arigo at codespeak.net Tue Nov 14 18:58:46 2006
From: arigo at codespeak.net (arigo at codespeak.net)
Date: Tue, 14 Nov 2006 18:58:46 +0100 (CET)
Subject: [py-svn] r34608 - py/dist/py/magic
Message-ID: <20061114175846.BDC3A101E6@code0.codespeak.net>
Author: arigo
Date: Tue Nov 14 18:58:45 2006
New Revision: 34608
Modified:
py/dist/py/magic/greenlet.py
Log:
Add support for using 'py.magic.greenlet' on programs that run on top of
a stackless pypy (you just get _stackless.greenlet, then).
Modified: py/dist/py/magic/greenlet.py
==============================================================================
--- py/dist/py/magic/greenlet.py (original)
+++ py/dist/py/magic/greenlet.py Tue Nov 14 18:58:45 2006
@@ -1,5 +1,10 @@
-
-import py
-gdir = py.path.local(py.__file__).dirpath()
-path = gdir.join('c-extension', 'greenlet', 'greenlet.c')
-greenlet = path.getpymodule().greenlet
+import sys
+if '_stackless' in sys.builtin_module_names:
+ # when running on top of a pypy with stackless support
+ from _stackless import greenlet
+else:
+ # regular CPython (or pypy without stackless support, and then crash :-)
+ import py
+ gdir = py.path.local(py.__file__).dirpath()
+ path = gdir.join('c-extension', 'greenlet', 'greenlet.c')
+ greenlet = path.getpymodule().greenlet
From guido at codespeak.net Wed Nov 15 09:54:56 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Wed, 15 Nov 2006 09:54:56 +0100 (CET)
Subject: [py-svn] r34616 - in py/dist/py/rst: . testing
Message-ID: <20061115085456.8324E10083@code0.codespeak.net>
Author: guido
Date: Wed Nov 15 09:54:54 2006
New Revision: 34616
Modified:
py/dist/py/rst/testing/test_transform.py
py/dist/py/rst/transform.py
Log:
Adding newlines.
Modified: py/dist/py/rst/testing/test_transform.py
==============================================================================
--- py/dist/py/rst/testing/test_transform.py (original)
+++ py/dist/py/rst/testing/test_transform.py Wed Nov 15 09:54:54 2006
@@ -14,25 +14,26 @@
endDocument = startDocument
def test_transform_basic_html():
- for rest, expected in ((Rest(Title('foo')), '
foo
'),
- (Rest(Paragraph('foo')), '
foo
'),
+ for rest, expected in ((Rest(Title('foo')), '
\n')
+ self._pop()
if closelist:
- nodename = type == 'o' and 'ol' or 'ul'
- self._data.append('%s>\n' % (nodename,))
+ self._pop()
def handleLink(self, text, target):
- self._data.append('%s' % (entitize(target),
- entitize(text)))
+ self.tagstack[-1].append(html.a(text, href=target))
+
+ def _push(self, el):
+ if self.tagstack:
+ self.tagstack[-1].append(el)
+ else:
+ self.root = el
+ self.tagstack.append(el)
+
+ def _pop(self):
+ self.tagstack.pop()
def _html(self):
- return ''.join(self._data)
+ return self.root.unicode()
html = property(_html)
From fijal at codespeak.net Tue Nov 21 13:25:22 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Tue, 21 Nov 2006 13:25:22 +0100 (CET)
Subject: [py-svn] r34820 - py/dist/py/documentation
Message-ID: <20061121122522.BB76D1006F@code0.codespeak.net>
Author: fijal
Date: Tue Nov 21 13:25:20 2006
New Revision: 34820
Added:
py/dist/py/documentation/source-viewer.txt (contents, props changed)
Log:
Added random notes about source-viewer
Added: py/dist/py/documentation/source-viewer.txt
==============================================================================
--- (empty file)
+++ py/dist/py/documentation/source-viewer.txt Tue Nov 21 13:25:20 2006
@@ -0,0 +1,37 @@
+=======================
+Source viewer for pylib
+=======================
+
+Random notes:
+-------------
+
+* We want to construct this using an AST. Introspection is somehow better in
+ many many places, but an AST is more sticked to source (which is by
+ conincidence what we actually want to see). Additional stuff like things
+ attached to the module might be nice if we want to document them, but
+ they do not appear in source.
+
+* We want to have rather free (without all AST hassle) access to basic
+ info about classess, functions variables etc. So we can get all the
+ necessary informations even if the module has changed a bit.
+
+* We want this access for both SVN and file based sources.
+
+* We want to have html backend of those - which means at least syntax
+ highlightning with possibility of linking to those items.
+
+* Some crosslinking might be cool, variables are resolved syntactically,
+ so in 95% cases we can crossling to at least module.function, module.class
+ etc.
+
+* First: We don't want to have *ANY* type inference there. Two: If at
+ any point we want such thing, we make it through introspection, but better
+ not at all.
+
+Implementation notes:
+---------------------
+
+Let's use compiler package and if at any point there will be sth better,
+like pypy's compiler package we'll move. We create out of AST stuff which
+can be accessed by dot. Like module.function.firstlineno, with interface
+to py.code.Source as well.
From fijal at codespeak.net Tue Nov 21 21:25:42 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Tue, 21 Nov 2006 21:25:42 +0100 (CET)
Subject: [py-svn] r34840 - in py/dist/py/test/rsession: . testing
Message-ID: <20061121202542.C977B1007A@code0.codespeak.net>
Author: fijal
Date: Tue Nov 21 21:25:39 2006
New Revision: 34840
Modified:
py/dist/py/test/rsession/conftest.py
py/dist/py/test/rsession/hostmanage.py
py/dist/py/test/rsession/rsession.py
py/dist/py/test/rsession/testing/test_boxing.py
py/dist/py/test/rsession/testing/test_executor.py
Log:
Moved default waittime to session options
Modified: py/dist/py/test/rsession/conftest.py
==============================================================================
--- py/dist/py/test/rsession/conftest.py (original)
+++ py/dist/py/test/rsession/conftest.py Tue Nov 21 21:25:39 2006
@@ -1,14 +1,14 @@
-import py
-Option = py.test.Config.Option
+#import py
+#Option = py.test.Config.Option
-defaultwait = 100.0
+#defaultwait = 100.0
-option = py.test.Config.addoptions("distributed testing options",
+#option = py.test.Config.addoptions("distributed testing options",
# Option('-D', '--disthosts',
# action="store", dest="disthosts", default=None,
# help="comma separated list of testhosts"),
- Option('', '--waittime',
- action="store", dest="waittime", default=defaultwait,
- help="How long (in seconds) to wait for hanging nodes"
- " (default=%s sec)" % defaultwait),
- )
+# Option('', '--waittime',
+# action="store", dest="waittime", default=defaultwait,
+# help="How long (in seconds) to wait for hanging nodes"
+# " (default=%s sec)" % defaultwait),
+# )
Modified: py/dist/py/test/rsession/hostmanage.py
==============================================================================
--- py/dist/py/test/rsession/hostmanage.py (original)
+++ py/dist/py/test/rsession/hostmanage.py Tue Nov 21 21:25:39 2006
@@ -7,9 +7,6 @@
from py.__.test.rsession import report
from py.__.test.rsession.rsync import RSync
-from py.__.test.rsession.conftest import option
-
-
class HostRSync(RSync):
def __init__(self, rsync_roots):
@@ -112,6 +109,8 @@
exitfirst=False):
for channel in channels:
channel.send(None)
+
+ from py.__.test.rsession.rsession import session_options
clean = exitfirst
while not clean:
@@ -124,7 +123,7 @@
for channel in channels:
try:
- report.wrapcall(reporter, channel.waitclose, int(option.waittime))
+ report.wrapcall(reporter, channel.waitclose, int(session_options.waittime))
except KeyboardInterrupt, SystemExit:
raise
except:
Modified: py/dist/py/test/rsession/rsession.py
==============================================================================
--- py/dist/py/test/rsession/rsession.py (original)
+++ py/dist/py/test/rsession/rsession.py Tue Nov 21 21:25:39 2006
@@ -37,6 +37,7 @@
'max_tasks_per_node' : 15,
'runner_policy' : 'plain_runner',
'nice_level' : 0,
+ 'waittime' : 100.0,
}
config = None
Modified: py/dist/py/test/rsession/testing/test_boxing.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_boxing.py (original)
+++ py/dist/py/test/rsession/testing/test_boxing.py Tue Nov 21 21:25:39 2006
@@ -9,7 +9,6 @@
from py.__.test.rsession.box import Box, RealBox, ScreenBox
from py.__.test.rsession.testing import example2
-from py.__.test.rsession.conftest import option
def setup_module(mod):
from py.__.test.rsession.rsession import remote_options
Modified: py/dist/py/test/rsession/testing/test_executor.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_executor.py (original)
+++ py/dist/py/test/rsession/testing/test_executor.py Tue Nov 21 21:25:39 2006
@@ -6,7 +6,6 @@
from py.__.test.rsession.outcome import ReprOutcome
from py.__.test.rsession.testing.test_slave import funcprint_spec, \
funcprintfail_spec
-from py.__.test.rsession.conftest import option
def setup_module(mod):
mod.rootdir = py.path.local(py.__file__).dirpath().dirpath()
From fijal at codespeak.net Tue Nov 21 21:27:38 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Tue, 21 Nov 2006 21:27:38 +0100 (CET)
Subject: [py-svn] r34841 - py/dist/py/documentation
Message-ID: <20061121202738.9AC221007A@code0.codespeak.net>
Author: fijal
Date: Tue Nov 21 21:27:37 2006
New Revision: 34841
Modified:
py/dist/py/documentation/test.txt
Log:
Added new option.
Modified: py/dist/py/documentation/test.txt
==============================================================================
--- py/dist/py/documentation/test.txt (original)
+++ py/dist/py/documentation/test.txt Tue Nov 21 21:27:37 2006
@@ -755,6 +755,8 @@
* `nice_level` - Level of nice under which tests are run
* `runner_policy` - (for `LSession` only) - contains policy for the test boxig.
`"plain_runner"` means no boxing, `"box_runner"` means boxing.
+* `waittime` - Default waiting time for remote host to finish test (after
+ that period we consider node as dead, default to 100s).
Development Notes
-----------------
From guido at codespeak.net Wed Nov 22 12:03:35 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Wed, 22 Nov 2006 12:03:35 +0100 (CET)
Subject: [py-svn] r34853 - in py/dist/py/rest: . testing
Message-ID: <20061122110335.42E3810063@code0.codespeak.net>
Author: guido
Date: Wed Nov 22 12:03:33 2006
New Revision: 34853
Modified:
py/dist/py/rest/rst.py
py/dist/py/rest/testing/test_rst.py
py/dist/py/rest/transform.py
Log:
Fixed bug in list item handling for items that don't have a parent (regardless
of type), fixed bug in title handling: title should never be split over lines,
fixed bug in LiteralBlock transformation to HTML when rendering only the pre
element.
Modified: py/dist/py/rest/rst.py
==============================================================================
--- py/dist/py/rest/rst.py (original)
+++ py/dist/py/rest/rst.py Wed Nov 22 12:03:33 2006
@@ -190,11 +190,11 @@
class Title(Paragraph):
parentclass = Rest
- belowchar = ""
+ belowchar = "="
abovechar = ""
def text(self):
- txt = Paragraph.text(self)
+ txt = self._get_text()
lines = []
if self.abovechar:
lines.append(self.abovechar * len(txt))
@@ -203,6 +203,12 @@
lines.append(self.belowchar * len(txt))
return "\n".join(lines)
+ def _get_text(self):
+ txt = []
+ for node in self.children:
+ txt.append(node.text().strip())
+ return ' '.join(txt)
+
class AbstractText(AbstractNode):
parentclass = [Paragraph, Title]
start = ""
@@ -298,10 +304,11 @@
def get_indent_depth(self):
depth = 0
current = self
- while current.parent is not None:
+ while (current.parent is not None and
+ isinstance(current.parent, ListItem)):
depth += 1
current = current.parent
- return depth - 1
+ return depth
class OrderedListItem(ListItem):
item_chars = ["#."] * 5
Modified: py/dist/py/rest/testing/test_rst.py
==============================================================================
--- py/dist/py/rest/testing/test_rst.py (original)
+++ py/dist/py/rest/testing/test_rst.py Wed Nov 22 12:03:33 2006
@@ -168,11 +168,29 @@
txt = Title(Text("Some title"), belowchar="=").text()
assert txt == "Some title\n=========="
checkrest(txt)
- txt = Title(Text("Some title"), belowchar="#", abovechar="#").text()
+ txt = Title("Some title", belowchar="#", abovechar="#").text()
assert txt == "##########\nSome title\n##########"
html = checkrest(txt)
assert '>Some title' in html
+def test_title_long():
+ txt = Title('Some very long title that doesn\'t fit on a single line '
+ 'but still should not be split into multiple lines').text()
+ assert txt == ("Some very long title that doesn't fit on a single line "
+ "but still should not be split into multiple lines\n"
+ "======================================================="
+ "=================================================")
+ checkrest(txt)
+
+def test_title_long_with_markup():
+ txt = Title('Some very long title with', Em('some markup'),
+ 'to test whether that works as expected too...').text()
+ assert txt == ("Some very long title with *some markup* to test whether "
+ "that works as expected too...\n"
+ "========================================================"
+ "=============================")
+ checkrest(txt)
+
def test_link():
expected = "`some link`_\n\n.. _`some link`: http://codespeak.net\n\n"
txt = Rest(Paragraph(Link("some link", "http://codespeak.net"))).text()
@@ -271,6 +289,15 @@
assert txt == expected
checkrest(txt)
+def test_list_multiline_no_parent():
+ expected = ("* test **strong**\n thisisaverylongwordthatdoesntfiton"
+ "thepreviouslineandthereforeshouldbeindented")
+ txt = ListItem(Text('test'), Strong('strong'),
+ Text('thisisaverylongwordthatdoesntfitontheprevious'
+ 'lineandthereforeshouldbeindented')).text()
+ assert txt == expected
+ checkrest(txt)
+
def test_ordered_list():
expected = "#. foo\n\n#. bar\n\n#. baz\n"
txt = Rest(OrderedListItem('foo'), OrderedListItem('bar'),
Modified: py/dist/py/rest/transform.py
==============================================================================
--- py/dist/py/rest/transform.py (original)
+++ py/dist/py/rest/transform.py Wed Nov 22 12:03:33 2006
@@ -139,7 +139,11 @@
self._pop()
def handleLiteralBlock(self, text):
- self.tagstack[-1].append(html.pre(text))
+ pre = html.pre(text)
+ if self.tagstack:
+ self.tagstack[-1].append(pre)
+ else:
+ self.root = pre
def handleText(self, text):
self.tagstack[-1].append(text)
From fijal at codespeak.net Wed Nov 22 12:16:07 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Wed, 22 Nov 2006 12:16:07 +0100 (CET)
Subject: [py-svn] r34854 - in py/dist/py/apigen: rest rest/testing source
source/testing
Message-ID: <20061122111607.C1CF410068@code0.codespeak.net>
Author: fijal
Date: Wed Nov 22 12:15:58 2006
New Revision: 34854
Added:
py/dist/py/apigen/source/ (props changed)
py/dist/py/apigen/source/__init__.py (contents, props changed)
py/dist/py/apigen/source/browser.py (contents, props changed)
py/dist/py/apigen/source/testing/ (props changed)
py/dist/py/apigen/source/testing/__init__.py (contents, props changed)
py/dist/py/apigen/source/testing/test_browser.py (contents, props changed)
Modified:
py/dist/py/apigen/rest/htmlhandlers.py (props changed)
py/dist/py/apigen/rest/testing/somemodule.py (props changed)
py/dist/py/apigen/rest/testing/someothermodule.py (props changed)
Log:
Added very silly source browser.
Added: py/dist/py/apigen/source/__init__.py
==============================================================================
Added: py/dist/py/apigen/source/browser.py
==============================================================================
--- (empty file)
+++ py/dist/py/apigen/source/browser.py Wed Nov 22 12:15:58 2006
@@ -0,0 +1,88 @@
+
+""" source browser using compiler module
+
+WARNING!!!
+
+This is very simple and very silly attempt to make so.
+
+"""
+
+from compiler import parse, ast
+import py
+
+from py.__.path.common import PathBase
+
+class Module(object):
+ def __init__(self, path, _dict):
+ self.path = path
+ self.dict = _dict
+
+ def __getattr__(self, attr):
+ try:
+ return self.dict[attr]
+ except KeyError:
+ raise AttributeError(attr)
+
+def get_endline(start, lst):
+ l = reversed(lst)
+ for i in l:
+ if i.lineno:
+ return i.lineno
+ end_ch = get_endline(None, i.getChildNodes())
+ if end_ch:
+ return end_ch
+ return start
+
+class Function(object):
+ def __init__(self, name, firstlineno, endlineno):
+ self.firstlineno = firstlineno
+ self.endlineno = endlineno
+ self.name = name
+
+class Method(object):
+ def __init__(self, name, firstlineno, endlineno):
+ self.name = name
+ self.firstlineno = firstlineno
+ self.endlineno = endlineno
+
+def function_from_ast(ast, cls=Function):
+ startline = ast.lineno
+ endline = get_endline(startline, ast.getChildNodes())
+ assert endline
+ return cls(ast.name, startline, endline)
+
+def class_from_ast(cls_ast):
+ bases = [i.name for i in cls_ast.bases]
+ # XXX
+ methods = {}
+ startline = cls_ast.lineno
+ name = cls_ast.name
+ endline = get_endline(startline, cls_ast.getChildNodes())
+ methods = dict([(i.name, function_from_ast(i, Method)) for i in \
+ cls_ast.code.nodes if isinstance(i, ast.Function)])
+ return Class(name, startline, endline, bases, methods)
+
+class Class(object):
+ def __init__(self, name, firstlineno, endlineno, bases, methods):
+ self.bases = bases
+ self.firstlineno = firstlineno
+ self.endlineno = endlineno
+ self.name = name
+ self.methods = methods
+
+ def __getattr__(self, attr):
+ try:
+ return self.methods[attr]
+ except KeyError:
+ raise AttributeError(attr)
+
+def parse_path(path):
+ assert isinstance(path, PathBase), "Cannot work on files directly"
+ buf = path.open().read()
+ st = parse(buf)
+ # first go - we get all functions and classes defined on top-level
+ function_ast = [i for i in st.node.nodes if isinstance(i, ast.Function)]
+ classes_ast = [i for i in st.node.nodes if isinstance(i, ast.Class)]
+ mod_dict = dict([(i.name, function_from_ast(i)) for i in function_ast]
+ + [(i.name, class_from_ast(i)) for i in classes_ast])
+ return Module(path, mod_dict)
Added: py/dist/py/apigen/source/testing/__init__.py
==============================================================================
Added: py/dist/py/apigen/source/testing/test_browser.py
==============================================================================
--- (empty file)
+++ py/dist/py/apigen/source/testing/test_browser.py Wed Nov 22 12:15:58 2006
@@ -0,0 +1,40 @@
+
+""" test source browser abilities
+"""
+
+from py.__.apigen.source.browser import parse_path, Class, Function, Method
+import py
+
+def test_browser():
+ tmp = py.test.ensuretemp("sourcebrowser")
+ tmp.ensure("a.py").write(py.code.Source("""
+ def f():
+ pass
+
+ def g():
+ pass
+
+ class X:
+ pass
+
+ class Z(object):
+ x = 1
+ def zzz(self):
+ 1
+ 2
+ 3
+ 4
+ """))
+ mod = parse_path(tmp.join("a.py"))
+ assert isinstance(mod.g, Function)
+ assert isinstance(mod.Z, Class)
+ py.test.raises(AttributeError, "mod.zzz")
+ assert mod.g.firstlineno == 5
+ assert mod.g.name == "g"
+ assert mod.g.endlineno == 6
+ assert mod.X.firstlineno == 8
+ assert mod.X.endlineno == 9
+ assert mod.Z.bases == ["object"]
+ assert isinstance(mod.Z.zzz, Method)
+ assert mod.Z.zzz.firstlineno == 13
+ assert mod.Z.zzz.endlineno == 17
From guido at codespeak.net Wed Nov 22 13:56:36 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Wed, 22 Nov 2006 13:56:36 +0100 (CET)
Subject: [py-svn] r34855 - in py/dist/py/rest: . testing
Message-ID: <20061122125636.60D4B10063@code0.codespeak.net>
Author: guido
Date: Wed Nov 22 13:56:34 2006
New Revision: 34855
Modified:
py/dist/py/rest/rst.py
py/dist/py/rest/testing/test_rst.py
Log:
Fixed bug in title escaping.
Modified: py/dist/py/rest/rst.py
==============================================================================
--- py/dist/py/rest/rst.py (original)
+++ py/dist/py/rest/rst.py Wed Nov 22 13:56:34 2006
@@ -206,7 +206,7 @@
def _get_text(self):
txt = []
for node in self.children:
- txt.append(node.text().strip())
+ txt += node.wordlist()
return ' '.join(txt)
class AbstractText(AbstractNode):
Modified: py/dist/py/rest/testing/test_rst.py
==============================================================================
--- py/dist/py/rest/testing/test_rst.py (original)
+++ py/dist/py/rest/testing/test_rst.py Wed Nov 22 13:56:34 2006
@@ -191,6 +191,11 @@
"=============================")
checkrest(txt)
+def test_title_escaping():
+ txt = Title('foo *bar* baz').text()
+ assert txt == 'foo \\*bar\\* baz\n==============='
+ checkrest(txt)
+
def test_link():
expected = "`some link`_\n\n.. _`some link`: http://codespeak.net\n\n"
txt = Rest(Paragraph(Link("some link", "http://codespeak.net"))).text()
From guido at codespeak.net Wed Nov 22 14:19:42 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Wed, 22 Nov 2006 14:19:42 +0100 (CET)
Subject: [py-svn] r34856 - py/dist/py/test
Message-ID: <20061122131942.EBB7D10063@code0.codespeak.net>
Author: guido
Date: Wed Nov 22 14:19:41 2006
New Revision: 34856
Modified:
py/dist/py/test/defaultconftest.py
Log:
Cleanups and consistency.
Modified: py/dist/py/test/defaultconftest.py
==============================================================================
--- py/dist/py/test/defaultconftest.py (original)
+++ py/dist/py/test/defaultconftest.py Wed Nov 22 14:19:41 2006
@@ -1,16 +1,16 @@
import py
-Module = py.test.collect.Module
-DoctestFile = py.test.collect.DoctestFile
+Module = py.test.collect.Module
+DoctestFile = py.test.collect.DoctestFile
Directory = py.test.collect.Directory
Class = py.test.collect.Class
-Generator = py.test.collect.Generator
-Function = py.test.Function
-Instance = py.test.collect.Instance
+Generator = py.test.collect.Generator
+Function = py.test.Function
+Instance = py.test.collect.Instance
additionalinfo = None
-def adddefaultoptions():
+def adddefaultoptions():
Option = py.test.Config.Option
py.test.Config.addoptions('general options',
Option('-v', '--verbose',
@@ -24,7 +24,8 @@
help="disable catching of sys.stdout/stderr output."),
Option('-k',
action="store", dest="keyword", default='',
- help="only run test items matching the given (google-style) keyword expression."),
+ help="only run test items matching the given (google-style) "
+ "keyword expression."),
Option('-l', '--showlocals',
action="store_true", dest="showlocals", default=False,
help="show locals in tracebacks (disabled by default)."),
@@ -49,32 +50,32 @@
help="trace considerations of conftest.py files."),
Option('', '--apigen',
action="store_true", dest="apigen", default=False,
- help="Generated API docs out of tests. Needs to have defined "\
- "__package__ for module or overwritten in conftest.")
+ help="generate api documentation while testing (requires "
+ "initpkg/conftest config)."),
)
- py.test.Config.addoptions('test-session related options',
+ py.test.Config.addoptions('test-session related options',
Option('', '--tkinter',
action="store_true", dest="tkinter", default=False,
- help="use tkinter test session frontend."),
+ help="use tkinter test session frontend."),
Option('', '--looponfailing',
action="store_true", dest="looponfailing", default=False,
- help="loop on failing test set."),
- Option('', '--session',
- action="store", dest="session", default=None,
+ help="loop on failing test set."),
+ Option('', '--session',
+ action="store", dest="session", default=None,
help="use given sessionclass, default is terminal."),
Option('', '--exec',
action="store", dest="executable", default=None,
help="python executable to run the tests with."),
Option('-w', '--startserver',
action="store_true", dest="startserver", default=False,
- help="Start HTTP server listening on localhost:8000 for test."
+ help="start HTTP server listening on localhost:8000 for test."
),
Option('', '--runbrowser',
action="store_true", dest="runbrowser", default=False,
- help="Run browser to point to your freshly started web server."
+ help="run browser to point to your freshly started web server."
),
Option('-r', '--rest',
action='store_true', dest="restreport", default=False,
- help="Use a ReST as an output reporting"),
+ help="restructured text output reporting."),
)
From guido at codespeak.net Wed Nov 22 14:23:41 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Wed, 22 Nov 2006 14:23:41 +0100 (CET)
Subject: [py-svn] r34857 - py/dist/py/compat/testing
Message-ID: <20061122132341.5F02710068@code0.codespeak.net>
Author: guido
Date: Wed Nov 22 14:23:40 2006
New Revision: 34857
Modified:
py/dist/py/compat/testing/_findpy.py
Log:
Directing 'inserting into sys.path' message to stderr.
Modified: py/dist/py/compat/testing/_findpy.py
==============================================================================
--- py/dist/py/compat/testing/_findpy.py (original)
+++ py/dist/py/compat/testing/_findpy.py Wed Nov 22 14:23:40 2006
@@ -19,7 +19,7 @@
# if p == current:
# return True
if current != sys.path[0]: # if we are already first, then ok
- print "inserting into sys.path:", current
+ print >>sys.stderr, "inserting into sys.path:", current
sys.path.insert(0, current)
return True
current = opd(current)
From guido at codespeak.net Wed Nov 22 14:26:04 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Wed, 22 Nov 2006 14:26:04 +0100 (CET)
Subject: [py-svn] r34858 - py/dist/py/apigen/tracer/testing/package
Message-ID: <20061122132604.92D111006C@code0.codespeak.net>
Author: guido
Date: Wed Nov 22 14:26:03 2006
New Revision: 34858
Modified:
py/dist/py/apigen/tracer/testing/package/ (props changed)
py/dist/py/apigen/tracer/testing/package/__init__.py (props changed)
Log:
fixeol
From guido at codespeak.net Wed Nov 22 14:30:54 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Wed, 22 Nov 2006 14:30:54 +0100 (CET)
Subject: [py-svn] r34859 - in py/dist/py/test/rsession: . testing
Message-ID: <20061122133054.80C0D1006C@code0.codespeak.net>
Author: guido
Date: Wed Nov 22 14:30:53 2006
New Revision: 34859
Modified:
py/dist/py/test/rsession/reporter.py
py/dist/py/test/rsession/rest.py
py/dist/py/test/rsession/testing/test_rest.py
Log:
Cleanup and improvements of the ReST reporter. More will follow, however
currently executing 'py.test --rest > output.rst' should at least result in a
parsable document with test results and exceptions.
Modified: py/dist/py/test/rsession/reporter.py
==============================================================================
--- py/dist/py/test/rsession/reporter.py (original)
+++ py/dist/py/test/rsession/reporter.py Wed Nov 22 14:30:53 2006
@@ -34,6 +34,9 @@
# XXX: Testing purposes only
return 'localhost'
+ def get_item_name(self, event, colitem):
+ return "/".join(colitem.listnames())
+
def report(self, what):
repfun = getattr(self, "report_" + what.__class__.__name__,
self.report_unknown)
Modified: py/dist/py/test/rsession/rest.py
==============================================================================
--- py/dist/py/test/rsession/rest.py (original)
+++ py/dist/py/test/rsession/rest.py Wed Nov 22 14:30:53 2006
@@ -4,34 +4,54 @@
import py
import sys
+from StringIO import StringIO
from py.__.test.rsession.reporter import AbstractReporter
from py.__.rest.rst import *
class RestReporter(AbstractReporter):
def report_unknown(self, what):
- print "Unknown report: %s" % what
+ self.add_rest(Paragraph("Unknown report: %s" % what))
+
+ def report_SendItem(self, item):
+ address = self.get_host(item)
+ if self.config.option.verbose:
+ self.add_rest(Paragraph('sending item %s to %s' % (item.item,
+ address)))
+
+ def report_HostRSyncing(self, item):
+ self.add_rest(LiteralBlock('%10s: RSYNC ==> %s' % (item.hostname[:10],
+ item.remoterootpath)))
+
+ def report_HostReady(self, item):
+ self.add_rest(LiteralBlock('%10s: READY' % (item.hostname[:10],)))
def report_TestStarted(self, event):
- txt = "Test started, hosts: %s" % ", ".join(event.hosts)
- print Title(txt, abovechar='=', belowchar='=').text() + "\n"
+ txt = "Running tests on hosts: %s" % ", ".join(event.hosts)
+ self.add_rest(Title(txt, abovechar='=', belowchar='='))
self.timestart = event.timestart
+ def report_TestFinished(self, item):
+ self.timeend = item.timeend
+ self.summary()
+
+ def report_ImmediateFailure(self, item):
+ pass
+
def report_ItemStart(self, event):
item = event.item
- print
if isinstance(item, py.test.collect.Module):
lgt = len(list(item.tryiter()))
- name = "/".join(item.listnames())
+ lns = item.listnames()
+ name = "/".join(lns)
txt = 'Testing module %s (%d items)' % (name, lgt)
- print Title(txt, belowchar='-').text()
+ self.add_rest(Title(txt, belowchar='-'))
def print_summary(self, total, skipped_str, failed_str):
- print "\n"
- txt = "%d test run%s%s in %.2fs (rsync: %.2f)" % \
+ txt = "%d tests run%s%s in %.2fs (rsync: %.2f)" % \
(total, skipped_str, failed_str, self.timeend - self.timestart,
self.timersync - self.timestart)
- print Title(txt, belowchar="=").text()
-
+ self.add_rest(Title(txt, belowchar='-'))
+
def report_ReceivedItemOutcome(self, event):
host = self.get_host(event)
if event.outcome.passed:
@@ -46,7 +66,20 @@
self.failed[host] += 1
self.failed_tests_outcome.append(event)
# we'll take care of them later
- sshhost = self.get_host(event)
- itempath = " ".join(event.item.listnames()[1:])
- print ListItem(Text("%10s: %s %s" %(sshhost[:10], status, itempath))).text()
-
+ lns = event.item.listnames()[1:]
+ for i, ln in enumerate(lns):
+ if i > 0 and ln != '()':
+ lns[i] = '/%s' % (ln,)
+ itempath = ''.join(lns)
+ self.add_rest(ListItem(Text("%10s:" % (host[:10],)), Strong(status),
+ Text(itempath)))
+ if event.outcome.excinfo:
+ excinfo = event.outcome.excinfo
+ self.add_rest(Paragraph('exception:', Strong(excinfo.typename)))
+ self.add_rest(LiteralBlock(excinfo.value))
+ self.add_rest(LiteralBlock('\n'.join([str(x) for x in
+ excinfo.traceback])))
+
+ def add_rest(self, item):
+ self.out.write('%s\n\n' % (item.text(),))
+
Modified: py/dist/py/test/rsession/testing/test_rest.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_rest.py (original)
+++ py/dist/py/test/rsession/testing/test_rest.py Wed Nov 22 14:30:53 2006
@@ -5,6 +5,133 @@
import py
from py.__.test.rsession.testing.test_reporter import AbstractTestReporter
from py.__.test.rsession.rest import RestReporter
+from py.__.rest.rst import *
+
+class RestTestReporter(RestReporter):
+ def __init__(self, *args, **kwargs):
+ if args:
+ super(RestReporter, self).__init__(*args, **kwargs)
+
+class Container(object):
+ def __init__(self, **kwargs):
+ self.__dict__.update(kwargs)
+
+class TestRestUnits(object):
+ def setup_method(self, method):
+ config, args = py.test.Config.parse(["some_sub"])
+ config.option.verbose = False
+ method.im_func.func_globals['reporter'] = r = RestReporter(config,
+ ['localhost'])
+ method.im_func.func_globals['stdout'] = s = py.std.StringIO.StringIO()
+ r.out = s # XXX will need to become a real reporter some time perhaps?
+
+ def test_report_unknown(self):
+ reporter.report_unknown('foo')
+ assert stdout.getvalue() == 'Unknown report\\: foo\n\n'
+
+ def test_report_SendItem(self):
+ item = Container(item='foo/bar.py', channel=False)
+ reporter.report_SendItem(item)
+ assert stdout.getvalue() == ''
+ stdout.seek(0)
+ stdout.truncate()
+ reporter.config.option.verbose = True
+ reporter.report_SendItem(item)
+ assert stdout.getvalue() == ('sending item foo/bar.py to '
+ 'localhost\n\n')
+
+ def test_report_HostRSyncing(self):
+ item = Container(hostname='localhost', remoterootpath='/foo/bar')
+ reporter.report_HostRSyncing(item)
+ assert stdout.getvalue() == ('::\n\n localhost: RSYNC ==> '
+ '/foo/bar\n\n')
+
+ def test_report_HostReady(self):
+ item = Container(hostname='localhost')
+ reporter.report_HostReady(item)
+ assert stdout.getvalue() == '::\n\n localhost: READY\n\n'
+
+ def test_report_TestStarted(self):
+ event = Container(hosts=['localhost', 'foo.com'], timestart=0)
+ reporter.report_TestStarted(event)
+ assert stdout.getvalue() == """\
+===========================================
+Running tests on hosts\: localhost, foo.com
+===========================================
+
+"""
+
+ def test_report_ItemStart(self):
+ class FakeModule(py.test.collect.Module):
+ def __init__(self):
+ pass
+ def tryiter(self):
+ return ['test_foo', 'test_bar']
+ def listnames(self):
+ return ['foo', 'bar.py']
+ event = Container(item=FakeModule())
+ reporter.report_ItemStart(event)
+ assert stdout.getvalue() == """\
+Testing module foo/bar.py (2 items)
+-----------------------------------
+
+"""
+
+ def test_print_summary(self):
+ reporter.timestart = 10
+ reporter.timeend = 20
+ reporter.timersync = 15
+ reporter.print_summary(10, '', '')
+ assert stdout.getvalue() == """\
+10 tests run in 10.00s (rsync\: 5.00)
+-------------------------------------
+
+"""
+
+ def test_ReceivedItemOutcome_PASSED(self):
+ outcome = Container(passed=True, excinfo=False)
+ item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz'])
+ event = Container(channel=False, outcome=outcome, item=item)
+ reporter.report_ReceivedItemOutcome(event)
+ assert stdout.getvalue() == ('* localhost\\: **PASSED** '
+ 'foo.py/bar()/baz\n\n')
+
+ def test_ReceivedItemOutcome_SKIPPED(self):
+ outcome = Container(passed=False, skipped=True, excinfo=False)
+ item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz'])
+ event = Container(channel=False, outcome=outcome, item=item)
+ reporter.report_ReceivedItemOutcome(event)
+ assert stdout.getvalue() == ('* localhost\\: **SKIPPED** '
+ 'foo.py/bar()/baz\n\n')
+
+ def test_ReceivedItemOutcome_FAILED(self):
+ excinfo = Container(typename='FooError', value='a foo has occurred',
+ traceback=[' in foo in line 1, in foo:',
+ ' bar()',
+ ' in bar in line 4, in bar:',
+ (' raise FooError("a foo has '
+ 'occurred")')])
+ outcome = Container(passed=False, skipped=False, excinfo=excinfo)
+ item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz'])
+ event = Container(channel=False, outcome=outcome, item=item)
+ reporter.report_ReceivedItemOutcome(event)
+ assert stdout.getvalue() == """\
+* localhost\: **FAILED** foo.py/bar()/baz
+
+exception\: **FooError**
+
+::
+
+ a foo has occurred
+
+::
+
+ in foo in line 1, in foo:
+ bar()
+ in bar in line 4, in bar:
+ raise FooError("a foo has occurred")
+
+"""
class TestRestReporter(AbstractTestReporter):
reporter = RestReporter
@@ -19,4 +146,29 @@
- localhost\\: FAILED py test rsession testing test\\_slave.py funcpass
- localhost\\: PASSED py test rsession testing test\\_slave.py funcpass
"""
- assert val == expected
+ print repr(val)
+ expected_start = """\
+* localhost\: **FAILED** py/test/rsession/testing/test\_slave.py/funcpass
+
+* localhost\: **SKIPPED** py/test/rsession/testing/test\_slave.py/funcpass
+
+* localhost\: **FAILED** py/test/rsession/testing/test\_slave.py/funcpass
+
+exception\\: **ZeroDivisionError**
+
+::
+
+ integer division or modulo by zero
+
+::
+
+"""
+
+ expected_end = """
+
+* localhost\: **PASSED** py/test/rsession/testing/test\_slave.py/funcpass
+
+"""
+ assert val.startswith(expected_start)
+ assert val.endswith(expected_end)
+
From fijal at codespeak.net Thu Nov 23 10:48:11 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Thu, 23 Nov 2006 10:48:11 +0100 (CET)
Subject: [py-svn] r34884 - py/dist/py/documentation
Message-ID: <20061123094811.1BDC410061@code0.codespeak.net>
Author: fijal
Date: Thu Nov 23 10:48:06 2006
New Revision: 34884
Modified:
py/dist/py/documentation/source-viewer.txt
Log:
Added note about introspection.
Modified: py/dist/py/documentation/source-viewer.txt
==============================================================================
--- py/dist/py/documentation/source-viewer.txt (original)
+++ py/dist/py/documentation/source-viewer.txt Thu Nov 23 10:48:06 2006
@@ -35,3 +35,11 @@
like pypy's compiler package we'll move. We create out of AST stuff which
can be accessed by dot. Like module.function.firstlineno, with interface
to py.code.Source as well.
+
+We can use introspection for some aspects. Right now only top-level functions
+and classes (not laying inside if and such) are exposed. We can use
+introspection to check which functions are exposed at a module level
+(all the ifs and such are executed ususally during initialisation of
+module, so we'll have all of necessary informations). Also we can check
+if elements was not overwritten, or has changed name by compiling code
+and checking.
From guido at codespeak.net Thu Nov 23 11:43:28 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Thu, 23 Nov 2006 11:43:28 +0100 (CET)
Subject: [py-svn] r34885 - in py/dist/py/test: . rsession rsession/testing
Message-ID: <20061123104328.2AED210061@code0.codespeak.net>
Author: guido
Date: Thu Nov 23 11:43:24 2006
New Revision: 34885
Modified:
py/dist/py/test/defaultconftest.py
py/dist/py/test/rsession/rest.py
py/dist/py/test/rsession/testing/test_rest.py
Log:
Added link writer mechanism to create links for paths in the ReST, added code
to display exceptions and signals.
Modified: py/dist/py/test/defaultconftest.py
==============================================================================
--- py/dist/py/test/defaultconftest.py (original)
+++ py/dist/py/test/defaultconftest.py Thu Nov 23 11:43:24 2006
@@ -10,6 +10,8 @@
additionalinfo = None
+linkwriter = py.test.rest.RelLinkWriter()
+
def adddefaultoptions():
Option = py.test.Config.Option
py.test.Config.addoptions('general options',
Modified: py/dist/py/test/rsession/rest.py
==============================================================================
--- py/dist/py/test/rsession/rest.py (original)
+++ py/dist/py/test/rsession/rest.py Thu Nov 23 11:43:24 2006
@@ -6,9 +6,21 @@
import sys
from StringIO import StringIO
from py.__.test.rsession.reporter import AbstractReporter
+from py.__.test.rsession import report
from py.__.rest.rst import *
class RestReporter(AbstractReporter):
+ linkwriter = None
+
+ def __init__(self, *args, **kwargs):
+ super(RestReporter, self).__init__(*args, **kwargs)
+ self.rest = Rest()
+
+ def get_linkwriter(self):
+ if self.linkwriter is None:
+ self.linkwriter = self.config.getinitialvalue('linkwriter')
+ return self.linkwriter
+
def report_unknown(self, what):
self.add_rest(Paragraph("Unknown report: %s" % what))
@@ -41,10 +53,21 @@
item = event.item
if isinstance(item, py.test.collect.Module):
lgt = len(list(item.tryiter()))
- lns = item.listnames()
+ lns = item.listnames()[1:]
name = "/".join(lns)
+ link = self.get_linkwriter().get_link(self.get_rootpath(item),
+ item.fspath)
+ if link:
+ name = Link(name, link)
txt = 'Testing module %s (%d items)' % (name, lgt)
- self.add_rest(Title(txt, belowchar='-'))
+ self.add_rest(Title('Testing module', name, '(%d items)' % (lgt,),
+ belowchar='-'))
+
+ def get_rootpath(self, item):
+ root = item.parent
+ while root.parent is not None:
+ root = root.parent
+ return root.fspath
def print_summary(self, total, skipped_str, failed_str):
txt = "%d tests run%s%s in %.2fs (rsync: %.2f)" % \
@@ -52,6 +75,13 @@
self.timersync - self.timestart)
self.add_rest(Title(txt, belowchar='-'))
+ self.skips()
+ self.failures()
+
+ # since we're rendering each item, the links haven't been rendered
+ # yet
+ self.out.write(self.rest.render_links())
+
def report_ReceivedItemOutcome(self, event):
host = self.get_host(event)
if event.outcome.passed:
@@ -66,20 +96,159 @@
self.failed[host] += 1
self.failed_tests_outcome.append(event)
# we'll take care of them later
- lns = event.item.listnames()[1:]
- for i, ln in enumerate(lns):
- if i > 0 and ln != '()':
- lns[i] = '/%s' % (ln,)
- itempath = ''.join(lns)
+ itempath = self.get_path_from_item(event.item)
self.add_rest(ListItem(Text("%10s:" % (host[:10],)), Strong(status),
Text(itempath)))
- if event.outcome.excinfo:
- excinfo = event.outcome.excinfo
- self.add_rest(Paragraph('exception:', Strong(excinfo.typename)))
- self.add_rest(LiteralBlock(excinfo.value))
- self.add_rest(LiteralBlock('\n'.join([str(x) for x in
- excinfo.traceback])))
+
+ def skips(self):
+ # XXX hrmph, copied code
+ texts = {}
+ for event in self.skipped_tests_outcome:
+ colitem = event.item
+ if isinstance(event, report.ReceivedItemOutcome):
+ outcome = event.outcome
+ text = outcome.skipped
+ itemname = self.get_item_name(event, colitem)
+ elif isinstance(event, report.SkippedTryiter):
+ text = str(event.excinfo.value)
+ itemname = "/".join(colitem.listnames())
+ if text not in texts:
+ texts[text] = [itemname]
+ else:
+ texts[text].append(itemname)
+ if texts:
+ self.add_rest(Title('Reasons for skipped tests:', belowchar='+'))
+ for text, items in texts.items():
+ for item in items:
+ self.add_rest(ListItem('%s: %s' % (item, text)))
+
+ def failures(self):
+ tbstyle = self.config.option.tbstyle
+ if self.failed_tests_outcome:
+ self.add_rest(Title('Exceptions:', belowchar='+'))
+ for i, event in enumerate(self.failed_tests_outcome):
+ if i > 0:
+ self.add_rest(Transition())
+ if isinstance(event, report.ReceivedItemOutcome):
+ host = self.get_host(event)
+ itempath = self.get_path_from_item(event.item)
+ root = self.get_rootpath(event.item)
+ link = self.get_linkwriter().get_link(root, event.item.fspath)
+ t = Title(belowchar='+')
+ if link:
+ t.add(Link(itempath, link))
+ else:
+ t.add(Text(itempath))
+ t.add(Text('on %s' % (host,)))
+ self.add_rest(t)
+ if event.outcome.signal:
+ self.repr_signal(event.item, event.outcome)
+ else:
+ self.repr_failure(event.item, event.outcome, tbstyle)
+ else:
+ itempath = self.get_path_from_item(event.item)
+ root = self.get_rootpath(event.item)
+ link = self.get_linkwriter().get_link(root, event.item.fspath)
+ t = Title(abovechar='+', belowchar='+')
+ if link:
+ t.add(Link(itempath, link))
+ else:
+ t.add(Text(itempath))
+ out = outcome.Outcome(excinfo=event.excinfo)
+ self.repr_failure(event.item,
+ outcome.ReprOutcome(out.make_repr()),
+ tbstyle)
+
+ def repr_signal(self, item, outcome):
+ signal = outcome.signal
+ self.add_rest(Title('Received signal: %d' % (outcome.signal,),
+ abovechar='+', belowchar='+'))
+ if outcome.stdout.strip():
+ self.add_rest(Paragraph('Captured process stdout:'))
+ self.add_rest(LiteralBlock(outcome.stdout))
+ if outcome.stderr.strip():
+ self.add_rest(Paragraph('Captured process stderr:'))
+ self.add_rest(LiteralBlock(outcome.stderr))
+
+ def repr_failure(self, item, outcome, style):
+ excinfo = outcome.excinfo
+ traceback = excinfo.traceback
+ if not traceback:
+ self.add_rest(Paragraph('empty traceback from item %r' % (item,)))
+ return
+ self.repr_traceback(item, excinfo, traceback, style)
+ if outcome.stdout:
+ self.add_rest(Title('Captured process stdout:', abovechar='+',
+ belowchar='+'))
+ self.add_rest(LiteralBlock(outcome.stdout))
+ if outcome.stderr:
+ self.add_rest(Title('Captured process stderr:', abovechar='+',
+ belowchar='+'))
+ self.add_rest(LiteralBlock(outcome.stderr))
+
+ def repr_traceback(self, item, excinfo, traceback, style):
+ root = self.get_rootpath(item)
+ if style == 'long':
+ for entry in traceback:
+ link = self.get_linkwriter().get_link(root,
+ py.path.local(entry.path))
+ if link:
+ self.add_rest(Title(Link(entry.path, link),
+ 'line %d' % (entry.lineno,),
+ belowchar='+', abovechar='+'))
+ else:
+ self.add_rest(Title('%s line %d' % (entry.path,
+ entry.lineno,),
+ belowchar='+', abovechar='+'))
+ self.add_rest(LiteralBlock(self.prepare_source(entry.relline,
+ entry.source)))
+ elif style == 'short':
+ text = []
+ for entry in traceback:
+ text.append('%s line %d' % (entry.path, entry.lineno))
+ text.append(' %s' % (entry.source.strip(),))
+ self.add_rest(LiteralBlock('\n'.join(text)))
+ self.add_rest(Title(excinfo.typename, belowchar='+'))
+ self.add_rest(LiteralBlock(excinfo.value))
+
+ def prepare_source(self, relline, source):
+ text = []
+ for num, line in enumerate(source.split('\n')):
+ if num == relline:
+ text.append('>>> %s' % (line,))
+ else:
+ text.append(' %s' % (line,))
+ return '\n'.join(text)
def add_rest(self, item):
+ self.rest.add(item)
self.out.write('%s\n\n' % (item.text(),))
+ def get_path_from_item(self, item):
+ lns = item.listnames()[1:]
+ for i, ln in enumerate(lns):
+ if i > 0 and ln != '()':
+ lns[i] = '/%s' % (ln,)
+ itempath = ''.join(lns)
+ return itempath
+
+class AbstractLinkWriter(object):
+ def get_link(self, base, path):
+ pass
+
+class NoLinkWriter(AbstractLinkWriter):
+ def get_link(self, base, path):
+ return ''
+
+class LinkWriter(AbstractLinkWriter):
+ def __init__(self, baseurl):
+ self.baseurl = baseurl
+
+ def get_link(self, base, path):
+ relpath = path.relto(base)
+ return self.baseurl + relpath
+
+class RelLinkWriter(AbstractLinkWriter):
+ def get_link(self, base, path):
+ return path.relto(base)
+
Modified: py/dist/py/test/rsession/testing/test_rest.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_rest.py (original)
+++ py/dist/py/test/rsession/testing/test_rest.py Thu Nov 23 11:43:24 2006
@@ -4,7 +4,8 @@
import py
from py.__.test.rsession.testing.test_reporter import AbstractTestReporter
-from py.__.test.rsession.rest import RestReporter
+from py.__.test.rsession import report
+from py.__.test.rsession.rest import RestReporter, NoLinkWriter
from py.__.rest.rst import *
class RestTestReporter(RestReporter):
@@ -16,6 +17,12 @@
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
+class FakeOutcome(Container, report.ReceivedItemOutcome):
+ pass
+
+class FakeTryiter(Container, report.SkippedTryiter):
+ pass
+
class TestRestUnits(object):
def setup_method(self, method):
config, args = py.test.Config.parse(["some_sub"])
@@ -24,6 +31,7 @@
['localhost'])
method.im_func.func_globals['stdout'] = s = py.std.StringIO.StringIO()
r.out = s # XXX will need to become a real reporter some time perhaps?
+ r.linkwriter = NoLinkWriter()
def test_report_unknown(self):
reporter.report_unknown('foo')
@@ -63,13 +71,15 @@
def test_report_ItemStart(self):
class FakeModule(py.test.collect.Module):
- def __init__(self):
- pass
+ def __init__(self, parent):
+ self.parent = parent
+ self.fspath = py.path.local('.')
def tryiter(self):
return ['test_foo', 'test_bar']
def listnames(self):
- return ['foo', 'bar.py']
- event = Container(item=FakeModule())
+ return ['package', 'foo', 'bar.py']
+ parent = Container(parent=None, fspath=py.path.local('.'))
+ event = Container(item=FakeModule(parent))
reporter.report_ItemStart(event)
assert stdout.getvalue() == """\
Testing module foo/bar.py (2 items)
@@ -105,31 +115,148 @@
'foo.py/bar()/baz\n\n')
def test_ReceivedItemOutcome_FAILED(self):
- excinfo = Container(typename='FooError', value='a foo has occurred',
- traceback=[' in foo in line 1, in foo:',
- ' bar()',
- ' in bar in line 4, in bar:',
- (' raise FooError("a foo has '
- 'occurred")')])
- outcome = Container(passed=False, skipped=False, excinfo=excinfo)
+ outcome = Container(passed=False, skipped=False)
item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz'])
event = Container(channel=False, outcome=outcome, item=item)
reporter.report_ReceivedItemOutcome(event)
assert stdout.getvalue() == """\
* localhost\: **FAILED** foo.py/bar()/baz
-exception\: **FooError**
+"""
+
+ def test_skips(self):
+ reporter.skips()
+ assert stdout.getvalue() == ''
+ reporter.skipped_tests_outcome = [
+ FakeOutcome(outcome=Container(skipped='problem X'),
+ item=Container(listnames=lambda: ['foo', 'bar.py'])),
+ FakeTryiter(excinfo=Container(value='problem Y'),
+ item=Container(listnames=lambda: ['foo', 'baz.py']))]
+ reporter.skips()
+ assert stdout.getvalue() == """\
+Reasons for skipped tests\:
++++++++++++++++++++++++++++
+
+* foo/bar.py\: problem X
+
+* foo/baz.py\: problem Y
+
+"""
+
+ def test_failures(self):
+ parent = Container(parent=None, fspath=py.path.local('.'))
+ reporter.failed_tests_outcome = [
+ FakeOutcome(
+ outcome=Container(
+ signal=False,
+ excinfo=Container(
+ typename='FooError',
+ value='A foo has occurred',
+ traceback=[
+ Container(
+ path='foo/bar.py',
+ lineno=1,
+ relline=1,
+ source='foo()',
+ ),
+ Container(
+ path='foo/baz.py',
+ lineno=4,
+ relline=1,
+ source='raise FooError("A foo has occurred")',
+ ),
+ ]
+ ),
+ stdout='',
+ stderr='',
+ ),
+ item=Container(
+ listnames=lambda: ['package', 'foo', 'bar.py',
+ 'baz', '()'],
+ parent=parent,
+ fspath=py.path.local('.'),
+ ),
+ channel=None,
+ ),
+ ]
+ reporter.config.option.tbstyle = 'no'
+ reporter.failures()
+ assert stdout.getvalue() == """\
+Exceptions\:
+++++++++++++
+
+foo/bar.py/baz() on localhost
++++++++++++++++++++++++++++++
+
+FooError
+++++++++
::
- a foo has occurred
+ A foo has occurred
+
+"""
+
+ reporter.config.option.tbstyle = 'short'
+ stdout.seek(0)
+ stdout.truncate()
+ reporter.failures()
+ assert stdout.getvalue() == """\
+Exceptions\:
+++++++++++++
+
+foo/bar.py/baz() on localhost
++++++++++++++++++++++++++++++
+
+::
+
+ foo/bar.py line 1
+ foo()
+ foo/baz.py line 4
+ raise FooError("A foo has occurred")
+
+FooError
+++++++++
::
- in foo in line 1, in foo:
- bar()
- in bar in line 4, in bar:
- raise FooError("a foo has occurred")
+ A foo has occurred
+
+"""
+
+ reporter.config.option.tbstyle = 'long'
+ stdout.seek(0)
+ stdout.truncate()
+ reporter.failures()
+ stdout.getvalue() == """\
+Exceptions\:
+++++++++++++
+
+foo/bar.py/baz() on localhost
++++++++++++++++++++++++++++++
+
++++++++++++++++++
+foo/bar.py line 1
++++++++++++++++++
+
+::
+
+ foo()
+
++++++++++++++++++
+foo/baz.py line 4
++++++++++++++++++
+
+::
+
+ raise FooError("A foo has occurred")
+
+FooError
+++++++++
+
+::
+
+ A foo has occurred
"""
@@ -141,34 +268,16 @@
def test_report_received_item_outcome(self):
val = self.report_received_item_outcome()
- expected = """- localhost\\: FAILED py test rsession testing test\\_slave.py funcpass
-- localhost\\: SKIPPED py test rsession testing test\\_slave.py funcpass
-- localhost\\: FAILED py test rsession testing test\\_slave.py funcpass
-- localhost\\: PASSED py test rsession testing test\\_slave.py funcpass
-"""
- print repr(val)
- expected_start = """\
+ expected = """\
* localhost\: **FAILED** py/test/rsession/testing/test\_slave.py/funcpass
* localhost\: **SKIPPED** py/test/rsession/testing/test\_slave.py/funcpass
* localhost\: **FAILED** py/test/rsession/testing/test\_slave.py/funcpass
-exception\\: **ZeroDivisionError**
-
-::
-
- integer division or modulo by zero
-
-::
-
-"""
-
- expected_end = """
-
* localhost\: **PASSED** py/test/rsession/testing/test\_slave.py/funcpass
"""
- assert val.startswith(expected_start)
- assert val.endswith(expected_end)
+ print val
+ assert val == expected
From guido at codespeak.net Thu Nov 23 14:37:38 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Thu, 23 Nov 2006 14:37:38 +0100 (CET)
Subject: [py-svn] r34893 - py/dist/py
Message-ID: <20061123133738.D708C10061@code0.codespeak.net>
Author: guido
Date: Thu Nov 23 14:37:36 2006
New Revision: 34893
Modified:
py/dist/py/__init__.py
Log:
Added initpkg entries for the py.test.rest stuff.
Modified: py/dist/py/__init__.py
==============================================================================
--- py/dist/py/__init__.py (original)
+++ py/dist/py/__init__.py Thu Nov 23 14:37:36 2006
@@ -50,6 +50,10 @@
'test.collect.Generator' : ('./test/collect.py', 'Generator'),
'test.Item' : ('./test/item.py', 'Item'),
'test.Function' : ('./test/item.py', 'Function'),
+ 'test.rest.RestReporter' : ('./test/rsession/rest.py', 'RestReporter'),
+ 'test.rest.NoLinkWriter' : ('./test/rsession/rest.py', 'NoLinkWriter'),
+ 'test.rest.LinkWriter' : ('./test/rsession/rest.py', 'LinkWriter'),
+ 'test.rest.RelLinkWriter': ('./test/rsession/rest.py', 'RelLinkWriter'),
# thread related API (still in early design phase)
'_thread.WorkerPool' : ('./thread/pool.py', 'WorkerPool'),
From guido at codespeak.net Thu Nov 23 16:01:19 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Thu, 23 Nov 2006 16:01:19 +0100 (CET)
Subject: [py-svn] r34904 - py/dist/py/misc
Message-ID: <20061123150119.E83B210061@code0.codespeak.net>
Author: guido
Date: Thu Nov 23 16:01:11 2006
New Revision: 34904
Modified:
py/dist/py/misc/error.py
Log:
Added another possible error code for ENOTDIR on win32
Modified: py/dist/py/misc/error.py
==============================================================================
--- py/dist/py/misc/error.py (original)
+++ py/dist/py/misc/error.py Thu Nov 23 16:01:11 2006
@@ -21,6 +21,7 @@
_winerrnomap = {
2: errno.ENOENT,
3: errno.ENOENT,
+ 22: errno.ENOTDIR,
267: errno.ENOTDIR,
5: errno.EACCES, # anything better?
}
From guido at codespeak.net Thu Nov 23 16:48:17 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Thu, 23 Nov 2006 16:48:17 +0100 (CET)
Subject: [py-svn] r34908 - in py/dist/py: misc path/svn/testing
Message-ID: <20061123154817.279A810063@code0.codespeak.net>
Author: guido
Date: Thu Nov 23 16:48:14 2006
New Revision: 34908
Modified:
py/dist/py/misc/error.py
py/dist/py/path/svn/testing/test_urlcommand.py
py/dist/py/path/svn/testing/test_wccommand.py
Log:
Added more error codes, fixed stupid win32 escaping issues in path.svn
Modified: py/dist/py/misc/error.py
==============================================================================
--- py/dist/py/misc/error.py (original)
+++ py/dist/py/misc/error.py Thu Nov 23 16:48:14 2006
@@ -21,6 +21,7 @@
_winerrnomap = {
2: errno.ENOENT,
3: errno.ENOENT,
+ 17: errno.EEXIST,
22: errno.ENOTDIR,
267: errno.ENOTDIR,
5: errno.EACCES, # anything better?
Modified: py/dist/py/path/svn/testing/test_urlcommand.py
==============================================================================
--- py/dist/py/path/svn/testing/test_urlcommand.py (original)
+++ py/dist/py/path/svn/testing/test_urlcommand.py Thu Nov 23 16:48:14 2006
@@ -31,6 +31,11 @@
py.path.svnurl("http://host.com:8080/some/dir")
def test_svnurl_characters_colon_path(self):
+ if py.std.sys.platform == 'win32':
+ # colons are allowed on win32, because they're part of the drive
+ # part of an absolute path... however, they shouldn't be allowed in
+ # other parts, I think
+ py.test.skip('XXX fixme win32')
py.test.raises(ValueError, 'py.path.svnurl("http://host.com/foo:bar")')
def test_svnurl_characters_tilde_end(self):
Modified: py/dist/py/path/svn/testing/test_wccommand.py
==============================================================================
--- py/dist/py/path/svn/testing/test_wccommand.py (original)
+++ py/dist/py/path/svn/testing/test_wccommand.py Thu Nov 23 16:48:14 2006
@@ -293,7 +293,13 @@
py.process.cmdexec('svnadmin create "%s"' %
svncommon._escape_helper(repo))
wc = py.path.svnwc(wcdir)
- wc.checkout(url='file://%s' % repo)
+ repopath = repo.strpath
+ if py.std.sys.platform.startswith('win32'):
+ # strange win problem, paths become something like file:///c:\\foo
+ repourl = 'file:///%s' % (repopath.replace('\\', '/'),)
+ else:
+ repourl = 'file://%s' % (repopath,)
+ wc.checkout(url=repourl)
cls.wc = wc
def test_info(self):
From fijal at codespeak.net Thu Nov 23 21:51:29 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Thu, 23 Nov 2006 21:51:29 +0100 (CET)
Subject: [py-svn] r34918 - in py/dist/py/apigen/source: . testing
Message-ID: <20061123205129.5A12E10068@code0.codespeak.net>
Author: fijal
Date: Thu Nov 23 21:51:21 2006
New Revision: 34918
Added:
py/dist/py/apigen/source/html.py (contents, props changed)
py/dist/py/apigen/source/testing/test_html.py (contents, props changed)
Modified:
py/dist/py/apigen/source/browser.py
Log:
(fijal, guido) - HTML generation out of source browser
Modified: py/dist/py/apigen/source/browser.py
==============================================================================
--- py/dist/py/apigen/source/browser.py (original)
+++ py/dist/py/apigen/source/browser.py Thu Nov 23 21:51:21 2006
@@ -12,7 +12,10 @@
from py.__.path.common import PathBase
-class Module(object):
+class BaseElem(object):
+ pass # purely for testing isinstance
+
+class Module(BaseElem):
def __init__(self, path, _dict):
self.path = path
self.dict = _dict
@@ -22,6 +25,9 @@
return self.dict[attr]
except KeyError:
raise AttributeError(attr)
+
+ def get_children(self):
+ return self.dict.values()
def get_endline(start, lst):
l = reversed(lst)
@@ -33,13 +39,13 @@
return end_ch
return start
-class Function(object):
+class Function(BaseElem):
def __init__(self, name, firstlineno, endlineno):
self.firstlineno = firstlineno
self.endlineno = endlineno
self.name = name
-class Method(object):
+class Method(BaseElem):
def __init__(self, name, firstlineno, endlineno):
self.name = name
self.firstlineno = firstlineno
@@ -62,7 +68,7 @@
cls_ast.code.nodes if isinstance(i, ast.Function)])
return Class(name, startline, endline, bases, methods)
-class Class(object):
+class Class(BaseElem):
def __init__(self, name, firstlineno, endlineno, bases, methods):
self.bases = bases
self.firstlineno = firstlineno
@@ -75,9 +81,13 @@
return self.methods[attr]
except KeyError:
raise AttributeError(attr)
+
+ def get_children(self):
+ return self.methods.values()
def parse_path(path):
- assert isinstance(path, PathBase), "Cannot work on files directly"
+ if not isinstance(path, PathBase):
+ path = py.path.local(path)
buf = path.open().read()
st = parse(buf)
# first go - we get all functions and classes defined on top-level
Added: py/dist/py/apigen/source/html.py
==============================================================================
--- (empty file)
+++ py/dist/py/apigen/source/html.py Thu Nov 23 21:51:21 2006
@@ -0,0 +1,59 @@
+
+""" html - generating ad-hoc html out of source browser
+"""
+
+from py.xml import html
+from compiler import ast
+
+class HtmlEnchanter(object):
+ def __init__(self, mod):
+ self.mod = mod
+ self.create_caches()
+
+ def create_caches(self):
+ mod = self.mod
+ linecache = {}
+ for item in mod.get_children():
+ linecache[item.firstlineno] = item
+ self.linecache = linecache
+
+ def enchant_row(self, num, row):
+ # add some informations to row, like functions defined in that line, etc.
+ try:
+ item = self.linecache[num]
+ # XXX: this should not be assertion, rather check, but we want to
+ # know if stuff is working
+ pos = row.find(item.name)
+ assert pos != -1
+ end = len(item.name) + pos
+ return [row[:pos], html.a(row[pos:end], href="#" + item.name,
+ name=item.name), row[end:]]
+ except KeyError:
+ return [row] # no more info
+
+def make_code(lst):
+ # I HATE HTML, I HATE HTML
+ output = []
+ for elem in lst:
+ if isinstance(elem, str):
+ output.append(html.code(elem))
+ else:
+ output.append(elem)
+ return output
+
+def create_html(mod):
+ # out is some kind of stream
+ #*[html.tr(html.td(i.name)) for i in mod.get_children()]
+ lines = mod.path.open().readlines()
+
+ enchanter = HtmlEnchanter(mod)
+ rows = [enchanter.enchant_row(num + 1, row[:-1]) for num, row in enumerate(lines)]
+ html_rows = [html.tr(html.td(html.pre(num + 1), html.td(html.pre(*i)))) \
+ for num, i in enumerate(rows)]
+
+ output = html.table(
+ html.tbody(
+ *html_rows
+ )
+ )
+ return output
Added: py/dist/py/apigen/source/testing/test_html.py
==============================================================================
--- (empty file)
+++ py/dist/py/apigen/source/testing/test_html.py Thu Nov 23 21:51:21 2006
@@ -0,0 +1,47 @@
+
+""" test of html generation
+"""
+
+from py.__.apigen.source.html import create_html
+from py.__.apigen.source.browser import parse_path
+
+import py
+import os
+
+def create_html_and_show(path):
+ mod = parse_path(path)
+ html = create_html(mod)
+ testfile = py.test.ensuretemp("htmloutput").ensure("test.html")
+ testfile.write(unicode(html))
+ return testfile
+
+def test_basic():
+ tmp = py.test.ensuretemp("sourcehtml")
+ inp = tmp.ensure("one.py")
+ inp.write(py.code.Source("""
+ def func_one():
+ pass
+
+ def func_two(x, y):
+ x = 1
+ y = 2
+ return x + y
+
+ class B:
+ pass
+
+ class A(B):
+ def meth1(self):
+ pass
+
+ def meth2(self):
+ pass
+ """))
+
+ testfile = create_html_and_show(inp)
+ data = testfile.open().read()
+ assert data.find('
Author: fijal
Date: Thu Nov 23 21:55:28 2006
New Revision: 34920
Modified:
py/dist/py/apigen/source/html.py
Log:
Make not
appear inside other
Modified: py/dist/py/apigen/source/html.py
==============================================================================
--- py/dist/py/apigen/source/html.py (original)
+++ py/dist/py/apigen/source/html.py Thu Nov 23 21:55:28 2006
@@ -48,7 +48,7 @@
enchanter = HtmlEnchanter(mod)
rows = [enchanter.enchant_row(num + 1, row[:-1]) for num, row in enumerate(lines)]
- html_rows = [html.tr(html.td(html.pre(num + 1), html.td(html.pre(*i)))) \
+ html_rows = [html.tr(html.td(html.pre(num + 1)), html.td(html.pre(*i))) \
for num, i in enumerate(rows)]
output = html.table(
From guido at codespeak.net Thu Nov 23 22:13:50 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Thu, 23 Nov 2006 22:13:50 +0100 (CET)
Subject: [py-svn] r34922 - py/dist/py/path/local
Message-ID: <20061123211350.513FA10061@code0.codespeak.net>
Author: guido
Date: Thu Nov 23 22:13:48 2006
New Revision: 34922
Modified:
py/dist/py/path/local/local.py
Log:
Fixed bare excepts.
Modified: py/dist/py/path/local/local.py
==============================================================================
--- py/dist/py/path/local/local.py (original)
+++ py/dist/py/path/local/local.py Thu Nov 23 22:13:48 2006
@@ -630,21 +630,21 @@
# make link...
try:
username = os.environ['USER'] #linux, et al
- except:
+ except KeyError:
try:
username = os.environ['USERNAME'] #windows
- except:
+ except KeyError:
username = 'current'
src = str(udir)
dest = src[:src.rfind('-')] + '-' + username
try:
os.unlink(dest)
- except:
+ except OSError:
pass
try:
os.symlink(src, dest)
- except:
+ except OSError:
pass
return udir
From guido at codespeak.net Thu Nov 23 22:17:44 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Thu, 23 Nov 2006 22:17:44 +0100 (CET)
Subject: [py-svn] r34923 - py/dist/py/path/local
Message-ID: <20061123211744.DCE3A10061@code0.codespeak.net>
Author: guido
Date: Thu Nov 23 22:17:43 2006
New Revision: 34923
Modified:
py/dist/py/path/local/local.py
Log:
On Windows an AttributeError is raised when trying to symlink (duh)
Modified: py/dist/py/path/local/local.py
==============================================================================
--- py/dist/py/path/local/local.py (original)
+++ py/dist/py/path/local/local.py Thu Nov 23 22:17:43 2006
@@ -644,7 +644,7 @@
pass
try:
os.symlink(src, dest)
- except OSError:
+ except (OSError, AttributeError): # AttributeError on win32
pass
return udir
From guido at codespeak.net Thu Nov 23 23:12:01 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Thu, 23 Nov 2006 23:12:01 +0100 (CET)
Subject: [py-svn] r34924 - in py/dist/py/apigen/rest: . testing
Message-ID: <20061123221201.E4CC410061@code0.codespeak.net>
Author: guido
Date: Thu Nov 23 23:11:59 2006
New Revision: 34924
Modified:
py/dist/py/apigen/rest/genrest.py
py/dist/py/apigen/rest/testing/test_rest.py
Log:
Fixed tests for win32, fixed problem with path to URL conversion in win32
Modified: py/dist/py/apigen/rest/genrest.py
==============================================================================
--- py/dist/py/apigen/rest/genrest.py (original)
+++ py/dist/py/apigen/rest/genrest.py Thu Nov 23 23:11:59 2006
@@ -44,6 +44,9 @@
relname = filename[len(path):]
if relname.endswith('.pyc'):
relname = relname[:-1]
+ sep = py.std.os.sep
+ if sep != '/':
+ relname = relname.replace(sep, '/')
return ('%s:%s' % (filename, lineno),
self.basepath + relname[1:] + '?view=markup')
Modified: py/dist/py/apigen/rest/testing/test_rest.py
==============================================================================
--- py/dist/py/apigen/rest/testing/test_rest.py (original)
+++ py/dist/py/apigen/rest/testing/test_rest.py Thu Nov 23 23:11:59 2006
@@ -18,6 +18,12 @@
from py.__.rest.transform import HTMLHandler
# XXX: UUuuuuuuuuuuuuuuuuuuuuuuu, dangerous import
+def _nl(s):
+ """normalize newlines (converting to \n)"""
+ s = s.replace('\r\n', '\n')
+ s = s.replace('\r', '\n')
+ return s
+
def setup_module(mod):
mod.temppath = py.test.ensuretemp('restgen')
@@ -86,8 +92,8 @@
fpaths = tempdir.listdir('*.txt')
assert len(fpaths) == 2
assert sorted([f.basename for f in fpaths]) == ['bar.txt', 'foo.txt']
- assert tempdir.join('foo.txt').read() == 'foo data\n'
- assert tempdir.join('bar.txt').read() == 'bar data\n'
+ assert _nl(tempdir.join('foo.txt').read()) == 'foo data\n'
+ assert _nl(tempdir.join('bar.txt').read()) == 'bar data\n'
def test_getlink(self):
dw = DirWriter(temppath.join('dirwriter_getlink'))
@@ -239,7 +245,7 @@
r.write()
index = tempdir.join('module_Unknown module.txt')
assert index.check(file=True)
- data = index.read()
+ data = _nl(index.read())
assert data.find('.. _`fun`: function_fun.html\n') > -1
assert data.find('.. _`fun`: #function-fun\n') == -1
@@ -247,7 +253,7 @@
file=True)
r = RestGen(ds, lg, FileWriter(tempfile))
r.write()
- data = tempfile.read()
+ data = _nl(tempfile.read())
assert data.find('.. _`fun`: #function-fun\n') > -1
assert data.find('.. _`fun`: function_fun.html') == -1
@@ -256,7 +262,7 @@
tempfile = temppath.join('internal_links.txt')
if not tempfile.check():
py.test.skip('depends on previous test, which failed')
- data = tempfile.read()
+ data = _nl(tempfile.read())
# index should be above the rest
print data
assert data.find('classes\\:') > -1
From guido at codespeak.net Thu Nov 23 23:35:32 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Thu, 23 Nov 2006 23:35:32 +0100 (CET)
Subject: [py-svn] r34925 - py/dist/py/test/rsession/testing
Message-ID: <20061123223532.4350B10061@code0.codespeak.net>
Author: guido
Date: Thu Nov 23 23:35:30 2006
New Revision: 34925
Modified:
py/dist/py/test/rsession/testing/test_lsession.py
Log:
Skipping tests that test forking code on platforms that don't have os.fork.
Modified: py/dist/py/test/rsession/testing/test_lsession.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_lsession.py (original)
+++ py/dist/py/test/rsession/testing/test_lsession.py Thu Nov 23 23:35:30 2006
@@ -68,6 +68,8 @@
assert str(tb[0].source).find("execute") != -1
def test_normal(self):
+ if not hasattr(py.std.os, 'fork'):
+ py.test.skip('operating system not supported')
self.example_distribution(box_runner)
def test_plain(self):
@@ -103,6 +105,8 @@
assert len(l) == 1
def test_minus_x(self):
+ if not hasattr(py.std.os, 'fork'):
+ py.test.skip('operating system not supported')
tmpdir = tmp
tmpdir.ensure("sub2", "__init__.py")
tmpdir.ensure("sub2", "test_one.py").write(py.code.Source("""
@@ -138,6 +142,8 @@
assert len(failevents) == 1
def test_minus_k(self):
+ if not hasattr(py.std.os, 'fork'):
+ py.test.skip('operating system not supported')
tmpdir = tmp
tmpdir.ensure("sub3", "__init__.py")
tmpdir.ensure("sub3", "test_some.py").write(py.code.Source("""
@@ -225,6 +231,8 @@
def test_assert_reinterpret(self):
+ if not hasattr(py.std.os, 'fork'):
+ py.test.skip('operating system not supported')
tmpdir = tmp
tmpdir.ensure("sub6", "__init__.py")
tmpdir.ensure("sub6", "test_some.py").write(py.code.Source("""
From guido at codespeak.net Thu Nov 23 23:44:59 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Thu, 23 Nov 2006 23:44:59 +0100 (CET)
Subject: [py-svn] r34926 - py/dist/py/documentation
Message-ID: <20061123224459.8236910061@code0.codespeak.net>
Author: guido
Date: Thu Nov 23 23:44:58 2006
New Revision: 34926
Removed:
py/dist/py/documentation/apigen_comparison.txt
Modified:
py/dist/py/documentation/apigen.txt
Log:
Merging apigen documents.
Modified: py/dist/py/documentation/apigen.txt
==============================================================================
--- py/dist/py/documentation/apigen.txt (original)
+++ py/dist/py/documentation/apigen.txt Thu Nov 23 23:44:58 2006
@@ -106,6 +106,110 @@
action you run `py.test --session=L --apigen` in the root of the py lib; this
will result in documentation (in HTML) being written to /tmp/output.
+Comparison with other documentation generation tools
+----------------------------------------------------
+
+Apigen is of course not the only documentation generation tool available for
+Python. Although we knew in advance that our tool had certain features the
+others do not offer, we decided to investigate a bit so that we could do a
+proper comparison.
+
+Tools examined
+++++++++++++++
+
+After some 'googling around', it turned out that the amount of documentation
+generation tools available was surprisingly low. There were only 5 packages
+I could find, of which 1 (called 'HappyDoc') seems dead (last release 2001),
+one (called 'Pudge') not yet born (perhaps DOA even? most of the links on the
+website are dead), and one (called 'Endo') specific to the Enthought suite.
+The remaining two were Epydoc, which is widely used [1]_, and PyDoctor, which is
+used only by (and written for) the Twisted project, but can be used seperately.
+
+Epydoc
+~~~~~~
+
+http://epydoc.sourceforge.net/
+
+Epydoc is the best known, and most widely used, documentation generation tool
+for Python. It builds a documentation tree by inspecting imported modules and
+using Python's introspection features. This way it can display information like
+containment, inheritance, and docstrings.
+
+The tool is relatively sophisticated, with support for generating HTML and PDF,
+choosing different styles (CSS), generating graphs using Graphviz, etc. Also
+it allows using markup (which can be ReST, JavaDoc, or their own 'epytext'
+format) inside docstrings for displaying rich text in the result.
+
+Quick overview:
+
+ * builds docs from object tree
+ * displays relatively little information, just inheritance trees, API and
+ docstrings
+ * supports some markup (ReST, 'epytext', JavaDoc) in docstrings
+
+PyDoctor
+~~~~~~~~
+
+http://codespeak.net/~mwh/pydoctor/
+
+This tool is written by Michael Hudson for the Twisted project. The major
+difference between this and Epydoc is that it browses the AST (Abstract Syntax
+Tree) instead of using 'live' objects, which makes that code that uses special
+import mechanisms, or depends on other code that is not available, can still
+be inspected.
+
+The tool is relatively simple and doesn't support the more advanced features
+that Epydoc offers, and since it's written basically only for Twisted, I don't
+think it will see a lot of development in the future.
+
+Quick overview:
+
+ * inspects AST rather than object tree
+ * again not a lot of information, the usual API docstrings, class inheritance
+ and module structure, but that's it
+ * rather heavy dependencies (depends on Twisted/Nevow (trunk version))
+ * written for Twisted, but quite nice output with other applications (except
+ that generating docs of the 'py lib' resulted in a max recursion depth
+ error)
+
+Quick overview lists of the other tools
++++++++++++++++++++++++++++++++++++++++
+
+HappyDoc
+~~~~~~~~
+
+http://happydoc.sourceforge.net/
+
+ * dead
+ * inspects AST
+ * quite flexible, different output formats (HTML, XML, SGML, PDF)
+ * pluggable docstring parsers
+
+Pudge
+~~~~~
+
+http://pudge.lesscode.org/
+
+ * immature, dead?
+ * builds docs from live object tree (I think?)
+ * supports ReST
+ * uses Kid templates
+
+Endo
+~~~~
+
+https://svn.enthought.com/enthought/wiki/EndoHowTo
+
+ * inspects object tree (I think?)
+ * 'traits' aware (see https://svn.enthought.com/enthought/wiki/Traits)
+ * customizable HTML output with custom templating engine
+ * little documentation, seems like it's written for Enthought's own use
+ mostly
+ * heavy dependencies
+
+.. [1] Epydoc doesn't seem to be developed anymore, either, but it's so
+ widely used it can not be ignored...
+
Questions, remarks, etc.
-------------------------
Deleted: /py/dist/py/documentation/apigen_comparison.txt
==============================================================================
--- /py/dist/py/documentation/apigen_comparison.txt Thu Nov 23 23:44:58 2006
+++ (empty file)
@@ -1,103 +0,0 @@
-Comparison of apigen with similar tools
-========================================
-
-Apigen is of course not the only documentation generation tool available for
-Python. Although we knew in advance that our tool had certain features the
-others do not offer, we decided to investigate a bit so that we could do a
-proper comparison.
-
-Tools examined
----------------
-
-After some 'googling around', it turned out that the amount of documentation
-generation tools available was surprisingly low. There were only 5 packages
-I could find, of which 1 (called 'HappyDoc') seems dead (last release 2001),
-one (called 'Pudge') not yet born (perhaps DOA even? most of the links on the
-website are dead), and one (called 'Endo') specific to the Enthought suite.
-The remaining two were Epydoc, which is widely used [1]_, and PyDoctor, which is
-used only by (and written for) the Twisted project, but can be used seperately.
-
-Epydoc
--------
-
-http://epydoc.sourceforge.net/
-
-Epydoc is the best known, and most widely used, documentation generation tool
-for Python. It builds a documentation tree by inspecting imported modules and
-using Python's introspection features. This way it can display information like
-containment, inheritance, and docstrings.
-
-The tool is relatively sophisticated, with support for generating HTML and PDF,
-choosing different styles (CSS), generating graphs using Graphviz, etc. Also
-it allows using markup (which can be ReST, JavaDoc, or their own 'epytext'
-format) inside docstrings for displaying rich text in the result.
-
-Quick overview:
-
- * builds docs from object tree
- * displays relatively little information, just inheritance trees, API and
- docstrings
- * supports some markup (ReST, 'epytext', JavaDoc) in docstrings
-
-PyDoctor
----------
-
-http://codespeak.net/~mwh/pydoctor/
-
-This tool is written by Michael Hudson for the Twisted project. The major
-difference between this and Epydoc is that it browses the AST (Abstract Syntax
-Tree) instead of using 'live' objects, which makes that code that uses special
-import mechanisms, or depends on other code that is not available, can still
-be inspected.
-
-The tool is relatively simple and doesn't support the more advanced features
-that Epydoc offers, and since it's written basically only for Twisted, I don't
-think it will see a lot of development in the future.
-
-Quick overview:
-
- * inspects AST rather than object tree
- * again not a lot of information, the usual API docstrings, class inheritance
- and module structure, but that's it
- * rather heavy dependencies (depends on Twisted/Nevow (trunk version))
- * written for Twisted, but quite nice output with other applications (except
- that generating docs of the 'py lib' resulted in a max recursion depth
- error)
-
-Quick overview lists of the other tools
-----------------------------------------
-
-HappyDoc
-+++++++++
-
-http://happydoc.sourceforge.net/
-
- * dead
- * inspects AST
- * quite flexible, different output formats (HTML, XML, SGML, PDF)
- * pluggable docstring parsers
-
-Pudge
-++++++
-
-http://pudge.lesscode.org/
-
- * immature, dead?
- * builds docs from live object tree (I think?)
- * supports ReST
- * uses Kid templates
-
-Endo
-+++++
-
-https://svn.enthought.com/enthought/wiki/EndoHowTo
-
- * inspects object tree (I think?)
- * 'traits' aware (see https://svn.enthought.com/enthought/wiki/Traits)
- * customizable HTML output with custom templating engine
- * little documentation, seems like it's written for Enthought's own use
- mostly
- * heavy dependencies
-
-.. [1] Epydoc doesn't seem to be developed anymore, either, but it's so
- widely used it can not be ignored...
From guido at codespeak.net Thu Nov 23 23:59:13 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Thu, 23 Nov 2006 23:59:13 +0100 (CET)
Subject: [py-svn] r34927 - py/dist/py/thread/testing
Message-ID: <20061123225913.D3E5810061@code0.codespeak.net>
Author: guido
Date: Thu Nov 23 23:59:01 2006
New Revision: 34927
Modified:
py/dist/py/thread/testing/test_pool.py
Log:
Not sure why, but this fixes the test on Windows (and doesn't break it on
Linux).
Modified: py/dist/py/thread/testing/test_pool.py
==============================================================================
--- py/dist/py/thread/testing/test_pool.py (original)
+++ py/dist/py/thread/testing/test_pool.py Thu Nov 23 23:59:01 2006
@@ -20,7 +20,13 @@
q.get()
assert len(pool._alive) == 4
pool.shutdown()
- pool.join(timeout=1.0)
+ # XXX I replaced the following join() with a time.sleep(1), which seems
+ # to fix the test on Windows, and doesn't break it on Linux... Completely
+ # unsure what the idea is, though, so it would be nice if someone with some
+ # more understanding of what happens here would either fix this better, or
+ # remove this comment...
+ # pool.join(timeout=1.0)
+ py.std.time.sleep(1)
assert len(pool._alive) == 0
assert len(pool._ready) == 0
From guido at codespeak.net Fri Nov 24 12:49:51 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Fri, 24 Nov 2006 12:49:51 +0100 (CET)
Subject: [py-svn] r34931 - py/dist/py/path/svn
Message-ID: <20061124114951.9813910075@code0.codespeak.net>
Author: guido
Date: Fri Nov 24 12:49:49 2006
New Revision: 34931
Added:
py/dist/py/path/svn/quoting.txt
Log:
Document describing problems with paths and URLs in Subversion, to serve as
a reference when implementing proper path/URL handling in path/svn/*.
Added: py/dist/py/path/svn/quoting.txt
==============================================================================
--- (empty file)
+++ py/dist/py/path/svn/quoting.txt Fri Nov 24 12:49:49 2006
@@ -0,0 +1,53 @@
+URL escaping in Subversion
+==========================
+
+A quick document describing the rules (as far as we've found out, that is) that
+apply to quoting of URLs and file paths in Subversion. Handling quoting
+properly is a bit of a challenge, since different rules apply for file paths
+and URLs, and those rules aren't entirely clear in either case.
+
+What follows is a list of semi-random notes that need to be taken into
+consideration when implementing proper quoting in the 'py lib'.
+
+**DISCLAIMER**: currently the idea is just to have this document around as a
+TODO list for implementation, not sure what will happen to it in the future...
+Don't consider it part of the py lib documentation, and do understand it may be
+incomplete or even incorrect...
+
+* SVN deals with remote objects using URLs and local ones using paths
+
+* URLs follow (almost) normal `URL encoding rules`_
+
+ characters that aren't allowed in URL paths (such as :, @, %, etc.) should
+ be replaced with a % sign following the ASCII value of the character (two
+ digit HEX)
+
+ an exception (the only one I could find so far) is the drive letter in a file
+ URL in windows, the following path was required to get a file 'bar' from a
+ repo in 'c:\\foo'::
+
+ file:///c:/foo/bar
+
+* URLs always have / as seperator
+
+ on Windows, the \\ characters in paths will have to be replaced with a /
+
+ also (see above) if the path contains a drive letter, a / should be prepended
+
+* paths don't require encoding
+
+ normally paths don't have to be encoded, however @ can confuse SVN in certain
+ cases; a workaround is to add @HEAD after the path (also works for relative
+ paths, I encountered this doing an SVN info on a file called 'bar at baz', in
+ the end the command 'svn info bar at baz@HEAD' worked)
+
+* all characters that are supported in paths by all operating systems seem to
+ be supported by SVN
+
+ basically SVN doesn't deal with platforms that aren't capable of using
+ certain characters: it will happily allow you to check a file with a name
+ containing a backslash (\\) in, resulting in a repo that isn't usable in
+ Windows anymore (you'll get a nasty message explaining how your local
+ checkout is broken on checking it out)...
+
+.. _`URL encoding rules`: http://en.wikipedia.org/wiki/Percent-encoding
From fijal at codespeak.net Fri Nov 24 16:18:46 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Fri, 24 Nov 2006 16:18:46 +0100 (CET)
Subject: [py-svn] r34936 - py/dist/py/documentation
Message-ID: <20061124151846.6C6E51007B@code0.codespeak.net>
Author: fijal
Date: Fri Nov 24 16:18:44 2006
New Revision: 34936
Modified:
py/dist/py/documentation/test-distributed.txt
py/dist/py/documentation/test.txt
Log:
Updated a bit distributed testing docs.
Modified: py/dist/py/documentation/test-distributed.txt
==============================================================================
--- py/dist/py/documentation/test-distributed.txt (original)
+++ py/dist/py/documentation/test-distributed.txt Fri Nov 24 16:18:44 2006
@@ -29,6 +29,12 @@
Writing down new reporter is relatively easy, way easier than writing session
from a scratch, so one can write down GTK reporter and whatnot.
+Only thing to do is to write down new reporter classs which subclasses
+`AbstractReporter` in `reporter.py`_ and overrides all the report_Xxx methods
+(each of these method is called when one of the message, defined in
+`report.py`_ arrives to reporter). Special consideration is needed when dealing
+with ReceivedItemOutcome, which is in details described in `outcome.py`_.
+
Another abstraction layer (present only in `LSession`) is runner. Actual
object which runs tests. There are two existing runners: box_runner and
plain_runner, both defined in `local.py`_. box_runner can run tests
@@ -42,16 +48,17 @@
.. _`report.py`: http://codespeak.net/svn/py/dist/py/test/rsession/report.py
.. _`web.py`: http://codespeak.net/svn/py/dist/py/test/rsession/web.py
.. _`local.py`: http://codespeak.net/svn/py/dist/py/test/rsession/local.py
+.. _`reporter.py`: http://codespeak.net/svn/py/dist/py/test/rsession/reporter.py
+.. _`outcome.py`: http://codespeak.net/svn/py/dist/py/test/rsession/outcome.py
Implemented features:
=====================
Actually most of normal py.test features are implemented in distributed
version. These are command line options: -v -x -k --pdb (only for LSession).
-Missing options are -s (makes sense for LSession, easy), --exec (moderatly
-easy for L/R Sessions), --pdb for RSession (with screen, unsure if it'll
-be implemented). Quite missing is testing LSession under OSX/Windows or other
-machines than mine.
+--exec (moderatly easy for L/R Sessions), --pdb for RSession (with screen,
+unsure if it'll be implemented). Quite missing is testing LSession under
+OSX/Windows or other machines than mine.
Unique features:
================
Modified: py/dist/py/documentation/test.txt
==============================================================================
--- py/dist/py/documentation/test.txt (original)
+++ py/dist/py/documentation/test.txt Fri Nov 24 16:18:44 2006
@@ -755,8 +755,9 @@
* `nice_level` - Level of nice under which tests are run
* `runner_policy` - (for `LSession` only) - contains policy for the test boxig.
`"plain_runner"` means no boxing, `"box_runner"` means boxing.
-* `waittime` - Default waiting time for remote host to finish test (after
+* `waittime` - Default waiting time for remote host to finish tests (after
that period we consider node as dead, default to 100s).
+* `max_tasks_per_node` - Maximum number of tasks which can be send to one node.
Development Notes
-----------------
@@ -764,11 +765,11 @@
Changing the behavior of the web based reporter requires `pypy`_ since the
javascript is actually generated fom rpython source.
-At some point it would be good to split the default collection process into a
-separate collector and reporter as well. This would all the web based reporter
-to be used locally.
+There exists as well `L/Rsession document`_ which discusses in more details
+unique features and developement notes.
.. _`pypy`: http://codespeak.net/pypy
+.. _`L/Rsession document`: test-distributed.html
Future/Planned Features of py.test
From arigo at codespeak.net Sat Nov 25 15:02:56 2006
From: arigo at codespeak.net (arigo at codespeak.net)
Date: Sat, 25 Nov 2006 15:02:56 +0100 (CET)
Subject: [py-svn] r34959 - py/dist/py/rest
Message-ID: <20061125140256.CC0A510077@code0.codespeak.net>
Author: arigo
Date: Sat Nov 25 15:02:55 2006
New Revision: 34959
Modified:
py/dist/py/rest/latex.py
Log:
Don't put a py.path object in sys.path. Confusion.
Modified: py/dist/py/rest/latex.py
==============================================================================
--- py/dist/py/rest/latex.py (original)
+++ py/dist/py/rest/latex.py Sat Nov 25 15:02:55 2006
@@ -82,7 +82,7 @@
configfile = py.path.local(configfile)
path = configfile.dirpath()
configfile_dic = {}
- py.std.sys.path.insert(0, path)
+ py.std.sys.path.insert(0, str(path))
execfile(str(configfile), configfile_dic)
pagebreak = configfile_dic.get("pagebreak", False)
rest_sources = [py.path.local(p)
From fijal at codespeak.net Sat Nov 25 15:50:35 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Sat, 25 Nov 2006 15:50:35 +0100 (CET)
Subject: [py-svn] r34962 - in py/dist/py/apigen/source: . testing
Message-ID: <20061125145035.B64A010084@code0.codespeak.net>
Author: fijal
Date: Sat Nov 25 15:50:32 2006
New Revision: 34962
Modified:
py/dist/py/apigen/source/browser.py
py/dist/py/apigen/source/testing/test_browser.py
Log:
Added possibility of ifing functions and classes.
Modified: py/dist/py/apigen/source/browser.py
==============================================================================
--- py/dist/py/apigen/source/browser.py (original)
+++ py/dist/py/apigen/source/browser.py Sat Nov 25 15:50:32 2006
@@ -12,6 +12,8 @@
from py.__.path.common import PathBase
+blockers = [ast.Function, ast.Class]
+
class BaseElem(object):
pass # purely for testing isinstance
@@ -85,14 +87,35 @@
def get_children(self):
return self.methods.values()
+def dir_nodes(st):
+ """ List all the subnodes, which are not blockers
+ """
+ res = []
+ for i in st.getChildNodes():
+ res.append(i)
+ if not i.__class__ in blockers:
+ res += dir_nodes(i)
+ return res
+
+def update_mod_dict(imp_mod, mod_dict):
+ # make sure that things that are in mod_dict, and not in imp_mod,
+ # are not shown
+ for key, value in mod_dict.items():
+ if not hasattr(imp_mod, key):
+ del mod_dict[key]
+
def parse_path(path):
if not isinstance(path, PathBase):
path = py.path.local(path)
buf = path.open().read()
st = parse(buf)
# first go - we get all functions and classes defined on top-level
- function_ast = [i for i in st.node.nodes if isinstance(i, ast.Function)]
- classes_ast = [i for i in st.node.nodes if isinstance(i, ast.Class)]
+ nodes = dir_nodes(st)
+ function_ast = [i for i in nodes if isinstance(i, ast.Function)]
+ classes_ast = [i for i in nodes if isinstance(i, ast.Class)]
mod_dict = dict([(i.name, function_from_ast(i)) for i in function_ast]
+ [(i.name, class_from_ast(i)) for i in classes_ast])
+ # we check all the elements, if they're really there
+ mod = path.pyimport()
+ update_mod_dict(mod, mod_dict)
return Module(path, mod_dict)
Modified: py/dist/py/apigen/source/testing/test_browser.py
==============================================================================
--- py/dist/py/apigen/source/testing/test_browser.py (original)
+++ py/dist/py/apigen/source/testing/test_browser.py Sat Nov 25 15:50:32 2006
@@ -38,3 +38,17 @@
assert isinstance(mod.Z.zzz, Method)
assert mod.Z.zzz.firstlineno == 13
assert mod.Z.zzz.endlineno == 17
+
+def test_if_browser():
+ tmp = py.test.ensuretemp("sourcebrowser")
+ tmp.ensure("b.py").write(py.code.Source("""
+ if 1:
+ def f():
+ pass
+ if 0:
+ def g():
+ pass
+ """))
+ mod = parse_path(tmp.join("b.py"))
+ assert isinstance(mod.f, Function)
+ py.test.raises(AttributeError, 'mod.g')
From fijal at codespeak.net Sat Nov 25 16:04:38 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Sat, 25 Nov 2006 16:04:38 +0100 (CET)
Subject: [py-svn] r34963 - in py/dist/py/test/rsession: . webdata
Message-ID: <20061125150438.62E2A10086@code0.codespeak.net>
Author: fijal
Date: Sat Nov 25 16:04:35 2006
New Revision: 34963
Modified:
py/dist/py/test/rsession/webdata/source.js
py/dist/py/test/rsession/webjs.py
Log:
Added counters.
Modified: py/dist/py/test/rsession/webdata/source.js
==============================================================================
Binary files. No diff available.
Modified: py/dist/py/test/rsession/webjs.py
==============================================================================
--- py/dist/py/test/rsession/webjs.py (original)
+++ py/dist/py/test/rsession/webjs.py Sat Nov 25 16:04:35 2006
@@ -23,8 +23,10 @@
tracebacks = {}
skips = {}
counters = {}
+max_items = {}
+short_item_names = {}
-MAX_COUNTER = 50
+MAX_COUNTER = 50 # Maximal size of one-line table
class Pending(object):
def __init__(self):
@@ -70,7 +72,10 @@
tr = create_elem("tr")
td = create_elem("td")
tr.appendChild(td)
- td.appendChild(create_text_elem("%s[%s]" % (msg['itemname'], msg['length'])))
+ td.appendChild(create_text_elem("%s[0/%s]" % (msg['itemname'], msg['length'])))
+ max_items[msg['fullitemname']] = int(msg['length'])
+ short_item_names[msg['fullitemname']] = msg['itemname']
+ td.id = '_txt_' + msg['fullitemname']
#tr.setAttribute("id", msg['fullitemname'])
td.setAttribute("onmouseover", "show_info('%s')" % msg['fullitemname'])
td.setAttribute("onmouseout", "hide_info()")
@@ -119,8 +124,12 @@
if counters[msg['fullmodulename']] % MAX_COUNTER == 0:
tr = create_elem("tr")
module_part.appendChild(tr)
-
- counters[msg['fullmodulename']] += 1
+
+ name = msg['fullmodulename']
+ counters[name] += 1
+ counter_part = get_elem('_txt_' + name)
+ counter_part.childNodes[0].nodeValue = "%s[%d/%d]" % \
+ (short_item_names[name], counters[name], max_items[name])
module_part.childNodes[-1].appendChild(td)
except:
dom.get_document().getElementById("testmain").innerHTML += "some error"
From fijal at codespeak.net Sat Nov 25 16:05:24 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Sat, 25 Nov 2006 16:05:24 +0100 (CET)
Subject: [py-svn] r34964 - py/dist/py/test/rsession/testing
Message-ID: <20061125150524.E99EC10086@code0.codespeak.net>
Author: fijal
Date: Sat Nov 25 16:05:23 2006
New Revision: 34964
Modified:
py/dist/py/test/rsession/testing/test_webjs.py
Log:
Fixed test.
Modified: py/dist/py/test/rsession/testing/test_webjs.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_webjs.py (original)
+++ py/dist/py/test/rsession/testing/test_webjs.py Sat Nov 25 16:05:23 2006
@@ -59,7 +59,7 @@
tr = trs[0]
assert len(tr.childNodes) == 2
assert tr.childNodes[0].nodeName == 'TD'
- assert tr.childNodes[0].innerHTML == 'foo.py[10]'
+ assert tr.childNodes[0].innerHTML == 'foo.py[0/10]'
# XXX this is bad I think! table should be inside td
assert tr.childNodes[1].nodeName == 'TABLE'
assert len(tr.childNodes[1].getElementsByTagName('tr')) == 0
From fijal at codespeak.net Sat Nov 25 16:23:04 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Sat, 25 Nov 2006 16:23:04 +0100 (CET)
Subject: [py-svn] r34965 - py/dist/py/test/rsession/testing
Message-ID: <20061125152304.1B30B1008E@code0.codespeak.net>
Author: fijal
Date: Sat Nov 25 16:23:02 2006
New Revision: 34965
Modified:
py/dist/py/test/rsession/testing/test_webjs.py
Log:
Added (partly failing) test. Guido please investigate failure.
Modified: py/dist/py/test/rsession/testing/test_webjs.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_webjs.py (original)
+++ py/dist/py/test/rsession/testing/test_webjs.py Sat Nov 25 16:23:02 2006
@@ -64,3 +64,25 @@
assert tr.childNodes[1].nodeName == 'TABLE'
assert len(tr.childNodes[1].getElementsByTagName('tr')) == 0
+def test_process_two():
+ main_t = dom.window.document.getElementById('main_table')
+ msg = {'type': 'ItemStart',
+ 'itemtype': 'Module',
+ 'itemname': 'foo.py',
+ 'fullitemname': 'modules/foo.py',
+ 'length': 10,
+ }
+ webjs.process(msg)
+ msg = {'type': 'ReceivedItemOutcome',
+ 'fullmodulename': 'modules/foo.py',
+ 'passed' : 'True',
+ 'fullitemname' : 'modules/foo.py/test_item',
+ }
+ webjs.process(msg)
+ trs = main_t.getElementsByTagName('tr')
+ tds = trs[0].getElementsByTagName('td')
+ assert len(tds) == 2
+ # XXX: This assert obviously is true in output code, why it does not work?
+ #assert tds[0].innerHTML == 'foo.py[1/10]'
+ assert tds[1].innerHTML == '.'
+
From arigo at codespeak.net Sun Nov 26 12:35:23 2006
From: arigo at codespeak.net (arigo at codespeak.net)
Date: Sun, 26 Nov 2006 12:35:23 +0100 (CET)
Subject: [py-svn] r35000 - py/dist/py/c-extension/greenlet
Message-ID: <20061126113523.952861007B@code0.codespeak.net>
Author: arigo
Date: Sun Nov 26 12:35:20 2006
New Revision: 35000
Modified:
py/dist/py/c-extension/greenlet/test_greenlet.py
Log:
Adapt the test so that it runs on top of pypy-c too.
It doesn't *pass* yet, mind.
Modified: py/dist/py/c-extension/greenlet/test_greenlet.py
==============================================================================
--- py/dist/py/c-extension/greenlet/test_greenlet.py (original)
+++ py/dist/py/c-extension/greenlet/test_greenlet.py Sun Nov 26 12:35:20 2006
@@ -4,8 +4,12 @@
except (ImportError, RuntimeError), e:
py.test.skip(str(e))
-import sys, thread, threading
+import sys, gc
from py.test import raises
+try:
+ import thread, threading
+except ImportError:
+ thread = None
def test_simple():
lst = []
@@ -22,6 +26,8 @@
assert lst == range(5)
def test_threads():
+ if not thread:
+ py.test.skip("this is a test about thread")
success = []
def f():
test_simple()
@@ -81,11 +87,15 @@
g2.switch(seen)
assert seen == []
del g1
+ gc.collect()
assert seen == [greenlet.GreenletExit]
del g2
+ gc.collect()
assert seen == [greenlet.GreenletExit, greenlet.GreenletExit]
def test_dealloc_other_thread():
+ if not thread:
+ py.test.skip("this is a test about thread")
seen = []
someref = []
lock = thread.allocate_lock()
@@ -97,6 +107,7 @@
g1.switch(seen)
someref.append(g1)
del g1
+ gc.collect()
lock.release()
lock2.acquire()
greenlet() # trigger release
@@ -108,6 +119,7 @@
assert seen == []
assert len(someref) == 1
del someref[:]
+ gc.collect()
# g1 is not released immediately because it's from another thread
assert seen == []
lock2.release()
From guido at codespeak.net Mon Nov 27 14:09:47 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Mon, 27 Nov 2006 14:09:47 +0100 (CET)
Subject: [py-svn] r35028 - py/dist/py/test/rsession/testing
Message-ID: <20061127130947.9E74110076@code0.codespeak.net>
Author: guido
Date: Mon Nov 27 14:09:45 2006
New Revision: 35028
Modified:
py/dist/py/test/rsession/testing/test_webjs.py
Log:
Test works after fixing a bug in pypy/translator/js/modules/dom.py.
Modified: py/dist/py/test/rsession/testing/test_webjs.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_webjs.py (original)
+++ py/dist/py/test/rsession/testing/test_webjs.py Mon Nov 27 14:09:45 2006
@@ -83,6 +83,6 @@
tds = trs[0].getElementsByTagName('td')
assert len(tds) == 2
# XXX: This assert obviously is true in output code, why it does not work?
- #assert tds[0].innerHTML == 'foo.py[1/10]'
+ assert tds[0].innerHTML == 'foo.py[1/10]'
assert tds[1].innerHTML == '.'
From mwh at codespeak.net Mon Nov 27 14:29:20 2006
From: mwh at codespeak.net (mwh at codespeak.net)
Date: Mon, 27 Nov 2006 14:29:20 +0100 (CET)
Subject: [py-svn] r35032 - py/dist/py/documentation
Message-ID: <20061127132920.2D25D1007E@code0.codespeak.net>
Author: mwh
Date: Mon Nov 27 14:29:18 2006
New Revision: 35032
Modified:
py/dist/py/documentation/apigen.txt
Log:
clarify pydoctor's intent.
also, it works on the py lib now.
Modified: py/dist/py/documentation/apigen.txt
==============================================================================
--- py/dist/py/documentation/apigen.txt (original)
+++ py/dist/py/documentation/apigen.txt Mon Nov 27 14:29:18 2006
@@ -154,13 +154,14 @@
This tool is written by Michael Hudson for the Twisted project. The major
difference between this and Epydoc is that it browses the AST (Abstract Syntax
-Tree) instead of using 'live' objects, which makes that code that uses special
-import mechanisms, or depends on other code that is not available, can still
-be inspected.
+Tree) instead of using 'live' objects, which means that code that uses special
+import mechanisms, or depends on other code that is not available can still be
+inspected. On the other hand, code that, for example, puts bound methods into a
+module namespace is not documented.
The tool is relatively simple and doesn't support the more advanced features
-that Epydoc offers, and since it's written basically only for Twisted, I don't
-think it will see a lot of development in the future.
+that Epydoc offers. It was written for Twisted and there are no current plans to
+promote its use for unrelated projects.
Quick overview:
@@ -168,9 +169,7 @@
* again not a lot of information, the usual API docstrings, class inheritance
and module structure, but that's it
* rather heavy dependencies (depends on Twisted/Nevow (trunk version))
- * written for Twisted, but quite nice output with other applications (except
- that generating docs of the 'py lib' resulted in a max recursion depth
- error)
+ * written for Twisted, but quite nice output with other applications
Quick overview lists of the other tools
+++++++++++++++++++++++++++++++++++++++
From guido at codespeak.net Mon Nov 27 21:14:01 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Mon, 27 Nov 2006 21:14:01 +0100 (CET)
Subject: [py-svn] r35056 - in py/dist/py/apigen/source: . testing
Message-ID: <20061127201401.BB71F1008D@code0.codespeak.net>
Author: guido
Date: Mon Nov 27 21:13:59 2006
New Revision: 35056
Modified:
py/dist/py/apigen/source/html.py
py/dist/py/apigen/source/testing/test_html.py
Log:
Improved HTML output; there's now an HTMLDocument class that takes care of
building the HTML, which has a method 'add_row()' to add a line to the
document. Also some whitespace fixes and cleanups.
Modified: py/dist/py/apigen/source/html.py
==============================================================================
--- py/dist/py/apigen/source/html.py (original)
+++ py/dist/py/apigen/source/html.py Mon Nov 27 21:13:59 2006
@@ -2,7 +2,7 @@
""" html - generating ad-hoc html out of source browser
"""
-from py.xml import html
+from py.xml import html, raw
from compiler import ast
class HtmlEnchanter(object):
@@ -18,7 +18,8 @@
self.linecache = linecache
def enchant_row(self, num, row):
- # add some informations to row, like functions defined in that line, etc.
+ # add some informations to row, like functions defined in that
+ # line, etc.
try:
item = self.linecache[num]
# XXX: this should not be assertion, rather check, but we want to
@@ -26,8 +27,8 @@
pos = row.find(item.name)
assert pos != -1
end = len(item.name) + pos
- return [row[:pos], html.a(row[pos:end], href="#" + item.name,
- name=item.name), row[end:]]
+ return [row[:pos], html.a(row[pos:end], href="#" + item.name,
+ name=item.name), row[end:]]
except KeyError:
return [row] # no more info
@@ -41,19 +42,75 @@
output.append(elem)
return output
+class HTMLDocument(object):
+ def __init__(self):
+ self.html = root = html.html()
+ self.head = head = self.create_head()
+ root.append(head)
+ self.body = body = self.create_body()
+ root.append(body)
+ self.table, self.tbody = table, tbody = self.create_table()
+ body.append(table)
+
+ def create_head(self):
+ return html.head(
+ html.title('source view'),
+ html.style("""
+ body, td {
+ background-color: #FFC;
+ color: black;
+ font-family: monospace;
+ }
+
+ table, tr {
+ margin: 0px;
+ padding: 0px;
+ border-width: 0px;
+ }
+
+ .lineno {
+ text-align: right;
+ color: blue;
+ width: 3em;
+ padding-right: 1em;
+ border: 0px solid black;
+ border-right-width: 1px;
+ }
+
+ .code {
+ padding-left: 1em;
+ white-space: pre;
+ }
+ """, type='text/css'),
+ )
+
+ def create_body(self):
+ return html.body()
+
+ def create_table(self):
+ table = html.table(cellpadding='0', cellspacing='0')
+ tbody = html.tbody()
+ table.append(tbody)
+ return table, tbody
+
+ def add_row(self, lineno, text):
+ if text == ['']:
+ text = [raw(' ')]
+ self.tbody.append(html.tr(html.td(str(lineno), class_='lineno'),
+ html.td(class_='code', *text)))
+
+ def unicode(self):
+ return unicode(self.html)
+
def create_html(mod):
# out is some kind of stream
#*[html.tr(html.td(i.name)) for i in mod.get_children()]
lines = mod.path.open().readlines()
enchanter = HtmlEnchanter(mod)
- rows = [enchanter.enchant_row(num + 1, row[:-1]) for num, row in enumerate(lines)]
- html_rows = [html.tr(html.td(html.pre(num + 1)), html.td(html.pre(*i))) \
- for num, i in enumerate(rows)]
-
- output = html.table(
- html.tbody(
- *html_rows
- )
- )
- return output
+ doc = HTMLDocument()
+ for i, row in enumerate(lines):
+ row = enchanter.enchant_row(i + 1, row)
+ doc.add_row(i + 1, row)
+ return doc.unicode()
+
Modified: py/dist/py/apigen/source/testing/test_html.py
==============================================================================
--- py/dist/py/apigen/source/testing/test_html.py (original)
+++ py/dist/py/apigen/source/testing/test_html.py Mon Nov 27 21:13:59 2006
@@ -2,8 +2,9 @@
""" test of html generation
"""
-from py.__.apigen.source.html import create_html
+from py.__.apigen.source.html import create_html, HTMLDocument
from py.__.apigen.source.browser import parse_path
+from py.xml import html
import py
import os
@@ -44,4 +45,46 @@
assert data.find('source view') > -1
+ assert py.std.re.search('',
+ rendered)
+
+ def test_body(self):
+ doc = _HTMLDocument()
+ body = doc.create_body()
+ assert unicode(body) == ''
+
+ def test_table(self):
+ doc = _HTMLDocument()
+ table, tbody = doc.create_table()
+ assert isinstance(table, html.table)
+ assert isinstance(tbody, html.tbody)
+ assert tbody == table[0]
+
+ def test_add_row(self):
+ doc = HTMLDocument()
+ doc.add_row(1, ['""" this is a foo implementation """'])
+ doc.add_row(2, [''])
+ doc.add_row(3, ['class ', html.a('Foo', name='Foo'), ':'])
+ doc.add_row(4, [' pass'])
+ tbody = doc.tbody
+ assert len(tbody) == 4
+ assert unicode(tbody[0][0]) == '