# HG changeset patch # User cmlenz # Date 1185269276 0 # Node ID 05c684ceb8c6a24d5b037fb177c1f6b0a356a988 # Parent 79262e20b073d1264fca16960290dd6d2e4cb3d4 Use `req.href` instead of `env.href` as that works much better in Trac>=0.10. That also means Trac 0.9 is no longer supported. diff --git a/README.txt b/README.txt --- a/README.txt +++ b/README.txt @@ -16,7 +16,7 @@ (http://trac.edgewall.com/) and provides a build management interface as well as presentation of build results. -Both the build master and the web interface depend on Trac 0.9, and need +Both the build master and the web interface depend on Trac 0.10, and need to be installed on the same machine, together with the Subversion repository. The build slave only requires Python (>= 2.3), setuptools (>= 0.6a2), as well as any tools required by the build process itself. A @@ -53,7 +53,7 @@ done. You might need to install software that the build of your project requires, but the Bitten build slave itself doesn't require anything extra. -For the build master and web interface, you'll need to install Trac 0.9.3 or +For the build master and web interface, you'll need to install Trac 0.10 or later. Please refer to the Trac documentation for information on how it is installed. diff --git a/bitten/trac_ext/summarizers.py b/bitten/trac_ext/summarizers.py --- a/bitten/trac_ext/summarizers.py +++ b/bitten/trac_ext/summarizers.py @@ -56,7 +56,7 @@ total_failure += num_failure total_error += num_error if file: - data[-1]['href'] = self.env.href.browser(config.path, file) + data[-1]['href'] = req.href.browser(config.path, file) hdf = HDFWrapper(loadpaths=Chrome(self.env).get_all_templates_dirs()) hdf['data'] = data @@ -102,7 +102,7 @@ if loc: d = {'name': unit, 'loc': loc, 'cov': int(cov)} if file: - d['href'] = self.env.href.browser(config.path, file) + d['href'] = req.href.browser(config.path, file) data.append(d) total_loc += loc total_cov += loc * cov diff --git a/bitten/trac_ext/tests/web_ui.py b/bitten/trac_ext/tests/web_ui.py --- a/bitten/trac_ext/tests/web_ui.py +++ b/bitten/trac_ext/tests/web_ui.py @@ -56,7 +56,7 @@ def test_overview(self): PermissionSystem(self.env).grant_permission('joe', 'BUILD_VIEW') req = Mock(method='GET', base_path='', cgi_location='', - path_info='/build', href=Href('/build'), args={}, chrome={}, + path_info='/build', href=Href('/trac'), args={}, chrome={}, hdf=HDFWrapper(), perm=PermissionCache(self.env, 'joe')) module = BuildConfigController(self.env) @@ -69,7 +69,7 @@ def test_overview_admin(self): PermissionSystem(self.env).grant_permission('joe', 'BUILD_ADMIN') req = Mock(method='GET', base_path='', cgi_location='', - path_info='/build', href=Href('/build'), args={}, chrome={}, + path_info='/build', href=Href('/trac'), args={}, chrome={}, hdf=HDFWrapper(), perm=PermissionCache(self.env, 'joe')) module = BuildConfigController(self.env) @@ -86,7 +86,7 @@ PermissionSystem(self.env).grant_permission('joe', 'BUILD_VIEW') req = Mock(method='GET', base_path='', cgi_location='', - path_info='/build/test', href=Href('/build'), args={}, + path_info='/build/test', href=Href('/trac'), args={}, chrome={}, hdf=HDFWrapper(), authname='joe', perm=PermissionCache(self.env, 'joe')) @@ -113,7 +113,7 @@ PermissionSystem(self.env).grant_permission('joe', 'BUILD_VIEW') req = Mock(method='GET', base_path='', cgi_location='', - path_info='/build/test', href=Href('/build/test'), args={}, + path_info='/build/test', href=Href('/trac'), args={}, chrome={}, hdf=HDFWrapper(), authname='joe', perm=PermissionCache(self.env, 'joe')) @@ -128,10 +128,10 @@ module.process_request(req) if req.chrome: # Trac 0.11 - self.assertEqual('/trac.cgi/build/test?page=2', + self.assertEqual('/trac/build/test?page=2', req.chrome['links']['next'][0]['href']) else: - self.assertEqual('/trac.cgi/build/test?page=2', + self.assertEqual('/trac/build/test?page=2', req.hdf.get('chrome.links.next.0.href')) def test_view_config_admin(self): @@ -141,7 +141,7 @@ PermissionSystem(self.env).grant_permission('joe', 'BUILD_ADMIN') req = Mock(method='GET', base_path='', cgi_location='', - path_info='/build/test', href=Href('/build'), args={}, + path_info='/build/test', href=Href('/trac'), args={}, chrome={}, hdf=HDFWrapper(), authname='joe', perm=PermissionCache(self.env, 'joe')) @@ -156,7 +156,7 @@ PermissionSystem(self.env).grant_permission('joe', 'BUILD_ADMIN') req = Mock(method='GET', base_path='', cgi_location='', path_info='/build', args={'action': 'new'}, hdf=HDFWrapper(), - href=Href('/build'), chrome={}, + href=Href('/trac'), chrome={}, perm=PermissionCache(self.env, 'joe')) module = BuildConfigController(self.env) @@ -172,15 +172,16 @@ redirected_to.append(url) raise RequestDone req = Mock(method='POST', base_path='', cgi_location='', - path_info='/build', redirect=redirect, hdf=HDFWrapper(), - authname='joe', perm=PermissionCache(self.env, 'joe'), + path_info='/build', href=Href('/trac'), redirect=redirect, + hdf=HDFWrapper(), authname='joe', + perm=PermissionCache(self.env, 'joe'), args={'action': 'new', 'name': 'test', 'path': 'test/trunk', 'label': 'Test', 'description': 'Bla bla'}) module = BuildConfigController(self.env) assert module.match_request(req) self.assertRaises(RequestDone, module.process_request, req) - self.assertEqual('/trac.cgi/build/test', redirected_to[0]) + self.assertEqual('/trac/build/test', redirected_to[0]) config = BuildConfig.fetch(self.env, 'test') assert config.exists @@ -192,7 +193,7 @@ def test_new_config_submit_without_name(self): PermissionSystem(self.env).grant_permission('joe', 'BUILD_ADMIN') req = Mock(method='POST', base_path='', cgi_location='', - path_info='/build', hdf=HDFWrapper(), + path_info='/build', href=Href('/trac'), hdf=HDFWrapper(), perm=PermissionCache(self.env, 'joe'), args={'action': 'new', 'name': '', 'path': 'test/trunk', 'label': 'Test', 'description': 'Bla bla'}) @@ -204,7 +205,7 @@ def test_new_config_submit_with_invalid_name(self): PermissionSystem(self.env).grant_permission('joe', 'BUILD_ADMIN') req = Mock(method='POST', base_path='', cgi_location='', - path_info='/build', hdf=HDFWrapper(), + path_info='/build', href=Href('/trac'), hdf=HDFWrapper(), perm=PermissionCache(self.env, 'joe'), args={'action': 'new', 'name': 'Foo bar', 'path': 'test/trunk', 'label': 'Test', @@ -217,7 +218,7 @@ def test_new_config_submit_invalid_path(self): PermissionSystem(self.env).grant_permission('joe', 'BUILD_ADMIN') req = Mock(method='POST', base_path='', cgi_location='', - path_info='/build', hdf=HDFWrapper(), + path_info='/build', href=Href('/trac'), hdf=HDFWrapper(), authname='joe', perm=PermissionCache(self.env, 'joe'), args={'action': 'new', 'name': 'test', 'path': 'test/trunk', 'label': 'Test', 'description': 'Bla bla'}) @@ -233,7 +234,7 @@ def test_new_config_submit_with_non_wellformed_recipe(self): PermissionSystem(self.env).grant_permission('joe', 'BUILD_ADMIN') req = Mock(method='POST', base_path='', cgi_location='', - path_info='/build', hdf=HDFWrapper(), + path_info='/build', href=Href('/trac'), hdf=HDFWrapper(), authname='joe', perm=PermissionCache(self.env, 'joe'), args={'action': 'new', 'name': 'test', 'path': 'test/trunk', 'label': 'Test', 'description': 'Bla bla', @@ -246,7 +247,7 @@ def test_new_config_submit_with_invalid_recipe(self): PermissionSystem(self.env).grant_permission('joe', 'BUILD_ADMIN') req = Mock(method='POST', base_path='', cgi_location='', - path_info='/build', hdf=HDFWrapper(), + path_info='/build', href=Href('/trac'), hdf=HDFWrapper(), authname='joe', perm=PermissionCache(self.env, 'joe'), args={'action': 'new', 'name': 'test', 'path': 'test/trunk', 'label': 'Test', 'description': 'Bla bla', @@ -263,14 +264,14 @@ redirected_to.append(url) raise RequestDone req = Mock(method='POST', base_path='', cgi_location='', - path_info='/build', redirect=redirect, hdf=HDFWrapper(), - perm=PermissionCache(self.env, 'joe'), + path_info='/build', href=Href('/trac'), redirect=redirect, + hdf=HDFWrapper(), perm=PermissionCache(self.env, 'joe'), args={'action': 'new', 'cancel': '1', 'name': 'test'}) module = BuildConfigController(self.env) assert module.match_request(req) self.assertRaises(RequestDone, module.process_request, req) - self.assertEqual('/trac.cgi/build', redirected_to[0]) + self.assertEqual('/trac/build', redirected_to[0]) self.assertEqual(None, BuildConfig.fetch(self.env, 'test')) @@ -281,7 +282,7 @@ PermissionSystem(self.env).grant_permission('joe', 'BUILD_ADMIN') req = Mock(method='GET', base_path='', cgi_location='', - path_info='/build/test', href=Href('/build'), chrome={}, + path_info='/build/test', href=Href('/trac'), chrome={}, hdf=HDFWrapper(), perm=PermissionCache(self.env, 'joe'), args={'action': 'delete'}) @@ -302,14 +303,15 @@ redirected_to.append(url) raise RequestDone req = Mock(method='POST', base_path='', cgi_location='', - path_info='/build/test', redirect=redirect, hdf=HDFWrapper(), + path_info='/build/test', href=Href('/trac'), + redirect=redirect, hdf=HDFWrapper(), perm=PermissionCache(self.env, 'joe'), args={'action': 'delete'}) module = BuildConfigController(self.env) assert module.match_request(req) self.assertRaises(RequestDone, module.process_request, req) - self.assertEqual('/trac.cgi/build', redirected_to[0]) + self.assertEqual('/trac/build', redirected_to[0]) self.assertEqual(None, BuildConfig.fetch(self.env, 'test')) @@ -324,14 +326,15 @@ redirected_to.append(url) raise RequestDone req = Mock(method='POST', base_path='', cgi_location='', - path_info='/build/test', redirect=redirect, hdf=HDFWrapper(), + path_info='/build/test', href=Href('/trac'), + redirect=redirect, hdf=HDFWrapper(), perm=PermissionCache(self.env, 'joe'), args={'action': 'delete', 'cancel': ''}) module = BuildConfigController(self.env) assert module.match_request(req) self.assertRaises(RequestDone, module.process_request, req) - self.assertEqual('/trac.cgi/build/test', redirected_to[0]) + self.assertEqual('/trac/build/test', redirected_to[0]) self.assertEqual(True, BuildConfig.fetch(self.env, 'test').exists) @@ -364,7 +367,8 @@ redirected_to.append(url) raise RequestDone req = Mock(method='POST', base_path='', cgi_location='', - path_info='/build/test', redirect=redirect, hdf=HDFWrapper(), + path_info='/build/test', href=Href('/trac'), + redirect=redirect, hdf=HDFWrapper(), authname='joe', perm=PermissionCache(self.env, 'joe'), args={'action': 'edit', 'name': 'foo', 'path': 'test/trunk', 'label': 'Test', 'description': 'Bla bla'}) @@ -372,7 +376,7 @@ module = BuildConfigController(self.env) assert module.match_request(req) self.assertRaises(RequestDone, module.process_request, req) - self.assertEqual('/trac.cgi/build/foo', redirected_to[0]) + self.assertEqual('/trac/build/foo', redirected_to[0]) self.assertEqual(None, BuildConfig.fetch(self.env, 'test')) @@ -393,14 +397,15 @@ redirected_to.append(url) raise RequestDone req = Mock(method='POST', base_path='', cgi_location='', - path_info='/build/test', redirect=redirect, hdf=HDFWrapper(), + path_info='/build/test', href=Href('/trac'), + redirect=redirect, hdf=HDFWrapper(), perm=PermissionCache(self.env, 'joe'), args={'action': 'edit', 'cancel': ''}) module = BuildConfigController(self.env) assert module.match_request(req) self.assertRaises(RequestDone, module.process_request, req) - self.assertEqual('/trac.cgi/build/test', redirected_to[0]) + self.assertEqual('/trac/build/test', redirected_to[0]) def test_new_platform(self): config = BuildConfig(self.env) @@ -409,9 +414,8 @@ PermissionSystem(self.env).grant_permission('joe', 'BUILD_ADMIN') req = Mock(method='GET', base_path='', cgi_location='', - path_info='/build/test', hdf=HDFWrapper(), - href=Href('/build/test'), chrome={}, - perm=PermissionCache(self.env, 'joe'), + path_info='/build/test', hdf=HDFWrapper(), href=Href('trac'), + chrome={}, perm=PermissionCache(self.env, 'joe'), args={'action': 'edit', 'new': '1'}) module = BuildConfigController(self.env) @@ -431,14 +435,15 @@ redirected_to.append(url) raise RequestDone req = Mock(method='POST', base_path='', cgi_location='', - path_info='/build/test', redirect=redirect, hdf=HDFWrapper(), + path_info='/build/test', href=Href('/trac'), + redirect=redirect, hdf=HDFWrapper(), perm=PermissionCache(self.env, 'joe'), args={'action': 'new', 'name': 'Test'}) module = BuildConfigController(self.env) assert module.match_request(req) self.assertRaises(RequestDone, module.process_request, req) - self.assertEqual('/trac.cgi/build/test?action=edit', redirected_to[0]) + self.assertEqual('/trac/build/test?action=edit', redirected_to[0]) def test_new_platform_cancel(self): config = BuildConfig(self.env) @@ -451,14 +456,15 @@ redirected_to.append(url) raise RequestDone req = Mock(method='POST', base_path='', cgi_location='', - path_info='/build/test', redirect=redirect, hdf=HDFWrapper(), + path_info='/build/test', href=Href('/trac'), + redirect=redirect, hdf=HDFWrapper(), perm=PermissionCache(self.env, 'joe'), args={'action': 'new', 'cancel': ''}) module = BuildConfigController(self.env) assert module.match_request(req) self.assertRaises(RequestDone, module.process_request, req) - self.assertEqual('/trac.cgi/build/test?action=edit', redirected_to[0]) + self.assertEqual('/trac/build/test?action=edit', redirected_to[0]) def test_edit_platform(self): config = BuildConfig(self.env) @@ -473,7 +479,7 @@ PermissionSystem(self.env).grant_permission('joe', 'BUILD_ADMIN') req = Mock(method='GET', base_path='', cgi_location='', path_info='/build/test', hdf=HDFWrapper(), - href=Href('/build'), chrome={}, + href=Href('/trac'), chrome={}, perm=PermissionCache(self.env, 'joe'), args={'action': 'edit', 'platform': platform.id}) @@ -499,7 +505,8 @@ redirected_to.append(url) raise RequestDone req = Mock(method='POST', base_path='', cgi_location='', - path_info='/build/test', redirect=redirect, hdf=HDFWrapper(), + path_info='/build/test', href=Href('/trac'), + redirect=redirect, hdf=HDFWrapper(), args={'action': 'edit', 'platform': platform.id, 'name': 'Test'}, perm=PermissionCache(self.env, 'joe')) @@ -507,7 +514,7 @@ module = BuildConfigController(self.env) assert module.match_request(req) self.assertRaises(RequestDone, module.process_request, req) - self.assertEqual('/trac.cgi/build/test?action=edit', redirected_to[0]) + self.assertEqual('/trac/build/test?action=edit', redirected_to[0]) def test_edit_platform_cancel(self): config = BuildConfig(self.env) @@ -525,7 +532,8 @@ redirected_to.append(url) raise RequestDone req = Mock(method='POST', base_path='', cgi_location='', - path_info='/build/test', redirect=redirect, hdf=HDFWrapper(), + path_info='/build/test', href=Href('/trac'), + redirect=redirect, hdf=HDFWrapper(), args={'action': 'edit', 'platform': platform.id, 'cancel': ''}, perm=PermissionCache(self.env, 'joe')) @@ -533,7 +541,7 @@ module = BuildConfigController(self.env) assert module.match_request(req) self.assertRaises(RequestDone, module.process_request, req) - self.assertEqual('/trac.cgi/build/test?action=edit', redirected_to[0]) + self.assertEqual('/trac/build/test?action=edit', redirected_to[0]) def suite(): diff --git a/bitten/trac_ext/web_ui.py b/bitten/trac_ext/web_ui.py --- a/bitten/trac_ext/web_ui.py +++ b/bitten/trac_ext/web_ui.py @@ -46,8 +46,8 @@ hdf = {'id': build.id, 'name': build.slave, 'rev': build.rev, 'status': _status_label[build.status], 'cls': _status_label[build.status].replace(' ', '-'), - 'href': env.href.build(build.config, build.id), - 'chgset_href': env.href.changeset(build.rev)} + 'href': req.href.build(build.config, build.id), + 'chgset_href': req.href.changeset(build.rev)} if build.started: hdf['started'] = format_datetime(build.started) hdf['started_delta'] = pretty_timedelta(build.started) @@ -89,7 +89,7 @@ return yield ('mainnav', 'build', \ Markup('Build Status', - self.env.href.build())) + req.href.build())) # ITemplatesProvider methods @@ -177,7 +177,7 @@ req.perm.assert_permission('BUILD_CREATE') if 'cancel' in req.args: - req.redirect(self.env.href.build()) + req.redirect(req.href.build()) config_name = req.args.get('name') @@ -189,14 +189,14 @@ self._process_config(req, config) config.insert() - req.redirect(self.env.href.build(config.name)) + req.redirect(req.href.build(config.name)) def _do_delete_config(self, req, config_name): """Save changes to a build configuration.""" req.perm.assert_permission('BUILD_DELETE') if 'cancel' in req.args: - req.redirect(self.env.href.build(config_name)) + req.redirect(req.href.build(config_name)) db = self.env.get_db_cnx() @@ -207,14 +207,14 @@ db.commit() - req.redirect(self.env.href.build()) + req.redirect(req.href.build()) def _do_save_config(self, req, config_name): """Save changes to a build configuration.""" req.perm.assert_permission('BUILD_MODIFY') if 'cancel' in req.args: - req.redirect(self.env.href.build(config_name)) + req.redirect(req.href.build(config_name)) config = BuildConfig.fetch(self.env, config_name) if not config: @@ -232,7 +232,7 @@ self._process_config(req, config) config.update() - req.redirect(self.env.href.build(config.name)) + req.redirect(req.href.build(config.name)) def _process_config(self, req, config): name = req.args.get('name') @@ -279,12 +279,12 @@ req.perm.assert_permission('BUILD_MODIFY') if 'cancel' in req.args: - req.redirect(self.env.href.build(config_name, action='edit')) + req.redirect(req.href.build(config_name, action='edit')) platform = TargetPlatform(self.env, config=config_name) if self._process_platform(req, platform): platform.insert() - req.redirect(self.env.href.build(config_name, action='edit')) + req.redirect(req.href.build(config_name, action='edit')) def _do_delete_platforms(self, req): """Delete selected target platforms.""" @@ -308,12 +308,12 @@ req.perm.assert_permission('BUILD_MODIFY') if 'cancel' in req.args: - req.redirect(self.env.href.build(config_name, action='edit')) + req.redirect(req.href.build(config_name, action='edit')) platform = TargetPlatform.fetch(self.env, platform_id) if self._process_platform(req, platform): platform.update() - req.redirect(self.env.href.build(config_name, action='edit')) + req.redirect(req.href.build(config_name, action='edit')) def _process_platform(self, req, platform): platform.name = req.args.get('name') @@ -361,7 +361,7 @@ 'name': config.name, 'label': config.label or config.name, 'active': config.active, 'path': config.path, 'description': description, - 'href': self.env.href.build(config.name), + 'href': req.href.build(config.name), } if not config.active: continue @@ -376,7 +376,7 @@ if prev_rev is None: chgset = repos.get_changeset(rev) req.hdf[prefix + '.youngest_rev'] = { - 'id': rev, 'href': self.env.href.changeset(rev), + 'id': rev, 'href': req.href.changeset(rev), 'author': chgset.author or 'anonymous', 'date': format_datetime(chgset.date), 'message': wiki_to_oneliner( @@ -403,18 +403,18 @@ config = BuildConfig.fetch(self.env, config_name, db=db) req.hdf['title'] = 'Build Configuration "%s"' \ % config.label or config.name - add_link(req, 'up', self.env.href.build(), 'Build Status') + add_link(req, 'up', req.href.build(), 'Build Status') description = config.description if description: description = wiki_to_html(description, self.env, req) req.hdf['config'] = { 'name': config.name, 'label': config.label, 'path': config.path, 'min_rev': config.min_rev, - 'min_rev_href': self.env.href.changeset(config.min_rev), + 'min_rev_href': req.href.changeset(config.min_rev), 'max_rev': config.max_rev, - 'max_rev_href': self.env.href.changeset(config.max_rev), + 'max_rev_href': req.href.changeset(config.max_rev), 'active': config.active, 'description': description, - 'browser_href': self.env.href.browser(config.path), + 'browser_href': req.href.browser(config.path), 'can_modify': req.perm.has_permission('BUILD_MODIFY'), 'can_delete': req.perm.has_permission('BUILD_DELETE') } @@ -433,8 +433,8 @@ if has_reports: req.hdf['config.charts'] = [ - {'href': self.env.href.build(config.name, 'chart/test')}, - {'href': self.env.href.build(config.name, 'chart/coverage')} + {'href': req.href.build(config.name, 'chart/test')}, + {'href': req.href.build(config.name, 'chart/coverage')} ] charts_license = self.config.get('bitten', 'charts_license') if charts_license: @@ -456,7 +456,7 @@ break elif idx >= (page - 1) * builds_per_page: prefix = 'config.builds.%d' % rev - req.hdf[prefix + '.href'] = self.env.href.changeset(rev) + req.hdf[prefix + '.href'] = req.href.changeset(rev) if build and build.status != Build.PENDING: build_hdf = _build_to_hdf(self.env, req, build) req.hdf['%s.%s' % (prefix, platform.id)] = build_hdf @@ -475,12 +475,12 @@ if page > 1: if page == 2: - prev_href = self.env.href.build(config.name) + prev_href = req.href.build(config.name) else: - prev_href = self.env.href.build(config.name, page=page - 1) + prev_href = req.href.build(config.name, page=page - 1) add_link(req, 'prev', prev_href, 'Previous Page') if more: - next_href = self.env.href.build(config.name, page=page + 1) + next_href = req.href.build(config.name, page=page + 1) add_link(req, 'next', next_href, 'Next Page') def _render_config_confirm(self, req, config_name): @@ -509,8 +509,8 @@ config_name)): req.hdf['config.platforms.%d' % idx] = { 'id': platform.id, 'name': platform.name, - 'href': self.env.href.build(config_name, action='edit', - platform=platform.id) + 'href': req.href.build(config_name, action='edit', + platform=platform.id) } else: req.perm.assert_permission('BUILD_CREATE') @@ -568,9 +568,9 @@ if req.method == 'POST': if req.args.get('action') == 'invalidate': self._do_invalidate(req, build, db) - req.redirect(self.env.href.build(build.config, build.id)) + req.redirect(req.href.build(build.config, build.id)) - add_link(req, 'up', self.env.href.build(build.config), + add_link(req, 'up', req.href.build(build.config), 'Build Configuration') status2title = {Build.SUCCESS: 'Success', Build.FAILURE: 'Failure', Build.IN_PROGRESS: 'In Progress'} @@ -580,7 +580,7 @@ config = BuildConfig.fetch(self.env, build.config, db=db) req.hdf['build.config'] = { 'name': config.label, - 'href': self.env.href.build(config.name) + 'href': req.href.build(config.name) } formatters = [] @@ -667,7 +667,7 @@ buf.write('') message = Markup(buf.getvalue()) else: - href = self.env.href.build(config, id) + href = req.href.build(config, id) if errors: steps = [] for step, error in errors: @@ -701,7 +701,7 @@ db.commit() - req.redirect(self.env.href.build(build.config)) + req.redirect(req.href.build(build.config)) def _render_log(self, req, build, formatters, step): items = [] @@ -738,7 +738,7 @@ """Return the log message formatter function.""" config = BuildConfig.fetch(self.env, name=build.config) repos = self.env.get_repository(req.authname) - href = self.env.href.browser + href = req.href.browser cache = {} def _replace(m): filepath = posixpath.normpath(m.group('path').replace('\\', '/'))