You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by br...@apache.org on 2020/08/27 20:35:25 UTC

[allura] branch db/8375 updated (6973f36 -> 352c329)

This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a change to branch db/8375
in repository https://gitbox.apache.org/repos/asf/allura.git.


    from 6973f36  [#8375] handle regex escape differences, which fixes a few tests
     new d32ccf8  [#8375] various mail formatting/encoding fixes for py3
     new 7e1d3c4  [#8375] nuanced str/bytes/charset handling for email messages
     new 8a17b6f  [#8375] for json dumping to temp files, set mode to not binary
     new d443bf1  [#8375] ForgeBlog core lookup fix
     new ad78115  [#8375] avoid "Running setup_app() from allura.websetup" output during test runs
     new 886cd0d  [#8375] requirements fine-tuning
     new e70fbe5  [#8375] more formencode bytes fixes
     new e522647  [#8375] git py3 fixes
     new 8c27232  [#8375] hide_private_info Markup py3 fix
     new 59c853f  [#8375] iterator compatibility for py3
     new f6cfee7  [#8375] ForgeImporters test fixes for py3
     new 7456010  [#8375] url quoting fixes
     new 18788c6  [#8375] simpler tg.jsonify.JSONEncoder patch
     new 833cbf0  [#8375] don't use a direct keys() view when mutating a dict in a loop
     new 727d750  [#8375] tracker fixes
     new 352c329  [#8375] svn fixes

The 16 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 Allura/allura/app.py                               |  2 +-
 Allura/allura/controllers/repository.py            | 13 +++++-----
 Allura/allura/lib/decorators.py                    |  2 +-
 Allura/allura/lib/helpers.py                       |  6 ++++-
 Allura/allura/lib/mail_util.py                     | 30 ++++++++++++++--------
 Allura/allura/lib/patches.py                       | 10 +-------
 Allura/allura/lib/utils.py                         |  1 +
 Allura/allura/lib/validators.py                    |  8 +++++-
 Allura/allura/lib/widgets/discuss.py               |  7 ++++-
 Allura/allura/model/auth.py                        |  4 ++-
 Allura/allura/model/neighborhood.py                |  2 +-
 Allura/allura/model/repository.py                  |  3 ++-
 Allura/allura/scripts/trac_export.py               |  1 +
 Allura/allura/tests/decorators.py                  | 11 ++++++++
 .../allura/tests/functional/test_user_profile.py   |  2 +-
 Allura/allura/tests/test_helpers.py                |  3 +++
 Allura/allura/tests/test_mail_util.py              |  2 +-
 Allura/allura/tests/test_tasks.py                  | 21 ++++++++-------
 AlluraTest/alluratest/controller.py                |  2 +-
 ForgeBlog/forgeblog/main.py                        |  2 +-
 ForgeBlog/forgeblog/tests/test_app.py              |  4 +--
 .../forgediscussion/tests/functional/test_forum.py |  3 +++
 ForgeDiscussion/forgediscussion/tests/test_app.py  |  4 +--
 ForgeGit/forgegit/model/git_repo.py                |  4 +--
 .../forgegit/tests/functional/test_controllers.py  |  4 +--
 ForgeGit/forgegit/tests/model/test_repository.py   |  2 +-
 ForgeImporters/forgeimporters/base.py              | 12 +++++++++
 .../forgeimporters/tests/github/test_extractor.py  | 22 ++++++++--------
 .../forgeimporters/tests/github/test_tracker.py    |  4 +--
 .../trac/tests/functional/test_trac.py             |  6 ++---
 ForgeLink/forgelink/link_main.py                   |  2 +-
 ForgeLink/forgelink/tests/functional/test_rest.py  | 14 +++++-----
 ForgeLink/forgelink/tests/functional/test_root.py  |  6 +++--
 ForgeLink/forgelink/tests/test_app.py              |  2 +-
 ForgeSVN/forgesvn/model/svn.py                     |  9 ++++---
 ForgeSVN/forgesvn/tests/model/test_repository.py   |  3 +--
 ForgeTracker/forgetracker/import_support.py        |  4 +--
 ForgeTracker/forgetracker/model/ticket.py          | 15 ++++++-----
 .../forgetracker/tests/functional/test_root.py     | 16 +++++++-----
 ForgeTracker/forgetracker/tests/test_app.py        |  4 +--
 .../forgetracker/tests/unit/test_ticket_model.py   | 16 ++++++------
 ForgeTracker/forgetracker/tracker_main.py          |  6 ++---
 ForgeTracker/forgetracker/widgets/ticket_form.py   |  2 +-
 ForgeWiki/forgewiki/tests/functional/test_rest.py  |  6 ++---
 ForgeWiki/forgewiki/tests/test_app.py              |  6 ++---
 requirements.in                                    |  2 ++
 requirements.txt                                   |  2 +-
 47 files changed, 184 insertions(+), 128 deletions(-)


[allura] 07/16: [#8375] more formencode bytes fixes

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8375
in repository https://gitbox.apache.org/repos/asf/allura.git

commit e70fbe52238a4ac58c0fe5315331dcd294edaf09
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Tue Aug 25 12:13:15 2020 -0400

    [#8375] more formencode bytes fixes
---
 Allura/allura/lib/validators.py                  |  8 +++++++-
 Allura/allura/lib/widgets/discuss.py             |  7 ++++++-
 ForgeImporters/forgeimporters/base.py            | 12 ++++++++++++
 ForgeTracker/forgetracker/widgets/ticket_form.py |  2 +-
 4 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/Allura/allura/lib/validators.py b/Allura/allura/lib/validators.py
index 9dd0c91..28c224b 100644
--- a/Allura/allura/lib/validators.py
+++ b/Allura/allura/lib/validators.py
@@ -84,6 +84,12 @@ class UnicodeString(fev.UnicodeString):
 String = UnicodeString if str is str else fev.ByteString
 
 
+class FieldStorageUploadConverter(fev.FieldStorageUploadConverter):
+    # https://github.com/formencode/formencode/issues/101 local fix
+    def is_empty(self, value):
+        return value == b'' or super(FieldStorageUploadConverter, self).is_empty(value)
+
+
 class Ming(fev.FancyValidator):
 
     def __init__(self, cls, **kw):
@@ -290,7 +296,7 @@ class JsonConverter(fev.FancyValidator):
         return obj
 
 
-class JsonFile(fev.FieldStorageUploadConverter):
+class JsonFile(FieldStorageUploadConverter):
 
     """Validates that a file is JSON and returns the deserialized Python object
 
diff --git a/Allura/allura/lib/widgets/discuss.py b/Allura/allura/lib/widgets/discuss.py
index 9338fbb..5abdf4b 100644
--- a/Allura/allura/lib/widgets/discuss.py
+++ b/Allura/allura/lib/widgets/discuss.py
@@ -40,6 +40,11 @@ class NullValidator(fev.FancyValidator):
     def _from_python(self, value, state):
         return value
 
+    # https://github.com/formencode/formencode/issues/101 local fix
+    def is_empty(self, value):
+        return value == b'' or super(NullValidator, self).is_empty(value)
+
+
 # Discussion forms
 
 
@@ -206,7 +211,7 @@ class NewTopicPost(EditPost):
         fields = super(NewTopicPost, self).fields
         fields.append(ew.InputField(name='attachment', label='Attachment', field_type='file',
                                     attrs={'multiple': 'True'},
-                                    validator=fev.FieldStorageUploadConverter(if_missing=None)))
+                                    validator=v.FieldStorageUploadConverter(if_missing=None)))
         return fields
 
 
diff --git a/ForgeImporters/forgeimporters/base.py b/ForgeImporters/forgeimporters/base.py
index ea87738..a37b8e3 100644
--- a/ForgeImporters/forgeimporters/base.py
+++ b/ForgeImporters/forgeimporters/base.py
@@ -73,6 +73,12 @@ class ProjectImportForm(schema.Schema):
     neighborhood = fev.NotEmpty()
     project_name = v.UnicodeString(not_empty=True, max=40)
 
+    # https://github.com/formencode/formencode/issues/101 local fix
+    def _value_is_iterator(self, value):
+        if isinstance(value, bytes):
+            return False
+        return super(ProjectImportForm, self)._value_is_iterator(value)
+
 
 class ToolImportForm(schema.Schema):
 
@@ -81,6 +87,12 @@ class ToolImportForm(schema.Schema):
         self.add_field('mount_point', v.MountPointValidator(tool_class))
     mount_label = v.UnicodeString()
 
+    # https://github.com/formencode/formencode/issues/101 local fix
+    def _value_is_iterator(self, value):
+        if isinstance(value, bytes):
+            return False
+        return super(ToolImportForm, self)._value_is_iterator(value)
+
 
 class ImportErrorHandler(object):
 
diff --git a/ForgeTracker/forgetracker/widgets/ticket_form.py b/ForgeTracker/forgetracker/widgets/ticket_form.py
index fa1ddd4..73eb753 100644
--- a/ForgeTracker/forgetracker/widgets/ticket_form.py
+++ b/ForgeTracker/forgetracker/widgets/ticket_form.py
@@ -124,7 +124,7 @@ class GenericTicketForm(ew.SimpleForm):
                         validator=fev.StringBool(),
                         attrs={'class': 'unlabeled'}),
             ew.InputField(name='attachment', label='Attachment', field_type='file', attrs={
-                          'multiple': 'True'}, validator=fev.FieldStorageUploadConverter(if_missing=None)),
+                          'multiple': 'True'}, validator=v.FieldStorageUploadConverter(if_missing=None)),
             ffw.MarkdownEdit(name='comment', label='Comment',
                              attrs={'style': 'min-height:7em; width:97%'}),
             ew.SubmitButton(label=self.submit_text, name='submit',


[allura] 08/16: [#8375] git py3 fixes

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8375
in repository https://gitbox.apache.org/repos/asf/allura.git

commit e5226472b1e0200df3b2e5ac4a9f1b502ebe64f1
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Tue Aug 25 17:00:17 2020 -0400

    [#8375] git py3 fixes
---
 Allura/allura/controllers/repository.py                | 13 +++++++------
 ForgeGit/forgegit/model/git_repo.py                    |  4 ++--
 ForgeGit/forgegit/tests/functional/test_controllers.py |  4 ++--
 ForgeGit/forgegit/tests/model/test_repository.py       |  2 +-
 4 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/Allura/allura/controllers/repository.py b/Allura/allura/controllers/repository.py
index 4959af7..3104e07 100644
--- a/Allura/allura/controllers/repository.py
+++ b/Allura/allura/controllers/repository.py
@@ -797,7 +797,7 @@ class TreeBrowser(BaseController, DispatchIndex):
         next = h.really_unicode(unquote(next))
         if not rest:
             # Might be a file rather than a dir
-            filename = h.really_unicode(request.environ['PATH_INFO'].rsplit(str('/'))[-1])
+            filename = h.really_unicode(request.path_info.rsplit(str('/'))[-1])
             if filename:
                 try:
                     obj = self._tree[filename]
@@ -809,7 +809,7 @@ class TreeBrowser(BaseController, DispatchIndex):
                         self._tree,
                         filename), rest
         elif rest == ('index', ):
-            rest = (request.environ['PATH_INFO'].rsplit(str('/'))[-1],)
+            rest = (request.path_info.rsplit(str('/'))[-1],)
         try:
             tree = self._tree[next]
         except KeyError:
@@ -899,10 +899,11 @@ class FileBrowser(BaseController):
             diff = "Cannot display: file marked as a binary type."
             return dict(a=a, b=b, diff=diff)
 
-        la = list(a)
-        lb = list(b)
-        adesc = ('a' + h.really_unicode(apath)).encode('utf-8')
-        bdesc = ('b' + h.really_unicode(b.path())).encode('utf-8')
+        # could consider making Blob.__iter__ do unicode conversion?
+        la = [h.really_unicode(line) for line in a]
+        lb = [h.really_unicode(line) for line in b]
+        adesc = 'a' + h.really_unicode(apath)
+        bdesc = 'b' + h.really_unicode(b.path())
 
         if not fmt:
             fmt = web_session.get('diformat', '')
diff --git a/ForgeGit/forgegit/model/git_repo.py b/ForgeGit/forgegit/model/git_repo.py
index 11638f3..7c5827b 100644
--- a/ForgeGit/forgegit/model/git_repo.py
+++ b/ForgeGit/forgegit/model/git_repo.py
@@ -353,7 +353,7 @@ class GitImplementation(M.RepositoryImplementation):
         If id_only is True, returns only the commit ID, otherwise it returns
         detailed information about each commit.
         """
-        path = path.strip('/').encode("utf-8") if path else None
+        path = path.strip('/') if path else None
         if exclude is not None:
             revs.extend(['^%s' % e for e in exclude])
         args = ['--follow', '--name-status', revs, '--', path or '.']
@@ -634,7 +634,7 @@ class GitImplementation(M.RepositoryImplementation):
         skip = 0
         while commit_id and not files:
             output = self._git.git.log(
-                commit_id, '--', *[p.encode('utf-8') for p in paths],
+                commit_id, '--', *[p for p in paths],
                 pretty='format:%H',
                 name_only=True,
                 max_count=1,
diff --git a/ForgeGit/forgegit/tests/functional/test_controllers.py b/ForgeGit/forgegit/tests/functional/test_controllers.py
index c5050c7..f65a823 100644
--- a/ForgeGit/forgegit/tests/functional/test_controllers.py
+++ b/ForgeGit/forgegit/tests/functional/test_controllers.py
@@ -302,13 +302,13 @@ class TestRootController(_TestCase):
         url = ci + 'tree/' + h.urlquote('with%2Furlquote-literal.txt') + '?format=raw'
         resp = self.app.get(url)
         assert_in('%2F means /', resp.body.decode('utf-8'))
-        assert_equal(resp.headers.get('Content-Disposition').decode('utf-8'),
+        assert_equal(resp.headers.get('Content-Disposition'),
                      'attachment;filename="with%252Furlquote-literal.txt"')
 
         url = ci + 'tree/' + h.urlquote('with"&:specials.txt') + '?format=raw'
         resp = self.app.get(url)
         assert_in('"&: encodes as %22%26%3A', resp.body.decode('utf-8'))
-        assert_equal(resp.headers.get('Content-Disposition').decode('utf-8'),
+        assert_equal(resp.headers.get('Content-Disposition'),
                      'attachment;filename="with%22%26%3Aspecials.txt"')
 
     def test_invalid_file(self):
diff --git a/ForgeGit/forgegit/tests/model/test_repository.py b/ForgeGit/forgegit/tests/model/test_repository.py
index 30672f3..39b055c 100644
--- a/ForgeGit/forgegit/tests/model/test_repository.py
+++ b/ForgeGit/forgegit/tests/model/test_repository.py
@@ -748,7 +748,7 @@ By Dave Brondsema''', text_body)
         tmp_repo.git.checkout.assert_called_once_with('target-branch')
         assert_equal(
             tmp_repo.git.config.call_args_list,
-            [mock.call('user.name', 'Test Admin'),
+            [mock.call('user.name', b'Test Admin'),
              mock.call('user.email', 'allura@localhost')])
         msg = 'Merge downstream-repo-url branch source-branch into target-branch'
         msg += '\n\nhttp://localhost/merge-request/1/'


[allura] 14/16: [#8375] don't use a direct keys() view when mutating a dict in a loop

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8375
in repository https://gitbox.apache.org/repos/asf/allura.git

commit 833cbf0b4de8e0b42cf47fba7dc724521fc5d747
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Wed Aug 26 16:48:40 2020 -0400

    [#8375] don't use a direct keys() view when mutating a dict in a loop
---
 Allura/allura/lib/decorators.py           | 2 +-
 Allura/allura/model/neighborhood.py       | 2 +-
 ForgeTracker/forgetracker/tracker_main.py | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Allura/allura/lib/decorators.py b/Allura/allura/lib/decorators.py
index 7eaeb22..7197748 100644
--- a/Allura/allura/lib/decorators.py
+++ b/Allura/allura/lib/decorators.py
@@ -178,7 +178,7 @@ def memoize_cleanup(obj):
     """
     Remove any _memoize_dic_* keys (if obj is a dict/obj hybrid) that were created by @memoize on methods
     """
-    for k in obj.keys():
+    for k in list(obj.keys()):
         if k.startswith('_memoize_dic'):
             del obj[k]
 
diff --git a/Allura/allura/model/neighborhood.py b/Allura/allura/model/neighborhood.py
index 74c18ac..33170fb 100644
--- a/Allura/allura/model/neighborhood.py
+++ b/Allura/allura/model/neighborhood.py
@@ -241,7 +241,7 @@ class Neighborhood(MappedClass):
     @staticmethod
     def compile_css_for_picker(css_form_dict):
         # Check css values
-        for key in css_form_dict.keys():
+        for key in list(css_form_dict.keys()):
             if ';' in css_form_dict[key] or '}' in css_form_dict[key]:
                 css_form_dict[key] = ''
 
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index 3b116c9..7588ecc 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -1707,7 +1707,7 @@ class TrackerAdminController(DefaultAdminController):
     @expose()
     @require_post()
     def allow_default_field(self, **post_data):
-        for column in self.app.globals['show_in_search'].keys():
+        for column in list(self.app.globals['show_in_search'].keys()):
             if post_data.get(column) == 'on':
                 self.app.globals['show_in_search'][column] = True
             else:


[allura] 15/16: [#8375] tracker fixes

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8375
in repository https://gitbox.apache.org/repos/asf/allura.git

commit 727d750b938bcffd63d8a677a4325673af9d17a9
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Wed Aug 26 16:48:56 2020 -0400

    [#8375] tracker fixes
---
 Allura/allura/tests/decorators.py                        | 11 +++++++++++
 ForgeTracker/forgetracker/import_support.py              |  4 ++--
 ForgeTracker/forgetracker/model/ticket.py                | 15 +++++++++------
 ForgeTracker/forgetracker/tests/functional/test_root.py  | 16 +++++++++-------
 .../forgetracker/tests/unit/test_ticket_model.py         | 16 ++++++++--------
 ForgeTracker/forgetracker/tracker_main.py                |  4 ++--
 6 files changed, 41 insertions(+), 25 deletions(-)

diff --git a/Allura/allura/tests/decorators.py b/Allura/allura/tests/decorators.py
index 6a72710..28f6bb6 100644
--- a/Allura/allura/tests/decorators.py
+++ b/Allura/allura/tests/decorators.py
@@ -21,7 +21,9 @@ import sys
 import re
 from functools import wraps
 import contextlib
+from six.moves.urllib.parse import parse_qs
 
+from nose.tools import assert_equal
 from ming.orm.ormsession import ThreadLocalORMSession
 from tg import tmpl_context as c
 from mock import patch
@@ -220,3 +222,12 @@ def assert_logmsg_and_no_warnings_or_errors(logs, msg):
         if r.levelno > logging.INFO:
             raise AssertionError('unexpected log {} {}'.format(r.levelname, r.getMessage()))
     assert found_msg, 'Did not find {} in logs: {}'.format(msg, '\n'.join([r.getMessage() for r in logs.records]))
+
+
+def assert_equivalent_urls(url1, url2):
+    base1, _, qs1 = url1.partition('?')
+    base2, _, qs2 = url2.partition('?')
+    assert_equal(
+        (base1, parse_qs(qs1)),
+        (base2, parse_qs(qs2)),
+    )
diff --git a/ForgeTracker/forgetracker/import_support.py b/ForgeTracker/forgetracker/import_support.py
index 3a482c6..d643134 100644
--- a/ForgeTracker/forgetracker/import_support.py
+++ b/ForgeTracker/forgetracker/import_support.py
@@ -73,11 +73,11 @@ class ResettableStream(object):
 
     def read(self, size=-1):
         self._read_header()
-        data = ''
+        data = b''
         if self.buf_pos < self.stream_pos:
             data = self.buf.read(size)
             self.buf_pos += len(data)
-            if len(data) == size:
+            if len(data) == size or size == -1:
                 return data
             size -= len(data)
 
diff --git a/ForgeTracker/forgetracker/model/ticket.py b/ForgeTracker/forgetracker/model/ticket.py
index 36b252f..0efbdca 100644
--- a/ForgeTracker/forgetracker/model/ticket.py
+++ b/ForgeTracker/forgetracker/model/ticket.py
@@ -390,8 +390,7 @@ class Globals(MappedClass):
         for ticket in tickets:
             message = ''
             if labels:
-                values['labels'] = self.append_new_labels(
-                    ticket.labels, labels.split(','))
+                values['labels'] = self.append_new_labels(ticket.labels, labels.split(','))
             for k, v in sorted(six.iteritems(values)):
                 if k == 'deleted':
                     if v:
@@ -533,9 +532,13 @@ class Globals(MappedClass):
         return filtered
 
     def append_new_labels(self, old_labels, new_labels):
-        old_labels = set(old_labels)
-        new_labels = set(l.strip() for l in new_labels)
-        return list(old_labels | new_labels)
+        # append without duplicating any.  preserve order
+        labels = old_labels[:]  # make copy to ensure no edits to possible underlying model field
+        for l in new_labels:
+            l = l.strip()
+            if l not in old_labels:
+                labels.append(l)
+        return labels
 
 
 class TicketHistory(Snapshot):
@@ -850,7 +853,7 @@ class Ticket(VersionedArtifact, ActivityObject, VotableArtifact):
             role_developer = ProjectRole.by_name('Developer')
             role_creator = ProjectRole.by_user(self.reported_by, upsert=True) if self.reported_by else None
             def _allow_all(role, perms):
-                return [ACE.allow(role._id, perm) for perm in perms]
+                return [ACE.allow(role._id, perm) for perm in sorted(perms)]  # sorted just for consistency (for tests)
             # maintain existing access for developers and the ticket creator,
             # but revoke all access for everyone else
             acl = _allow_all(role_developer, security.all_allowed(self, role_developer))
diff --git a/ForgeTracker/forgetracker/tests/functional/test_root.py b/ForgeTracker/forgetracker/tests/functional/test_root.py
index eb341cc..bb6ff6f 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_root.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_root.py
@@ -45,6 +45,7 @@ from tg import tmpl_context as c
 from tg import app_globals as g
 from tg import config
 
+from allura.tests.decorators import assert_equivalent_urls
 from allura.tests.test_globals import squish_spaces
 from alluratest.controller import TestController, setup_basic_test
 from allura import model as M
@@ -1623,7 +1624,7 @@ class TestFunctionalController(TrackerTestController):
         edit_link = response.html.find('a', {'title': 'Bulk Edit'})
         expected_link = "/p/test/bugs/edit/?q=%21status%3Awont-fix+%26%26+%21status%3Aclosed"\
                         "&sort=snippet_s+asc&limit=25&filter=&page=0"
-        assert_equal(expected_link, edit_link['href'])
+        assert_equivalent_urls(expected_link, edit_link['href'])
         response = self.app.get(edit_link['href'])
         ticket_rows = response.html.find('tbody', {'class': 'ticket-list'})
         assert_in('test first ticket', ticket_rows.text)
@@ -1646,7 +1647,7 @@ class TestFunctionalController(TrackerTestController):
         assert_in('test third ticket', ticket_rows.text)
         edit_link = response.html.find('a', {'title': 'Bulk Edit'})
         expected_link = "/p/test/bugs/edit/?q=_milestone%3A1.0&sort=ticket_num_i+asc&limit=25&filter=&page=0"
-        assert_equal(expected_link, edit_link['href'])
+        assert_equivalent_urls(expected_link, edit_link['href'])
         response = self.app.get(edit_link['href'])
         ticket_rows = response.html.find('tbody', {'class': 'ticket-list'})
         assert_in('test first ticket', ticket_rows.text)
@@ -1667,7 +1668,7 @@ class TestFunctionalController(TrackerTestController):
         assert_false('test third ticket' in ticket_rows.text)
         edit_link = response.html.find('a', {'title': 'Bulk Edit'})
         expected_link = "/p/test/bugs/edit/?q=status%3Aopen&limit=25&filter=%7B%7D&page=0"
-        assert_equal(expected_link, edit_link['href'])
+        assert_equivalent_urls(expected_link, edit_link['href'])
         response = self.app.get(edit_link['href'])
         ticket_rows = response.html.find('tbody', {'class': 'ticket-list'})
         assert_in('test first ticket', ticket_rows.text)
@@ -1983,19 +1984,19 @@ class TestFunctionalController(TrackerTestController):
         # invalid vote
         r = self.app.post('/bugs/1/vote', dict(vote='invalid'))
         expected_resp = json.dumps(dict(status='error', votes_up=0, votes_down=0, votes_percent=0))
-        assert r.response.content == expected_resp
+        assert_equal(r.response.text, expected_resp)
 
         # vote up
         r = self.app.post('/bugs/1/vote', dict(vote='u'))
         expected_resp = json.dumps(dict(status='ok', votes_up=1, votes_down=0, votes_percent=100))
-        assert r.response.content == expected_resp
+        assert_equal(r.response.text, expected_resp)
 
         # vote down by another user
         r = self.app.post('/bugs/1/vote', dict(vote='d'),
                           extra_environ=dict(username=str('test-user-0')))
 
         expected_resp = json.dumps(dict(status='ok', votes_up=1, votes_down=1, votes_percent=50))
-        assert r.response.content == expected_resp
+        assert_equal(r.response.text, expected_resp)
 
         # make sure that on the page we see the same result
         r = self.app.get('/bugs/1/')
@@ -2949,7 +2950,8 @@ class TestHelpTextOptions(TrackerTestController):
         assert len(r.html.findAll(attrs=dict(id='new-ticket-help-msg'))) == 0
 
 
-class test_show_default_fields(TrackerTestController):
+class TestShowDefaultFields(TrackerTestController):
+
     def test_show_default_fields(self):
         r = self.app.get('/admin/bugs/fields')
         assert '<td>Ticket Number</td> <td><input type="checkbox" name="ticket_num" checked ></td>' in r
diff --git a/ForgeTracker/forgetracker/tests/unit/test_ticket_model.py b/ForgeTracker/forgetracker/tests/unit/test_ticket_model.py
index 149cc8a..f1ca974 100644
--- a/ForgeTracker/forgetracker/tests/unit/test_ticket_model.py
+++ b/ForgeTracker/forgetracker/tests/unit/test_ticket_model.py
@@ -139,17 +139,17 @@ class TestTicketModel(TrackerTestWithModel):
 
         t.private = True
         assert_equal(t.acl, [
-            ACE.allow(role_developer, 'save_searches'),
-            ACE.allow(role_developer, 'read'),
             ACE.allow(role_developer, 'create'),
-            ACE.allow(role_developer, 'update'),
-            ACE.allow(role_developer, 'unmoderated_post'),
-            ACE.allow(role_developer, 'post'),
-            ACE.allow(role_developer, 'moderate'),
             ACE.allow(role_developer, 'delete'),
-            ACE.allow(role_creator, 'read'),
-            ACE.allow(role_creator, 'post'),
+            ACE.allow(role_developer, 'moderate'),
+            ACE.allow(role_developer, 'post'),
+            ACE.allow(role_developer, 'read'),
+            ACE.allow(role_developer, 'save_searches'),
+            ACE.allow(role_developer, 'unmoderated_post'),
+            ACE.allow(role_developer, 'update'),
             ACE.allow(role_creator, 'create'),
+            ACE.allow(role_creator, 'post'),
+            ACE.allow(role_creator, 'read'),
             ACE.allow(role_creator, 'unmoderated_post'),
             DENY_ALL])
         assert has_access(t, 'read', user=admin)()
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index 7588ecc..d3228e6 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -864,7 +864,7 @@ class RootController(BaseController, FeedController):
         else:
             feed = FG.Rss201rev2Feed(**d)
         for t in result['tickets']:
-            url = h.absurl(t.url().encode('utf-8'))
+            url = h.absurl(t.url())
             feed_kwargs = dict(title=t.summary,
                                link=url,
                                pubdate=t.mod_date,
@@ -1920,7 +1920,7 @@ class MilestoneController(BaseController):
         else:
             raise exc.HTTPNotFound()
         for m in fld.milestones:
-            if m.name == unquote(milestone).decode('utf-8'):
+            if m.name == six.ensure_text(unquote(milestone)):
                 break
         else:
             raise exc.HTTPNotFound()


[allura] 16/16: [#8375] svn fixes

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8375
in repository https://gitbox.apache.org/repos/asf/allura.git

commit 352c3295ec3dd3f0696ec8352d68eb2ad5e397f7
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Thu Aug 27 15:43:12 2020 -0400

    [#8375] svn fixes
---
 Allura/allura/model/repository.py                | 3 ++-
 ForgeSVN/forgesvn/model/svn.py                   | 9 +++++----
 ForgeSVN/forgesvn/tests/model/test_repository.py | 3 +--
 3 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/Allura/allura/model/repository.py b/Allura/allura/model/repository.py
index e858947..4fbb768 100644
--- a/Allura/allura/model/repository.py
+++ b/Allura/allura/model/repository.py
@@ -19,6 +19,7 @@ from __future__ import absolute_import
 import json
 import os
 import stat
+from operator import itemgetter
 import mimetypes
 import logging
 import string
@@ -1207,7 +1208,7 @@ class Commit(RepoObject, ActivityObject):
             added=sorted(diffs['added']),
             removed=sorted(diffs['removed']),
             changed=sorted(diffs['changed']),
-            copied=sorted(diffs['copied']),
+            copied=sorted(diffs['copied'], key=itemgetter('new', 'old')),  # this is a list of dicts
             renamed=sorted(diffs['renamed']),
             total=diffs['total'])
 
diff --git a/ForgeSVN/forgesvn/model/svn.py b/ForgeSVN/forgesvn/model/svn.py
index a01fdd4..5b40b5d 100644
--- a/ForgeSVN/forgesvn/model/svn.py
+++ b/ForgeSVN/forgesvn/model/svn.py
@@ -32,6 +32,7 @@ from datetime import datetime
 import tempfile
 from shutil import rmtree
 
+import six
 import tg
 import pysvn
 from paste.deploy.converters import asbool, asint
@@ -218,12 +219,12 @@ class SVNImplementation(M.RepositoryImplementation):
         # check for svn version 1.7 or later
         stdout, stderr, returncode = self.check_call(['svn', '--version'])
         pattern = r'version (?P<maj>\d+)\.(?P<min>\d+)'
-        m = re.search(pattern, stdout)
+        m = re.search(pattern, six.ensure_text(stdout))
         return m and (int(m.group('maj')) * 10 + int(m.group('min'))) >= 17
 
     def check_call(self, cmd, fail_on_error=True):
         p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
-        stdout, stderr = p.communicate(input='p\n')
+        stdout, stderr = p.communicate(input=b'p\n')
         if p.returncode != 0 and fail_on_error:
             self._repo.set_status('ready')
             raise SVNCalledProcessError(cmd, p.returncode, stdout, stderr)
@@ -236,7 +237,7 @@ class SVNImplementation(M.RepositoryImplementation):
         def set_hook(hook_name):
             fn = os.path.join(self._repo.fs_path, self._repo.name,
                               'hooks', hook_name)
-            with open(fn, 'wb') as fp:
+            with open(fn, 'w') as fp:
                 fp.write('#!/bin/sh\n')
             os.chmod(fn, 0o755)
 
@@ -611,7 +612,7 @@ class SVNImplementation(M.RepositoryImplementation):
             url=self._repo.refresh_url())
         fn = os.path.join(self._repo.fs_path, self._repo.name,
                           'hooks', 'post-commit')
-        with open(fn, 'wb') as fp:
+        with open(fn, 'w') as fp:
             fp.write(text)
         os.chmod(fn, 0o755)
 
diff --git a/ForgeSVN/forgesvn/tests/model/test_repository.py b/ForgeSVN/forgesvn/tests/model/test_repository.py
index 6cd8976..14e6602 100644
--- a/ForgeSVN/forgesvn/tests/model/test_repository.py
+++ b/ForgeSVN/forgesvn/tests/model/test_repository.py
@@ -682,8 +682,7 @@ class _Test(unittest.TestCase):
             # BSON datetime resolution is to 1 millisecond, not 1 microsecond
             # like Python. Round this now so it'll match the value that's
             # pulled from MongoDB in the tests.
-            ci.authored.date = dt.replace(
-                microsecond=dt.microsecond / 1000 * 1000)
+            ci.authored.date = dt.replace(microsecond=dt.microsecond // 1000 * 1000)
             ci.message = 'summary\n\nddescription'
             ci.set_context(self.repo)
             ci.tree_id = 't_' + object_id


[allura] 03/16: [#8375] for json dumping to temp files, set mode to not binary

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8375
in repository https://gitbox.apache.org/repos/asf/allura.git

commit 8a17b6fffe6e4359fdf4a9019217dbd268bb60ae
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Mon Aug 24 17:53:38 2020 -0400

    [#8375] for json dumping to temp files, set mode to not binary
---
 ForgeBlog/forgeblog/tests/test_app.py             | 4 ++--
 ForgeDiscussion/forgediscussion/tests/test_app.py | 4 ++--
 ForgeLink/forgelink/tests/test_app.py             | 2 +-
 ForgeTracker/forgetracker/tests/test_app.py       | 4 ++--
 ForgeWiki/forgewiki/tests/test_app.py             | 6 +++---
 5 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/ForgeBlog/forgeblog/tests/test_app.py b/ForgeBlog/forgeblog/tests/test_app.py
index 26089b9..8c92ec0 100644
--- a/ForgeBlog/forgeblog/tests/test_app.py
+++ b/ForgeBlog/forgeblog/tests/test_app.py
@@ -82,7 +82,7 @@ class TestBulkExport(object):
             post2.make_slug()
             post2.commit()
 
-        f = tempfile.TemporaryFile()
+        f = tempfile.TemporaryFile('w+')
         blog.bulk_export(f)
         f.seek(0)
         blog = json.loads(f.read())
@@ -116,7 +116,7 @@ class TestBulkExport(object):
             p = post.discussion_thread.add_post(text='test comment')
             p.add_multiple_attachments(test_file1)
             ThreadLocalORMSession.flush_all()
-        f = tempfile.TemporaryFile()
+        f = tempfile.TemporaryFile('w+')
         temp_dir = tempfile.mkdtemp()
         blog.bulk_export(f, temp_dir, True)
         f.seek(0)
diff --git a/ForgeDiscussion/forgediscussion/tests/test_app.py b/ForgeDiscussion/forgediscussion/tests/test_app.py
index 30f9d90..9495b6f 100644
--- a/ForgeDiscussion/forgediscussion/tests/test_app.py
+++ b/ForgeDiscussion/forgediscussion/tests/test_app.py
@@ -64,7 +64,7 @@ class TestBulkExport(TestDiscussionApiBase):
 
         project = M.Project.query.get(shortname='test')
         discussion = project.app_instance('discussion')
-        f = tempfile.TemporaryFile()
+        f = tempfile.TemporaryFile('w+')
         discussion.bulk_export(f)
         f.seek(0)
         discussion = json.loads(f.read())
@@ -100,7 +100,7 @@ class TestBulkExport(TestDiscussionApiBase):
         post.add_attachment(test_file1)
         ThreadLocalORMSession.flush_all()
 
-        f = tempfile.TemporaryFile()
+        f = tempfile.TemporaryFile('w+')
         temp_dir = tempfile.mkdtemp()
         discussion.bulk_export(f, temp_dir, True)
         f.seek(0)
diff --git a/ForgeLink/forgelink/tests/test_app.py b/ForgeLink/forgelink/tests/test_app.py
index 310a4d2..1055f81 100644
--- a/ForgeLink/forgelink/tests/test_app.py
+++ b/ForgeLink/forgelink/tests/test_app.py
@@ -42,7 +42,7 @@ class TestBulkExport(object):
         project = M.Project.query.get(shortname='test')
         link = project.app_instance('link')
         link.config.options['url'] = 'http://domain.net'
-        f = tempfile.TemporaryFile()
+        f = tempfile.TemporaryFile('w+')
         link.bulk_export(f)
         f.seek(0)
         assert_equal(json.loads(f.read())['url'], 'http://domain.net')
diff --git a/ForgeTracker/forgetracker/tests/test_app.py b/ForgeTracker/forgetracker/tests/test_app.py
index 5053990..72c64cd 100644
--- a/ForgeTracker/forgetracker/tests/test_app.py
+++ b/ForgeTracker/forgetracker/tests/test_app.py
@@ -111,7 +111,7 @@ class TestBulkExport(TrackerTestController):
         # Besides, core functionality shouldn't need the c context vars
         c.app = c.project = None
 
-        f = tempfile.TemporaryFile()
+        f = tempfile.TemporaryFile('w+')
         self.tracker.bulk_export(f)
         f.seek(0)
         tracker = json.loads(f.read())
@@ -141,7 +141,7 @@ class TestBulkExport(TrackerTestController):
 
     def test_export_with_attachments(self):
 
-        f = tempfile.TemporaryFile()
+        f = tempfile.TemporaryFile('w+')
         temp_dir = tempfile.mkdtemp()
         self.tracker.bulk_export(f, temp_dir, True)
         f.seek(0)
diff --git a/ForgeWiki/forgewiki/tests/test_app.py b/ForgeWiki/forgewiki/tests/test_app.py
index d7f80e8..66b11b9 100644
--- a/ForgeWiki/forgewiki/tests/test_app.py
+++ b/ForgeWiki/forgewiki/tests/test_app.py
@@ -69,7 +69,7 @@ class TestBulkExport(object):
         # Besides, it's better not to need c context vars
         c.app = c.project = None
 
-        f = tempfile.TemporaryFile()
+        f = tempfile.TemporaryFile('w+')
         self.wiki.bulk_export(f)
         f.seek(0)
         wiki = json.loads(f.read())
@@ -102,7 +102,7 @@ class TestBulkExport(object):
     def test_bulk_export_with_attachmetns(self):
         self.add_page_with_attachmetns()
         temp_dir = tempfile.mkdtemp()
-        f = tempfile.TemporaryFile(dir=temp_dir)
+        f = tempfile.TemporaryFile('w+', dir=temp_dir)
         self.wiki.bulk_export(f, temp_dir, True)
         f.seek(0)
         wiki = json.loads(f.read())
@@ -116,7 +116,7 @@ class TestBulkExport(object):
     def test_bulk_export_without_attachments(self):
         self.add_page_with_attachmetns()
         temp_dir = tempfile.mkdtemp()
-        f = tempfile.TemporaryFile(dir=temp_dir)
+        f = tempfile.TemporaryFile('w+', dir=temp_dir)
         self.wiki.bulk_export(f, temp_dir)
         f.seek(0)
         wiki = json.loads(f.read())


[allura] 12/16: [#8375] url quoting fixes

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8375
in repository https://gitbox.apache.org/repos/asf/allura.git

commit 745601001484d372261e602eb5cdf115e8389958
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Wed Aug 26 12:55:22 2020 -0400

    [#8375] url quoting fixes
---
 ForgeLink/forgelink/link_main.py                  |  2 +-
 ForgeLink/forgelink/tests/functional/test_rest.py | 14 +++++++-------
 ForgeLink/forgelink/tests/functional/test_root.py |  6 ++++--
 ForgeWiki/forgewiki/tests/functional/test_rest.py |  4 ++--
 4 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/ForgeLink/forgelink/link_main.py b/ForgeLink/forgelink/link_main.py
index ef2dcb0..964ea24 100644
--- a/ForgeLink/forgelink/link_main.py
+++ b/ForgeLink/forgelink/link_main.py
@@ -135,7 +135,7 @@ class RootController(BaseController):
         if url:
             # h.urlquote is better than utf8 encoding for Location headers, but in this case the url can be a full
             # http://... url and we don't want to urlquote/urlencode that part
-            redirect(url + h.really_unicode(path).encode('utf-8'))
+            redirect(url + h.really_unicode(path))
         return dict()
 
 
diff --git a/ForgeLink/forgelink/tests/functional/test_rest.py b/ForgeLink/forgelink/tests/functional/test_rest.py
index 7d5c419..c93f2c5 100644
--- a/ForgeLink/forgelink/tests/functional/test_rest.py
+++ b/ForgeLink/forgelink/tests/functional/test_rest.py
@@ -37,20 +37,20 @@ class TestLinkApi(TestRestApiBase):
         h.set_context('test', 'link', neighborhood='Projects')
 
     def test_rest_link(self):
-        r = self.api_get('/rest/p/test/link'.encode('utf-8'))
+        r = self.api_get('/rest/p/test/link')
         assert_equal(r.json['url'], None)
 
-        r = self.api_post('/rest/p/test/link'.encode('utf-8'),
+        r = self.api_post('/rest/p/test/link',
                           url='http://google.com')
         assert_equal(r.json['url'], 'http://google.com')
 
-        self.api_post('/rest/p/test/link'.encode('utf-8'),
+        self.api_post('/rest/p/test/link',
                       url='http://yahoo.com')
-        r = self.api_get('/rest/p/test/link'.encode('utf-8'))
+        r = self.api_get('/rest/p/test/link')
         assert_equal(r.json['url'], 'http://yahoo.com')
 
-        self.api_post('/rest/p/test/link'.encode('utf-8'))
-        r = self.api_get('/rest/p/test/link'.encode('utf-8'))
+        self.api_post('/rest/p/test/link')
+        r = self.api_get('/rest/p/test/link')
         assert_equal(r.json['url'], 'http://yahoo.com')
 
     def test_rest_link_get_permissions(self):
@@ -78,7 +78,7 @@ class TestLinkApi(TestRestApiBase):
                       params={'url': 'http://yahoo.com'},
                       extra_environ={'username': str('*anonymous')},
                       status=200)
-        r = self.api_get('/rest/p/test/link'.encode('utf-8'))
+        r = self.api_get('/rest/p/test/link')
         assert_equal(r.json['url'], 'http://yahoo.com')
 
 
diff --git a/ForgeLink/forgelink/tests/functional/test_root.py b/ForgeLink/forgelink/tests/functional/test_root.py
index 527178a..fe2f1c3 100644
--- a/ForgeLink/forgelink/tests/functional/test_root.py
+++ b/ForgeLink/forgelink/tests/functional/test_root.py
@@ -1,3 +1,4 @@
+# coding=utf-8
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information
@@ -22,6 +23,7 @@ import json
 from nose.tools import assert_equal, assert_in
 
 from allura import model as M
+from allura.lib import helpers as h
 from allura.tests import decorators as td
 from alluratest.controller import TestController
 
@@ -61,8 +63,8 @@ class TestRootController(TestController):
         response = self.app.get('/admin/link/options', validate_chunk=True)
         response.form['url'] = 'http://www.google.de/search?q='
         response.form.submit()
-        redir = self.app.get('/link/help', status=302)
-        assert_equal(redir.location, 'http://www.google.de/search?q=help')
+        redir = self.app.get(h.urlquote('/link/helpåß'), status=302)
+        assert_equal(redir.location, 'http://www.google.de/search?q=help%C3%A5%C3%9F')
 
 
 class TestConfigOptions(TestController):
diff --git a/ForgeWiki/forgewiki/tests/functional/test_rest.py b/ForgeWiki/forgewiki/tests/functional/test_rest.py
index 44b697f..e15f90f 100644
--- a/ForgeWiki/forgewiki/tests/functional/test_rest.py
+++ b/ForgeWiki/forgewiki/tests/functional/test_rest.py
@@ -85,9 +85,9 @@ class TestWikiApi(TestRestApiBase):
             'text': 'Embrace the Dark Side',
             'labels': 'head hunting,dark side'
         }
-        r = self.api_post('/rest/p/test/wiki/tést/'.encode('utf-8'), **data)
+        r = self.api_post(h.urlquote('/rest/p/test/wiki/tést/'), **data)
         assert_equal(r.status_int, 200)
-        r = self.api_get('/rest/p/test/wiki/tést/'.encode('utf-8'))
+        r = self.api_get(h.urlquote('/rest/p/test/wiki/tést/'))
         assert_equal(r.json['text'], data['text'])
         assert_equal(r.json['labels'], data['labels'].split(','))
 


[allura] 06/16: [#8375] requirements fine-tuning

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8375
in repository https://gitbox.apache.org/repos/asf/allura.git

commit 886cd0d962fc4fc0661313830b991135a0875ae8
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Tue Aug 25 11:37:54 2020 -0400

    [#8375] requirements fine-tuning
---
 requirements.in  | 2 ++
 requirements.txt | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/requirements.in b/requirements.in
index af2dc8d..a4da5a0 100644
--- a/requirements.in
+++ b/requirements.in
@@ -8,6 +8,8 @@ cryptography==2.6.1
 decorator
 EasyWidgets>=0.3.6
 emoji
+# only needed < py3.4 and causes problems >=3.6 https://stackoverflow.com/a/45716067/
+enum34 ; python_version < "3.4"
 faulthandler ; python_version < "3.3"
 feedgenerator
 feedparser
diff --git a/requirements.txt b/requirements.txt
index fcc1a31..ec7dc38 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -24,7 +24,7 @@ decorator==4.4.0          # via -r requirements.in, ipython, traitlets
 docutils==0.15.2          # via pypeline
 easywidgets==0.3.6        # via -r requirements.in
 emoji==0.5.3              # via -r requirements.in
-enum34==1.1.6             # via colander, cryptography, traitlets
+enum34==1.1.6 ; python_version < "3.4"  # via -r requirements.in, colander, cryptography, traitlets
 faulthandler==3.1 ; python_version < "3.3"  # via -r requirements.in
 feedgenerator==1.9.1      # via -r requirements.in
 feedparser==5.2.1         # via -r requirements.in


[allura] 09/16: [#8375] hide_private_info Markup py3 fix

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8375
in repository https://gitbox.apache.org/repos/asf/allura.git

commit 8c27232091819e056b60d035ee049281c302ae56
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Tue Aug 25 17:00:44 2020 -0400

    [#8375] hide_private_info Markup py3 fix
---
 Allura/allura/lib/helpers.py        | 6 +++++-
 Allura/allura/tests/test_helpers.py | 3 +++
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index 1bcff39..fd660ad 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -1271,7 +1271,11 @@ email_re = re.compile(r'(([a-z0-9_]|\-|\.)+)@([\w\.-]+)', re.IGNORECASE)
 
 def hide_private_info(message):
     if asbool(tg.config.get('hide_private_info', 'true')) and message:
-        return email_re.sub(r'\1@...', message)
+        hidden = email_re.sub(r'\1@...', message)
+        if type(message) not in six.string_types:
+            # custom subclass like markupsafe.Markup, convert to that type again
+            hidden = type(message)(hidden)
+        return hidden
     else:
         return message
 
diff --git a/Allura/allura/tests/test_helpers.py b/Allura/allura/tests/test_helpers.py
index 4b84bce..0206b02 100644
--- a/Allura/allura/tests/test_helpers.py
+++ b/Allura/allura/tests/test_helpers.py
@@ -665,6 +665,9 @@ def test_hide_private_info():
     assert_equals(h.hide_private_info(''), '')
     assert_equals(h.hide_private_info('foo bar baz@bing.com'), 'foo bar baz@...')
     assert_equals(h.hide_private_info('some <1...@2.com>\nor asdf+asdf.f@g.f.x'), 'some <1...@...>\nor asdf+asdf.f@...')
+    safe_markup_converted = h.hide_private_info(Markup('foo bar baz@bing.com'))
+    assert_equals(type(safe_markup_converted), Markup)
+    assert_equals(safe_markup_converted, Markup('foo bar baz@...'))
 
     with h.push_config(h.tg.config, hide_private_info=False):
         assert_equals(h.hide_private_info('foo bar baz@bing.com'), 'foo bar baz@bing.com')


[allura] 11/16: [#8375] ForgeImporters test fixes for py3

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8375
in repository https://gitbox.apache.org/repos/asf/allura.git

commit f6cfee7eece810ea7cecb5fb6a6b937ab9afb042
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Tue Aug 25 18:02:03 2020 -0400

    [#8375] ForgeImporters test fixes for py3
---
 .../forgeimporters/tests/github/test_extractor.py  | 22 +++++++++++-----------
 .../forgeimporters/tests/github/test_tracker.py    |  4 ++--
 .../trac/tests/functional/test_trac.py             |  6 ++----
 3 files changed, 15 insertions(+), 17 deletions(-)

diff --git a/ForgeImporters/forgeimporters/tests/github/test_extractor.py b/ForgeImporters/forgeimporters/tests/github/test_extractor.py
index a3c16f8..42c9818 100644
--- a/ForgeImporters/forgeimporters/tests/github/test_extractor.py
+++ b/ForgeImporters/forgeimporters/tests/github/test_extractor.py
@@ -63,24 +63,24 @@ class TestGitHubProjectExtractor(TestCase):
     def mocked_urlopen(self, url):
         headers = {}
         if url.endswith('/test_project'):
-            response = BytesIO(json.dumps(self.PROJECT_INFO))
+            response = BytesIO(json.dumps(self.PROJECT_INFO).encode('utf-8'))
         elif url.endswith('/issues?state=closed'):
-            response = BytesIO(json.dumps(self.CLOSED_ISSUES_LIST))
+            response = BytesIO(json.dumps(self.CLOSED_ISSUES_LIST).encode('utf-8'))
         elif url.endswith('/issues?state=open'):
-            response = BytesIO(json.dumps(self.OPENED_ISSUES_LIST))
+            response = BytesIO(json.dumps(self.OPENED_ISSUES_LIST).encode('utf-8'))
             headers = {'Link': '</issues?state=open&page=2>; rel="next"'}
         elif url.endswith('/issues?state=open&page=2'):
-            response = BytesIO(json.dumps(self.OPENED_ISSUES_LIST_PAGE2))
+            response = BytesIO(json.dumps(self.OPENED_ISSUES_LIST_PAGE2).encode('utf-8'))
         elif url.endswith('/comments'):
-            response = BytesIO(json.dumps(self.ISSUE_COMMENTS))
+            response = BytesIO(json.dumps(self.ISSUE_COMMENTS).encode('utf-8'))
             headers = {'Link': '</comments?page=2>; rel="next"'}
         elif url.endswith('/comments?page=2'):
-            response = BytesIO(json.dumps(self.ISSUE_COMMENTS_PAGE2))
+            response = BytesIO(json.dumps(self.ISSUE_COMMENTS_PAGE2).encode('utf-8'))
         elif url.endswith('/events'):
-            response = BytesIO(json.dumps(self.ISSUE_EVENTS))
+            response = BytesIO(json.dumps(self.ISSUE_EVENTS).encode('utf-8'))
             headers = {'Link': '</events?page=2>; rel="next"'}
         elif url.endswith('/events?page=2'):
-            response = BytesIO(json.dumps(self.ISSUE_EVENTS_PAGE2))
+            response = BytesIO(json.dumps(self.ISSUE_EVENTS_PAGE2).encode('utf-8'))
 
         response.info = lambda: headers
         return response
@@ -167,7 +167,7 @@ class TestGitHubProjectExtractor(TestCase):
         response_ok.info = lambda: {}
         urlopen.side_effect = [response_limit_exceeded, response_ok]
         e = github.GitHubProjectExtractor('test_project')
-        e.get_page('fake')
+        e.get_page('http://example.com/')
         self.assertEqual(sleep.call_count, 1)
         self.assertEqual(urlopen.call_count, 2)
         log.warn.assert_called_once_with(
@@ -180,7 +180,7 @@ class TestGitHubProjectExtractor(TestCase):
         response_ok = BytesIO(b'{}')
         response_ok.info = lambda: {}
         urlopen.side_effect = [response_ok]
-        e.get_page('fake 2')
+        e.get_page('http://example.com/2')
         self.assertEqual(sleep.call_count, 0)
         self.assertEqual(urlopen.call_count, 1)
         self.assertEqual(log.warn.call_count, 0)
@@ -204,7 +204,7 @@ class TestGitHubProjectExtractor(TestCase):
                 'url', 403, 'msg', limit_exceeded_headers, BytesIO(b'{}'))
         urlopen.side_effect = urlopen_side_effect
         e = github.GitHubProjectExtractor('test_project')
-        e.get_page('fake')
+        e.get_page('http://example.com/')
         self.assertEqual(sleep.call_count, 1)
         self.assertEqual(urlopen.call_count, 2)
         log.warn.assert_called_once_with(
diff --git a/ForgeImporters/forgeimporters/tests/github/test_tracker.py b/ForgeImporters/forgeimporters/tests/github/test_tracker.py
index 4f241bf..8064045 100644
--- a/ForgeImporters/forgeimporters/tests/github/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/github/test_tracker.py
@@ -150,8 +150,8 @@ class TestTrackerImporter(TestCase):
             attachments[0].url, 'https://f.cloud.github.com/assets/979771/1027411/a393ab5e-0e70-11e3-8a38-b93a3df904cf.jpg')
         self.assertEqual(
             attachments[1].url, 'http://f.cl.ly/items/13453x43053r2G0d3x0v/Screen%20Shot%202012-04-28%20at%2010.48.17%20AM.png')
-        self.assertEqual(attachments[0].file.read(), 'data')
-        self.assertEqual(attachments[1].file.read(), 'data')
+        self.assertEqual(attachments[0].file.read(), b'data')
+        self.assertEqual(attachments[1].file.read(), b'data')
 
     def test_get_attachments_404(self):
         importer = tracker.GitHubTrackerImporter()
diff --git a/ForgeImporters/forgeimporters/trac/tests/functional/test_trac.py b/ForgeImporters/forgeimporters/trac/tests/functional/test_trac.py
index 86626f2..fa34cec 100644
--- a/ForgeImporters/forgeimporters/trac/tests/functional/test_trac.py
+++ b/ForgeImporters/forgeimporters/trac/tests/functional/test_trac.py
@@ -25,7 +25,6 @@ from allura.lib import helpers as h
 from allura.tests import TestController
 
 
-
 class TestTracImportController(TestController):
 
     def test_index(self):
@@ -49,11 +48,10 @@ class TestTracImportController(TestController):
                 r.status_int,
                 r.location,
                 self.webflash(r),
-                hasattr(r, 'html') and r.html.find('div', {'class': 'error'})
+                hasattr(r, 'html') and r.html.find_all('div', {'class': 'error'})
             )
 
-
     def test_import_with_phone_validation(self):
         self.app.extra_environ = {'username': str('test-user')}
         with h.push_config(config, **{'project.verify_phone': 'true'}):
-            self.test_submit()
\ No newline at end of file
+            self.test_submit()


[allura] 01/16: [#8375] various mail formatting/encoding fixes for py3

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8375
in repository https://gitbox.apache.org/repos/asf/allura.git

commit d32ccf8ba17a357783262a7cbbd0926f01dcc6b2
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Mon Aug 24 17:38:51 2020 -0400

    [#8375] various mail formatting/encoding fixes for py3
---
 Allura/allura/app.py                                |  2 +-
 Allura/allura/lib/mail_util.py                      |  2 +-
 Allura/allura/model/auth.py                         |  4 +++-
 Allura/allura/tests/functional/test_user_profile.py |  2 +-
 Allura/allura/tests/test_mail_util.py               |  2 +-
 Allura/allura/tests/test_tasks.py                   | 21 ++++++++++-----------
 .../forgediscussion/tests/functional/test_forum.py  |  3 +++
 7 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/Allura/allura/app.py b/Allura/allura/app.py
index ef751ef..fb59e52 100644
--- a/Allura/allura/app.py
+++ b/Allura/allura/app.py
@@ -736,7 +736,7 @@ class Application(object):
                 thread_id=thd._id,
                 post_id=message_id)
         else:
-            text = message['payload'] or '--no text body--'
+            text = six.ensure_text(message['payload']) or '--no text body--'
             post = thd.post(
                 message_id=message_id,
                 parent_id=parent_id,
diff --git a/Allura/allura/lib/mail_util.py b/Allura/allura/lib/mail_util.py
index 9d61333..3c417b4 100644
--- a/Allura/allura/lib/mail_util.py
+++ b/Allura/allura/lib/mail_util.py
@@ -201,7 +201,7 @@ def encode_email_part(content, content_type):
             # switch to Quoted-Printable encoding to avoid too-long lines
             # we could always Quoted-Printabl, but it makes the output a little messier and less human-readable
             # the particular order of all these operations seems to be very important for everything to end up right
-            msg = MIMEText(None, content_type)
+            msg = MIMEText('', content_type)
             msg.replace_header('content-transfer-encoding', 'quoted-printable')
             cs = email.charset.Charset('utf-8')
             cs.header_encoding = email.charset.QP
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index 10c6550..65e47dc 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -20,6 +20,7 @@ from __future__ import absolute_import
 import logging
 import calendar
 
+import six
 from markupsafe import Markup
 from six.moves.urllib.parse import urlparse
 from email import header
@@ -791,7 +792,8 @@ class User(MappedClass, ActivityNode, ActivityObject, SearchIndexable):
 
     def email_address_header(self):
         h = header.Header()
-        h.append('"%s" ' % self.get_pref('display_name'))
+        h.append('"%s"%s' % (self.get_pref('display_name'),
+                             ' ' if six.PY2 else ''))  # py2 needs explicit space for unicode/text_type cast of Header
         h.append('<%s>' % self.get_pref('email_address'))
         return h
 
diff --git a/Allura/allura/tests/functional/test_user_profile.py b/Allura/allura/tests/functional/test_user_profile.py
index 96162ca..4583da3 100644
--- a/Allura/allura/tests/functional/test_user_profile.py
+++ b/Allura/allura/tests/functional/test_user_profile.py
@@ -115,7 +115,7 @@ class TestUserProfile(TestController):
         response = self.app.get(
             '/u/test-user/profile/send_message', status=200)
         assert 'you currently have user messages disabled' not in response
-        assert '<b>From:</b> &#34;Test Admin&#34; &lt;test-admin@users.localhost&gt;' in response
+        response.mustcontain('<b>From:</b> &#34;Test Admin&#34; &lt;test-admin@users.localhost&gt;')
 
         self.app.post('/u/test-user/profile/send_user_message',
                       params={'subject': 'test subject',
diff --git a/Allura/allura/tests/test_mail_util.py b/Allura/allura/tests/test_mail_util.py
index 3c107be..7391aec 100644
--- a/Allura/allura/tests/test_mail_util.py
+++ b/Allura/allura/tests/test_mail_util.py
@@ -210,7 +210,7 @@ Content-Type: text/html; charset="utf-8"
         for part in msg2['parts']:
             if part['payload'] is None:
                 continue
-            assert isinstance(part['payload'], six.text_type)
+            assert isinstance(part['payload'], six.text_type), type(part['payload'])
 
 
 class TestHeader(object):
diff --git a/Allura/allura/tests/test_tasks.py b/Allura/allura/tests/test_tasks.py
index 6c82b52..bacf6c1 100644
--- a/Allura/allura/tests/test_tasks.py
+++ b/Allura/allura/tests/test_tasks.py
@@ -23,6 +23,8 @@ import operator
 import shutil
 import sys
 import unittest
+
+import six
 from base64 import b64encode
 import logging
 import pkg_resources
@@ -143,9 +145,6 @@ class TestEventTasks(unittest.TestCase):
         assert M.MonQTask.query.get(task_name='allura.tasks.event_tasks.event', args=['my_event4'])
 
     def test_compound_error(self):
-        '''test_compound_exception -- make sure our multi-exception return works
-        OK
-        '''
         t = raise_exc.post()
         with LogCapture(level=logging.ERROR) as l, \
                 mock.patch.dict(tg.config, {'monq.raise_errors': False}):  # match normal non-test behavior
@@ -153,8 +152,8 @@ class TestEventTasks(unittest.TestCase):
         # l.check() would be nice, but string is too detailed to check
         assert_equal(l.records[0].name, 'allura.model.monq_model')
         msg = l.records[0].getMessage()
-        assert_in("AssertionError('assert 0',)", msg)
-        assert_in("AssertionError('assert 5',)", msg)
+        assert_in("AssertionError('assert 0'", msg)
+        assert_in("AssertionError('assert 5'", msg)
         assert_in(' on job <MonQTask ', msg)
         assert_in(' (error) P:10 allura.tests.test_tasks.raise_exc ', msg)
         for x in range(10):
@@ -297,16 +296,16 @@ class TestMailTasks(unittest.TestCase):
             assert_in('Reply-To: %s' % g.noreply, body)
 
             # The address portion must not be encoded, only the name portion can be.
-            # Also it is apparently not necessary to have the double-quote separators present
-            # when the name portion is encoded.  That is, the encoding below is
-            # just По and not "По"
-            assert_in('From: =?utf-8?b?0J/Qvg==?= <fo...@bar.com>', body)
+            # Also py2 and py3 vary in handling of double-quote separators when the name portion is encoded
+            unquoted_cyrillic_No = '=?utf-8?b?0J/Qvg==?='  # По
+            quoted_cyrillic_No = '=?utf-8?b?ItCf0L4i?='  # "По"
+            assert ('From: {} <fo...@bar.com>'.format(quoted_cyrillic_No) in body or
+                    'From: {} <fo...@bar.com>'.format(unquoted_cyrillic_No) in body), body
             assert_in(
                 'Subject: =?utf-8?b?0J/QviDQvtC20LjQstC70ZHQvdC90YvQvCDQsdC10YDQtdCz0LDQvA==?=', body)
             assert_in('Content-Type: text/plain; charset="utf-8"', body)
             assert_in('Content-Transfer-Encoding: base64', body)
-            assert_in(
-                b64encode('Громады стройные теснятся'.encode('utf-8')), body)
+            assert_in(six.ensure_text(b64encode('Громады стройные теснятся'.encode('utf-8'))), body)
 
     def test_send_email_with_disabled_user(self):
         c.user = M.User.by_username('test-admin')
diff --git a/ForgeDiscussion/forgediscussion/tests/functional/test_forum.py b/ForgeDiscussion/forgediscussion/tests/functional/test_forum.py
index 657262a..a1d2614 100644
--- a/ForgeDiscussion/forgediscussion/tests/functional/test_forum.py
+++ b/ForgeDiscussion/forgediscussion/tests/functional/test_forum.py
@@ -212,12 +212,15 @@ class TestForumMessageHandling(TestController):
         assert_equal(FM.ForumPost.query.find().count(), 3)
 
     def test_attach(self):
+        # runs handle_artifact_message() with filename field
         self._post('testforum', 'Attachment Thread', 'This is text attachment',
                    message_id='test.attach.100@domain.net',
                    filename='test.txt',
                    content_type='text/plain')
+        # runs handle_artifact_message() where there's no post with given message_id yet
         self._post('testforum', 'Test Thread', b'Nothing here',
                    message_id='test.attach.100@domain.net')
+        # runs handle_artifact_message() where there IS a post with given message_id
         self._post('testforum', 'Attachment Thread', 'This is binary ¶¬¡™£¢¢•º™™¶'.encode('utf-8'),
                    message_id='test.attach.100@domain.net',
                    content_type='text/plain')


[allura] 02/16: [#8375] nuanced str/bytes/charset handling for email messages

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8375
in repository https://gitbox.apache.org/repos/asf/allura.git

commit 7e1d3c4f02618f57889d83176ba278ed298a60b8
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Tue Aug 25 13:37:13 2020 -0400

    [#8375] nuanced str/bytes/charset handling for email messages
---
 Allura/allura/lib/mail_util.py | 28 ++++++++++++++++++----------
 1 file changed, 18 insertions(+), 10 deletions(-)

diff --git a/Allura/allura/lib/mail_util.py b/Allura/allura/lib/mail_util.py
index 3c417b4..9b50e46 100644
--- a/Allura/allura/lib/mail_util.py
+++ b/Allura/allura/lib/mail_util.py
@@ -20,7 +20,7 @@ from __future__ import absolute_import
 import re
 import logging
 import smtplib
-import email.feedparser
+import email.parser
 from six.moves.email_mime_multipart import MIMEMultipart
 from six.moves.email_mime_text import MIMEText
 from email import header
@@ -127,9 +127,19 @@ def parse_address(addr):
 
 def parse_message(data):
     # Parse the email to its constituent parts
-    parser = email.feedparser.FeedParser()
-    parser.feed(data)
-    msg = parser.close()
+
+    # https://bugs.python.org/issue25545 says
+    # > A unicode string has no RFC defintion as an email, so things do not work right...
+    # > You do have to conditionalize your 2/3 code to use the bytes parser and generator if you are dealing with 8-bit
+    # > messages. There's just no way around that.
+    if six.PY2:
+        parser = email.feedparser.FeedParser()
+        parser.feed(data)
+        msg = parser.close()
+    else:
+        # works the same as BytesFeedParser, and better than non-"Bytes" parsers for some messages
+        parser = email.parser.BytesParser()
+        msg = parser.parsebytes(data.encode('utf-8'))
     # Extract relevant data
     result = {}
     result['multipart'] = multipart = msg.is_multipart()
@@ -152,17 +162,15 @@ def parse_message(data):
                 content_type=part.get_content_type(),
                 filename=part.get_filename(None),
                 payload=part.get_payload(decode=True))
-            charset = part.get_content_charset()
             # payload is sometimes already unicode (due to being saved in mongo?)
-            if isinstance(dpart['payload'], six.binary_type) and charset:
-                dpart['payload'] = dpart['payload'].decode(charset)
+            if part.get_content_maintype() == 'text':
+                dpart['payload'] = six.ensure_text(dpart['payload'])
             result['parts'].append(dpart)
     else:
         result['payload'] = msg.get_payload(decode=True)
-        charset = msg.get_content_charset()
         # payload is sometimes already unicode (due to being saved in mongo?)
-        if isinstance(result['payload'], six.binary_type) and charset:
-            result['payload'] = result['payload'].decode(charset)
+        if msg.get_content_maintype() == 'text':
+            result['payload'] = six.ensure_text(result['payload'])
 
     return result
 


[allura] 13/16: [#8375] simpler tg.jsonify.JSONEncoder patch

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8375
in repository https://gitbox.apache.org/repos/asf/allura.git

commit 18788c6c5cd12d0bfb36c634e8cac42599a54d5c
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Wed Aug 26 14:04:19 2020 -0400

    [#8375] simpler tg.jsonify.JSONEncoder patch
    
    works even if stdlib json has more functions in C and not patchable
    also fixes test that was incorrectly changed in [a15d3ecc1] but happened to be ok on py2 still
---
 Allura/allura/lib/patches.py                      | 10 +---------
 ForgeWiki/forgewiki/tests/functional/test_rest.py |  2 +-
 2 files changed, 2 insertions(+), 10 deletions(-)

diff --git a/Allura/allura/lib/patches.py b/Allura/allura/lib/patches.py
index 7080fa4..5eefc39 100644
--- a/Allura/allura/lib/patches.py
+++ b/Allura/allura/lib/patches.py
@@ -99,18 +99,10 @@ def apply():
     # This is to avoid IE9 and earlier, which don't know the json content type
     # and may attempt to render JSON data as HTML if the URL ends in .html
     original_tg_jsonify_JSONEncoder_encode = tg.jsonify.JSONEncoder.encode
-    escape_pattern_with_lt = re.compile(
-        json.encoder.ESCAPE.pattern.rstrip(']') + '<' + ']')
 
     @h.monkeypatch(tg.jsonify.JSONEncoder)
     def encode(self, o):
-        # ensure_ascii=False forces encode_basestring() to be called instead of
-        # encode_basestring_ascii() and encode_basestring_ascii may likely be c-compiled
-        # and thus not monkeypatchable
-        with h.push_config(self, ensure_ascii=False), \
-                h.push_config(json.encoder, ESCAPE=escape_pattern_with_lt), \
-                mock.patch.dict(json.encoder.ESCAPE_DCT, {'<': r'\u003C'}):
-            return original_tg_jsonify_JSONEncoder_encode(self, o)
+        return original_tg_jsonify_JSONEncoder_encode(self, o).replace('<', r'\u003C')
 
 
 old_controller_call = tg.controllers.DecoratedController._call
diff --git a/ForgeWiki/forgewiki/tests/functional/test_rest.py b/ForgeWiki/forgewiki/tests/functional/test_rest.py
index e15f90f..a41f3f7 100644
--- a/ForgeWiki/forgewiki/tests/functional/test_rest.py
+++ b/ForgeWiki/forgewiki/tests/functional/test_rest.py
@@ -119,7 +119,7 @@ class TestWikiApi(TestRestApiBase):
 
     def test_json_encoding_directly(self):
         # used in @expose('json'), monkey-patched in our patches.py
-        assert_equal(tg.jsonify.encode('<'), '"\u003C"')
+        assert_equal(tg.jsonify.encode('<'), r'"\u003C"')
         # make sure these are unchanged
         assert_equal(json.dumps('<'), '"<"')
 


[allura] 04/16: [#8375] ForgeBlog core lookup fix

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8375
in repository https://gitbox.apache.org/repos/asf/allura.git

commit d443bf15106dc32252a3c586ea02b7ff324f6d7e
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Mon Aug 24 18:04:15 2020 -0400

    [#8375] ForgeBlog core lookup fix
---
 ForgeBlog/forgeblog/main.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ForgeBlog/forgeblog/main.py b/ForgeBlog/forgeblog/main.py
index 6e286c2..a362c9b 100644
--- a/ForgeBlog/forgeblog/main.py
+++ b/ForgeBlog/forgeblog/main.py
@@ -332,7 +332,7 @@ class RootController(BaseController, FeedController):
     def _lookup(self, year=None, month=None, name=None, *rest):
         if year is None or month is None or name is None:
             raise exc.HTTPNotFound()
-        slug = '/'.join((year, month, six.moves.urllib.parse.unquote(name).decode('utf-8')))
+        slug = '/'.join((year, month, six.ensure_text(six.moves.urllib.parse.unquote(name))))
         post = BM.BlogPost.query.get(slug=slug, app_config_id=c.app.config._id)
         if post is None:
             raise exc.HTTPNotFound()


[allura] 05/16: [#8375] avoid "Running setup_app() from allura.websetup" output during test runs

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8375
in repository https://gitbox.apache.org/repos/asf/allura.git

commit ad781154fb0486cdd803cc207e7d92b891c26861
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Mon Aug 24 18:06:57 2020 -0400

    [#8375] avoid "Running setup_app() from allura.websetup" output during test runs
---
 AlluraTest/alluratest/controller.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/AlluraTest/alluratest/controller.py b/AlluraTest/alluratest/controller.py
index 918beb5..4372584 100644
--- a/AlluraTest/alluratest/controller.py
+++ b/AlluraTest/alluratest/controller.py
@@ -98,7 +98,7 @@ def setup_basic_test(config=None, app_name=DFL_APP_NAME):
     # setup our app without depending on gearbox (we still depend on Paste anyway)
     # uses [paste.app_install] entry point which call our setup_app()
     cmd = SetupCommand('setup-app')
-    cmd.run([test_file])
+    cmd.run([test_file, '--quiet'])
 
     ew.TemplateEngine.initialize({})
 


[allura] 10/16: [#8375] iterator compatibility for py3

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8375
in repository https://gitbox.apache.org/repos/asf/allura.git

commit 59c853fe702c6f5d12de6502c6e2b9694f991cc0
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Tue Aug 25 18:15:33 2020 -0400

    [#8375] iterator compatibility for py3
---
 Allura/allura/lib/utils.py           | 1 +
 Allura/allura/scripts/trac_export.py | 1 +
 2 files changed, 2 insertions(+)

diff --git a/Allura/allura/lib/utils.py b/Allura/allura/lib/utils.py
index a6f782e..9a7063a 100644
--- a/Allura/allura/lib/utils.py
+++ b/Allura/allura/lib/utils.py
@@ -637,6 +637,7 @@ class EmptyCursor(ODMCursor):
 
     def next(self):
         raise StopIteration
+    __next__ = next
 
     def options(self, **kw):
         return self
diff --git a/Allura/allura/scripts/trac_export.py b/Allura/allura/scripts/trac_export.py
index b5934d8..4c2e937 100644
--- a/Allura/allura/scripts/trac_export.py
+++ b/Allura/allura/scripts/trac_export.py
@@ -293,6 +293,7 @@ class TracExport(object):
             if id >= self.start_id:
                 break
         return self.get_ticket(id, extra)
+    __next__ = next
 
     def clean_missing_wiki_links(self, doc):
         for link in doc.findAll('a', 'missing wiki'):