From fijal at codespeak.net Wed Jan 3 17:06:21 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 3 Jan 2007 17:06:21 +0100 (CET) Subject: [py-svn] r36123 - in py/dist/py/test/rsession: . webdata Message-ID: <20070103160621.5837210068@code0.codespeak.net> Author: fijal Date: Wed Jan 3 17:06:18 2007 New Revision: 36123 Modified: py/dist/py/test/rsession/webdata/source.js py/dist/py/test/rsession/webjs.py Log: Adhere to new API. 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 Wed Jan 3 17:06:18 2007 @@ -12,13 +12,13 @@ py.test.skip("PyPy not found") def create_elem(s): - return dom.get_document().createElement(s) + return dom.document.createElement(s) def get_elem(el): - return dom.get_document().getElementById(el) + return dom.document.getElementById(el) def create_text_elem(txt): - return dom.get_document().createTextNode(txt) + return dom.document.createTextNode(txt) tracebacks = {} skips = {} @@ -49,7 +49,7 @@ exported_methods.show_all_statuses(glob.sessid, comeback) def show_info(data="aa"): - info = dom.get_document().getElementById("info") + info = dom.document.getElementById("info") info.style.visibility = "visible" while len(info.childNodes): info.removeChild(info.childNodes[0]) @@ -59,7 +59,7 @@ # XXX: Need guido def hide_info(): - info = dom.get_document().getElementById("info") + info = dom.document.getElementById("info") info.style.visibility = "hidden" def make_module_box(msg): @@ -88,7 +88,7 @@ def add_received_item_outcome(msg, module_part): if msg['hostkey']: - host_elem = dom.get_document().getElementById(msg['hostkey']) + host_elem = dom.document.getElementById(msg['hostkey']) glob.host_pending[msg['hostkey']].pop() count = len(glob.host_pending[msg['hostkey']]) host_elem.childNodes[0].nodeValue = '%s[%s]' % ( @@ -135,23 +135,23 @@ def process(msg): if len(msg) == 0: return False - elem = dom.get_document().getElementById("testmain") + elem = dom.document.getElementById("testmain") #elem.innerHTML += '%s
' % msg['event'] - main_t = dom.get_document().getElementById("main_table") + main_t = dom.document.getElementById("main_table") if msg['type'] == 'ItemStart': # we start a new directory or what if msg['itemtype'] == 'Module': tr = make_module_box(msg) main_t.appendChild(tr) elif msg['type'] == 'SendItem': - host_elem = dom.get_document().getElementById(msg['hostkey']) + host_elem = dom.document.getElementById(msg['hostkey']) glob.host_pending[msg['hostkey']].insert(0, msg['fullitemname']) count = len(glob.host_pending[msg['hostkey']]) host_elem.childNodes[0].nodeValue = '%s[%s]' % ( glob.host_dict[msg['hostkey']], count) elif msg['type'] == 'HostReady': - host_elem = dom.get_document().getElementById(msg['hostkey']) + host_elem = dom.document.getElementById(msg['hostkey']) host_elem.style.background = \ "#00ff00" host_elem.childNodes[0].nodeValue = '%s[0]' % ( @@ -165,8 +165,8 @@ add_received_item_outcome(msg, module_part) elif msg['type'] == 'TestFinished': text = "FINISHED %s run, %s failures, %s skipped" % (msg['run'], msg['fails'], msg['skips']) - dom.get_document().title = "Py.test %s" % text - dom.get_document().getElementById("Tests").childNodes[0].nodeValue = \ + dom.document.title = "Py.test %s" % text + dom.document.getElementById("Tests").childNodes[0].nodeValue = \ "Tests [%s]" % text elif msg['type'] == 'FailedTryiter': module_part = get_elem(msg['fullitemname']) @@ -191,7 +191,7 @@ tr.appendChild(td) module_part.appendChild(tr) if glob.data_empty: - mbox = dom.get_document().getElementById('messagebox') + mbox = dom.document.getElementById('messagebox') mbox.parentNode.scrollIntoView() return True @@ -206,7 +206,7 @@ txt = create_text_elem(item_name + "\n" + data) pre.appendChild(txt) msgbox.appendChild(pre) - dom.get_document().location = "#message" + dom.document.location = "#message" glob.data_empty = False def show_traceback(item_name="aa"): @@ -227,7 +227,7 @@ show_host(glob.host) def show_host(host_name="aa"): - elem = dom.get_document().getElementById("jobs") + elem = dom.document.getElementById("jobs") while len(elem.childNodes): elem.removeChild(elem.childNodes[0]) for item in glob.host_pending[host_name]: @@ -241,14 +241,14 @@ dom.setTimeout(reshow_host, 100) def hide_host(): - elem = dom.get_document().getElementById("jobs") + elem = dom.document.getElementById("jobs") while len(elem.childNodes): elem.removeChild(elem.childNodes[0]) elem.style.visibility = "hidden" glob.host = "" def host_init(host_dict): - tbody = dom.get_document().getElementById("hostsbody") + tbody = dom.document.getElementById("hostsbody") for host in host_dict.keys(): tr = create_elem('tr') tbody.appendChild(tr) From fijal at codespeak.net Wed Jan 3 19:27:30 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 3 Jan 2007 19:27:30 +0100 (CET) Subject: [py-svn] r36129 - py/dist/py/path/svn/testing Message-ID: <20070103182730.7D32310082@code0.codespeak.net> Author: fijal Date: Wed Jan 3 19:27:28 2007 New Revision: 36129 Modified: py/dist/py/path/svn/testing/test_urlcommand.py Log: Fix a test 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 Wed Jan 3 19:27:28 2007 @@ -68,7 +68,7 @@ assert info.last_author == 'hpk' assert info.created_rev == 2256 assert info.kind == 'file' - assert time.gmtime(info.mtime)[:6] == (now.year, 11, 24, 17, 55, 0) + assert time.gmtime(info.mtime)[:6] == (2006, 11, 24, 17, 55, 0) assert info.size == 165 assert info.time == info.mtime * 1000000 From fijal at codespeak.net Wed Jan 3 20:17:44 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 3 Jan 2007 20:17:44 +0100 (CET) Subject: [py-svn] r36131 - in py/dist/py/test: . testing Message-ID: <20070103191744.BEC8110072@code0.codespeak.net> Author: fijal Date: Wed Jan 3 20:17:40 2007 New Revision: 36131 Modified: py/dist/py/test/collect.py py/dist/py/test/testing/test_collect.py Log: Add __hash__ for items and test for it Modified: py/dist/py/test/collect.py ============================================================================== --- py/dist/py/test/collect.py (original) +++ py/dist/py/test/collect.py Wed Jan 3 20:17:40 2007 @@ -102,6 +102,9 @@ except AttributeError: return False + def __hash__(self): + return hash((self.name, self.parent)) + def __ne__(self, other): return not self == other Modified: py/dist/py/test/testing/test_collect.py ============================================================================== --- py/dist/py/test/testing/test_collect.py (original) +++ py/dist/py/test/testing/test_collect.py Wed Jan 3 20:17:40 2007 @@ -410,3 +410,30 @@ l = list(col.tryiter(reporterror=errors.append)) assert len(errors) == 0 +def test_check_collect_hashes(): + tmp = py.test.ensuretemp("check_collect_hashes") + tmp.ensure("test_one.py").write(py.code.Source(""" + def test_1(): + pass + + def test_2(): + pass + """)) + tmp.ensure("test_two.py").write(py.code.Source(""" + def test_1(): + pass + + def test_2(): + pass + """)) + tmp.ensure("__init__.py") + col = py.test.collect.Directory(tmp) + errors = [] + l = list(col.tryiter(reporterror=errors.append)) + #assert len(errors) == 0 + assert len(l) == 4 + for numi, i in enumerate(l): + for numj, j in enumerate(l): + if numj != numi: + assert hash(i) != hash(j) + assert i != j From fijal at codespeak.net Wed Jan 3 20:20:42 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 3 Jan 2007 20:20:42 +0100 (CET) Subject: [py-svn] r36132 - py/dist/py/test/testing Message-ID: <20070103192042.7B7D110072@code0.codespeak.net> Author: fijal Date: Wed Jan 3 20:20:40 2007 New Revision: 36132 Modified: py/dist/py/test/testing/test_collect.py Log: Remove unnecessary code Modified: py/dist/py/test/testing/test_collect.py ============================================================================== --- py/dist/py/test/testing/test_collect.py (original) +++ py/dist/py/test/testing/test_collect.py Wed Jan 3 20:20:40 2007 @@ -428,9 +428,7 @@ """)) tmp.ensure("__init__.py") col = py.test.collect.Directory(tmp) - errors = [] - l = list(col.tryiter(reporterror=errors.append)) - #assert len(errors) == 0 + l = list(col.tryiter()) assert len(l) == 4 for numi, i in enumerate(l): for numj, j in enumerate(l): From fijal at codespeak.net Thu Jan 4 09:49:39 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 4 Jan 2007 09:49:39 +0100 (CET) Subject: [py-svn] r36138 - in py/dist/py/test/rsession: . testing Message-ID: <20070104084939.D9B4910070@code0.codespeak.net> Author: fijal Date: Thu Jan 4 09:49:34 2007 New Revision: 36138 Modified: py/dist/py/test/rsession/master.py py/dist/py/test/rsession/reporter.py py/dist/py/test/rsession/rsession.py py/dist/py/test/rsession/testing/test_boxing.py py/dist/py/test/rsession/testing/test_master.py py/dist/py/test/rsession/testing/test_rsession.py Log: Added check if test was not actually reported. This is intermediate checkin, because it does nothing actually. Modified: py/dist/py/test/rsession/master.py ============================================================================== --- py/dist/py/test/rsession/master.py (original) +++ py/dist/py/test/rsession/master.py Thu Jan 4 09:49:34 2007 @@ -6,15 +6,21 @@ from py.__.test.rsession import report class MasterNode(object): - def __init__(self, channel, reporter): + def __init__(self, channel, reporter, done_dict): self.channel = channel self.reporter = reporter - channel.setcallback(self.receive_result) + + def callback(outcome): + #import pdb;pdb.set_trace() + item = self.pending.pop() + if not item in done_dict: + self.receive_result(outcome, item) + done_dict[item] = True + channel.setcallback(callback) self.pending = [] - def receive_result(self, outcomestring): + def receive_result(self, outcomestring, item): repr_outcome = ReprOutcome(outcomestring) - item = self.pending.pop() # send finish report self.reporter(report.ReceivedItemOutcome( self.channel, item, repr_outcome)) @@ -48,7 +54,6 @@ break waiter() - def setup_slave(gateway, pkgpath, options): from py.__.test.rsession import slave import os Modified: py/dist/py/test/rsession/reporter.py ============================================================================== --- py/dist/py/test/rsession/reporter.py (original) +++ py/dist/py/test/rsession/reporter.py Thu Jan 4 09:49:34 2007 @@ -2,9 +2,7 @@ """ reporter - different reporter for different purposes ;-) Still lacks: - 1. Reporting of Failed to load module inside the module - 2. Tests for remote reporter - 3. Hanging nodes are not good done + 1. Hanging nodes are not good done """ import py Modified: py/dist/py/test/rsession/rsession.py ============================================================================== --- py/dist/py/test/rsession/rsession.py (original) +++ py/dist/py/test/rsession/rsession.py Thu Jan 4 09:49:34 2007 @@ -203,14 +203,16 @@ yield y itemgenerator = itemgen() - dispatch_loop(nodes, itemgenerator, checkfun) - teardown_hosts(reporter, [node.channel for node in nodes], nodes, - exitfirst=self.config.option.exitfirst) + try: + dispatch_loop(nodes, itemgenerator, checkfun) + finally: + teardown_hosts(reporter, [node.channel for node in nodes], nodes, + exitfirst=self.config.option.exitfirst) + if startserverflag: + from py.__.test.rsession.web import kill_server + kill_server() reporter(report.Nodes(nodes)) retval = reporter(report.TestFinished()) - if startserverflag: - from py.__.test.rsession.web import kill_server - kill_server() return retval class LSession(AbstractSession): 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 Thu Jan 4 09:49:34 2007 @@ -92,4 +92,3 @@ os.kill(pid, 15) par(pid) assert b.signal == 15 - Modified: py/dist/py/test/rsession/testing/test_master.py ============================================================================== --- py/dist/py/test/rsession/testing/test_master.py (original) +++ py/dist/py/test/rsession/testing/test_master.py Thu Jan 4 09:49:34 2007 @@ -42,7 +42,7 @@ ch = DummyChannel() reportlist = [] - mnode = MasterNode(ch, reportlist.append) + mnode = MasterNode(ch, reportlist.append, {}) mnode.send(py.test.Item("ok")) mnode.send(py.test.Item("notok")) ch.callback(Outcome().make_repr()) @@ -53,6 +53,16 @@ assert received[0].outcome.passed assert not received[1].outcome.passed +def test_unique_nodes(): + ch = DummyChannel() + reportlist = [] + mnode = MasterNode(ch, reportlist.append, {}) + mnode.send(py.test.Item("ok")) + mnode.send(py.test.Item("ok")) + ch.callback(Outcome().make_repr()) + ch.callback(Outcome().make_repr()) + assert len(reportlist) == 3 + def test_outcome_repr(): out = ReprOutcome(Outcome(skipped=True).make_repr()) s = repr(out) @@ -97,7 +107,7 @@ def open_gw(): gw = py.execnet.PopenGateway() channel = setup_slave(gw, pkgdir, remote_options.d) - mn = MasterNode(channel, simple_report) + mn = MasterNode(channel, simple_report, {}) return mn master_nodes = [open_gw(), open_gw(), open_gw()] Modified: py/dist/py/test/rsession/testing/test_rsession.py ============================================================================== --- py/dist/py/test/rsession/testing/test_rsession.py (original) +++ py/dist/py/test/rsession/testing/test_rsession.py Thu Jan 4 09:49:34 2007 @@ -165,6 +165,7 @@ passevents = [i for i in testevents if i.outcome.passed] failevents = [i for i in testevents if i.outcome.excinfo] skippedevents = [i for i in testevents if i.outcome.skipped] + assert len(testevents) == 4 assert len(passevents) == 1 assert len(failevents) == 3 tb = failevents[0].outcome.excinfo.traceback From fijal at codespeak.net Thu Jan 4 09:52:34 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 4 Jan 2007 09:52:34 +0100 (CET) Subject: [py-svn] r36139 - py/dist/py/test/rsession Message-ID: <20070104085234.9259D10070@code0.codespeak.net> Author: fijal Date: Thu Jan 4 09:52:33 2007 New Revision: 36139 Modified: py/dist/py/test/rsession/hostmanage.py Log: Forgotten to check that one in Modified: py/dist/py/test/rsession/hostmanage.py ============================================================================== --- py/dist/py/test/rsession/hostmanage.py (original) +++ py/dist/py/test/rsession/hostmanage.py Thu Jan 4 09:52:33 2007 @@ -63,10 +63,12 @@ hosts.append((num, host, gw, str(pkgdir.dirpath()))) return hosts -# XXX: Options has grown a bit too much, but most of them is just for tests +# XXX: Options has grown a bit too much, but most of them are just for tests def init_hosts(reporter, sshhosts, relpath, pkgdir, rsync_roots=None, \ remote_python=None, remote_options={}, optimise_localhost=True,\ - do_sync=True): + do_sync=True, done_dict=None): + if done_dict is None: + done_dict = {} assert pkgdir.join("__init__.py").check(), ( "%s probably wrong" %(pkgdir,)) assert relpath, relpath @@ -98,14 +100,14 @@ rsync.send(pkgdir.dirpath()) # hosts ready - return setup_nodes(hosts, pkgdir, remote_options, reporter) + return setup_nodes(hosts, pkgdir, remote_options, reporter, done_dict) -def setup_nodes(hosts, pkgdir, remote_options, reporter): +def setup_nodes(hosts, pkgdir, remote_options, reporter, done_dict): nodes = [] for num, host, gw, remoterootpath in hosts: ch = setup_slave(gw, os.path.join(remoterootpath, pkgdir.basename), remote_options) - nodes.append(MasterNode(ch, reporter)) + nodes.append(MasterNode(ch, reporter, done_dict)) return nodes From fijal at codespeak.net Thu Jan 4 11:18:13 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 4 Jan 2007 11:18:13 +0100 (CET) Subject: [py-svn] r36141 - py/dist/py/test/rsession/testing Message-ID: <20070104101813.9F7A110070@code0.codespeak.net> Author: fijal Date: Thu Jan 4 11:18:06 2007 New Revision: 36141 Modified: py/dist/py/test/rsession/testing/test_webjs.py Log: Fixed tests to new pypy.js api. 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 Thu Jan 4 11:18:06 2007 @@ -13,6 +13,7 @@ from pypy.translator.js.modules import dom mod.dom = dom dom.window = dom.Window(html) + dom.document = dom.window.document config, args = py.test.Config.parse([]) from py.__.test.rsession.rsession import session_options session_options.bind_config(config) @@ -120,5 +121,5 @@ webjs.process(msg) schedule_callbacks(exported_methods) # ouch - assert dom.get_document().getElementById('modules/foo.py').childNodes[1].\ + assert dom.document.getElementById('modules/foo.py').childNodes[1].\ childNodes[0].childNodes[0].childNodes[0].nodeValue == 'F' From fijal at codespeak.net Mon Jan 8 10:09:17 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 8 Jan 2007 10:09:17 +0100 (CET) Subject: [py-svn] r36221 - in py/dist/py/test/rsession: . testing Message-ID: <20070108090917.5DD4A10071@code0.codespeak.net> Author: fijal Date: Mon Jan 8 10:09:11 2007 New Revision: 36221 Modified: py/dist/py/test/rsession/hostmanage.py py/dist/py/test/rsession/master.py py/dist/py/test/rsession/rsession.py py/dist/py/test/rsession/testing/test_master.py py/dist/py/test/rsession/testing/test_rsession.py py/dist/py/test/rsession/web.py Log: Added rescheduling of tests when there are empty hosts. Modified: py/dist/py/test/rsession/hostmanage.py ============================================================================== --- py/dist/py/test/rsession/hostmanage.py (original) +++ py/dist/py/test/rsession/hostmanage.py Mon Jan 8 10:09:11 2007 @@ -3,7 +3,7 @@ import time import thread, threading from py.__.test.rsession.master import \ - setup_slave, MasterNode, dispatch_loop + setup_slave, MasterNode from py.__.test.rsession import report from py.__.test.rsession.rsync import RSync Modified: py/dist/py/test/rsession/master.py ============================================================================== --- py/dist/py/test/rsession/master.py (original) +++ py/dist/py/test/rsession/master.py Mon Jan 8 10:09:11 2007 @@ -35,24 +35,47 @@ # send start report self.reporter(report.SendItem(self.channel, item)) +def itemgen(colitems, reporter, keyword, reporterror): + for x in colitems: + for y in x.tryiter(reporterror = lambda x: reporterror(reporter, x), keyword = keyword): + yield y + +def randomgen(items, done_dict): + """ Generator, which randomly gets all the tests from items as long + as they're not in done_dict + """ + import random + while items: + values = items.keys() + item = values[int(random.random()*len(values))] + if item in done_dict: + del items[item] + else: + yield item + def dispatch_loop(masternodes, itemgenerator, shouldstop, - waiter = lambda: py.std.time.sleep(0.1)): - from py.__.test.rsession.rsession import session_options + waiter = lambda: py.std.time.sleep(0.1), + max_tasks_per_node=None): + if not max_tasks_per_node: + from py.__.test.rsession.rsession import session_options - max_tasks_per_node = session_options.max_tasks_per_node + max_tasks_per_node = session_options.max_tasks_per_node + all_tests = {} while 1: try: for node in masternodes: if len(node.pending) < max_tasks_per_node: item = itemgenerator.next() + all_tests[item] = True if shouldstop(): for _node in masternodes: _node.send(StopIteration) # magic connector - return + return None node.send(item) except StopIteration: break waiter() + return all_tests def setup_slave(gateway, pkgpath, options): from py.__.test.rsession import slave Modified: py/dist/py/test/rsession/rsession.py ============================================================================== --- py/dist/py/test/rsession/rsession.py (original) +++ py/dist/py/test/rsession/rsession.py Mon Jan 8 10:09:11 2007 @@ -10,7 +10,7 @@ from py.__.test.rsession import report from py.__.test.rsession.master import \ - setup_slave, MasterNode, dispatch_loop + setup_slave, MasterNode, dispatch_loop, itemgen, randomgen from py.__.test.rsession.hostmanage import init_hosts, teardown_hosts from py.__.test.rsession.local import local_loop, plain_runner, apigen_runner,\ @@ -168,7 +168,7 @@ class RSession(AbstractSession): """ Remote version of session """ - def main(self, args, reporter=None): + def main(self, args, reporter=None, override_checkfun=None): """ main loop for running tests. """ if not args: args = [py.path.local()] @@ -182,6 +182,8 @@ session_options.bind_config(self.config) reporter, checkfun, startserverflag = self.init_reporter(reporter, sshhosts, RemoteReporter) + if override_checkfun: + checkfun = override_checkfun reporter(report.TestStarted(sshhosts)) pkgdir = self.getpkgdir(args[0]) colitems = self.make_colitems(args, baseon=pkgdir.dirpath()) @@ -190,21 +192,24 @@ except: remotepython = None + done_dict = {} nodes = init_hosts(reporter, sshhosts, directories, pkgdir, rsync_roots, remotepython, remote_options=remote_options.d, - optimise_localhost=self.optimise_localhost) + optimise_localhost=self.optimise_localhost, done_dict=done_dict) reporter(report.RsyncFinished()) keyword = self.config.option.keyword - - def itemgen(): - for x in colitems: - for y in x.tryiter(reporterror = lambda x: self.reporterror(reporter, x), keyword = keyword): - yield y - itemgenerator = itemgen() + itemgenerator = itemgen(colitems, reporter, keyword, self.reporterror) try: - dispatch_loop(nodes, itemgenerator, checkfun) + all_tests = dispatch_loop(nodes, itemgenerator, checkfun) + if all_tests: + todo = {} + for key, value in all_tests.items(): + if key not in done_dict: + todo[key] = True + rg = randomgen(todo, done_dict) + dispatch_loop(nodes, rg, lambda:False, max_tasks_per_node=1) finally: teardown_hosts(reporter, [node.channel for node in nodes], nodes, exitfirst=self.config.option.exitfirst) Modified: py/dist/py/test/rsession/testing/test_master.py ============================================================================== --- py/dist/py/test/rsession/testing/test_master.py (original) +++ py/dist/py/test/rsession/testing/test_master.py Mon Jan 8 10:09:11 2007 @@ -9,7 +9,7 @@ if sys.platform == 'win32': py.test.skip("rsession is unsupported on Windows.") -from py.__.test.rsession.master import dispatch_loop, setup_slave, MasterNode +from py.__.test.rsession.master import dispatch_loop, setup_slave, MasterNode, randomgen from py.__.test.rsession.outcome import ReprOutcome, Outcome from py.__.test.rsession.testing.test_slave import funcpass_spec, funcfail_spec from py.__.test.rsession import report @@ -118,3 +118,16 @@ [funcpass_item] * 5 + [funcfail_item] * 5) shouldstop = lambda : False dispatch_loop(master_nodes, itemgenerator, shouldstop) + +def test_randomgen(): + d = {} + gen = randomgen({1:True, 2:True, 3:True}, d) + for i in range(100): + assert gen.next() in [1,2,3] + d[3] = True + for i in range(100): + assert gen.next() in [1,2] + d[2] = True + d[1] = True + py.test.raises(StopIteration, "gen.next()") + Modified: py/dist/py/test/rsession/testing/test_rsession.py ============================================================================== --- py/dist/py/test/rsession/testing/test_rsession.py (original) +++ py/dist/py/test/rsession/testing/test_rsession.py Mon Jan 8 10:09:11 2007 @@ -109,7 +109,8 @@ ## res = channel.receive() ## assert res == "ok" - def test_example_distribution_minus_x(self): + def test_example_distribution_minus_x(self): + #py.test.skip("Works, but does not test what it should") # XXX find a better way for the below tmpdir = py.path.local(py.__file__).dirpath().dirpath() tmpdir.ensure("sub", "conftest.py").write(py.code.Source(""" @@ -131,7 +132,11 @@ config, args = py.test.Config.parse(args) rsession = RSession(config) allevents = [] - rsession.main(args, reporter=allevents.append) + def check(): + return [x for x in allevents if isinstance(x, report.ReceivedItemOutcome) and + not x.outcome.passed] + + rsession.main(args, reporter=allevents.append, override_checkfun=check) testevents = [x for x in allevents if isinstance(x, report.ReceivedItemOutcome)] assert len(testevents) == 2 Modified: py/dist/py/test/rsession/web.py ============================================================================== --- py/dist/py/test/rsession/web.py (original) +++ py/dist/py/test/rsession/web.py Mon Jan 8 10:09:11 2007 @@ -24,11 +24,6 @@ FUNCTION_LIST = ["main", "show_skip", "show_traceback", "show_info", "hide_info", "show_host", "hide_host"] -def escape(s): - return s - #return s.replace("&", "&").replace("<", "<").replace(">", ">"). \ - # replace("'", "\\'").replace(" ", " ").replace("\n", "
") - try: try: if not session_options.import_pypy: @@ -160,12 +155,12 @@ def show_skip(self, item_name="aa"): return {'item_name': item_name, - 'reason': escape(self.skip_reasons[item_name])} + 'reason': self.skip_reasons[item_name]} show_skip = described(retval={"aa": "aa"})(show_skip) def show_fail(self, item_name="aa"): return {'item_name':item_name, - 'traceback':escape(str(self.fail_reasons[item_name])), + 'traceback':str(self.fail_reasons[item_name]), 'stdout':self.stdout[item_name], 'stderr':self.stderr[item_name]} show_fail = described(retval={"aa": "aa"})(show_fail) @@ -260,7 +255,7 @@ args['reason'] = str(event.excinfo.value) else: args = {} - args['event'] = escape(str(event)) + args['event'] = str(event) args['type'] = event.__class__.__name__ return args @@ -287,6 +282,7 @@ self.pending_events.put(event) def report_ItemStart(self, event): + #if isinstance(event.item, py.test.collect.Module): self.pending_events.put(event) def report_unknown(self, event): @@ -391,7 +387,6 @@ javascript_source = rpython2javascript(webjs, FUNCTION_LIST, use_pdb=False) - # XXX: This did not work for some reason, no idea why open(str(js_name), "w").write(javascript_source) self.serve_data("text/javascript", javascript_source) else: From fijal at codespeak.net Mon Jan 8 10:12:09 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 8 Jan 2007 10:12:09 +0100 (CET) Subject: [py-svn] r36222 - py/dist/py/documentation Message-ID: <20070108091209.6058310071@code0.codespeak.net> Author: fijal Date: Mon Jan 8 10:12:08 2007 New Revision: 36222 Modified: py/dist/py/documentation/test.txt Log: Updated to more current state. Modified: py/dist/py/documentation/test.txt ============================================================================== --- py/dist/py/documentation/test.txt (original) +++ py/dist/py/documentation/test.txt Mon Jan 8 10:12:08 2007 @@ -720,10 +720,7 @@ Differences from local tests ---------------------------- -* The only working command line options are ``--session=R``, ``-x`` and ``-k``. * Test order is *not* guaranteed. -* ``-x`` is currently not working in the web reporter. -* Hanging nodes or tests are not detected. * ``conftest.py`` cannot reference files outside of the copied packages. Configuration From fijal at codespeak.net Mon Jan 8 10:44:22 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 8 Jan 2007 10:44:22 +0100 (CET) Subject: [py-svn] r36224 - in py/dist/py/test/rsession: . webdata Message-ID: <20070108094422.9A98D10075@code0.codespeak.net> Author: fijal Date: Mon Jan 8 10:44:17 2007 New Revision: 36224 Modified: py/dist/py/test/rsession/webdata/source.js py/dist/py/test/rsession/webjs.py Log: Hopefully resolve the mozilla issue with displaying tests. 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 Mon Jan 8 10:44:17 2007 @@ -228,14 +228,16 @@ def show_host(host_name="aa"): elem = dom.document.getElementById("jobs") - while len(elem.childNodes): + if elem.childNodes: elem.removeChild(elem.childNodes[0]) + tbody = create_elem("tbody") for item in glob.host_pending[host_name]: tr = create_elem("tr") td = create_elem("td") td.appendChild(create_text_elem(item)) tr.appendChild(td) - elem.appendChild(tr) + tbody.appendChild(tr) + elem.appendChild(tbody) elem.style.visibility = "visible" glob.host = host_name dom.setTimeout(reshow_host, 100) From fijal at codespeak.net Mon Jan 8 10:44:34 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 8 Jan 2007 10:44:34 +0100 (CET) Subject: [py-svn] r36225 - py/dist/py/test/rsession/webdata Message-ID: <20070108094434.D89FA1007A@code0.codespeak.net> Author: fijal Date: Mon Jan 8 10:44:32 2007 New Revision: 36225 Modified: py/dist/py/test/rsession/webdata/index.html Log: Forgotten to check that one in. Modified: py/dist/py/test/rsession/webdata/index.html ============================================================================== --- py/dist/py/test/rsession/webdata/index.html (original) +++ py/dist/py/test/rsession/webdata/index.html Mon Jan 8 10:44:32 2007 @@ -81,9 +81,7 @@ - - - +
From fijal at codespeak.net Mon Jan 8 11:24:26 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 8 Jan 2007 11:24:26 +0100 (CET) Subject: [py-svn] r36232 - py/dist/py/test/rsession/testing Message-ID: <20070108102426.4B0031007D@code0.codespeak.net> Author: fijal Date: Mon Jan 8 11:24:24 2007 New Revision: 36232 Modified: py/dist/py/test/rsession/testing/test_rsession.py Log: Make test use ensuretemp. Modified: py/dist/py/test/rsession/testing/test_rsession.py ============================================================================== --- py/dist/py/test/rsession/testing/test_rsession.py (original) +++ py/dist/py/test/rsession/testing/test_rsession.py Mon Jan 8 11:24:24 2007 @@ -110,12 +110,9 @@ ## assert res == "ok" def test_example_distribution_minus_x(self): - #py.test.skip("Works, but does not test what it should") - # XXX find a better way for the below - tmpdir = py.path.local(py.__file__).dirpath().dirpath() + tmpdir = py.test.ensuretemp("example_distribution_minus_x") tmpdir.ensure("sub", "conftest.py").write(py.code.Source(""" disthosts = [%r] - distrsync_roots = ["sub", "py"] """ % 'localhost')) tmpdir.ensure("sub", "__init__.py") tmpdir.ensure("sub", "test_one.py").write(py.code.Source(""" From fijal at codespeak.net Mon Jan 8 11:25:40 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 8 Jan 2007 11:25:40 +0100 (CET) Subject: [py-svn] r36233 - py/dist/py/test/rsession Message-ID: <20070108102540.58FF31007D@code0.codespeak.net> Author: fijal Date: Mon Jan 8 11:25:39 2007 New Revision: 36233 Modified: py/dist/py/test/rsession/rsession.py Log: Kill some dead code. Modified: py/dist/py/test/rsession/rsession.py ============================================================================== --- py/dist/py/test/rsession/rsession.py (original) +++ py/dist/py/test/rsession/rsession.py Mon Jan 8 11:25:39 2007 @@ -247,9 +247,7 @@ if runner is None and self.config.option.apigen: from py.__.apigen.tracer.tracer import Tracer - # XXX module = py - #module = __import__(str(pkgdir.join('__init__.py'))) try: self.docstorage = self.config.getinitialvalue('ApiGen').get_doc_storage() except (ValueError, AttributeError): @@ -257,24 +255,13 @@ "way of generating DocStorage") self.tracer = Tracer(self.docstorage) runner = apigen_runner - #elif runner is None and (self.config.option.usepdb or self.config.option.nocapture): - # runner = plain_runner - #elif runner is None: - # runner = box_runner + elif runner is None: runner = RunnerPolicy[session_options.runner_policy] keyword = self.config.option.keyword - def itemgen(): - for x in colitems: - for y in x.tryiter(reporterror = lambda x: self.reporterror(reporter, x), keyword = keyword): - yield y - - itemgenerator = itemgen() - #assert 0, "\n".join([",".join(x.listnames()) for x in - # list(itemgenerator)]) - # XXX: We have to decide which runner to use at this point + itemgenerator = itemgen(colitems, reporter, keyword, self.reporterror) local_loop(self, reporter, itemgenerator, checkfun, self.config, runner=runner) retval = reporter(report.TestFinished()) @@ -282,7 +269,6 @@ from py.__.test.rsession.web import kill_server kill_server() - #py.test.Function.state.teardown_all() if not self.config.option.nomagic: py.magic.revoke(assertion=1) From hpk at codespeak.net Mon Jan 8 11:27:09 2007 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 8 Jan 2007 11:27:09 +0100 (CET) Subject: [py-svn] r36234 - py/dist/py/documentation Message-ID: <20070108102709.33DAD1007D@code0.codespeak.net> Author: hpk Date: Mon Jan 8 11:27:06 2007 New Revision: 36234 Modified: py/dist/py/documentation/TODO.txt Log: tracking todo-items for 0.9 in py/documentation ... Modified: py/dist/py/documentation/TODO.txt ============================================================================== --- py/dist/py/documentation/TODO.txt (original) +++ py/dist/py/documentation/TODO.txt Mon Jan 8 11:27:06 2007 @@ -1,6 +1,34 @@ -Things to do before 0.8.0 +Things to do before 0.9.0 ========================= +review all py lib documentation +------------------------------------- + +streamline exported API +------------------------------------- + +* move not-to-be-exported Gateway() methods to _ - methods. +* docstrings for all exported API + +testing +----------- + +* windows tests +* these should all work on 0.9 and on the py lib and pypy: + - running "py.test -s" + - running "py.test --pdb" + - running "py.test --looponfailing" + - running "py.test" distributed on some hosts + +* tests should not create any tempdirectories in the source code base + +* try to be as 2.2 compatible as possible + + +quality +--------- + +* don't have distutils install ----------------- From fijal at codespeak.net Mon Jan 8 11:27:37 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 8 Jan 2007 11:27:37 +0100 (CET) Subject: [py-svn] r36235 - py/dist/py/test/rsession Message-ID: <20070108102737.27E261007F@code0.codespeak.net> Author: fijal Date: Mon Jan 8 11:27:30 2007 New Revision: 36235 Modified: py/dist/py/test/rsession/rsession.py Log: move kill server to a separate method Modified: py/dist/py/test/rsession/rsession.py ============================================================================== --- py/dist/py/test/rsession/rsession.py (original) +++ py/dist/py/test/rsession/rsession.py Mon Jan 8 11:27:30 2007 @@ -152,6 +152,12 @@ reporter(report.FailedTryiter(excinfo, item)) reporterror = staticmethod(reporterror) + def kill_server(self, startserverflag): + if startserverflag: + from py.__.test.rsession.web import kill_server + kill_server() + + def parse_directories(sshhosts): # dictionary containing directories for hosts # XXX: should be class with some info like key, etc. in future @@ -213,9 +219,7 @@ finally: teardown_hosts(reporter, [node.channel for node in nodes], nodes, exitfirst=self.config.option.exitfirst) - if startserverflag: - from py.__.test.rsession.web import kill_server - kill_server() + self.kill_server(startserverflag) reporter(report.Nodes(nodes)) retval = reporter(report.TestFinished()) return retval @@ -265,9 +269,7 @@ local_loop(self, reporter, itemgenerator, checkfun, self.config, runner=runner) retval = reporter(report.TestFinished()) - if startserverflag: - from py.__.test.rsession.web import kill_server - kill_server() + self.kill_server(startserverflag) if not self.config.option.nomagic: py.magic.revoke(assertion=1) From fijal at codespeak.net Mon Jan 8 11:35:41 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 8 Jan 2007 11:35:41 +0100 (CET) Subject: [py-svn] r36237 - py/dist/py/test/rsession Message-ID: <20070108103541.616EB10080@code0.codespeak.net> Author: fijal Date: Mon Jan 8 11:35:40 2007 New Revision: 36237 Modified: py/dist/py/test/rsession/rsession.py Log: a bit of cleanup of rsession.main Modified: py/dist/py/test/rsession/rsession.py ============================================================================== --- py/dist/py/test/rsession/rsession.py (original) +++ py/dist/py/test/rsession/rsession.py Mon Jan 8 11:35:40 2007 @@ -190,39 +190,43 @@ sshhosts, RemoteReporter) if override_checkfun: checkfun = override_checkfun + reporter(report.TestStarted(sshhosts)) - pkgdir = self.getpkgdir(args[0]) - colitems = self.make_colitems(args, baseon=pkgdir.dirpath()) try: remotepython = self.config.getinitialvalue("dist_remotepython") except: remotepython = None + pkgdir = self.getpkgdir(args[0]) done_dict = {} nodes = init_hosts(reporter, sshhosts, directories, pkgdir, rsync_roots, remotepython, remote_options=remote_options.d, optimise_localhost=self.optimise_localhost, done_dict=done_dict) reporter(report.RsyncFinished()) - keyword = self.config.option.keyword - - itemgenerator = itemgen(colitems, reporter, keyword, self.reporterror) try: - all_tests = dispatch_loop(nodes, itemgenerator, checkfun) - if all_tests: - todo = {} - for key, value in all_tests.items(): - if key not in done_dict: - todo[key] = True - rg = randomgen(todo, done_dict) - dispatch_loop(nodes, rg, lambda:False, max_tasks_per_node=1) + self.dispatch_tests(nodes, args, pkgdir, reporter, checkfun, done_dict) finally: teardown_hosts(reporter, [node.channel for node in nodes], nodes, exitfirst=self.config.option.exitfirst) self.kill_server(startserverflag) reporter(report.Nodes(nodes)) - retval = reporter(report.TestFinished()) - return retval + return reporter(report.TestFinished()) + + def dispatch_tests(self, nodes, args, pkgdir, reporter, checkfun, done_dict): + colitems = self.make_colitems(args, baseon=pkgdir.dirpath()) + keyword = self.config.option.keyword + itemgenerator = itemgen(colitems, reporter, keyword, self.reporterror) + + all_tests = dispatch_loop(nodes, itemgenerator, checkfun) + if all_tests: + todo = {} + for key, value in all_tests.items(): + if key not in done_dict: + todo[key] = True + rg = randomgen(todo, done_dict) + dispatch_loop(nodes, rg, lambda:False, max_tasks_per_node=1) + class LSession(AbstractSession): """ Local version of session From fijal at codespeak.net Mon Jan 8 11:38:33 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 8 Jan 2007 11:38:33 +0100 (CET) Subject: [py-svn] r36238 - py/dist/py/test/rsession Message-ID: <20070108103833.6FD591007F@code0.codespeak.net> Author: fijal Date: Mon Jan 8 11:38:32 2007 New Revision: 36238 Modified: py/dist/py/test/rsession/rsession.py Log: Another round of cleanups Modified: py/dist/py/test/rsession/rsession.py ============================================================================== --- py/dist/py/test/rsession/rsession.py (original) +++ py/dist/py/test/rsession/rsession.py Mon Jan 8 11:38:32 2007 @@ -178,24 +178,15 @@ """ main loop for running tests. """ if not args: args = [py.path.local()] - sshhosts = self.config.getinitialvalue("disthosts") - directories = parse_directories(sshhosts) - try: - rsync_roots = self.config.getinitialvalue("distrsync_roots") - except: - rsync_roots = None # all files and directories in the pkgdir session_options.bind_config(self.config) + sshhosts, directories, remotepython, rsync_roots = self.read_distributed_config() reporter, checkfun, startserverflag = self.init_reporter(reporter, sshhosts, RemoteReporter) if override_checkfun: checkfun = override_checkfun reporter(report.TestStarted(sshhosts)) - try: - remotepython = self.config.getinitialvalue("dist_remotepython") - except: - remotepython = None pkgdir = self.getpkgdir(args[0]) done_dict = {} @@ -213,6 +204,19 @@ reporter(report.Nodes(nodes)) return reporter(report.TestFinished()) + def read_distributed_config(self): + try: + rsync_roots = self.config.getinitialvalue("distrsync_roots") + except: + rsync_roots = None # all files and directories in the pkgdir + sshhosts = self.config.getinitialvalue("disthosts") + directories = parse_directories(sshhosts) + try: + remotepython = self.config.getinitialvalue("dist_remotepython") + except: + remotepython = None + return sshhosts, directories, remotepython, rsync_roots + def dispatch_tests(self, nodes, args, pkgdir, reporter, checkfun, done_dict): colitems = self.make_colitems(args, baseon=pkgdir.dirpath()) keyword = self.config.option.keyword From fijal at codespeak.net Mon Jan 8 11:41:08 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 8 Jan 2007 11:41:08 +0100 (CET) Subject: [py-svn] r36239 - py/dist/py/test/rsession Message-ID: <20070108104108.831F510080@code0.codespeak.net> Author: fijal Date: Mon Jan 8 11:41:07 2007 New Revision: 36239 Modified: py/dist/py/test/rsession/rsession.py Log: Cleanup of Lsession.main Modified: py/dist/py/test/rsession/rsession.py ============================================================================== --- py/dist/py/test/rsession/rsession.py (original) +++ py/dist/py/test/rsession/rsession.py Mon Jan 8 11:41:07 2007 @@ -256,20 +256,9 @@ pkgdir = self.getpkgdir(args[0]) colitems = self.make_colitems(args, baseon=pkgdir.dirpath()) reporter(report.RsyncFinished()) - - if runner is None and self.config.option.apigen: - from py.__.apigen.tracer.tracer import Tracer - module = py - try: - self.docstorage = self.config.getinitialvalue('ApiGen').get_doc_storage() - except (ValueError, AttributeError): - raise NotImplementedError("Need to provide conftest " - "way of generating DocStorage") - self.tracer = Tracer(self.docstorage) - runner = apigen_runner - elif runner is None: - runner = RunnerPolicy[session_options.runner_policy] + if runner is None: + runner = self.init_runner() keyword = self.config.option.keyword @@ -281,7 +270,11 @@ if not self.config.option.nomagic: py.magic.revoke(assertion=1) - + + self.write_docs() + return retval + + def write_docs(self): if self.config.option.apigen: try: apigen = self.config.getinitialvalue('ApiGen') @@ -290,4 +283,18 @@ "provided way of doing that in conftest") else: apigen.write_docs(self.docstorage) - return retval + + + def init_runner(self): + if self.config.option.apigen: + from py.__.apigen.tracer.tracer import Tracer + module = py + try: + self.docstorage = self.config.getinitialvalue('ApiGen').get_doc_storage() + except (ValueError, AttributeError): + raise NotImplementedError("Need to provide conftest " + "way of generating DocStorage") + self.tracer = Tracer(self.docstorage) + return apigen_runner + else: + return RunnerPolicy[session_options.runner_policy] From hpk at codespeak.net Mon Jan 8 11:44:41 2007 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 8 Jan 2007 11:44:41 +0100 (CET) Subject: [py-svn] r36240 - py/dist/py/test/rsession/testing Message-ID: <20070108104441.8EDD010082@code0.codespeak.net> Author: hpk Date: Mon Jan 8 11:44:40 2007 New Revision: 36240 Modified: py/dist/py/test/rsession/testing/test_lsession.py Log: fix tempdir creation 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 Mon Jan 8 11:44:40 2007 @@ -7,14 +7,8 @@ from py.__.test.rsession import report from py.__.test.rsession.local import box_runner, plain_runner -basepath = py.path.local(py.__file__).dirpath().dirpath() - -try: - tmp = basepath.mkdir("pytemp") -except py.error.EEXIST: - tmp = basepath.join("pytemp") - tmp.remove(rec=1) - tmp = basepath.mkdir("pytemp") +def setup_module(mod): + mod.tmp = py.test.ensuretemp("lsession_module") class TestLSession(object): # XXX: Some tests of that should be run as well on RSession, while From hpk at codespeak.net Mon Jan 8 11:47:18 2007 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 8 Jan 2007 11:47:18 +0100 (CET) Subject: [py-svn] r36241 - in py/dist/py/documentation: . apigen talk Message-ID: <20070108104718.A832D10084@code0.codespeak.net> Author: hpk Date: Mon Jan 8 11:47:15 2007 New Revision: 36241 Modified: py/dist/py/documentation/ (props changed) py/dist/py/documentation/TODO.txt py/dist/py/documentation/apigen/ (props changed) py/dist/py/documentation/talk/ (props changed) Log: more todo, ignore html files Modified: py/dist/py/documentation/TODO.txt ============================================================================== --- py/dist/py/documentation/TODO.txt (original) +++ py/dist/py/documentation/TODO.txt Mon Jan 8 11:47:15 2007 @@ -23,12 +23,8 @@ * tests should not create any tempdirectories in the source code base * try to be as 2.2 compatible as possible + (use e.g. py.builtin.enumerate instead of "enumerate" directly) - -quality ---------- - -* don't have distutils install ----------------- From fijal at codespeak.net Mon Jan 8 11:53:15 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 8 Jan 2007 11:53:15 +0100 (CET) Subject: [py-svn] r36242 - py/dist/py/test/rsession Message-ID: <20070108105315.AA7D710083@code0.codespeak.net> Author: fijal Date: Mon Jan 8 11:53:14 2007 New Revision: 36242 Modified: py/dist/py/test/rsession/rsession.py Log: Comment out not working code. Modified: py/dist/py/test/rsession/rsession.py ============================================================================== --- py/dist/py/test/rsession/rsession.py (original) +++ py/dist/py/test/rsession/rsession.py Mon Jan 8 11:53:14 2007 @@ -223,13 +223,13 @@ itemgenerator = itemgen(colitems, reporter, keyword, self.reporterror) all_tests = dispatch_loop(nodes, itemgenerator, checkfun) - if all_tests: - todo = {} - for key, value in all_tests.items(): - if key not in done_dict: - todo[key] = True - rg = randomgen(todo, done_dict) - dispatch_loop(nodes, rg, lambda:False, max_tasks_per_node=1) + #if all_tests: + # todo = {} + # for key, value in all_tests.items(): + # if key not in done_dict: + # todo[key] = True + # rg = randomgen(todo, done_dict) + # dispatch_loop(nodes, rg, lambda:False, max_tasks_per_node=1) class LSession(AbstractSession): From hpk at codespeak.net Mon Jan 8 12:16:54 2007 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 8 Jan 2007 12:16:54 +0100 (CET) Subject: [py-svn] r36245 - py/dist/py/documentation Message-ID: <20070108111654.6983F10070@code0.codespeak.net> Author: hpk Date: Mon Jan 8 12:16:51 2007 New Revision: 36245 Modified: py/dist/py/documentation/TODO.txt Log: adding more tasks (apigen related) Modified: py/dist/py/documentation/TODO.txt ============================================================================== --- py/dist/py/documentation/TODO.txt (original) +++ py/dist/py/documentation/TODO.txt Mon Jan 8 12:16:51 2007 @@ -10,6 +10,18 @@ * move not-to-be-exported Gateway() methods to _ - methods. * docstrings for all exported API +packaging +------------------------------------- + +APIGEN / source viewer +------------------------------------- + +* deploying all that is neccessary on codespeak.net + +* (cfbolz, guido) writing the ReST directive, make it available + with eg py.__.misc.docutils.install_doclink(NAME, urlbase ...) + in a tested way. call the install from e.g. py/documentation/conftest.py + testing ----------- @@ -25,6 +37,21 @@ * try to be as 2.2 compatible as possible (use e.g. py.builtin.enumerate instead of "enumerate" directly) +distributed testing +---------------------- + +* the main rsession methods should have docstrings + explaining the purpose + +* move RSync class to py.execnet.RSync, document its usage and + features in the class and method docstrings + + +other +------- + +* no lines longer than 80 characters + distutils install ----------------- From hpk at codespeak.net Mon Jan 8 12:39:13 2007 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 8 Jan 2007 12:39:13 +0100 (CET) Subject: [py-svn] r36249 - in py/dist/py/documentation: . future Message-ID: <20070108113913.74DA01007D@code0.codespeak.net> Author: hpk Date: Mon Jan 8 12:39:06 2007 New Revision: 36249 Added: py/dist/py/documentation/future/ (props changed) py/dist/py/documentation/future/code_template.txt - copied unchanged from r36246, py/dist/py/documentation/code_template.txt py/dist/py/documentation/future/future.txt - copied, changed from r36246, py/dist/py/documentation/future.txt Removed: py/dist/py/documentation/code_template.txt py/dist/py/documentation/future.txt Modified: py/dist/py/documentation/coding-style.txt py/dist/py/documentation/getting-started.txt py/dist/py/documentation/home.txt py/dist/py/documentation/index.txt py/dist/py/documentation/misc.txt py/dist/py/documentation/why_py.txt Log: creating a future subdir and starting to move things into it to have a cleaner "documentation" directory Deleted: /py/dist/py/documentation/code_template.txt ============================================================================== --- /py/dist/py/documentation/code_template.txt Mon Jan 8 12:39:06 2007 +++ (empty file) @@ -1,640 +0,0 @@ -=============================================================== -py.code_template: Lightweight and flexible code template system -=============================================================== - -.. contents:: -.. sectnum:: - -Motivation -========== - -There are as many python templating systems as there are web frameworks -(a lot). This is partly because it is so darned easy to write a templating -system in Python. What are the distinguishing characteristics of the -py.code_template templating system? - - * Optimized for generating code (Python, C, bash scripts, etc.), - not XML or HTML - - * Designed for use by Python programmers, not by web artists - - + Aesthetic sensibilities are different - - + The templates should be an organic part of a module -- just more code - - + Templates do not need to be incredibly full-featured, because - programmers are perfectly capable of escaping to Python for - advanced features. - - - No requirement to support inheritance - - No requirement to support exec - - * Designed so that templates can be coded in the most natural way - for the task at hand - - + Generation of code and scripts often does not follow MVC paradigm! - - + Small template fragments are typically coded *inside* Python modules - - + Sometimes it is natural to put strings inside code; sometimes it is - natural to put code inside strings. Both should be supported as - reasonably and naturally as possible. - -Imaginary-world examples -======================== - -These would be real-world examples, but, not only is this module not yet -implemented, as of now, PyPy is not incredibly useful to the average -programmer... - -translator/c/genc.py --------------------- - -The original function:: - - def gen_readable_parts_of_main_c_file(f, database, preimplementationlines=[]): - # - # All declarations - # - structdeflist = database.getstructdeflist() - print >> f - print >> f, '/***********************************************************/' - print >> f, '/*** Structure definitions ***/' - print >> f - for node in structdeflist: - print >> f, 'struct %s;' % node.name - print >> f - for node in structdeflist: - for line in node.definition(): - print >> f, line - print >> f - print >> f, '/***********************************************************/' - print >> f, '/*** Forward declarations ***/' - print >> f - for node in database.globalcontainers(): - for line in node.forward_declaration(): - print >> f, line - - # - # Implementation of functions and global structures and arrays - # - print >> f - print >> f, '/***********************************************************/' - print >> f, '/*** Implementations ***/' - print >> f - for line in preimplementationlines: - print >> f, line - print >> f, '#include "src/g_include.h"' - print >> f - blank = True - for node in database.globalcontainers(): - if blank: - print >> f - blank = False - for line in node.implementation(): - print >> f, line - blank = True - -This could be refactored heavily. An initial starting point -would look something like this, although later, the template -instance could be passed in and reused directly, rather than -passing the file handle around:: - - def gen_readable_parts_of_main_c_file(f, database, preimplementationlines=[]): - def container_implementation(): - # Helper function designed to introduce blank lines - # between container implementations - - blank = True - for node in database.globalcontainers(): - if blank: - yield '' - blank = False - for line in node.implementation(): - yield line - blank = True - - t = code_template.Template() - # - # All declarations - # - structdeflist = database.getstructdeflist() - t.write(dedent=8, text=''' - - /***********************************************************/ - /*** Structure definitions ***/ - - {for node in structdeflist} - struct {node.name}; - {endfor} - - {for node in structdeflist} - {for line in node.definition} - {line} - {endfor} - {endfor} - - /***********************************************************/ - /*** Forward declarations ***/ - - {for node in database.globalcontainers()} - {for line in node.forward_declaration()} - {line} - {endfor} - {endfor} - - {** - ** Implementation of functions and global structures and arrays - **} - - /***********************************************************/ - /*** Implementations ***/ - - {for line in preimplementationlines} - {line} - {endfor} - - #include "src/g_include.h" - - {for line in container_implementation()} - {line} - {endfor} - """) - t.output(f) - -translator/c/genc.py gen_makefile ---------------------------------- - -The original code:: - - MAKEFILE = ''' - CC = gcc - - $(TARGET): $(OBJECTS) - \t$(CC) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBDIRS) $(LIBS) - - %.o: %.c - \t$(CC) $(CFLAGS) -o $@ -c $< $(INCLUDEDIRS) - - clean: - \trm -f $(OBJECTS) - ''' - - def gen_makefile(self, targetdir): - def write_list(lst, prefix): - for i, fn in enumerate(lst): - print >> f, prefix, fn, - if i < len(lst)-1: - print >> f, '\\' - else: - print >> f - prefix = ' ' * len(prefix) - - compiler = self.getccompiler(extra_includes=['.']) - cfiles = [] - ofiles = [] - for fn in compiler.cfilenames: - fn = py.path.local(fn).basename - assert fn.endswith('.c') - cfiles.append(fn) - ofiles.append(fn[:-2] + '.o') - - f = targetdir.join('Makefile').open('w') - print >> f, '# automatically generated Makefile' - print >> f - print >> f, 'TARGET =', py.path.local(compiler.outputfilename).basename - print >> f - write_list(cfiles, 'SOURCES =') - print >> f - write_list(ofiles, 'OBJECTS =') - print >> f - args = ['-l'+libname for libname in compiler.libraries] - print >> f, 'LIBS =', ' '.join(args) - args = ['-L'+path for path in compiler.library_dirs] - print >> f, 'LIBDIRS =', ' '.join(args) - args = ['-I'+path for path in compiler.include_dirs] - write_list(args, 'INCLUDEDIRS =') - print >> f - print >> f, 'CFLAGS =', ' '.join(compiler.compile_extra) - print >> f, 'LDFLAGS =', ' '.join(compiler.link_extra) - print >> f, MAKEFILE.strip() - f.close() - - -Could look something like this:: - - MAKEFILE = ''' - # automatically generated Makefile - - TARGET = {py.path.local(compiler.outputfilename).basename} - - {for line in write_list(cfiles, 'SOURCES =')} - {line} - {endfor} - - {for line in write_list(ofiles, 'OBJECTS =')} - {line} - {endfor} - - LIBS ={for libname in compiler.libraries} -l{libname}{endfor} - LIBDIRS ={for path in compiler.library_dirs} -L{path}{endfor} - INCLUDEDIRS ={for path in compiler.include_dirs} -I{path}{endfor} - - CFLAGS ={for extra in compiler.compile_extra} {extra}{endfor} - LDFLAGS ={for extra in compiler.link_extra} {extra}{endfor} - - CC = gcc - - $(TARGET): $(OBJECTS) - \t$(CC) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBDIRS) $(LIBS) - - %.o: %.c - \t$(CC) $(CFLAGS) -o $@ -c $< $(INCLUDEDIRS) - - clean: - \trm -f $(OBJECTS) - ''' - - def gen_makefile(self, targetdir): - def write_list(lst, prefix): - for i, fn in enumerate(lst): - yield '%s %s %s' % (prefix, fn, i < len(list)-1 and '\\' or '') - prefix = ' ' * len(prefix) - - compiler = self.getccompiler(extra_includes=['.']) - cfiles = [] - ofiles = [] - for fn in compiler.cfilenames: - fn = py.path.local(fn).basename - assert fn.endswith('.c') - cfiles.append(fn) - ofiles.append(fn[:-2] + '.o') - - code_template.Template(MAKEFILE).output(targetdir.join('Makefile')) - - -translator/llvm/module/excsupport.py ------------------------------------- - -The original string:: - - invokeunwind_code = ''' - ccc %(returntype)s%%__entrypoint__%(entrypointname)s { - %%result = invoke %(cconv)s %(returntype)s%%%(entrypointname)s to label %%no_exception except label %%exception - - no_exception: - store %%RPYTHON_EXCEPTION_VTABLE* null, %%RPYTHON_EXCEPTION_VTABLE** %%last_exception_type - ret %(returntype)s %%result - - exception: - ret %(noresult)s - } - - ccc int %%__entrypoint__raised_LLVMException() { - %%tmp = load %%RPYTHON_EXCEPTION_VTABLE** %%last_exception_type - %%result = cast %%RPYTHON_EXCEPTION_VTABLE* %%tmp to int - ret int %%result - } - - internal fastcc void %%unwind() { - unwind - } - ''' - -Could look something like this if it was used in conjunction with a template:: - - invokeunwind_code = ''' - ccc {returntype}%__entrypoint__{entrypointname} { - %result = invoke {cconv} {returntype}%{entrypointname} to label %no_exception except label %exception - - no_exception: - store %RPYTHON_EXCEPTION_VTABLE* null, %RPYTHON_EXCEPTION_VTABLE** %last_exception_type - ret {returntype} %result - - exception: - ret {noresult} - } - - ccc int %__entrypoint__raised_LLVMException() { - %tmp = load %RPYTHON_EXCEPTION_VTABLE** %last_exception_type - %result = cast %RPYTHON_EXCEPTION_VTABLE* %tmp to int - ret int %result - } - - internal fastcc void %unwind() { - unwind - } - ''' - - -Template syntax -=============== - -Design decision ---------------- - -As all programmers must know by now, all the special symbols on the keyboard -are quite heavily overloaded. Often, template systems work around this fact -by having special notation like `<*` ... `*>` or {% ... %}. Some template systems -even have multiple special notations -- one for comments, one for statements, -one for expressions, etc. - -I find these hard to type and ugly. Other markups are either too lightweight, -or use characters which occur so frequently in the target languages that it -becomes hard to distinguish marked-up content from content which should be -rendered as-is. - -The compromise taken by *code_template* is to use braces (**{}**) for markup. - -This immediately raises the question: what about when the marked-up language -is C or C++? The answer is that if the leading brace is immediately followed -by whitespace, it is normal text; if not it is the start of markup. - -To support normal text which has a leading brace immediately followed by -an identifier, if the first whitespace character after the brace is a space -character (e.g. not a newline or tab), it will be removed from the output. - -Examples:: - - { This is normal text and the space between { and This will be removed} - {'this must be a valid Python expression' + ' because it is treated as markup'} - { - This is normal text, but nothing is altered (the newline is kept intact) - } - - {{1:'Any valid Python expression is allowed as markup'}[1].ljust(30)} - -.. _`Code element`: - -Elements --------- - -Templates consist of normal text and code elements. -(Comments are considered to be code elements.) - -All code elements start with a `left brace`_ which is not followed by -whitespace. - -Keyword element -~~~~~~~~~~~~~~~ - -A keyword element is a `code element`_ which starts with a keyword_. - -For example, *{if foo}* is a keyword element, but *{foo}* is a `substituted expression`_. - -Keyword -~~~~~~~ - -A keyword is a word used in `conditional text`_ or in `repeated text`_, e.g. -one of *if*, *elif*, *else*, *endif*, *for*, or *endfor*. - -Keywords are designed to match their Python equivalents. However, since -templates cannot use spacing to indicate expression nesting, the additional -keywords *endif* and *endfor* are required. - -Left brace -~~~~~~~~~~ - -All elements other than normal text start with a left brace -- the symbol '{', -sometimes known as a 'curly bracket'. A left brace is itself considered -to be normal text if it is followed by whitespace. If the whitespace starts -with a space character, that space character will be stripped from the output. -If the whitespace starts with a tab or linefeed character, the whitespace will -be left in the output. - -Normal Text -~~~~~~~~~~~ - -Normal text remains unsubstituted. Transition from text to the other elements -is effected by use of a `left brace`_ which is not followed by whitespace. - -Comment -~~~~~~~ - -A comment starts with a left brace followed by an asterisk ('{`*`'), and -ends with an asterisk followed by a right brace ('`*`}'):: - - This is a template -- this text will be copied to the output. - {* This is a comment and this text will not be copied to the output *} - - {* - Comments can span lines, - but cannot be nested - *} - -Substituted expression -~~~~~~~~~~~~~~~~~~~~~~ - -Any python expression may be used:: - - Dear {record.name}, - we are sorry to inform you that you did not win {record.contest}. - -The expression must be surrounded by braces, and there must not be any -whitespace between the leftmost brace and the start of the expression. - -The expression will automatically be converted to a string with str(). - -Conditional text -~~~~~~~~~~~~~~~~ - -The following template has text which is included conditionally:: - - This text will always be included in the output - {if foo} - This text will be included if foo is true - {elif bar} - This text will be included if foo is not true but bar is true - {else} - This text will be included if neither foo nor bar is true - {endif} - -The {elif} and {else} elements are optional. - -Repeated text -~~~~~~~~~~~~~ - -The following template shows how to pull multiple items out of a list:: - - {for student, score in sorted(scorelist)} - {student.ljust(20)} {score} - {endfor} - -Whitespace removal or modification ----------------------------------- - -In general, whitespace in `Normal Text`_ is transferred unchanged to the -output. There are three exceptions to this rule: - -Line separators -~~~~~~~~~~~~~~~ - -Each newline is converted to the final output using os.linesep. - -Beginning or end of string -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -py.code_template is designed to allow easy use of templates inside of python -modules. The canonical way to write a template is inside a triple-quoted -string, e.g.:: - - my_template = ''' - This is my template. It can have any text at all in it except - another triple-single-quote. - ''' - -To support this usage, if the first character is a newline, it will be -removed, and if the last line consists solely of whitespace with no -trailing newline, it will also be removed. - -A comment or single keyword element on a line -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Whenever a `keyword element`_ or comment_ is on a line -*by itself*, that line will not be copied to the output. - -This happens when: - - There is nothing on the line before the keyword element - or comment except whitespace (spaces and/or tabs). - - - There is nothing on the line after the keyword element - or comment except a newline. - -Note that even a multi-line comment or keyword element can -have the preceding whitespace and subsequent newline stripped -by this rule. - -The primary purpose of this rule is to allow the Python -programmer to use indentation, **even inside a template**:: - - This is a template - - {if mylist} - List items: - {for item in mylist} - - {item} - {endfor} - {endif} - -Template usage -============== - -Templates are used by importing the Template class from py.code_template, -constructing a template, and then sending data with the write() method. - -In general, there are four methods for getting the formatted data back out -of the template object: - - - read() reads all the data currently in the object - - - output(fobj) outputs the data to a file - - fobj can either be an open file object, or a string. If it is - a string, the file will be opened, written, and closed. - - - open(fobj) (or calling the object constructor with a file object) - - If the open() method is used, or if a file object is passed to - the constructor, each write() will automatically flush the data - out to the file. If the fobj is a string, it is considered to - be *owned*, otherwise it is considered to be *borrowed*. *Owned* - file objects are closed when the class is deleted. - - - write() can be explicitly called with a file object, in which case - it will invoke output() on that object after it generates the data. - -Template instantiation and methods -================================== - -template = code_template.Template(outf=None, cache=None) - -If outf is given, it will be passed to the open() method - -cache may be given as a mapping. If not given, the template will use -the shared default cache. This is not thread safe. - -template.open -------------- - -template.open(outf, borrowed = None) - -The open method closes the internal file object if it was already open, -and then re-opens it on the given file. It is an error to call open() -if there is data in the object left over from previous writes. (Call -output() instead.) - -borrowed defaults to 0 if outf is a string, and 1 if it is a file object. - -borrowed can also be set explicitly if required. - -template.close --------------- - -close() disassociates the file from the template, and closes the file if -it was not borrowed. close() is automatically called by the destructor. - -template.write --------------- - -template.write(text='', outf=None, dedent=0, localvars=None, globalvars=None, -framelevel=1) - -The write method has the following parameters: - - - text is the template itself - - - if outf is not None, the output method will be invoked on the object - after the current template is processed. If no outf is given, data - will be accumulated internal to the instance until a write() with outf - is processed, or read() or output() is called, whichever comes first, if - there is no file object. If there is a file object, data will be flushed - to the file after every write. - - - dedent, if given is applied to each line in the template, to "de-indent" - - - localvars and globalvars default to the dictionaries of the caller. A copy - of localvars is made so that the __TrueSpace__ identifier can be added. - - - cache may be given as a mapping. If not given, the template will use - the shared default cache. This is not thread safe. - - - framelevel is used to determine which stackframe to access for globals - and locals if localvars and/or globalvars are not specified. The default - is to use the caller's frame. - -The write method supports the print >> file protocol by deleting the softspace -attribute on every invocation. This allows code like:: - - t = code_template.Template() - print >> t, "Hello, world" - - -template.read --------------- - -This method reads and flushes all accumulated data in the object. Note that -if a file has been associated with the object, there will never be any data -to read. - -template.output ---------------- - -This method takes one parameter, outf. template.output() first -invokes template.read() to read and flush all accumulated data, -and then outputs the data to the file specified by outf. - -If outf has a write() method, that will be invoked with the -data. If outf has no write() method, it will be treated as -a filename, and that file will be replaced. - -Caching and thread safety -========================= - -The compiled version of every template is cached internal to the -code_template module (unless a separate cache object is specified). - -This allows efficient template reuse, but is not currently thread-safe. -Alternatively, each invocation of a template object can specify a -cache object. This is thread-safe, but not very efficient. A shared -model could be implemented later. - Modified: py/dist/py/documentation/coding-style.txt ============================================================================== --- py/dist/py/documentation/coding-style.txt (original) +++ py/dist/py/documentation/coding-style.txt Mon Jan 8 12:39:06 2007 @@ -70,4 +70,4 @@ .. _`PEP 8 Style Guide for Python Code`: http://www.python.org/peps/pep-0008.html .. _`py-dev mailing list`: http://codespeak.net/mailman/listinfo/py-dev -.. _`future`: future.html +.. _`future`: future/future.html Deleted: /py/dist/py/documentation/future.txt ============================================================================== --- /py/dist/py/documentation/future.txt Mon Jan 8 12:39:06 2007 +++ (empty file) @@ -1,423 +0,0 @@ -======================================================= -Visions and ideas for further development of the py lib -======================================================= - -.. contents:: -.. sectnum:: - -This document tries to describe directions and guiding ideas -for the near-future development of the py lib. *Note that all -statements within this document - even if they sound factual - -mostly just express thoughts and ideas. They not always refer to -real code so read with some caution. This is not a reference guide -(tm). Moreover, the order in which appear here in the file does -not reflect the order in which they may be implemented.* - -.. _`general-path`: -.. _`a more general view on path objects`: - -A more general view on ``py.path`` objects -========================================== - -Seen from a more general persective, the current ``py.path.extpy`` path -offers a way to go from a file to the structured content of -a file, namely a python object. The ``extpy`` path retains some -common ``path`` operations and semantics but offers additional -methods, e.g. ``resolve()`` gets you a true python object. - -But apart from python files there are many other examples -of structured content like xml documents or INI-style -config files. While some tasks will only be convenient -to perform in a domain specific manner (e.g. applying xslt -etc.pp) ``py.path`` offers a common behaviour for -structured content paths. So far only ``py.path.extpy`` -is implemented and used by py.test to address tests -and traverse into test files. - -*You are in a maze of twisty passages, all alike* -------------------------------------------------- - -Now, for the sake of finding out a good direction, -let's consider some code that wants to find all -*sections* which have a certain *option* value -within some given ``startpath``:: - - def find_option(startpath, optionname): - for section in startpath.listdir(dir=1): - opt = section.join(optionname) - if opt.check(): # does the option exist here? - print section.basename, "found:", opt.read() - -Now the point is that ``find_option()`` would obviously work -when ``startpath`` is a filesystem-like path like a local -filesystem path or a subversion URL path. It would then see -directories as sections and files as option-names and the -content of the file as values. - -But it also works (today) for ``extpy`` paths if you put the following -python code in a file:: - - class Section1: - someoption = "i am an option value" - - class Section2: - someoption = "i am another option value" - -An ``extpy()`` path maps classes and modules to directories and -name-value bindings to file/read() operations. - -And it could also work for 'xml' paths if you put -the following xml string in a file:: - - - - - value - - value - -where tags containing non-text tags map to directories -and tags with just text-children map to files (which -upon read() return the joined content of the text -tags possibly as unicode. - -Now, to complete the picture, we could make Config-Parser -*ini-style* config files also available:: - - [section1] - name = value - - [section2] - othername = value - -where sections map to directories and name=value mappings -to file/contents. - -So it seems that our above ``find_option()`` function would -work nicely on all these *mappings*. - -Of course, the somewhat open question is how to make the -transition from a filesystem path to structured content -useful and unified, as much as possible without overdoing it. - -Again, there are tasks that will need fully domain specific -solutions (DOM/XSLT/...) but i think the above view warrants -some experiments and refactoring. The degree of uniformity -still needs to be determined and thought about. - -path objects should be stackable --------------------------------- - -Oh, and btw, a ``py.path.extpy`` file could live on top of a -'py.path.xml' path as well, i.e. take:: - - - - - - - import py - ... - - def getmsg(x): pass - -and use it to have a ``extpy`` path living on it:: - - p = py.path.local(xmlfilename) - xmlp = py.path.extxml(p, 'py/magic/exprinfo') - p = py.path.extpy(xmlp, 'getmsg') - - assert p.check(func=1, basename='getmsg') - getmsg = p.resolve() - # we now have a *live* getmsg() function taken and compiled from - # the above xml fragment - -There could be generic converters which convert between -different content formats ... allowing configuration files to e.g. -be in XML/Ini/python or filesystem-format with some common way -to find and iterate values. - -*After all the unix filesystem and the python namespaces are -two honking great ideas, why not do more of them? :-)* - - -.. _importexport: - -Revising and improving the import/export system -=============================================== - - or let's wrap the world all around - -the export/import interface ---------------------------- - -The py lib already incorporates a mechanism to select which -namespaces and names get exposed to a user of the library. -Apart from reducing the outside visible namespaces complexity -this allows to quickly rename and refactor stuff in the -implementation without affecting the caller side. This export -control can be used by other python packages as well. - -However, all is not fine as the import/export has a -few major deficiencies and shortcomings: - -- it doesn't allow to specify doc-strings -- it is a bit hackish (see py/initpkg.py) -- it doesn't present a complete and consistent view of the API. -- ``help(constructed_namespace)`` doesn't work for the root - package namespace -- when the py lib implementation accesses parts of itself - it uses the native python import mechanism which is - limiting in some respects. Especially for distributed - programs as encouraged by `py.execnet`_ it is not clear - how the mechanism can nicely integrate to support remote - lazy importing. - -Discussions have been going on for a while but it is -still not clear how to best tackle the problem. Personally, -i believe the main missing thing for the first major release -is the docstring one. The current specification -of exported names is dictionary based. It would be -better to declare it in terms of Objects. - - -Example sketch for a new export specification ---------------------------------------------- - -Here is a sketch of how the py libs ``__init__.py`` file -might or should look like:: - - """ - the py lib version 0.8 - http://codespeak.net/py/0.8 - """ - - from py import pkg - pkg.export(__name__, - pkg.Module('path', - '''provides path objects for local filesystem, - subversion url and working copy, and extension paths. - ''', - pkg.Class('local', ''' - the local filesystem path offering a single - point of interaction for many purposes. - ''', extpy='./path/local.LocalPath'), - - pkg.Class('svnurl', ''' - the subversion url path. - ''', extpy='./path/local/svn/urlcommand.SvnUrlPath'), - ), - # it goes on ... - ) - -The current ``initpkg.py`` code can be cleaned up to support -this new more explicit style of stating things. Note that -in principle there is nothing that stops us from retrieving -implementations over the network, e.g. a subversion repository. - - -Let there be alternatives -------------------------- - -We could also specify alternative implementations easily:: - - pkg.Class('svnwc', ''' - the subversion working copy. - ''', extpy=('./path/local/svn/urlbinding.SvnUrlPath', - './path/local/svn/urlcommand.SvnUrlPath',) - ) - -This would prefer the python binding based implementation over -the one working through he 'svn' command line utility. And -of course, it could uniformly signal if no implementation is -available at all. - - -Problems problems ------------------ - -Now there are reasons there isn't a clear conclusion so far. -For example, the above approach has some implications, the -main one being that implementation classes like -``py/path/local.LocalPath`` are visible to the caller side but -this presents an inconsistency because the user started out with -``py.path.local`` and expects that the two classes are really much -the same. We have the same problem today, of course. - -The naive solution strategy of wrapping the "implementation -level" objects into their exported representations may remind -of the `wrapping techniques PyPy uses`_. But it -*may* result in a slightly heavyweight mechanism that affects -runtime speed. However, I guess that this standard strategy -is probably the cleanest. - - -Every problem can be solved with another level ... --------------------------------------------------- - -The wrapping of implementation level classes in their export -representations objects adds another level of indirection. -But this indirection would have interesting advantages: - -- we could easily present a consistent view of the library -- it could take care of exceptions as well -- it provides natural interception points for logging -- it enables remote lazy loading of implementations - or certain versions of interfaces - -And quite likely the extra indirection wouldn't hurt so much -as it is not much more than a function call and we cared -we could even generate some c-code (with PyPy :-) to speed -it up. - -But it can lead to new problems ... ------------------------------------ - -However, it is critical to avoid to burden the implementation -code of being aware of its wrapping. This is what we have -to do in PyPy but the import/export mechanism works at -a higher level of the language, i think. - -Oh, and we didn't talk about bootstrapping :-) - -.. _`py.execnet`: execnet.html -.. _`wrapping techniques PyPy uses`: http://codespeak.net/pypy/index.cgi?doc/wrapping.html -.. _`lightweight xml generation`: - -Extension of py.path.local.sysexec() -==================================== - -The `sysexec mechanism`_ allows to directly execute -binaries on your system. Especially after we'll have this -nicely integrated into Win32 we may also want to run python -scripts both locally and from the net:: - - vadm = py.path.svnurl('http://codespeak.net/svn/vadm/dist/vadm/cmdline.py') - stdoutput = vadm.execute('diff') - -To be able to execute this code fragement, we need either or all of - -- an improved import system that allows remote imports - -- a way to specify what the "neccessary" python import - directories are. for example, the above scriptlet will - require a certain root included in the python search for module - in order to execute something like "import vadm". - -- a way to specify dependencies ... which opens up another - interesting can of worms, suitable for another chapter - in the neverending `future book`_. - -.. _`sysexec mechanism`: misc.html#sysexec -.. _`compile-on-the-fly`: - -we need a persistent storage for the py lib -------------------------------------------- - -A somewhat open question is where to store the underlying -generated pyc-files and other files generated on the fly -with `CPython's distutils`_. We want to have a -*persistent location* in order to avoid runtime-penalties -when switching python versions and platforms (think NFS). - -A *persistent location* for the py lib would be a good idea -maybe also for other reasons. We could cache some of the -expensive test setups, like the multi-revision subversion -repository that is created for each run of the tests. - -.. _`CPython's distutils`: http://www.python.org/dev/doc/devel/lib/module-distutils.html - -.. _`getting started`: getting-started.html -.. _`restructured text`: http://docutils.sourceforge.net/docs/user/rst/quickref.html -.. _`python standard library`: http://www.python.org/doc/2.3.4/lib/lib.html -.. _`xpython EuroPython 2004 talk`: http://codespeak.net/svn/user/hpk/talks/xpython-talk.txt -.. _`under the xpy tree`: http://codespeak.net/svn/user/hpk/xpy/xml.py -.. _`future book`: future.html -.. _`PEP-324 subprocess module`: http://www.python.org/peps/pep-0324.html -.. _`subprocess implementation`: http://www.lysator.liu.se/~astrand/popen5/ -.. _`py.test`: test.html - -Refactor path implementations to use a Filesystem Abstraction -============================================================= - -It seems like a good idea to refactor all python implementations to -use an internal Filesystem abstraction. The current code base -would be transformed to have Filesystem implementations for e.g. -local, subversion and subversion "working copy" filesystems. Today -the according code is scattered through path-handling code. - -On a related note, Armin Rigo has hacked `pylufs`_ which allows to -implement kernel-level linux filesystems with pure python. Now -the idea is that the mentioned filesystem implementations would -be directly usable for such linux-filesystem glue code. - -In other words, implementing a `memoryfs`_ or a `dictfs`_ would -give you two things for free: a filesystem mountable at kernel level -as well as a uniform "path" object allowing you to access your -filesystem in convenient ways. (At some point it might -even become interesting to think about interfacing to -`reiserfs v4 features`_ at the Filesystem level but that -is a can of subsequent worms). - -.. _`memoryfs`: http://codespeak.net/svn/user/arigo/hack/pyfuse/memoryfs.py -.. _`dictfs`: http://codespeak.net/pipermail/py-dev/2005-January/000191.html -.. _`pylufs`: http://codespeak.net/svn/user/arigo/hack/pylufs/ -.. _`reiserfs v4 features`: http://www.namesys.com/v4/v4.html - - -Improve and unify Path API -========================== - -visit() grows depth control ---------------------------- - -Add a ``maxdepth`` argument to the path.visit() method, -which will limit traversal to subdirectories. Example:: - - x = py.path.local.get_tmproot() - for x in p.visit('bin', stop=N): - ... - -This will yield all file or directory paths whose basename -is 'bin', depending on the values of ``stop``:: - - p # stop == 0 or higher (and p.basename == 'bin') - p / bin # stop == 1 or higher - p / ... / bin # stop == 2 or higher - p / ... / ... / bin # stop == 3 or higher - -The default for stop would be `255`. - -But what if `stop < 0`? We could let that mean to go upwards:: - - for x in x.visit('py/bin', stop=-255): - # will yield all parent direcotires which have a - # py/bin subpath - -visit() returning a lazy list? ------------------------------- - -There is a very nice "no-API" `lazy list`_ implementation from -Armin Rigo which presents a complete list interface, given some -iterable. The iterable is consumed only on demand and retains -memory efficiency as much as possible. The lazy list -provides a number of advantages in addition to the fact that -a list interface is nicer to deal with than an iterator. -For example it lets you do:: - - for x in p1.visit('*.cfg') + p2.visit('*.cfg'): - # will iterate through all results - -Here the for-iter expression will retain all lazyness (with -the result of adding lazy lists being another another lazy -list) by internally concatenating the underlying -lazylists/iterators. Moreover, the lazylist implementation -will know that there are no references left to the lazy list -and throw away iterated elements. This makes the iteration -over the sum of the two visit()s as efficient as if we had -used iterables to begin with! - -For this, we would like to move the lazy list into the -py lib's namespace, most probably at `py.builtin.lazylist`. - -.. _`lazy list`: http://codespeak.net/svn/user/arigo/hack/misc/collect.py Copied: py/dist/py/documentation/future/future.txt (from r36246, py/dist/py/documentation/future.txt) ============================================================================== --- py/dist/py/documentation/future.txt (original) +++ py/dist/py/documentation/future/future.txt Mon Jan 8 12:39:06 2007 @@ -280,7 +280,7 @@ Oh, and we didn't talk about bootstrapping :-) -.. _`py.execnet`: execnet.html +.. _`py.execnet`: ../execnet.html .. _`wrapping techniques PyPy uses`: http://codespeak.net/pypy/index.cgi?doc/wrapping.html .. _`lightweight xml generation`: @@ -308,7 +308,7 @@ interesting can of worms, suitable for another chapter in the neverending `future book`_. -.. _`sysexec mechanism`: misc.html#sysexec +.. _`sysexec mechanism`: ../misc.html#sysexec .. _`compile-on-the-fly`: we need a persistent storage for the py lib @@ -327,7 +327,7 @@ .. _`CPython's distutils`: http://www.python.org/dev/doc/devel/lib/module-distutils.html -.. _`getting started`: getting-started.html +.. _`getting started`: ../getting-started.html .. _`restructured text`: http://docutils.sourceforge.net/docs/user/rst/quickref.html .. _`python standard library`: http://www.python.org/doc/2.3.4/lib/lib.html .. _`xpython EuroPython 2004 talk`: http://codespeak.net/svn/user/hpk/talks/xpython-talk.txt @@ -335,7 +335,7 @@ .. _`future book`: future.html .. _`PEP-324 subprocess module`: http://www.python.org/peps/pep-0324.html .. _`subprocess implementation`: http://www.lysator.liu.se/~astrand/popen5/ -.. _`py.test`: test.html +.. _`py.test`: ../test.html Refactor path implementations to use a Filesystem Abstraction ============================================================= Modified: py/dist/py/documentation/getting-started.txt ============================================================================== --- py/dist/py/documentation/getting-started.txt (original) +++ py/dist/py/documentation/getting-started.txt Mon Jan 8 12:39:06 2007 @@ -104,7 +104,7 @@ .. _`zope3`: http://zope3.zwiki.org/ .. _twisted: http://www.twistedmatrix.org -.. _future: future.html +.. _future: future/future.html .. _`get an account`: Modified: py/dist/py/documentation/home.txt ============================================================================== --- py/dist/py/documentation/home.txt (original) +++ py/dist/py/documentation/home.txt Mon Jan 8 12:39:06 2007 @@ -4,9 +4,3 @@ documentation issues - seen primarily from the perspective of a FOSS (Free and Open Source) developer. -Heading towards a first 0.8.0 py.test/py lib release! -====================================================== - -``py.test`` and the py lib are heading towards their first release. -The main missing feature is proper testing and integration with win32 -platforms and improved documentation. *holger (06/11/2005)* Modified: py/dist/py/documentation/index.txt ============================================================================== --- py/dist/py/documentation/index.txt (original) +++ py/dist/py/documentation/index.txt Mon Jan 8 12:39:06 2007 @@ -27,7 +27,7 @@ .. _`py.test`: test.html .. _`py.xml`: xml.html .. _`Why What how py?`: why_py.html -.. _`future`: future.html +.. _`future`: future/future.html .. _`getting started`: getting-started.html .. _`miscellaneous features`: misc.html Modified: py/dist/py/documentation/misc.txt ============================================================================== --- py/dist/py/documentation/misc.txt (original) +++ py/dist/py/documentation/misc.txt Mon Jan 8 12:39:06 2007 @@ -136,11 +136,11 @@ will have to install the `pywin32 package`_. -.. _`compile-on-the-fly`: future.html#compile-on-the-fly -.. _`future book`: future.html +.. _`compile-on-the-fly`: future/future.html#compile-on-the-fly +.. _`future book`: future/future.html .. _`PEP-324 subprocess module`: http://www.python.org/peps/pep-0324.html .. _`subprocess implementation`: http://www.lysator.liu.se/~astrand/popen5/ -.. _`a more general view on path objects`: future.html#general-path +.. _`a more general view on path objects`: future/future.html#general-path .. _`pywin32 package`: http://pywin32.sourceforge.net/ finding an executable local path Modified: py/dist/py/documentation/why_py.txt ============================================================================== --- py/dist/py/documentation/why_py.txt (original) +++ py/dist/py/documentation/why_py.txt Mon Jan 8 12:39:06 2007 @@ -266,8 +266,8 @@ .. _`py-dev mailing list`: http://codespeak.net/mailman/listinfo/py-dev .. _`test environment`: test.html .. _`PyPy`: http://codespeak.net/pypy -.. _`envisioned import/export system`: future.html#importexport -.. _future: future.html +.. _`envisioned import/export system`: future/future.html#importexport +.. _future: future/future.html .. _`py.test tool and library`: test.html .. _`py API`: api.html .. _`great work that Fred L. Drake, Jr. is doing`: http://www.python.org/doc/2.3.4/lib/lib.html From fijal at codespeak.net Mon Jan 8 12:43:13 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 8 Jan 2007 12:43:13 +0100 (CET) Subject: [py-svn] r36253 - py/dist/py/test/rsession/testing Message-ID: <20070108114313.32BD410084@code0.codespeak.net> Author: fijal Date: Mon Jan 8 12:43:09 2007 New Revision: 36253 Modified: py/dist/py/test/rsession/testing/test_lsession.py py/dist/py/test/rsession/testing/test_rsession.py Log: Cleanup a bit sub directories and add additional check for sub being different sub. 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 Mon Jan 8 12:43:09 2007 @@ -16,7 +16,7 @@ def example_distribution(self, runner): # XXX find a better way for the below tmpdir = tmp - dirname = "sub"+runner.func_name + dirname = "sub_lsession"+runner.func_name tmpdir.ensure(dirname, "__init__.py") tmpdir.ensure(dirname, "test_one.py").write(py.code.Source(""" def test_1(): @@ -72,8 +72,9 @@ def test_pdb_run(self): # we make sure that pdb is engaged tmpdir = tmp - tmpdir.ensure("sub", "__init__.py") - tmpdir.ensure("sub", "test_one.py").write(py.code.Source(""" + subdir = "sub_pdb_run" + tmpdir.ensure(subdir, "__init__.py") + tmpdir.ensure(subdir, "test_one.py").write(py.code.Source(""" def test_1(): assert 0 """)) @@ -83,7 +84,7 @@ l.append(args) pdb.post_mortem = some_fun - args = [str(tmpdir.join("sub")), '--pdb'] + args = [str(tmpdir.join(subdir)), '--pdb'] config, args = py.test.Config.parse(args) lsession = LSession(config) allevents = [] @@ -102,8 +103,9 @@ 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(""" + subdir = "sub_lsession_minus_x" + tmpdir.ensure(subdir, "__init__.py") + tmpdir.ensure(subdir, "test_one.py").write(py.code.Source(""" def test_1(): pass def test_2(): @@ -113,7 +115,7 @@ def test_4(someargs): pass """)) - args = [str(tmpdir.join("sub2")), '-x'] + args = [str(tmpdir.join(subdir)), '-x'] config, args = py.test.Config.parse(args) assert config.option.exitfirst lsession = LSession(config) Modified: py/dist/py/test/rsession/testing/test_rsession.py ============================================================================== --- py/dist/py/test/rsession/testing/test_rsession.py (original) +++ py/dist/py/test/rsession/testing/test_rsession.py Mon Jan 8 12:43:09 2007 @@ -138,15 +138,15 @@ if isinstance(x, report.ReceivedItemOutcome)] assert len(testevents) == 2 - def test_example_distribution(self): - # XXX find a better way for the below - tmpdir = py.path.local(py.__file__).dirpath().dirpath() - tmpdir.ensure("sub", "conftest.py").write(py.code.Source(""" + def test_example_distribution(self): + subdir = "sub_example_dist" + tmpdir = py.test.ensuretemp("example_distribution") + tmpdir.ensure(subdir, "conftest.py").write(py.code.Source(""" disthosts = [%r] - distrsync_roots = ["sub", "py"] - """ % 'localhost')) - tmpdir.ensure("sub", "__init__.py") - tmpdir.ensure("sub", "test_one.py").write(py.code.Source(""" + distrsync_roots = ["%s"] + """ % ('localhost', subdir))) + tmpdir.ensure(subdir, "__init__.py") + tmpdir.ensure(subdir, "test_one.py").write(py.code.Source(""" def test_1(): pass def test_2(): @@ -155,8 +155,10 @@ raise ValueError(23) def test_4(someargs): pass - """)) - args = [str(tmpdir.join("sub"))] + def test_5(): + assert __file__ != '%s' + """ % str(tmpdir.join(subdir)))) + args = [str(tmpdir.join(subdir))] config, args = py.test.Config.parse(args) rsession = RSession(config, optimise_localhost=False) allevents = [] @@ -167,8 +169,8 @@ passevents = [i for i in testevents if i.outcome.passed] failevents = [i for i in testevents if i.outcome.excinfo] skippedevents = [i for i in testevents if i.outcome.skipped] - assert len(testevents) == 4 - assert len(passevents) == 1 + assert len(testevents) == 5 + assert len(passevents) == 2 assert len(failevents) == 3 tb = failevents[0].outcome.excinfo.traceback assert tb[0].path.find("test_one") != -1 From hpk at codespeak.net Mon Jan 8 12:58:47 2007 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 8 Jan 2007 12:58:47 +0100 (CET) Subject: [py-svn] r36255 - py/dist/py Message-ID: <20070108115847.0EA9110078@code0.codespeak.net> Author: hpk Date: Mon Jan 8 12:58:45 2007 New Revision: 36255 Modified: py/dist/py/__init__.py Log: shift to 0.8.80-alpha2 for now Modified: py/dist/py/__init__.py ============================================================================== --- py/dist/py/__init__.py (original) +++ py/dist/py/__init__.py Mon Jan 8 12:58:45 2007 @@ -5,17 +5,19 @@ """ from initpkg import initpkg +version = "0.8.80-alpha2" + initpkg(__name__, description = "py.test and the py lib", revision = int('$LastChangedRevision$'.split(':')[1][:-1]), lastchangedate = '$LastChangedDate$', - version = "0.8.0-alpha2", + version = version, url = "http://codespeak.net/py", - download_url = "http://codespeak.net/download/py/py-0.8.0-alpha2.tar.gz", + download_url = "http://codespeak.net/download/py/%s.tar.gz" %(version,), license = "MIT license", platforms = ['unix', 'linux', 'cygwin'], author = "holger krekel & others", - author_email = "hpk at merlinux.de", + author_email = "py-dev at codespeak.net", long_description = globals()['__doc__'], exportdefs = { From hpk at codespeak.net Mon Jan 8 12:58:59 2007 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 8 Jan 2007 12:58:59 +0100 (CET) Subject: [py-svn] r36256 - py/dist/py/test/rsession/testing Message-ID: <20070108115859.C757510086@code0.codespeak.net> Author: hpk Date: Mon Jan 8 12:58:57 2007 New Revision: 36256 Modified: py/dist/py/test/rsession/testing/test_rsession.py Log: better test class name Modified: py/dist/py/test/rsession/testing/test_rsession.py ============================================================================== --- py/dist/py/test/rsession/testing/test_rsession.py (original) +++ py/dist/py/test/rsession/testing/test_rsession.py Mon Jan 8 12:58:57 2007 @@ -69,7 +69,7 @@ assert len(events) == 2 assert str(events[1][0].value) == "Reason" -class TestWithRealSshHosts: +class TestRSessionRemote: #def setup_class(cls): # from py.__.test.rsession.conftest import option # if not option.disthosts: From afayolle at codespeak.net Mon Jan 8 13:23:04 2007 From: afayolle at codespeak.net (afayolle at codespeak.net) Date: Mon, 8 Jan 2007 13:23:04 +0100 (CET) Subject: [py-svn] r36259 - in py/dist/py: misc/testing path/local path/local/testing path/svn/testing rest rest/testing Message-ID: <20070108122304.C9DA61007F@code0.codespeak.net> Author: afayolle Date: Mon Jan 8 13:23:02 2007 New Revision: 36259 Removed: py/dist/py/rest/testing/shared_helpers.py Modified: py/dist/py/misc/testing/test_initpkg.py py/dist/py/misc/testing/test_svnlook.py py/dist/py/path/local/local.py py/dist/py/path/local/testing/test_local.py py/dist/py/path/svn/testing/test_test_repo.py py/dist/py/path/svn/testing/test_urlcommand.py py/dist/py/path/svn/testing/test_wccommand.py py/dist/py/rest/convert.py py/dist/py/rest/latex.py py/dist/py/rest/testing/test_convert.py py/dist/py/rest/testing/test_directive.py py/dist/py/rest/testing/test_htmlrest.py py/dist/py/rest/testing/test_rst2pdf.py Log: * Changed py.path.local.sysfind to return None instead of raising ENOENT when file is not found. * Fixed tests and files using sysfind. * Removed py/rest/testing/shared_helpers.py and fixed code using the is_on_path function defined therein to use the new sysfind semantics. Modified: py/dist/py/misc/testing/test_initpkg.py ============================================================================== --- py/dist/py/misc/testing/test_initpkg.py (original) +++ py/dist/py/misc/testing/test_initpkg.py Mon Jan 8 13:23:02 2007 @@ -77,9 +77,8 @@ def test_getrev(): d = py.__package__.getrev() - try: - svnversion = py.path.local.sysfind('svnversion') - except py.error.ENOENT: + svnversion = py.path.local.sysfind('svnversion') + if svnversion is None: py.test.skip("cannot test svnversion, 'svnversion' binary not found") v = svnversion.sysexec(py.path.local(py.__file__).dirpath()) assert v.startswith(str(d)) Modified: py/dist/py/misc/testing/test_svnlook.py ============================================================================== --- py/dist/py/misc/testing/test_svnlook.py (original) +++ py/dist/py/misc/testing/test_svnlook.py Mon Jan 8 13:23:02 2007 @@ -3,10 +3,8 @@ from py.__.misc import svnlook data = py.magic.autopath().dirpath('data') -try: - py.path.local.sysfind('svnlook') - py.path.local.sysfind('svnadmin') -except py.error.ENOENT: +if py.path.local.sysfind('svnlook') is None or \ + py.path.local.sysfind('svnadmin') is None: py.test.skip("cannot test py.misc.svnlook, svn binaries not found") def test_svnlook(): Modified: py/dist/py/path/local/local.py ============================================================================== --- py/dist/py/path/local/local.py (original) +++ py/dist/py/path/local/local.py Mon Jan 8 13:23:02 2007 @@ -491,7 +491,7 @@ """ return a path object found by looking at the systems underlying PATH specification. If the checker is not None it will be invoked to filter matching paths. If a binary - cannot be found, py.error.ENOENT is raised. + cannot be found, None is returned Note: This is probably not working on plain win32 systems but may work on cygwin. """ @@ -525,7 +525,7 @@ return p except py.error.EACCES: pass - raise py.error.ENOENT(name) + return None sysfind = classmethod(sysfind) #""" #special class constructors for local filesystem paths Modified: py/dist/py/path/local/testing/test_local.py ============================================================================== --- py/dist/py/path/local/testing/test_local.py (original) +++ py/dist/py/path/local/testing/test_local.py Mon Jan 8 13:23:02 2007 @@ -175,9 +175,7 @@ def test_sysfind(self): x = py.path.local.sysfind('cmd') assert x.check(file=1) - py.test.raises(py.error.ENOENT, """ - py.path.local.sysfind('jaksdkasldqwe') - """) + assert py.path.local.sysfind('jaksdkasldqwe') is None class TestExecution(LocalSetup): disabled = py.std.sys.platform == 'win32' @@ -185,9 +183,7 @@ def test_sysfind(self): x = py.path.local.sysfind('test') assert x.check(file=1) - py.test.raises(py.error.ENOENT, """ - py.path.local.sysfind('jaksdkasldqwe') - """) + assert py.path.local.sysfind('jaksdkasldqwe') is None def test_sysfind_no_permisson(self): dir = py.test.ensuretemp('sysfind') @@ -197,8 +193,8 @@ noperm = dir.ensure('noperm', dir=True) env['PATH'] += ":%s" % (noperm) noperm.chmod(0) - py.test.raises(py.error.ENOENT, """ py.path.local.sysfind('a') - """) + assert py.path.local.sysfind('a') is None + finally: env['PATH'] = oldpath noperm.chmod(0644) @@ -224,9 +220,7 @@ assert x.basename == 'a' assert x.dirpath().basename == 'b' checker = lambda x: None - py.test.raises(py.error.ENOENT, """ - py.path.local.sysfind('a', checker=checker) - """) + assert py.path.local.sysfind('a', checker=checker) is None finally: env['PATH'] = oldpath #dir.remove() Modified: py/dist/py/path/svn/testing/test_test_repo.py ============================================================================== --- py/dist/py/path/svn/testing/test_test_repo.py (original) +++ py/dist/py/path/svn/testing/test_test_repo.py Mon Jan 8 13:23:02 2007 @@ -1,9 +1,8 @@ import py from py.__.path.svn.testing.svntestbase import make_test_repo -try: - py.path.local.sysfind('svn') -except py.error.ENOENT: + +if py.path.local.sysfind('svn') is None: py.test.skip("cannot test py.path.svn, 'svn' binary not found") class TestMakeRepo(object): 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 Mon Jan 8 13:23:02 2007 @@ -5,9 +5,8 @@ import datetime import time -try: - svnversion = py.path.local.sysfind('svn') -except py.error.ENOENT: + +if py.path.local.sysfind('svn') is None: py.test.skip("cannot test py.path.svn, 'svn' binary not found") class TestSvnCommandPath(CommonCommandAndBindingTests): 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 Mon Jan 8 13:23:02 2007 @@ -4,9 +4,8 @@ from py.__.path.svn.wccommand import parse_wcinfotime from py.__.path.svn import svncommon -try: - svnversion = py.path.local.sysfind('svn') -except py.error.ENOENT: + +if py.path.local.sysfind('svn') is None: py.test.skip("cannot test py.path.svn, 'svn' binary not found") Modified: py/dist/py/rest/convert.py ============================================================================== --- py/dist/py/rest/convert.py (original) +++ py/dist/py/rest/convert.py Mon Jan 8 13:23:02 2007 @@ -1,7 +1,6 @@ import py from py.__.process.cmdexec import ExecutionFailed -from py.__.rest.testing.shared_helpers import is_on_path # utility functions to convert between various formats format_to_dotargument = {"png": "png", @@ -12,7 +11,8 @@ def ps2eps(ps): # XXX write a pure python version - if not is_on_path("ps2epsi") and not is_on_path("ps2eps"): + if not py.path.local.sysfind("ps2epsi") and \ + not py.path.local.sysfind("ps2eps"): raise SystemExit("neither ps2eps nor ps2epsi found") try: eps = ps.new(ext=".eps") @@ -21,7 +21,7 @@ py.process.cmdexec("ps2eps -l -f %s" % ps) def ps2pdf(ps, compat_level="1.2"): - if not is_on_path("gs"): + if not py.path.local.sysfind("gs"): raise SystemExit("ERROR: gs not found") pdf = ps.new(ext=".pdf") options = dict(OPTIONS="-dSAFER -dCompatibilityLevel=%s" % compat_level, @@ -34,7 +34,7 @@ def eps2pdf(eps): # XXX write a pure python version - if not is_on_path("epstopdf"): + if not py.path.local.sysfind("epstopdf"): raise SystemExit("ERROR: epstopdf not found") py.process.cmdexec("epstopdf %s" % eps) @@ -42,12 +42,12 @@ if dest is None: dest = eps.new(ext=".eps") command = 'dvips -q -E -n 1 -D 600 -p 1 -o %s %s' % (dest, dvi) - if not is_on_path("dvips"): + if not py.path.local.sysfind("dvips"): raise SystemExit("ERROR: dvips not found") py.process.cmdexec(command) def convert_dot(fn, new_extension): - if not is_on_path("dot"): + if not py.path.local.sysfind("dot"): raise SystemExit("ERROR: dot not found") result = fn.new(ext=new_extension) print result Modified: py/dist/py/rest/latex.py ============================================================================== --- py/dist/py/rest/latex.py (original) +++ py/dist/py/rest/latex.py Mon Jan 8 13:23:02 2007 @@ -2,7 +2,6 @@ from docutils.core import publish_cmdline from py.__.process.cmdexec import ExecutionFailed -from py.__.rest.testing.shared_helpers import is_on_path font_to_package = {"times": "times", "helvetica": "times", "new century schoolbock": "newcent", "avant garde": "newcent", @@ -108,7 +107,7 @@ old.chdir() def process_rest_file(restfile, stylesheet=None, debug=False, rest_options=None): - if not is_on_path("pdflatex"): + if not py.path.local.sysfind("pdflatex"): raise SystemExit("ERROR: pdflatex not found") old = py.path.local() f = py.path.local(restfile) Deleted: /py/dist/py/rest/testing/shared_helpers.py ============================================================================== --- /py/dist/py/rest/testing/shared_helpers.py Mon Jan 8 13:23:02 2007 +++ (empty file) @@ -1,11 +0,0 @@ -import py - -def is_on_path(name): - try: - py.path.local.sysfind(name) - except py.error.ENOENT: - return False - else: - return True - - Modified: py/dist/py/rest/testing/test_convert.py ============================================================================== --- py/dist/py/rest/testing/test_convert.py (original) +++ py/dist/py/rest/testing/test_convert.py Mon Jan 8 13:23:02 2007 @@ -1,11 +1,12 @@ import py from py.__.rest.convert import convert_dot, latexformula2png -from shared_helpers import is_on_path datadir = py.magic.autopath().dirpath().join("data") def setup_module(mod): - if not is_on_path("gs") or not is_on_path("dot") or not is_on_path("latex"): + if not py.path.local.sysfind("gs") or \ + not py.path.local.sysfind("dot") or \ + not py.path.local.sysfind("latex"): py.test.skip("ghostscript, graphviz and latex needed") def test_convert_dot(): Modified: py/dist/py/rest/testing/test_directive.py ============================================================================== --- py/dist/py/rest/testing/test_directive.py (original) +++ py/dist/py/rest/testing/test_directive.py Mon Jan 8 13:23:02 2007 @@ -5,16 +5,15 @@ py.test.skip("docutils not present") from py.__.misc import rest from py.__.rest.latex import process_rest_file -from py.__.rest.testing.shared_helpers import is_on_path datadir = py.magic.autopath().dirpath().join("data") def test_graphviz_html(): - if not is_on_path("dot"): + if not py.path.local.sysfind("dot"): py.test.skip("graphviz needed") directive.set_backend_and_register_directives("html") #for reasons that elude me rest.process expects svnwcs??? - if not is_on_path("svn"): + if not py.path.local.sysfind("svn"): py.test.skip("svn needed") txt = py.path.svnwc(datadir.join("graphviz.txt")) html = txt.new(ext="html") @@ -28,7 +27,7 @@ png.remove() def test_graphviz_pdf(): - if not is_on_path("dot") or not is_on_path("latex"): + if not py.path.local.sysfind("dot") or not py.path.local.sysfind("latex"): py.test.skip("graphviz and latex needed") directive.set_backend_and_register_directives("latex") Modified: py/dist/py/rest/testing/test_htmlrest.py ============================================================================== --- py/dist/py/rest/testing/test_htmlrest.py (original) +++ py/dist/py/rest/testing/test_htmlrest.py Mon Jan 8 13:23:02 2007 @@ -2,10 +2,11 @@ import py from py.__.misc import rest -from py.__.rest.testing.shared_helpers import is_on_path def setup_module(mod): - if not is_on_path("gs") or not is_on_path("dot") or not is_on_path("latex"): + if not py.path.local.sysfind("gs") or \ + not py.path.local.sysfind("dot") or \ + not py.path.local.sysfind("latex"): py.test.skip("ghostscript, graphviz and latex needed") try: import docutils Modified: py/dist/py/rest/testing/test_rst2pdf.py ============================================================================== --- py/dist/py/rest/testing/test_rst2pdf.py (original) +++ py/dist/py/rest/testing/test_rst2pdf.py Mon Jan 8 13:23:02 2007 @@ -6,10 +6,11 @@ except ImportError: py.test.skip("docutils not present") -from py.__.rest.testing.shared_helpers import is_on_path def setup_module(mod): - if not is_on_path("gs") or not is_on_path("dot") or not is_on_path("latex"): + if not py.path.local.sysfind("gs") or \ + not py.path.local.sysfind("dot") or \ + not py.path.local.sysfind("latex"): py.test.skip("ghostscript, graphviz and latex needed") data = py.magic.autopath().dirpath().join("data") From hpk at codespeak.net Mon Jan 8 14:43:01 2007 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 8 Jan 2007 14:43:01 +0100 (CET) Subject: [py-svn] r36267 - py/dist/py/documentation Message-ID: <20070108134301.2070310075@code0.codespeak.net> Author: hpk Date: Mon Jan 8 14:43:00 2007 New Revision: 36267 Modified: py/dist/py/documentation/apigen.txt Log: a bit of rewriting the apigen introduction ... the real thing is to consider all apigen docs and sort/merge them. Modified: py/dist/py/documentation/apigen.txt ============================================================================== --- py/dist/py/documentation/apigen.txt (original) +++ py/dist/py/documentation/apigen.txt Mon Jan 8 14:43:00 2007 @@ -5,18 +5,27 @@ ------------ Apigen is a tool for automatically generating API reference documentation for -Python projects. It distinguishes itself from comparable tools by examining -code at runtime, rather than at compile time. This way it is capable of -displaying more information about registered and discovered classes and -functions (although it may find less of them). The tool can either be used -from code, or from py.test, in the latter case it will gather information -about modules registered using `initpkg`_. +Python projects. It works by examining code at runtime rather than at +compile time. This way it is capable of displaying information +about the code base after initialization. A drawback is that +you cannot easily document source code that automatically +starts server processes upon getting imported. + +The apigen functionality can either be used from code, or from +py.test, in the latter case it will gather information about +modules and names exported explicitely via the `initpkg`_ mechanism. + +Please note that apigen is currently geared towards documenting the +py library itself, making it nicely work for other projects +may still require a bit of adaption and refinement work. Using from code ---------------- +XXX how to use it without any Tracer? + The library provides a simple API to generate a py.rest.rst tree (which -can be converted to ReStructuredText), along with some helper classes to +represents a ReStructuredText document), along with some helper classes to control the output. The most important objects are the Tracer, which traces code execution by registering itself with sys.settrace, the DocStorage class, that stores Tracer information, and the RestGen class which creates a ReST From hpk at codespeak.net Mon Jan 8 14:44:27 2007 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 8 Jan 2007 14:44:27 +0100 (CET) Subject: [py-svn] r36268 - in py/dist/py/documentation: . future Message-ID: <20070108134427.5146A10075@code0.codespeak.net> Author: hpk Date: Mon Jan 8 14:44:25 2007 New Revision: 36268 Added: py/dist/py/documentation/future/planning.txt - copied, changed from r36258, py/dist/py/documentation/planning.txt Removed: py/dist/py/documentation/planning.txt Log: refine and move old planning file Copied: py/dist/py/documentation/future/planning.txt (from r36258, py/dist/py/documentation/planning.txt) ============================================================================== --- py/dist/py/documentation/planning.txt (original) +++ py/dist/py/documentation/future/planning.txt Mon Jan 8 14:44:25 2007 @@ -60,14 +60,3 @@ * fix -k option to py.test * add --report=(text|terminal|session|rest|tkinter|rest) to py.test -PyCon sprint -============= - -HP -== - -Vision -====== - - * define necessary minimal abstractions to make a working path documentation - Deleted: /py/dist/py/documentation/planning.txt ============================================================================== --- /py/dist/py/documentation/planning.txt Mon Jan 8 14:44:25 2007 +++ (empty file) @@ -1,73 +0,0 @@ -Release -======= - -currently working configurations --------------------------------- - -2.3 - 2.4.2 work - -2.5 has obscure problems - -with setuptools: 2.3 - 2.4.2 as 'develop' - -regular installation: works mostly, strange test-failures - -to be tested: 2.2, windows - -absolutely necessary steps: ----------------------------- - - * documentation - - * improving getting started, describe install methods - * describe the rest stuff? - * py.log - * py.path is mostly undocumented, API documentation - - * basic windows testing, maybe disabling execnet?, what about the scripts in windows? - - * are all c extensions compiled when installing globally? - - * refactoring py.log - - * write/read methods on py.path should be renamed/deprecated: setcontent, getcontent instead? - - * what about _subprocess.c? - - * warning for docutils - - * don't expose _extpy - - * py/bin should be nicefied, get optparse interface - - * _findpy.py - * py.cleanup: - * py.lookup: add -i option - * pytest.cmd - * rst2pdf.py: merge with py.rest, add warnings when missing tex - * _makepyrelease.py: move somewhere - * py.countloc - * py.test - * py.rest - * win32 - - * skip tests if dependencies are not installed - -nice to have ------------- - - * sets.py, subprocess.py in compat - * fix -k option to py.test - * add --report=(text|terminal|session|rest|tkinter|rest) to py.test - -PyCon sprint -============= - -HP -== - -Vision -====== - - * define necessary minimal abstractions to make a working path documentation - From cfbolz at codespeak.net Mon Jan 8 14:50:00 2007 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 8 Jan 2007 14:50:00 +0100 (CET) Subject: [py-svn] r36269 - in py/dist/py: misc test/terminal Message-ID: <20070108135000.469B610076@code0.codespeak.net> Author: cfbolz Date: Mon Jan 8 14:49:46 2007 New Revision: 36269 Added: py/dist/py/misc/terminal_helper.py Modified: py/dist/py/test/terminal/out.py Log: introduce a terminal_helper file that contains ansi_print and terminal_width, currently. use this from the terminal output of py.test Added: py/dist/py/misc/terminal_helper.py ============================================================================== --- (empty file) +++ py/dist/py/misc/terminal_helper.py Mon Jan 8 14:49:46 2007 @@ -0,0 +1,21 @@ +import sys, os + +terminal_width = int(os.environ.get('COLUMNS', 80))-1 + +def ansi_print(text, esc, file=None, newline=True, flush=False): + if file is None: + file = sys.stderr + text = text.rstrip() + if esc and sys.platform != "win32" and file.isatty(): + if not isinstance(esc, tuple): + esc = (esc,) + text = (''.join(['\x1b[%sm' % cod for cod in esc]) + + text + + '\x1b[0m') # ANSI color code "reset" + if newline: + text += '\n' + file.write(text) + if flush: + file.flush() + + Modified: py/dist/py/test/terminal/out.py ============================================================================== --- py/dist/py/test/terminal/out.py (original) +++ py/dist/py/test/terminal/out.py Mon Jan 8 14:49:46 2007 @@ -2,10 +2,11 @@ import sys import os import py +from py.misc import terminal_helper class Out(object): tty = False - fullwidth = int(os.environ.get('COLUMNS', 80))-1 + fullwidth = terminal_helper.terminal_width def __init__(self, file): self.file = py.io.dupfile(file) From cfbolz at codespeak.net Mon Jan 8 14:51:15 2007 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 8 Jan 2007 14:51:15 +0100 (CET) Subject: [py-svn] r36270 - py/dist/py/bin Message-ID: <20070108135115.4B14910076@code0.codespeak.net> Author: cfbolz Date: Mon Jan 8 14:51:13 2007 New Revision: 36270 Modified: py/dist/py/bin/py.lookup Log: color the search term coloured in the output Modified: py/dist/py/bin/py.lookup ============================================================================== --- py/dist/py/bin/py.lookup (original) +++ py/dist/py/bin/py.lookup Mon Jan 8 14:51:13 2007 @@ -3,6 +3,7 @@ import sys, os sys.path.insert(0, os.path.dirname(__file__)) from _findpy import py +from py.__.misc.terminal_helper import ansi_print, terminal_width import re curdir = py.path.local() @@ -17,6 +18,18 @@ parser.add_option("-C", "--context", action="store", type="int", dest="context", default=0, help="How many lines of output to show") +def find_indexes(search_line, string): + indexes = [] + before = 0 + while 1: + i = search_line.find(string, before) + if i == -1: + break + indexes.append(i) + before = i + len(string) + return indexes + + if __name__ == '__main__': (options, args) = parser.parse_args() string = args[0] @@ -34,11 +47,20 @@ else: searchlines = lines for i, (line, searchline) in enumerate(zip(lines, searchlines)): - if searchline.find(string) != -1: - if not options.context: - print "%s:%d: %s" %(x.relto(curdir), i+1, line.rstrip()) - else: - context = (options.context)/2 - for count in range(max(0, i-context), min(len(lines) - 1, i+context+1)): - print "%s:%d: %s" %(x.relto(curdir), count+1, lines[count].rstrip()) - print "-"*50 + indexes = find_indexes(searchline, string) + if not indexes: + continue + if not options.context: + sys.stdout.write("%s:%d: " %(x.relto(curdir), i+1)) + last_index