Browse Source

Project wide black fixes, including tests, docs and all

Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>
Pierre-Yves Chibon 9 months ago
parent
commit
73d1200552
100 changed files with 30790 additions and 27689 deletions
  1. 24 16
      createdb.py
  2. 231 234
      dev-data.py
  3. 2 1
      dev/containers/f29-rpms-py3
  4. 20 9
      dev/run-tests-container.py
  5. 90 90
      doc/conf.py
  6. 3 8
      fedmsg.d/pagure.py
  7. 1 3
      fedmsg.d/pagure_ci.py
  8. 1 1
      files/aclchecker.py
  9. 38 26
      files/api_key_expire_mail.py
  10. 6 6
      files/emoji_clean_json.py
  11. 28 18
      files/mirror_project_in.py
  12. 67 55
      pagure-ev/pagure_stream_server.py
  13. 95 91
      pagure-milters/comment_email_milter.py
  14. 32 18
      rundocserver.py
  15. 40 26
      runserver.py
  16. 95 47
      runtests.py
  17. 21 15
      runworker.py
  18. 32 30
      setup.py
  19. 267 247
      tests/__init__.py
  20. 9 8
      tests/test_alembic.py
  21. 3 2
      tests/test_dev_data.py
  22. 17 17
      tests/test_fnmatch.py
  23. 575 620
      tests/test_pagure_admin.py
  24. 43 47
      tests/test_pagure_exclude_group_index.py
  25. 104 101
      tests/test_pagure_flask.py
  26. 128 123
      tests/test_pagure_flask_api.py
  27. 51 43
      tests/test_pagure_flask_api_auth.py
  28. 1779 1719
      tests/test_pagure_flask_api_fork.py
  29. 80 89
      tests/test_pagure_flask_api_fork_assign.py
  30. 445 394
      tests/test_pagure_flask_api_fork_update.py
  31. 154 209
      tests/test_pagure_flask_api_group.py
  32. 2097 2230
      tests/test_pagure_flask_api_issue.py
  33. 109 126
      tests/test_pagure_flask_api_issue_change_status.py
  34. 127 141
      tests/test_pagure_flask_api_issue_comment.py
  35. 131 150
      tests/test_pagure_flask_api_issue_create.py
  36. 93 61
      tests/test_pagure_flask_api_issue_custom_fields.py
  37. 555 520
      tests/test_pagure_flask_api_pr_flag.py
  38. 1772 2035
      tests/test_pagure_flask_api_project.py
  39. 16 17
      tests/test_pagure_flask_api_project_blockuser.py
  40. 90 107
      tests/test_pagure_flask_api_project_update_watch.py
  41. 1052 1147
      tests/test_pagure_flask_api_ui_private_repo.py
  42. 942 784
      tests/test_pagure_flask_api_user.py
  43. 91 74
      tests/test_pagure_flask_docs.py
  44. 61 59
      tests/test_pagure_flask_dump_load_ticket.py
  45. 45 41
      tests/test_pagure_flask_form.py
  46. 1207 1356
      tests/test_pagure_flask_internal.py
  47. 171 148
      tests/test_pagure_flask_rebase.py
  48. 1242 973
      tests/test_pagure_flask_ui_app.py
  49. 166 179
      tests/test_pagure_flask_ui_app_browse.py
  50. 152 146
      tests/test_pagure_flask_ui_app_give_project.py
  51. 21 16
      tests/test_pagure_flask_ui_app_index.py
  52. 113 93
      tests/test_pagure_flask_ui_app_userdash.py
  53. 170 122
      tests/test_pagure_flask_ui_archives.py
  54. 93 63
      tests/test_pagure_flask_ui_clone.py
  55. 2064 1566
      tests/test_pagure_flask_ui_fork.py
  56. 343 219
      tests/test_pagure_flask_ui_groups.py
  57. 50 47
      tests/test_pagure_flask_ui_issue_pr_link.py
  58. 2164 1946
      tests/test_pagure_flask_ui_issues.py
  59. 341 325
      tests/test_pagure_flask_ui_issues_acl_checks.py
  60. 595 551
      tests/test_pagure_flask_ui_issues_open_access.py
  61. 118 104
      tests/test_pagure_flask_ui_issues_private.py
  62. 149 126
      tests/test_pagure_flask_ui_issues_read_only.py
  63. 104 104
      tests/test_pagure_flask_ui_issues_templates.py
  64. 569 378
      tests/test_pagure_flask_ui_login.py
  65. 99 85
      tests/test_pagure_flask_ui_no_master_branch.py
  66. 96 60
      tests/test_pagure_flask_ui_old_commit.py
  67. 51 55
      tests/test_pagure_flask_ui_plugins.py
  68. 6 7
      tests/test_pagure_flask_ui_plugins_default_hook.py
  69. 177 92
      tests/test_pagure_flask_ui_plugins_fedmsg.py
  70. 105 54
      tests/test_pagure_flask_ui_plugins_irc.py
  71. 79 57
      tests/test_pagure_flask_ui_plugins_mail.py
  72. 150 92
      tests/test_pagure_flask_ui_plugins_mirror.py
  73. 165 75
      tests/test_pagure_flask_ui_plugins_noff.py
  74. 253 159
      tests/test_pagure_flask_ui_plugins_pagure_ci.py
  75. 241 146
      tests/test_pagure_flask_ui_plugins_pagure_hook.py
  76. 118 66
      tests/test_pagure_flask_ui_plugins_pagure_no_new_branch.py
  77. 102 62
      tests/test_pagure_flask_ui_plugins_pagure_request_hook.py
  78. 109 72
      tests/test_pagure_flask_ui_plugins_pagure_ticket_hook.py
  79. 96 63
      tests/test_pagure_flask_ui_plugins_rtd_hook.py
  80. 93 54
      tests/test_pagure_flask_ui_plugins_unsigned.py
  81. 90 93
      tests/test_pagure_flask_ui_pr_no_sources.py
  82. 684 452
      tests/test_pagure_flask_ui_priorities.py
  83. 83 82
      tests/test_pagure_flask_ui_quick_reply.py
  84. 275 235
      tests/test_pagure_flask_ui_remote_pr.py
  85. 2806 2196
      tests/test_pagure_flask_ui_repo.py
  86. 141 90
      tests/test_pagure_flask_ui_repo_delete_project.py
  87. 168 151
      tests/test_pagure_flask_ui_repo_flag_commit.py
  88. 69 58
      tests/test_pagure_flask_ui_repo_milestones.py
  89. 85 74
      tests/test_pagure_flask_ui_repo_slash_name.py
  90. 141 101
      tests/test_pagure_flask_ui_repo_view_file.py
  91. 312 238
      tests/test_pagure_flask_ui_roadmap.py
  92. 97 88
      tests/test_pagure_flask_ui_slash_branch_name.py
  93. 72 89
      tests/test_pagure_flask_ui_star_project.py
  94. 23 23
      tests/test_pagure_flask_util.py
  95. 76 48
      tests/test_pagure_hooks_pagure_hook.py
  96. 2025 1984
      tests/test_pagure_lib.py
  97. 115 129
      tests/test_pagure_lib_add_user_to_project.py
  98. 43 58
      tests/test_pagure_lib_drop_issue.py
  99. 51 34
      tests/test_pagure_lib_encoding_utils.py
  100. 0 0
      tests/test_pagure_lib_git.py

+ 24 - 16
createdb.py

@@ -8,33 +8,40 @@ import os
 
 
 parser = argparse.ArgumentParser(
-    description='Create/Update the Pagure database')
+    description="Create/Update the Pagure database"
+)
 parser.add_argument(
-    '--config', '-c', dest='config',
-    help='Configuration file to use for pagure.')
+    "--config",
+    "-c",
+    dest="config",
+    help="Configuration file to use for pagure.",
+)
 parser.add_argument(
-    '--initial', '-i', dest='alembic_cfg',
-    help='With this option, the database will be automatically stamped to '
-         'the latest version according to alembic. Point to the alembic.ini '
-         'file to use.')
+    "--initial",
+    "-i",
+    dest="alembic_cfg",
+    help="With this option, the database will be automatically stamped to "
+    "the latest version according to alembic. Point to the alembic.ini "
+    "file to use.",
+)
 
 
 args = parser.parse_args()
 
 if args.config:
     config = args.config
-    if not config.startswith('/'):
+    if not config.startswith("/"):
         here = os.path.join(os.path.dirname(os.path.abspath(__file__)))
         config = os.path.join(here, config)
-    os.environ['PAGURE_CONFIG'] = config
+    os.environ["PAGURE_CONFIG"] = config
 
 
 if args.alembic_cfg:
-    if not args.alembic_cfg.endswith('alembic.ini'):
-        print('--initial should point to the alembic.ini file to use.')
+    if not args.alembic_cfg.endswith("alembic.ini"):
+        print("--initial should point to the alembic.ini file to use.")
         sys.exit(1)
     if not os.path.exists(args.alembic_cfg):
-        print('The file `{0}` could not be found'.format(args.alembic_cfg))
+        print("The file `{0}` could not be found".format(args.alembic_cfg))
         sys.exit(2)
 
 
@@ -44,7 +51,8 @@ from pagure.lib import model
 _config = pagure.config.reload_config()
 
 model.create_tables(
-    _config['DB_URL'],
-    _config.get('PATH_ALEMBIC_INI', args.alembic_cfg),
-    acls=_config.get('ACLS', {}),
-    debug=True)
+    _config["DB_URL"],
+    _config.get("PATH_ALEMBIC_INI", args.alembic_cfg),
+    acls=_config.get("ACLS", {}),
+    debug=True,
+)

+ 231 - 234
dev-data.py

@@ -23,24 +23,24 @@ from pagure.lib.model import create_default_status
 from pagure.lib.repo import PagureRepo
 
 
-'''
+"""
 Usage:
 python dev-data.py --init
 python dev-data.py --clean
 python dev-data.py --populate
 python dev-data.py --all
-'''
+"""
 
 _config = pagure.config.reload_config()
 
 
 def empty_dev_db(session):
-    print('')
-    print('WARNING: Deleting all data from', _config['DB_URL'])
+    print("")
+    print("WARNING: Deleting all data from", _config["DB_URL"])
     response = os.environ.get("FORCE_DELETE")
     if not response:
-        response = six.moves.input('Do you want to continue? (yes/no)    ')
-    if response.lower().startswith('y'):
+        response = six.moves.input("Do you want to continue? (yes/no)    ")
+    if response.lower().startswith("y"):
         tables = reversed(pagure.lib.model_base.BASE.metadata.sorted_tables)
         for tbl in tables:
             session.execute(tbl.delete())
@@ -49,14 +49,12 @@ def empty_dev_db(session):
 
 
 def insert_data(session, username, user_email):
-    _config['EMAIL_SEND'] = False
-    _config['TESTING'] = True
+    _config["EMAIL_SEND"] = False
+    _config["TESTING"] = True
 
     ######################################
     # tags
-    item = pagure.lib.model.Tag(
-        tag='tag1',
-    )
+    item = pagure.lib.model.Tag(tag="tag1")
     session.add(item)
     session.commit()
 
@@ -64,46 +62,58 @@ def insert_data(session, username, user_email):
     # Users
     # Create a couple of users
     pingou = item = pagure.lib.model.User(
-        user='pingou',
-        fullname='PY C',
-        password=generate_hashed_value(u'testing123'),
+        user="pingou",
+        fullname="PY C",
+        password=generate_hashed_value("testing123"),
         token=None,
-        default_email='bar@pingou.com',
+        default_email="bar@pingou.com",
     )
     session.add(item)
     session.commit()
-    print("User created: {} <{}>, {}".format(item.user, item.default_email, 'testing123'))
+    print(
+        "User created: {} <{}>, {}".format(
+            item.user, item.default_email, "testing123"
+        )
+    )
 
     foo = item = pagure.lib.model.User(
-        user='foo',
-        fullname='foo bar',
-        password=generate_hashed_value(u'testing123'),
+        user="foo",
+        fullname="foo bar",
+        password=generate_hashed_value("testing123"),
         token=None,
-        default_email='foo@bar.com',
+        default_email="foo@bar.com",
     )
     session.add(item)
     session.commit()
-    print("User created: {} <{}>, {}".format(item.user, item.default_email, 'testing123'))
+    print(
+        "User created: {} <{}>, {}".format(
+            item.user, item.default_email, "testing123"
+        )
+    )
 
     you = item = pagure.lib.model.User(
         user=username,
         fullname=username,
-        password=generate_hashed_value(u'testing123'),
+        password=generate_hashed_value("testing123"),
         token=None,
         default_email=user_email,
     )
     session.add(item)
     session.commit()
-    print("User created: {} <{}>, {}".format(item.user, item.default_email, 'testing123'))
+    print(
+        "User created: {} <{}>, {}".format(
+            item.user, item.default_email, "testing123"
+        )
+    )
 
     ######################################
     # pagure_group
     item = pagure.lib.model.PagureGroup(
-        group_name='admin',
-        group_type='admin',
+        group_name="admin",
+        group_type="admin",
         user_id=pingou.id,
-        display_name='admin',
-        description='Admin Group',
+        display_name="admin",
+        description="Admin Group",
     )
     session.add(item)
     session.commit()
@@ -111,22 +121,22 @@ def insert_data(session, username, user_email):
 
     # Add a couple of groups so that we can list them
     item = pagure.lib.model.PagureGroup(
-        group_name='group',
-        group_type='user',
+        group_name="group",
+        group_type="user",
         user_id=pingou.id,
-        display_name='group group',
-        description='this is a group group',
+        display_name="group group",
+        description="this is a group group",
     )
     session.add(item)
     session.commit()
     print('Created "group" group. Pingou is a member.')
 
     item = pagure.lib.model.PagureGroup(
-        group_name='rel-eng',
-        group_type='user',
+        group_name="rel-eng",
+        group_type="user",
         user_id=pingou.id,
-        display_name='Release Engineering',
-        description='The group of release engineers',
+        display_name="Release Engineering",
+        description="The group of release engineers",
     )
     session.add(item)
     session.commit()
@@ -135,86 +145,82 @@ def insert_data(session, username, user_email):
     # projects
 
     import shutil
+
     # delete folder from local instance to start from a clean slate
-    if os.path.exists(_config['GIT_FOLDER']):
-        shutil.rmtree(_config['GIT_FOLDER'])
+    if os.path.exists(_config["GIT_FOLDER"]):
+        shutil.rmtree(_config["GIT_FOLDER"])
 
     # Create projects
     item = project1 = pagure.lib.model.Project(
         user_id=pingou.id,
-        name='test',
+        name="test",
         is_fork=False,
         parent_id=None,
-        description='test project #1',
-        hook_token='aaabbbccc',
+        description="test project #1",
+        hook_token="aaabbbccc",
     )
-    item.close_status = ['Invalid', 'Insufficient data', 'Fixed', 'Duplicate']
+    item.close_status = ["Invalid", "Insufficient data", "Fixed", "Duplicate"]
     session.add(item)
     session.flush()
     tests.create_locks(session, item)
 
     item = project2 = pagure.lib.model.Project(
         user_id=pingou.id,
-        name='test2',
+        name="test2",
         is_fork=False,
         parent_id=None,
-        description='test project #2',
-        hook_token='aaabbbddd',
+        description="test project #2",
+        hook_token="aaabbbddd",
     )
-    item.close_status = ['Invalid', 'Insufficient data', 'Fixed', 'Duplicate']
+    item.close_status = ["Invalid", "Insufficient data", "Fixed", "Duplicate"]
     session.add(item)
 
     item = project3 = pagure.lib.model.Project(
         user_id=pingou.id,
-        name='test3',
+        name="test3",
         is_fork=False,
         parent_id=None,
-        description='namespaced test project',
-        hook_token='aaabbbeee',
-        namespace='somenamespace',
+        description="namespaced test project",
+        hook_token="aaabbbeee",
+        namespace="somenamespace",
     )
-    item.close_status = ['Invalid', 'Insufficient data', 'Fixed', 'Duplicate']
+    item.close_status = ["Invalid", "Insufficient data", "Fixed", "Duplicate"]
     session.add(item)
 
     session.commit()
 
-    tests.create_projects_git(_config['GIT_FOLDER'], bare=True)
-    add_content_git_repo(
-        os.path.join(_config['GIT_FOLDER'], 'test.git'))
-    tests.add_readme_git_repo(
-        os.path.join(_config['GIT_FOLDER'], 'test.git'))
+    tests.create_projects_git(_config["GIT_FOLDER"], bare=True)
+    add_content_git_repo(os.path.join(_config["GIT_FOLDER"], "test.git"))
+    tests.add_readme_git_repo(os.path.join(_config["GIT_FOLDER"], "test.git"))
 
     # Add some content to the git repo
     add_content_git_repo(
-        os.path.join(_config['GIT_FOLDER'], 'forks', 'pingou',
-                     'test.git'))
+        os.path.join(_config["GIT_FOLDER"], "forks", "pingou", "test.git")
+    )
     tests.add_readme_git_repo(
-        os.path.join(_config['GIT_FOLDER'], 'forks', 'pingou',
-                     'test.git'))
+        os.path.join(_config["GIT_FOLDER"], "forks", "pingou", "test.git")
+    )
     tests.add_commit_git_repo(
-        os.path.join(_config['GIT_FOLDER'], 'forks', 'pingou',
-                     'test.git'), ncommits=10)
+        os.path.join(_config["GIT_FOLDER"], "forks", "pingou", "test.git"),
+        ncommits=10,
+    )
 
     ######################################
     # user_emails
     item = pagure.lib.model.UserEmail(
-        user_id=pingou.id,
-        email='bar@pingou.com')
+        user_id=pingou.id, email="bar@pingou.com"
+    )
     session.add(item)
 
     item = pagure.lib.model.UserEmail(
-        user_id=pingou.id,
-        email='foo@pingou.com')
+        user_id=pingou.id, email="foo@pingou.com"
+    )
     session.add(item)
 
-    item = pagure.lib.model.UserEmail(
-        user_id=foo.id,
-        email='foo@bar.com')
+    item = pagure.lib.model.UserEmail(user_id=foo.id, email="foo@bar.com")
     session.add(item)
 
-    item = pagure.lib.model.UserEmail(
-        user_id=you.id,
-        email=user_email)
+    item = pagure.lib.model.UserEmail(user_id=you.id, email=user_email)
     session.add(item)
 
     session.commit()
@@ -222,9 +228,7 @@ def insert_data(session, username, user_email):
     ######################################
     # user_emails_pending
     email_pend = pagure.lib.model.UserEmailPending(
-        user_id=pingou.id,
-        email='foo@fp.o',
-        token='abcdef',
+        user_id=pingou.id, email="foo@fp.o", token="abcdef"
     )
     session.add(email_pend)
     session.commit()
@@ -234,10 +238,10 @@ def insert_data(session, username, user_email):
     # Add an issue and tag it so that we can list them
     item = pagure.lib.model.Issue(
         id=1001,
-        uid='foobar',
+        uid="foobar",
         project_id=project1.id,
-        title='Problem with jenkins build',
-        content='For some reason the tests fail at line:24',
+        title="Problem with jenkins build",
+        content="For some reason the tests fail at line:24",
         user_id=pingou.id,
     )
     session.add(item)
@@ -245,11 +249,11 @@ def insert_data(session, username, user_email):
 
     item = pagure.lib.model.Issue(
         id=1002,
-        uid='foobar2',
+        uid="foobar2",
         project_id=project1.id,
-        title='Unit tests failing',
-        content='Need to fix code for the unit tests to '
-                'pass so jenkins build can complete.',
+        title="Unit tests failing",
+        content="Need to fix code for the unit tests to "
+        "pass so jenkins build can complete.",
         user_id=pingou.id,
     )
     session.add(item)
@@ -257,10 +261,10 @@ def insert_data(session, username, user_email):
 
     item = pagure.lib.model.Issue(
         id=1003,
-        uid='foobar3',
+        uid="foobar3",
         project_id=project1.id,
-        title='Segfault during execution',
-        content='Index out of bounds for variable i?',
+        title="Segfault during execution",
+        content="Index out of bounds for variable i?",
         user_id=you.id,
     )
     session.add(item)
@@ -268,166 +272,155 @@ def insert_data(session, username, user_email):
 
     ######################################
     # pagure_user_group
-    group = pagure.lib.query.search_groups(session, pattern=None,
-                                     group_name="rel-eng", group_type=None)
+    group = pagure.lib.query.search_groups(
+        session, pattern=None, group_name="rel-eng", group_type=None
+    )
     item = pagure.lib.model.PagureUserGroup(
-        user_id=pingou.id,
-        group_id=group.id
+        user_id=pingou.id, group_id=group.id
     )
     session.add(item)
     session.commit()
 
-    group = pagure.lib.query.search_groups(session, pattern=None,
-                                     group_name="admin", group_type=None)
-
-    item = pagure.lib.model.PagureUserGroup(
-        user_id=you.id,
-        group_id=group.id
+    group = pagure.lib.query.search_groups(
+        session, pattern=None, group_name="admin", group_type=None
     )
+
+    item = pagure.lib.model.PagureUserGroup(user_id=you.id, group_id=group.id)
     session.add(item)
     session.commit()
 
-    group = pagure.lib.query.search_groups(session, pattern=None,
-                                     group_name="group", group_type=None)
-
-    item = pagure.lib.model.PagureUserGroup(
-        user_id=foo.id,
-        group_id=group.id
+    group = pagure.lib.query.search_groups(
+        session, pattern=None, group_name="group", group_type=None
     )
+
+    item = pagure.lib.model.PagureUserGroup(user_id=foo.id, group_id=group.id)
     session.add(item)
     session.commit()
 
     ######################################
     # projects_groups
-    group = pagure.lib.query.search_groups(session, pattern=None,
-                                     group_name="rel-eng", group_type=None)
-    repo = pagure.lib.query.get_authorized_project(session, 'test')
+    group = pagure.lib.query.search_groups(
+        session, pattern=None, group_name="rel-eng", group_type=None
+    )
+    repo = pagure.lib.query.get_authorized_project(session, "test")
     item = pagure.lib.model.ProjectGroup(
-        project_id=repo.id,
-        group_id=group.id,
-        access="commit"
+        project_id=repo.id, group_id=group.id, access="commit"
     )
     session.add(item)
     session.commit()
 
-    group = pagure.lib.query.search_groups(session, pattern=None,
-                                     group_name="admin", group_type=None)
-    repo = pagure.lib.query.get_authorized_project(session, 'test2')
+    group = pagure.lib.query.search_groups(
+        session, pattern=None, group_name="admin", group_type=None
+    )
+    repo = pagure.lib.query.get_authorized_project(session, "test2")
     item = pagure.lib.model.ProjectGroup(
-        project_id=repo.id,
-        group_id=group.id,
-        access="admin"
+        project_id=repo.id, group_id=group.id, access="admin"
     )
     session.add(item)
     session.commit()
 
     ######################################
     # pull_requests
-    repo = pagure.lib.query.get_authorized_project(session, 'test')
-    forked_repo = pagure.lib.query.get_authorized_project(session, 'test')
+    repo = pagure.lib.query.get_authorized_project(session, "test")
+    forked_repo = pagure.lib.query.get_authorized_project(session, "test")
     req = pagure.lib.query.new_pull_request(
         session=session,
         repo_from=forked_repo,
-        branch_from='master',
+        branch_from="master",
         repo_to=repo,
-        branch_to='master',
-        title='Fixing code for unittest',
+        branch_to="master",
+        title="Fixing code for unittest",
         user=username,
-        status="Open"
+        status="Open",
     )
     session.commit()
 
-    repo = pagure.lib.query.get_authorized_project(session, 'test')
-    forked_repo = pagure.lib.query.get_authorized_project(session, 'test')
+    repo = pagure.lib.query.get_authorized_project(session, "test")
+    forked_repo = pagure.lib.query.get_authorized_project(session, "test")
     req = pagure.lib.query.new_pull_request(
         session=session,
         repo_from=forked_repo,
-        branch_from='master',
+        branch_from="master",
         repo_to=repo,
-        branch_to='master',
-        title='add very nice README',
+        branch_to="master",
+        title="add very nice README",
         user=username,
-        status="Open"
+        status="Open",
     )
     session.commit()
 
-    repo = pagure.lib.query.get_authorized_project(session, 'test')
-    forked_repo = pagure.lib.query.get_authorized_project(session, 'test')
+    repo = pagure.lib.query.get_authorized_project(session, "test")
+    forked_repo = pagure.lib.query.get_authorized_project(session, "test")
     req = pagure.lib.query.new_pull_request(
         session=session,
         repo_from=forked_repo,
-        branch_from='master',
+        branch_from="master",
         repo_to=repo,
-        branch_to='master',
-        title='Add README',
+        branch_to="master",
+        title="Add README",
         user=username,
-        status="Closed"
+        status="Closed",
     )
     session.commit()
 
-    repo = pagure.lib.query.get_authorized_project(session, 'test')
-    forked_repo = pagure.lib.query.get_authorized_project(session, 'test')
+    repo = pagure.lib.query.get_authorized_project(session, "test")
+    forked_repo = pagure.lib.query.get_authorized_project(session, "test")
     req = pagure.lib.query.new_pull_request(
         session=session,
         repo_from=forked_repo,
-        branch_from='master',
+        branch_from="master",
         repo_to=repo,
-        branch_to='master',
-        title='Fix some containers',
+        branch_to="master",
+        title="Fix some containers",
         user=username,
-        status="Merged"
+        status="Merged",
     )
     session.commit()
 
-    repo = pagure.lib.query.get_authorized_project(session, 'test')
-    forked_repo = pagure.lib.query.get_authorized_project(session, 'test')
+    repo = pagure.lib.query.get_authorized_project(session, "test")
+    forked_repo = pagure.lib.query.get_authorized_project(session, "test")
     req = pagure.lib.query.new_pull_request(
         session=session,
         repo_from=forked_repo,
-        branch_from='master',
+        branch_from="master",
         repo_to=repo,
-        branch_to='master',
-        title='Fix pull request statuses',
+        branch_to="master",
+        title="Fix pull request statuses",
         user=username,
-        status="Closed"
+        status="Closed",
     )
     session.commit()
 
-    repo = pagure.lib.query.get_authorized_project(session, 'test')
-    forked_repo = pagure.lib.query.get_authorized_project(session, 'test')
+    repo = pagure.lib.query.get_authorized_project(session, "test")
+    forked_repo = pagure.lib.query.get_authorized_project(session, "test")
     req = pagure.lib.query.new_pull_request(
         session=session,
         repo_from=forked_repo,
-        branch_from='master',
+        branch_from="master",
         repo_to=repo,
-        branch_to='master',
-        title='Fixing UI of issue',
+        branch_to="master",
+        title="Fixing UI of issue",
         user=username,
-        status="Merged"
+        status="Merged",
     )
     session.commit()
 
-
     #####################################
     # tokens
     tests.create_tokens(session, user_id=pingou.id, project_id=project1.id)
 
     ######################################
     # user_projects
-    repo = pagure.lib.query.get_authorized_project(session, 'test')
+    repo = pagure.lib.query.get_authorized_project(session, "test")
     item = pagure.lib.model.ProjectUser(
-        project_id=repo.id,
-        user_id=foo.id,
-        access="commit"
+        project_id=repo.id, user_id=foo.id, access="commit"
     )
     session.add(item)
     session.commit()
 
-    repo = pagure.lib.query.get_authorized_project(session, 'test2')
+    repo = pagure.lib.query.get_authorized_project(session, "test2")
     item = pagure.lib.model.ProjectUser(
-        project_id=repo.id,
-        user_id=you.id,
-        access="commit"
+        project_id=repo.id, user_id=you.id, access="commit"
     )
     session.add(item)
     session.commit()
@@ -436,29 +429,30 @@ def insert_data(session, username, user_email):
     # issue_comments
     item = pagure.lib.model.IssueComment(
         user_id=pingou.id,
-        issue_uid='foobar',
-        comment='We may need to adjust the unittests instead of the code.',
+        issue_uid="foobar",
+        comment="We may need to adjust the unittests instead of the code.",
     )
     session.add(item)
     session.commit()
 
     ######################################
     # issue_to_issue
-    repo = pagure.lib.query.get_authorized_project(session, 'test')
+    repo = pagure.lib.query.get_authorized_project(session, "test")
     all_issues = pagure.lib.query.search_issues(session, repo)
-    pagure.lib.query.add_issue_dependency(session, all_issues[0],
-                                    all_issues[1], 'pingou')
+    pagure.lib.query.add_issue_dependency(
+        session, all_issues[0], all_issues[1], "pingou"
+    )
 
     ######################################
     # pull_request_comments
-    user = pagure.lib.query.search_user(session, username='pingou')
+    user = pagure.lib.query.search_user(session, username="pingou")
     # only 1 pull request available atm
     pr = pagure.lib.query.get_pull_request_of_user(session, "pingou")[0]
     item = pagure.lib.model.PullRequestComment(
         pull_request_uid=pr.uid,
         user_id=user.id,
         comment="+1 for me. Btw, could you rebase before you merge?",
-        notification=0
+        notification=0,
     )
     session.add(item)
     session.commit()
@@ -475,7 +469,7 @@ def insert_data(session, username, user_email):
         percent=80,
         comment="Jenkins build passes",
         url=str(pr.id),
-        status="success"
+        status="success",
     )
     session.add(item)
     session.commit()
@@ -489,33 +483,30 @@ def insert_data(session, username, user_email):
         percent=80,
         comment="Jenkins does not pass",
         url=str(pr.id),
-        status="failure"
+        status="failure",
     )
     session.add(item)
     session.commit()
 
     ######################################
     # pull_request_assignee
-    pr = pagure.lib.query.search_pull_requests(session, requestid='1006')
+    pr = pagure.lib.query.search_pull_requests(session, requestid="1006")
     pr.assignee_id = pingou.id
     session.commit()
 
-    pr = pagure.lib.query.search_pull_requests(session, requestid='1007')
+    pr = pagure.lib.query.search_pull_requests(session, requestid="1007")
     pr.assignee_id = you.id
     session.commit()
 
-    pr = pagure.lib.query.search_pull_requests(session, requestid='1004')
+    pr = pagure.lib.query.search_pull_requests(session, requestid="1004")
     pr.assignee_id = foo.id
     session.commit()
 
     ######################################
     # tags_issues
-    repo = pagure.lib.query.get_authorized_project(session, 'test')
+    repo = pagure.lib.query.get_authorized_project(session, "test")
     issues = pagure.lib.query.search_issues(session, repo)
-    item = pagure.lib.model.TagIssue(
-        issue_uid=issues[0].uid,
-        tag='tag1',
-    )
+    item = pagure.lib.model.TagIssue(issue_uid=issues[0].uid, tag="tag1")
     session.add(item)
     session.commit()
 
@@ -528,55 +519,54 @@ def insert_data(session, username, user_email):
     # delete fork data
     fork_proj_location = "forks/foo/test.git"
     try:
-        shutil.rmtree(os.path.join(_config['GIT_FOLDER'],
-                                   fork_proj_location))
+        shutil.rmtree(os.path.join(_config["GIT_FOLDER"], fork_proj_location))
     except:
-        print('git folder already deleted')
+        print("git folder already deleted")
 
     try:
-        shutil.rmtree(os.path.join(_config['DOCS_FOLDER'],
-                                   fork_proj_location))
+        shutil.rmtree(os.path.join(_config["DOCS_FOLDER"], fork_proj_location))
     except:
-        print('docs folder already deleted')
+        print("docs folder already deleted")
 
     try:
-        shutil.rmtree(os.path.join(_config['TICKETS_FOLDER'],
-                                   fork_proj_location))
+        shutil.rmtree(
+            os.path.join(_config["TICKETS_FOLDER"], fork_proj_location)
+        )
     except:
-        print('tickets folder already deleted')
+        print("tickets folder already deleted")
 
     try:
-        shutil.rmtree(os.path.join(_config['REQUESTS_FOLDER'],
-                                   fork_proj_location))
+        shutil.rmtree(
+            os.path.join(_config["REQUESTS_FOLDER"], fork_proj_location)
+        )
     except:
-        print('requests folder already deleted')
+        print("requests folder already deleted")
 
-    repo = pagure.lib.query.get_authorized_project(session, 'test')
-    result = pagure.lib.query.fork_project(session, 'foo', repo)
+    repo = pagure.lib.query.get_authorized_project(session, "test")
+    result = pagure.lib.query.fork_project(session, "foo", repo)
     if result == 'Repo "test" cloned to "foo/test"':
         session.commit()
 
 
-def add_content_git_repo(folder, branch='master'):
+def add_content_git_repo(folder, branch="master"):
     """ Create some content for the specified git repo. """
     if not os.path.exists(folder):
         os.makedirs(folder)
     brepo = pygit2.init_repository(folder, bare=True)
 
-    newfolder = tempfile.mkdtemp(prefix='pagure-tests')
+    newfolder = tempfile.mkdtemp(prefix="pagure-tests")
     repo = pygit2.clone_repository(folder, newfolder)
 
     # Create a file in that git repo
-    with open(os.path.join(newfolder, 'sources'), 'w') as stream:
-        stream.write('foo\n bar')
-    repo.index.add('sources')
+    with open(os.path.join(newfolder, "sources"), "w") as stream:
+        stream.write("foo\n bar")
+    repo.index.add("sources")
     repo.index.write()
 
     parents = []
     commit = None
     try:
-        commit = repo.revparse_single(
-            'HEAD' if branch == 'master' else branch)
+        commit = repo.revparse_single("HEAD" if branch == "master" else branch)
     except KeyError:
         pass
     if commit:
@@ -584,15 +574,13 @@ def add_content_git_repo(folder, branch='master'):
 
     # Commits the files added
     tree = repo.index.write_tree()
-    author = pygit2.Signature(
-        'Alice Author', 'alice@authors.tld')
-    committer = pygit2.Signature(
-        'Cecil Committer', 'cecil@committers.tld')
+    author = pygit2.Signature("Alice Author", "alice@authors.tld")
+    committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
     repo.create_commit(
-        'refs/heads/%s' % branch,  # the name of the reference to update
+        "refs/heads/%s" % branch,  # the name of the reference to update
         author,
         committer,
-        'Add sources file for testing',
+        "Add sources file for testing",
         # binary string representing the tree object ID
         tree,
         # list of binary strings representing parents of the new commit
@@ -602,44 +590,42 @@ def add_content_git_repo(folder, branch='master'):
     parents = []
     commit = None
     try:
-        commit = repo.revparse_single(
-            'HEAD' if branch == 'master' else branch)
+        commit = repo.revparse_single("HEAD" if branch == "master" else branch)
     except KeyError:
         pass
     if commit:
         parents = [commit.oid.hex]
 
-    subfolder = os.path.join('folder1', 'folder2')
+    subfolder = os.path.join("folder1", "folder2")
     if not os.path.exists(os.path.join(newfolder, subfolder)):
         os.makedirs(os.path.join(newfolder, subfolder))
     # Create a file in that git repo
-    with open(os.path.join(newfolder, subfolder, 'file'), 'w') as stream:
-        stream.write('foo\n bar\nbaz')
-    repo.index.add(os.path.join(subfolder, 'file'))
+    with open(os.path.join(newfolder, subfolder, "file"), "w") as stream:
+        stream.write("foo\n bar\nbaz")
+    repo.index.add(os.path.join(subfolder, "file"))
     repo.index.write()
 
     # Commits the files added
     tree = repo.index.write_tree()
-    author = pygit2.Signature(
-        'Alice Author', 'alice@authors.tld')
-    committer = pygit2.Signature(
-        'Cecil Committer', 'cecil@committers.tld')
+    author = pygit2.Signature("Alice Author", "alice@authors.tld")
+    committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
     repo.create_commit(
-        'refs/heads/%s' % branch,  # the name of the reference to update
+        "refs/heads/%s" % branch,  # the name of the reference to update
         author,
         committer,
-        'Add some directory and a file for more testing',
+        "Add some directory and a file for more testing",
         # binary string representing the tree object ID
         tree,
         # list of binary strings representing parents of the new commit
-        parents
+        parents,
     )
 
     # Push to origin
     ori_remote = repo.remotes[0]
     master_ref = repo.lookup_reference(
-        'HEAD' if branch == 'master' else 'refs/heads/%s' % branch).resolve()
-    refname = '%s:%s' % (master_ref.name, master_ref.name)
+        "HEAD" if branch == "master" else "refs/heads/%s" % branch
+    ).resolve()
+    refname = "%s:%s" % (master_ref.name, master_ref.name)
 
     PagureRepo.push(ori_remote, refname)
 
@@ -647,18 +633,19 @@ def add_content_git_repo(folder, branch='master'):
 
 
 def _get_username():
-    invalid_option = ['pingou', 'foo']
+    invalid_option = ["pingou", "foo"]
     user_name = os.environ.get("USER_NAME")
     if not user_name:
         print("")
         user_name = six.moves.input(
-            "Enter your username so we can add you into the test data:  ")
+            "Enter your username so we can add you into the test data:  "
+        )
     cnt = 0
     while not user_name.strip() or user_name in invalid_option:
         print("Reserved names: " + str(invalid_option))
         user_name = six.moves.input(
-            "Enter your username so we can add you into the "
-            "test data:  ")
+            "Enter your username so we can add you into the " "test data:  "
+        )
         cnt += 1
         if cnt == 4:
             print("We asked too many times, bailing")
@@ -668,7 +655,7 @@ def _get_username():
 
 
 def _get_user_email():
-    invalid_option = ['bar@pingou.com', 'foo@bar.com']
+    invalid_option = ["bar@pingou.com", "foo@bar.com"]
     user_email = os.environ.get("USER_EMAIL")
     if not user_email:
         print("")
@@ -687,23 +674,32 @@ def _get_user_email():
 
 
 if __name__ == "__main__":
-    desc = "Run the dev database initialization/insertion/deletion " \
-           "script for db located  " + str(_config['DB_URL'])
+    desc = (
+        "Run the dev database initialization/insertion/deletion "
+        "script for db located  " + str(_config["DB_URL"])
+    )
     parser = argparse.ArgumentParser(prog="dev-data", description=desc)
-    parser.add_argument('-i', '--init', action="store_true",
-                        help="Create the dev db")
-    parser.add_argument('-p', '--populate', action="store_true",
-                        help="Add test data to the db")
-    parser.add_argument('-d', '--delete', action="store_true",
-                        help="Wipe the dev db")
-    parser.add_argument('-a', '--all', action="store_true",
-                        help="Create, Populate then Wipe the dev db")
+    parser.add_argument(
+        "-i", "--init", action="store_true", help="Create the dev db"
+    )
+    parser.add_argument(
+        "-p", "--populate", action="store_true", help="Add test data to the db"
+    )
+    parser.add_argument(
+        "-d", "--delete", action="store_true", help="Wipe the dev db"
+    )
+    parser.add_argument(
+        "-a",
+        "--all",
+        action="store_true",
+        help="Create, Populate then Wipe the dev db",
+    )
 
     args = parser.parse_args()
 
     # forcing the user to choose
     if not any(vars(args).values()):
-        parser.error('No arguments provided.')
+        parser.error("No arguments provided.")
 
     session = None
 
@@ -712,12 +708,13 @@ if __name__ == "__main__":
             db_url=_config["DB_URL"],
             alembic_ini=None,
             acls=_config["ACLS"],
-            debug=False)
+            debug=False,
+        )
         print("Database created")
 
     if args.populate or args.all:
         if not session:
-            session = pagure.lib.query.create_session(_config['DB_URL'])
+            session = pagure.lib.query.create_session(_config["DB_URL"])
 
         user_name = _get_username()
         user_email = _get_user_email()

+ 2 - 1
dev/containers/f29-rpms-py3

@@ -20,7 +20,8 @@ RUN dnf -y install \
 
 RUN cd / \
     && git clone -b $BRANCH $REPO \
-    && chmod +x /pagure/dev/containers/runtests_py3.sh
+    && chmod +x /pagure/dev/containers/runtests_py3.sh \
+    && sed -i -e "s|\['alembic',|\['alembic-3',|" /pagure/tests/test_alembic.py
 
 # Install all the requirements from the spec file and replace the macro
 # %{python_pkgversion} by '3' which thus installs all the py3 version of

+ 20 - 9
dev/run-tests-container.py

@@ -58,12 +58,14 @@ if __name__ == "__main__":
         container_files = ["fedora-pip-py3"]
     else:
         container_names = [
-            "pagure-f29-rpms-py3", "pagure-c7-rpms-py2",
-            "pagure-fedora-pip-py3"
+            "pagure-f29-rpms-py3",
+            "pagure-c7-rpms-py2",
+            "pagure-fedora-pip-py3",
         ]
         container_files = [
-            "f29-rpms-py3", "centos7-rpms-py2",
-            "fedora-pip-py3"
+            "f29-rpms-py3",
+            "centos7-rpms-py2",
+            "fedora-pip-py3",
         ]
 
     failed = []
@@ -77,7 +79,10 @@ if __name__ == "__main__":
                     "--build-arg",
                     "branch={}".format(os.environ.get("BRANCH") or "master"),
                     "--build-arg",
-                    "repo={}".format(os.environ.get("REPO") or "https://pagure.io/pagure.git"),
+                    "repo={}".format(
+                        os.environ.get("REPO")
+                        or "https://pagure.io/pagure.git"
+                    ),
                     "--rm",
                     "-t",
                     container_name,
@@ -105,11 +110,14 @@ if __name__ == "__main__":
                 container_name,
                 "-v",
                 "{}/results_{}:/pagure/results:z".format(
-                    os.getcwd(), container_files[idx]),
+                    os.getcwd(), container_files[idx]
+                ),
                 "-e",
                 "BRANCH={}".format(os.environ.get("BRANCH") or "master"),
                 "-e",
-                "REPO={}".format(os.environ.get("REPO") or "https://pagure.io/pagure.git"),
+                "REPO={}".format(
+                    os.environ.get("REPO") or "https://pagure.io/pagure.git"
+                ),
                 "--entrypoint=/bin/bash",
                 container_name,
             ]
@@ -125,11 +133,14 @@ if __name__ == "__main__":
                 container_name,
                 "-v",
                 "{}/results_{}:/pagure/results:z".format(
-                    os.getcwd(), container_files[idx]),
+                    os.getcwd(), container_files[idx]
+                ),
                 "-e",
                 "BRANCH={}".format(os.environ.get("BRANCH") or "master"),
                 "-e",
-                "REPO={}".format(os.environ.get("REPO") or "https://pagure.io/pagure.git"),
+                "REPO={}".format(
+                    os.environ.get("REPO") or "https://pagure.io/pagure.git"
+                ),
                 "-e",
                 "TESTCASE={}".format(args.test_case or ""),
                 container_name,

+ 90 - 90
doc/conf.py

@@ -16,234 +16,227 @@ import os
 import re
 
 pagurefile = os.path.join(
-    os.path.dirname(__file__), '..', 'pagure', '__init__.py')
+    os.path.dirname(__file__), "..", "pagure", "__init__.py"
+)
 
 # Thanks to SQLAlchemy:
 # https://github.com/zzzeek/sqlalchemy/blob/master/setup.py#L104
 with open(pagurefile) as stream:
-    VERSION = re.compile(
-        r".*__version__ = \"(.*?)\"", re.S
-    ).match(stream.read()).group(1)
+    VERSION = (
+        re.compile(r".*__version__ = \"(.*?)\"", re.S)
+        .match(stream.read())
+        .group(1)
+    )
 
 # If extensions (or modules to document with autodoc) are in another
 # directory, add these directories to sys.path here. If the directory is
 # relative to the documentation root, use os.path.abspath to make it
 # absolute, like shown here.
-#sys.path.insert(0, os.path.abspath('.'))
+# sys.path.insert(0, os.path.abspath('.'))
 
 # -- General configuration ------------------------------------------------
 
 # If your documentation needs a minimal Sphinx version, state it here.
-#needs_sphinx = '1.0'
+# needs_sphinx = '1.0'
 
 # Add any Sphinx extension module names here, as strings. They can be
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
 extensions = [
-    'sphinx.ext.autodoc', 'sphinx.ext.coverage', 'sphinx.ext.viewcode'
+    "sphinx.ext.autodoc",
+    "sphinx.ext.coverage",
+    "sphinx.ext.viewcode",
 ]
 
 # Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
+templates_path = ["_templates"]
 
 # The suffix of source filenames.
-source_suffix = '.rst'
+source_suffix = ".rst"
 
 # The encoding of source files.
-#source_encoding = 'utf-8-sig'
+# source_encoding = 'utf-8-sig'
 
 # The master toctree document.
-master_doc = 'index'
+master_doc = "index"
 
 # General information about the project.
-project = u'pagure'
-copyright = u'2015, Red Hat Inc, Pierre-Yves Chibon <pingou@pingoured.fr>'
+project = u"pagure"
+copyright = u"2015, Red Hat Inc, Pierre-Yves Chibon <pingou@pingoured.fr>"
 
 # The version info for the project you're documenting, acts as replacement
 # for |version| and |release|, also used in various other places throughout
 # the built documents.
 #
 # The short X.Y version.
-#version = __version__
+# version = __version__
 version = VERSION
 # The full version, including alpha/beta/rc tags.
-#release = '1'
+# release = '1'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
-#language = None
+# language = None
 
 # There are two options for replacing |today|: either, you set today to some
 # non-false value, then it is used:
-#today = ''
+# today = ''
 # Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
+# today_fmt = '%B %d, %Y'
 
 # List of patterns, relative to source directory, that match files and
 # directories to ignore when looking for source files.
-exclude_patterns = ['_build']
+exclude_patterns = ["_build"]
 
 # The reST default role (used for this markup: `text`) to use for all
 # documents.
-#default_role = None
+# default_role = None
 
 # If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
+# add_function_parentheses = True
 
 # If true, the current module name will be prepended to all description
 # unit titles (such as .. function::).
-#add_module_names = True
+# add_module_names = True
 
 # If true, sectionauthor and moduleauthor directives will be shown in the
 # output. They are ignored by default.
-#show_authors = False
+# show_authors = False
 
 # The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
+pygments_style = "sphinx"
 
 # A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
+# modindex_common_prefix = []
 
 
 # -- Options for HTML output ----------------------------------------------
 
 import cloud_sptheme as csp
 
-html_style = 'site.css'
+html_style = "site.css"
 
 # The theme to use for HTML and HTML Help pages. See the documentation for
 # a list of builtin themes.
-#html_theme = 'default'
+# html_theme = 'default'
 html_theme = "cloud"
 
 # Theme options are theme-specific and customize the look and feel of a theme
 # further. For a list of options available for each theme, see the
 # documentation.
-#html_theme_options = {}
+# html_theme_options = {}
 
 html_theme_options = {
     "sidebarwidth": "200px",
     "max_width": "900px",
     "compact_width": "800px",
     "minimal_width": "700px",
-
     # Style it like Fedora..
     "bodyfont": "Cantarell",
-
     "highlightcolor": "#79db32",  # First Green
-
     "sidebarbgcolor": "#FEFEFE",
     "sidebartrimcolor": "#FEFEFE",
-
     "sectionbgcolor": "#FEFEFE",
     "sectiontrimcolor": "#FEFEFE",
     "sectiontextcolor": "#444444",
-
     "relbarbgcolor": "#FEFEFE",
     "relbartextcolor": "#444444",
     "relbarlinkcolor": "#444444",
-
     "bgcolor": "#FEFEFE",
     "textcolor": "#444444",
-    #"linkcolor": "#79db32",  # First Green
+    # "linkcolor": "#79db32",  # First Green
     "linkcolor": "#00009d",
-
     "headtextcolor": "#444444",
     "headlinkcolor": "#444444",
-
-    #"codebgcolor"
-    #"codetextcolor"
+    # "codebgcolor"
+    # "codetextcolor"
     "codetrimcolor": "#79db32",  # First Green
-
     "footerbgcolor": "#FEFEFE",
-
-    "fontcssurl": "_static/site.css"
+    "fontcssurl": "_static/site.css",
 }
 # Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
+# html_theme_path = []
 html_theme_path = [csp.get_theme_dir()]
 
 # The name for this set of Sphinx documents. If None, it defaults to
 # "<project> v<release> documentation".
-#html_title = None
+# html_title = None
 
 # A shorter title for the navigation bar. Default is the same as html_title.
-#html_short_title = None
+# html_short_title = None
 
 # The name of an image file (relative to this directory) to place at the top
 # of the sidebar.
-#html_logo = None
+# html_logo = None
 
 # The name of an image file (within the static path) to use as favicon of the
 # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
 # pixels large.
-#html_favicon = None
+# html_favicon = None
 
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
+html_static_path = ["_static"]
 
 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
 # using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
+# html_last_updated_fmt = '%b %d, %Y'
 
 # If true, SmartyPants will be used to convert quotes and dashes to
 # typographically correct entities.
-#html_use_smartypants = True
+# html_use_smartypants = True
 
 # Custom sidebar templates, maps document names to template names.
 html_sidebars = {
-    '**': [
-        'pagure-logo.html',
-        'localtoc.html',
-        'relations.html',
-        'sourcelink.html',
-        'searchbox.html',
+    "**": [
+        "pagure-logo.html",
+        "localtoc.html",
+        "relations.html",
+        "sourcelink.html",
+        "searchbox.html",
     ]
 }
 
 # Additional templates that should be rendered to pages, maps page names to
 # template names.
-#html_additional_pages = {}
+# html_additional_pages = {}
 
 # If false, no module index is generated.
-#html_domain_indices = True
+# html_domain_indices = True
 
 # If false, no index is generated.
-#html_use_index = True
+# html_use_index = True
 
 # If true, the index is split into individual pages for each letter.
-#html_split_index = False
+# html_split_index = False
 
 # If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
+# html_show_sourcelink = True
 
 # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
+# html_show_sphinx = True
 
 # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-#html_show_copyright = True
+# html_show_copyright = True
 
 # If true, an OpenSearch description file will be output, and all pages will
 # contain a <link> tag referring to it. The value of this option must be the
 # base URL from which the finished HTML is served.
-#html_use_opensearch = ''
+# html_use_opensearch = ''
 
 # This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
+# html_file_suffix = None
 
 # Output file base name for HTML help builder.
-htmlhelp_basename = 'pagure'
+htmlhelp_basename = "pagure"
 
 # -- Options for LaTeX output ---------------------------------------------
 
 latex_elements = {
     # The paper size ('letterpaper' or 'a4paper').
     #'papersize': 'letterpaper',
-
     # The font size ('10pt', '11pt' or '12pt').
     #'pointsize': '10pt',
-
     # Additional stuff for the LaTeX preamble.
     #'preamble': '',
 }
@@ -253,31 +246,33 @@ latex_elements = {
 # [howto/manual]).
 latex_documents = [
     (
-        'index', 'pagure.tex', u'Pagure Documentation',
-        u'Pierre-Yves Chibon \\textless{}pingou@pingoured.fr\\textgreater{}',
-        'manual'
-    ),
+        "index",
+        "pagure.tex",
+        u"Pagure Documentation",
+        u"Pierre-Yves Chibon \\textless{}pingou@pingoured.fr\\textgreater{}",
+        "manual",
+    )
 ]
 
 # The name of an image file (relative to this directory) to place at the top of
 # the title page.
-#latex_logo = None
+# latex_logo = None
 
 # For "manual" documents, if this is true, then toplevel headings are parts,
 # not chapters.
-#latex_use_parts = False
+# latex_use_parts = False
 
 # If true, show page references after internal links.
-#latex_show_pagerefs = False
+# latex_show_pagerefs = False
 
 # If true, show URL addresses after external links.
-#latex_show_urls = False
+# latex_show_urls = False
 
 # Documents to append as an appendix to all manuals.
-#latex_appendices = []
+# latex_appendices = []
 
 # If false, no module index is generated.
-#latex_domain_indices = True
+# latex_domain_indices = True
 
 # -- Options for manual page output ---------------------------------------
 
@@ -285,14 +280,16 @@ latex_documents = [
 # (source start file, name, description, authors, manual section).
 man_pages = [
     (
-        'index', 'pagure', u'Pagure Documentation',
-        [u'Pierre-Yves Chibon <pingou@pingoured.fr>'],
-        1
+        "index",
+        "pagure",
+        u"Pagure Documentation",
+        [u"Pierre-Yves Chibon <pingou@pingoured.fr>"],
+        1,
     )
 ]
 
 # If true, show URL addresses after external links.
-#man_show_urls = False
+# man_show_urls = False
 
 
 # -- Options for Texinfo output -------------------------------------------
@@ -302,18 +299,21 @@ man_pages = [
 # dir menu entry, description, category)
 texinfo_documents = [
     (
-        'index', 'pagure', u'Pagure Documentation',
-        u'Pierre-Yves Chibon <pingou@pingoured.fr>', 'pagure',
-        'Small git-centric forge',
-        'Miscellaneous'
-    ),
+        "index",
+        "pagure",
+        u"Pagure Documentation",
+        u"Pierre-Yves Chibon <pingou@pingoured.fr>",
+        "pagure",
+        "Small git-centric forge",
+        "Miscellaneous",
+    )
 ]
 
 # Documents to append as an appendix to all manuals.
-#texinfo_appendices = []
+# texinfo_appendices = []
 
 # If false, no module index is generated.
-#texinfo_domain_indices = True
+# texinfo_domain_indices = True
 
 # How to display URL addresses: 'footnote', 'no', or 'inline'.
-#texinfo_show_urls = 'footnote'
+# texinfo_show_urls = 'footnote'

+ 3 - 8
fedmsg.d/pagure.py

@@ -9,12 +9,7 @@ pagure producer (wsgi process).
 """
 
 import socket
-hostname = socket.gethostname().split('.')[0]
 
-config = dict(
-    endpoints={
-        "pagure.%s" % hostname: [
-            "tcp://127.0.0.1:3005",
-        ],
-    },
-)
+hostname = socket.gethostname().split(".")[0]
+
+config = dict(endpoints={"pagure.%s" % hostname: ["tcp://127.0.0.1:3005"]})

+ 1 - 3
fedmsg.d/pagure_ci.py

@@ -1,3 +1 @@
-config = {
-    'integrator.enabled': True,
-}
+config = {"integrator.enabled": True}

+ 1 - 1
files/aclchecker.py

@@ -99,7 +99,7 @@ result.update({"username": remoteuser, "cmd": cmd})
 
 for key in result:
     if result[key] is None:
-        result[key] = ''
+        result[key] = ""
 
 runargs = [arg % result for arg in runner]
 if env:

+ 38 - 26
files/api_key_expire_mail.py

@@ -13,29 +13,29 @@ import pagure.lib.model_base
 import pagure.lib.notify
 import pagure.lib.query
 
-if 'PAGURE_CONFIG' not in os.environ \
-        and os.path.exists('/etc/pagure/pagure.cfg'):
-    print('Using configuration file `/etc/pagure/pagure.cfg`')
-    os.environ['PAGURE_CONFIG'] = '/etc/pagure/pagure.cfg'
+if "PAGURE_CONFIG" not in os.environ and os.path.exists(
+    "/etc/pagure/pagure.cfg"
+):
+    print("Using configuration file `/etc/pagure/pagure.cfg`")
+    os.environ["PAGURE_CONFIG"] = "/etc/pagure/pagure.cfg"
 
 _config = pagure.config.reload_config()
 
 
 def main(check=False, debug=False):
-    ''' The function that actually sends the email
-    in case the expiration date is near'''
+    """ The function that actually sends the email
+    in case the expiration date is near"""
 
     current_time = datetime.utcnow()
     day_diff_for_mail = [10, 5, 1]
     email_dates = [
         email_day.date()
         for email_day in [
-            current_time + timedelta(days=i)
-                   for i in day_diff_for_mail
+            current_time + timedelta(days=i) for i in day_diff_for_mail
         ]
     ]
 
-    session = pagure.lib.model_base.create_session(_config['DB_URL'])
+    session = pagure.lib.model_base.create_session(_config["DB_URL"])
     tokens = session.query(model.Token).all()
 
     for token in tokens:
@@ -46,51 +46,63 @@ def main(check=False, debug=False):
             username = user.fullname or user.username
             user_email = user.default_email
             days_left = (token.expiration - datetime.utcnow()).days
-            subject = 'Pagure API key expiration date is near!'
+            subject = "Pagure API key expiration date is near!"
             if token.project:
-                text = '''Hi %s,
+                text = """Hi %s,
 Your Pagure API key %s linked to the project %s
 will expire in %s day(s).
 Please get a new key for non-interrupted service.
 
 Thanks,
-Your Pagure Admin. ''' % (
+Your Pagure Admin. """ % (
                     username,
                     token.description,
                     token.project.fullname,
-                    days_left
+                    days_left,
                 )
             else:
-                text = '''Hi %s,
+                text = """Hi %s,
 Your Pagure API key %s will expire in %s day(s).
 Please get a new key for non-interrupted service.
 
 Thanks,
-Your Pagure Admin. ''' % (
+Your Pagure Admin. """ % (
                     username,
                     token.description,
-                    days_left)
+                    days_left,
+                )
             if not check:
                 msg = pagure.lib.notify.send_email(text, subject, user_email)
             else:
-                print('Sending email to %s (%s) about key: %s' % (
-                    username, user_email, token.id))
+                print(
+                    "Sending email to %s (%s) about key: %s"
+                    % (username, user_email, token.id)
+                )
             if debug:
-                print('Sent mail to %s' % username)
+                print("Sent mail to %s" % username)
 
     session.remove()
     if debug:
-        print('Done')
+        print("Done")
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     parser = argparse.ArgumentParser(
-            description='Script to send email before the api token expires')
+        description="Script to send email before the api token expires"
+    )
     parser.add_argument(
-        '--check', dest='check', action='store_true', default=False,
-        help='Print the some output but does not send any email')
+        "--check",
+        dest="check",
+        action="store_true",
+        default=False,
+        help="Print the some output but does not send any email",
+    )
     parser.add_argument(
-        '--debug', dest='debug', action='store_true', default=False,
-        help='Print the debugging output')
+        "--debug",
+        dest="debug",
+        action="store_true",
+        default=False,
+        help="Print the debugging output",
+    )
     args = parser.parse_args()
     main(debug=args.debug)

+ 6 - 6
files/emoji_clean_json.py

@@ -6,27 +6,27 @@ import os
 import sys
 
 data = None
-with open('emoji_strategy.json') as stream:
+with open("emoji_strategy.json") as stream:
     data = json.load(stream)
 
 if not data:
-    print('Could not load the data from the JSON file')
+    print("Could not load the data from the JSON file")
     sys.exit(1)
 
 # Retrieve the items we keep in the JSON
 tokeep = {}
 for key in data:
-    if '-' in data[key]['unicode'] and data[key]['unicode'].startswith('1F'):
+    if "-" in data[key]["unicode"] and data[key]["unicode"].startswith("1F"):
         continue
     tokeep[key] = data[key]
 
 # Check if we have the keys of all images we kept
 
-unicodes = [tokeep[key]['unicode'] for key in tokeep]
-images = [item.replace('.png', '') for item in os.listdir('png')]
+unicodes = [tokeep[key]["unicode"] for key in tokeep]
+images = [item.replace(".png", "") for item in os.listdir("png")]
 
 print(set(unicodes).symmetric_difference(set(images)))
 
 
-with open('emoji_strategy2.json', 'w') as stream:
+with open("emoji_strategy2.json", "w") as stream:
     json.dump(tokeep, stream)

+ 28 - 18
files/mirror_project_in.py

@@ -13,23 +13,24 @@ import pagure.lib.model_base
 import pagure.lib.notify
 import pagure.lib.query
 
-if 'PAGURE_CONFIG' not in os.environ \
-        and os.path.exists('/etc/pagure/pagure.cfg'):
-    print('Using configuration file `/etc/pagure/pagure.cfg`')
-    os.environ['PAGURE_CONFIG'] = '/etc/pagure/pagure.cfg'
+if "PAGURE_CONFIG" not in os.environ and os.path.exists(
+    "/etc/pagure/pagure.cfg"
+):
+    print("Using configuration file `/etc/pagure/pagure.cfg`")
+    os.environ["PAGURE_CONFIG"] = "/etc/pagure/pagure.cfg"
 
 _config = pagure.config.reload_config()
 
 
 def main(check=False, debug=False):
-    ''' The function pulls in all the changes from upstream'''
+    """ The function pulls in all the changes from upstream"""
 
-    session = pagure.lib.model_base.create_session(_config['DB_URL'])
-    projects = session.query(
-        model.Project
-    ).filter(
-        model.Project.mirrored_from != None
-    ).all()
+    session = pagure.lib.model_base.create_session(_config["DB_URL"])
+    projects = (
+        session.query(model.Project)
+        .filter(model.Project.mirrored_from != None)
+        .all()
+    )
 
     for project in projects:
         if debug:
@@ -41,17 +42,26 @@ def main(check=False, debug=False):
 
     session.remove()
     if debug:
-        print('Done')
+        print("Done")
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     parser = argparse.ArgumentParser(
-            description='Script to send email before the api token expires')
+        description="Script to send email before the api token expires"
+    )
     parser.add_argument(
-        '--check', dest='check', action='store_true', default=False,
-        help='Print the some output but does not send any email')
+        "--check",
+        dest="check",
+        action="store_true",
+        default=False,
+        help="Print the some output but does not send any email",
+    )
     parser.add_argument(
-        '--debug', dest='debug', action='store_true', default=False,
-        help='Print the debugging output')
+        "--debug",
+        dest="debug",
+        action="store_true",
+        default=False,
+        help="Print the debugging output",
+    )
     args = parser.parse_args()
     main(debug=args.debug)

+ 67 - 55
pagure-ev/pagure_stream_server.py

@@ -33,10 +33,11 @@ from six.moves.urllib.parse import urlparse
 log = logging.getLogger(__name__)
 
 
-if 'PAGURE_CONFIG' not in os.environ \
-        and os.path.exists('/etc/pagure/pagure.cfg'):
-    print('Using configuration file `/etc/pagure/pagure.cfg`')
-    os.environ['PAGURE_CONFIG'] = '/etc/pagure/pagure.cfg'
+if "PAGURE_CONFIG" not in os.environ and os.path.exists(
+    "/etc/pagure/pagure.cfg"
+):
+    print("Using configuration file `/etc/pagure/pagure.cfg`")
+    os.environ["PAGURE_CONFIG"] = "/etc/pagure/pagure.cfg"
 
 
 import pagure  # noqa: E402
@@ -47,17 +48,19 @@ from pagure.exceptions import PagureException, PagureEvException  # noqa: E402
 SERVER = None
 SESSION = None
 POOL = redis.ConnectionPool(
-    host=pagure.config.config['REDIS_HOST'],
-    port=pagure.config.config['REDIS_PORT'],
-    db=pagure.config.config['REDIS_DB'])
+    host=pagure.config.config["REDIS_HOST"],
+    port=pagure.config.config["REDIS_PORT"],
+    db=pagure.config.config["REDIS_DB"],
+)
 
 
 def _get_session():
     global SESSION
     if SESSION is None:
-        print(pagure.config.config['DB_URL'])
+        print(pagure.config.config["DB_URL"])
         SESSION = pagure.lib.model_base.create_session(
-            pagure.config.config['DB_URL'])
+            pagure.config.config["DB_URL"]
+        )
 
     return SESSION
 
@@ -67,7 +70,7 @@ def _get_issue(repo, objid):
     objid (issue number).
     """
     issue = None
-    if not repo.settings.get('issue_tracker', True):
+    if not repo.settings.get("issue_tracker", True):
         raise PagureEvException("No issue tracker found for this project")
 
     session = _get_session()
@@ -79,7 +82,8 @@ def _get_issue(repo, objid):
     if issue.private:
         # TODO: find a way to do auth
         raise PagureEvException(
-            "This issue is private and you are not allowed to view it")
+            "This issue is private and you are not allowed to view it"
+        )
 
     return issue
 
@@ -88,13 +92,15 @@ def _get_pull_request(repo, objid):
     """Get a PullRequest instance for a given repo (Project) and objid
     (request number).
     """
-    if not repo.settings.get('pull_requests', True):
+    if not repo.settings.get("pull_requests", True):
         raise PagureEvException(
-            "No pull-request tracker found for this project")
+            "No pull-request tracker found for this project"
+        )
 
     session = _get_session()
     request = pagure.lib.query.search_pull_requests(
-        session, project_id=repo.id, requestid=objid)
+        session, project_id=repo.id, requestid=objid
+    )
 
     if request is None or request.project != repo:
         raise PagureEvException("Pull-Request '%s' not found" % objid)
@@ -105,20 +111,19 @@ def _get_pull_request(repo, objid):
 # Dict representing known object types that we handle requests for,
 # and the bound functions for getting an object instance from the
 # parsed path data. Has to come after the functions it binds
-OBJECTS = {
-    'issue': _get_issue,
-    'pull-request': _get_pull_request
-}
+OBJECTS = {"issue": _get_issue, "pull-request": _get_pull_request}
 
 
 def get_obj_from_path(path):
     """ Return the Ticket or Request object based on the path provided.
     """
     (username, namespace, reponame, objtype, objid) = pagure.utils.parse_path(
-        path)
+        path
+    )
     session = _get_session()
     repo = pagure.lib.query.get_authorized_project(
-            session, reponame, user=username, namespace=namespace)
+        session, reponame, user=username, namespace=namespace
+    )
 
     if repo is None:
         raise PagureEvException("Project '%s' not found" % reponame)
@@ -137,9 +142,9 @@ def handle_client(client_reader, client_writer):
     data = None
     while True:
         # give client a chance to respond, timeout after 10 seconds
-        line = yield trololio.From(trololio.asyncio.wait_for(
-            client_reader.readline(),
-            timeout=10.0))
+        line = yield trololio.From(
+            trololio.asyncio.wait_for(client_reader.readline(), timeout=10.0)
+        )
         if not line.decode().strip():
             break
         line = line.decode().rstrip()
@@ -156,7 +161,7 @@ def handle_client(client_reader, client_writer):
         log.warning("No URL provided: %s" % data)
         return
 
-    if '/' not in data[1]:
+    if "/" not in data[1]:
         log.warning("Invalid URL provided: %s" % data[1])
         return
 
@@ -168,24 +173,25 @@ def handle_client(client_reader, client_writer):
         log.warning(err.message)
         return
 
-    origin = pagure.config.config.get('APP_URL')
-    if origin.endswith('/'):
+    origin = pagure.config.config.get("APP_URL")
+    if origin.endswith("/"):
         origin = origin[:-1]
 
-    client_writer.write((
-        "HTTP/1.0 200 OK\n"
-        "Content-Type: text/event-stream\n"
-        "Cache: nocache\n"
-        "Connection: keep-alive\n"
-        "Access-Control-Allow-Origin: %s\n\n" % origin
-    ).encode())
-
+    client_writer.write(
+        (
+            "HTTP/1.0 200 OK\n"
+            "Content-Type: text/event-stream\n"
+            "Cache: nocache\n"
+            "Connection: keep-alive\n"
+            "Access-Control-Allow-Origin: %s\n\n" % origin
+        ).encode()
+    )
 
     conn = redis.Redis(connection_pool=POOL)
     subscriber = conn.pubsub(ignore_subscribe_messages=True)
 
     try:
-        subscriber.subscribe('pagure.%s' % obj.uid)
+        subscriber.subscribe("pagure.%s" % obj.uid)
 
         # Inside a while loop, wait for incoming events.
         oncall = 0
@@ -195,14 +201,14 @@ def handle_client(client_reader, client_writer):
                 # Send a ping to see if the client is still alive
                 if oncall >= 5:
                     # Only send a ping once every 5 seconds
-                    client_writer.write(('event: ping\n\n').encode())
+                    client_writer.write(("event: ping\n\n").encode())
                     oncall = 0
                 oncall += 1
                 yield trololio.From(client_writer.drain())
                 yield trololio.From(trololio.asyncio.sleep(1))
             else:
-                log.info("Sending %s", msg['data'])
-                client_writer.write(('data: %s\n\n' % msg['data']).encode())
+                log.info("Sending %s", msg["data"])
+                client_writer.write(("data: %s\n\n" % msg["data"]).encode())
                 yield trololio.From(client_writer.drain())
 
     except OSError:
@@ -223,12 +229,11 @@ def handle_client(client_reader, client_writer):
 def stats(client_reader, client_writer):
 
     try:
-        log.info('Clients: %s', SERVER.active_count)
-        client_writer.write((
-            "HTTP/1.0 200 OK\n"
-            "Cache: nocache\n\n"
-        ).encode())
-        client_writer.write(('data: %s\n\n' % SERVER.active_count).encode())
+        log.info("Clients: %s", SERVER.active_count)
+        client_writer.write(
+            ("HTTP/1.0 200 OK\n" "Cache: nocache\n\n").encode()
+        )
+        client_writer.write(("data: %s\n\n" % SERVER.active_count).encode())
         yield trololio.From(client_writer.drain())
 
     except trololio.ConnectionResetError as err:
@@ -247,20 +252,26 @@ def main():
         coro = trololio.asyncio.start_server(
             handle_client,
             host=None,
-            port=pagure.config.config['EVENTSOURCE_PORT'],
-            loop=loop)
+            port=pagure.config.config["EVENTSOURCE_PORT"],
+            loop=loop,
+        )
         SERVER = loop.run_until_complete(coro)
         log.info(
-            'Serving server at {}'.format(SERVER.sockets[0].getsockname()))
-        if pagure.config.config.get('EV_STATS_PORT'):
+            "Serving server at {}".format(SERVER.sockets[0].getsockname())
+        )
+        if pagure.config.config.get("EV_STATS_PORT"):
             stats_coro = trololio.asyncio.start_server(
                 stats,
                 host=None,
-                port=pagure.config.config.get('EV_STATS_PORT'),
-                loop=loop)
+                port=pagure.config.config.get("EV_STATS_PORT"),
+                loop=loop,
+            )
             stats_server = loop.run_until_complete(stats_coro)
-            log.info('Serving stats  at {}'.format(
-                stats_server.sockets[0].getsockname()))
+            log.info(
+                "Serving stats  at {}".format(
+                    stats_server.sockets[0].getsockname()
+                )
+            )
         loop.run_forever()
     except KeyboardInterrupt:
         pass
@@ -271,7 +282,7 @@ def main():
     finally:
         # Close the server
         SERVER.close()
-        if pagure.config.config.get('EV_STATS_PORT'):
+        if pagure.config.config.get("EV_STATS_PORT"):
             stats_server.close()
         log.info("End Connection")
         loop.run_until_complete(SERVER.wait_closed())
@@ -279,10 +290,11 @@ def main():
         log.info("End")
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     log = logging.getLogger("")
     formatter = logging.Formatter(
-        "%(asctime)s %(levelname)s [%(module)s:%(lineno)d] %(message)s")
+        "%(asctime)s %(levelname)s [%(module)s:%(lineno)d] %(message)s"
+    )
 
     # setup console logging
     log.setLevel(logging.DEBUG)

+ 95 - 91
pagure-milters/comment_email_milter.py

@@ -26,9 +26,10 @@ import pagure.lib.model_base
 import pagure.lib.query
 
 
-if 'PAGURE_CONFIG' not in os.environ \
-        and os.path.exists('/etc/pagure/pagure.cfg'):
-    os.environ['PAGURE_CONFIG'] = '/etc/pagure/pagure.cfg'
+if "PAGURE_CONFIG" not in os.environ and os.path.exists(
+    "/etc/pagure/pagure.cfg"
+):
+    os.environ["PAGURE_CONFIG"] = "/etc/pagure/pagure.cfg"
 
 
 logq = Queue(maxsize=4)
@@ -36,8 +37,9 @@ _config = pagure.config.reload_config()
 
 
 def get_email_body(emailobj):
-    ''' Return the body of the email, preferably in text.
-    '''
+    """ Return the body of the email, preferably in text.
+    """
+
     def _get_body(emailobj):
         """ Return the first text/plain body found if the email is multipart
         or just the regular payload otherwise.
@@ -51,34 +53,33 @@ def get_email_body(emailobj):
                     return _get_body(payload)
 
                 body = payload.get_payload()
-                if payload.get_content_type() == 'text/plain':
+                if payload.get_content_type() == "text/plain":
                     return body
         else:
             return emailobj.get_payload()
 
     body = _get_body(emailobj)
 
-    enc = emailobj['Content-Transfer-Encoding']
-    if enc == 'base64':
+    enc = emailobj["Content-Transfer-Encoding"]
+    if enc == "base64":
         body = base64.decodestring(body)
 
     return body
 
 
 def clean_item(item):
-    ''' For an item provided as <item> return the content, if there are no
+    """ For an item provided as <item> return the content, if there are no
     <> then return the string.
-    '''
-    if '<' in item:
-        item = item.split('<')[1]
-    if '>' in item:
-        item = item.split('>')[0]
+    """
+    if "<" in item:
+        item = item.split("<")[1]
+    if ">" in item:
+        item = item.split(">")[0]
 
     return item
 
 
 class PagureMilter(Milter.Base):
-
     def __init__(self):  # A new instance with each new connection.
         self.id = Milter.uniqueID()  # Integer incremented with each call.
         self.fp = None
@@ -94,28 +95,28 @@ class PagureMilter(Milter.Base):
         # must use addheader, chgheader, replacebody to change the message
         # on the MTA.
         self.fp = BytesIO()
-        self.canon_from = '@'.join(parse_addr(mailfrom))
-        from_txt = 'From %s %s\n' % (self.canon_from, time.ctime())
-        self.fp.write(from_txt.encode('utf-8'))
+        self.canon_from = "@".join(parse_addr(mailfrom))
+        from_txt = "From %s %s\n" % (self.canon_from, time.ctime())
+        self.fp.write(from_txt.encode("utf-8"))
         return Milter.CONTINUE
 
     @Milter.noreply
     def header(self, name, hval):
-        ''' Headers '''
+        """ Headers """
         # add header to buffer
         header_txt = "%s: %s\n" % (name, hval)
-        self.fp.write(header_txt.encode('utf-8'))
+        self.fp.write(header_txt.encode("utf-8"))
         return Milter.CONTINUE
 
     @Milter.noreply
     def eoh(self):
-        ''' End of Headers '''
+        """ End of Headers """
         self.fp.write(b"\n")
         return Milter.CONTINUE
 
     @Milter.noreply
     def body(self, chunk):
-        ''' Body '''
+        """ Body """
         self.fp.write(chunk)
         return Milter.CONTINUE
 
@@ -127,138 +128,139 @@ class PagureMilter(Milter.Base):
         return Milter.CONTINUE
 
     def eom(self):
-        ''' End of Message '''
+        """ End of Message """
         self.fp.seek(0)
         msg = email.message_from_file(self.fp)
 
-        msg_id = msg.get('In-Reply-To', None)
+        msg_id = msg.get("In-Reply-To", None)
         if msg_id is None:
-            self.log('No In-Reply-To, keep going')
+            self.log("No In-Reply-To, keep going")
             return Milter.CONTINUE
 
         # Ensure we don't get extra lines in the message-id
-        msg_id = msg_id.split('\n')[0].strip()
+        msg_id = msg_id.split("\n")[0].strip()
 
-        self.log('msg-ig %s' % msg_id)
-        self.log('To %s' % msg['to'])
-        self.log('Cc %s' % msg.get('cc'))
-        self.log('From %s' % msg['From'])
+        self.log("msg-ig %s" % msg_id)
+        self.log("To %s" % msg["to"])
+        self.log("Cc %s" % msg.get("cc"))
+        self.log("From %s" % msg["From"])
 
         # Check the email was sent to the right address
-        email_address = msg['to']
-        if 'reply+' in msg.get('cc', ''):
-            email_address = msg['cc']
-        if 'reply+' not in email_address:
+        email_address = msg["to"]
+        if "reply+" in msg.get("cc", ""):
+            email_address = msg["cc"]
+        if "reply+" not in email_address:
             self.log(
-                'No valid recipient email found in To/Cc: %s'
-                % email_address)
+                "No valid recipient email found in To/Cc: %s" % email_address
+            )
             return Milter.CONTINUE
 
         # Ensure the user replied to his/her own notification, not that
         # they are trying to forge their ID into someone else's
-        salt = _config.get('SALT_EMAIL')
-        from_email = clean_item(msg['From'])
-        session = pagure.lib.model_base.create_session(_config['DB_URL'])
+        salt = _config.get("SALT_EMAIL")
+        from_email = clean_item(msg["From"])
+        session = pagure.lib.model_base.create_session(_config["DB_URL"])
         try:
             user = pagure.lib.query.get_user(session, from_email)
         except:
             self.log(
-                "Could not find an user in the DB associated with %s" %
-                from_email)
+                "Could not find an user in the DB associated with %s"
+                % from_email
+            )
             session.remove()
             return Milter.CONTINUE
 
         hashes = []
         for email_obj in user.emails:
-            m = hashlib.sha512('%s%s%s' % (msg_id, salt, email_obj.email))
+            m = hashlib.sha512("%s%s%s" % (msg_id, salt, email_obj.email))
             hashes.append(m.hexdigest())
 
-        tohash = email_address.split('@')[0].split('+')[-1]
+        tohash = email_address.split("@")[0].split("+")[-1]
         if tohash not in hashes:
-            self.log('hash list: %s' % hashes)
-            self.log('tohash:    %s' % tohash)
-            self.log('Hash does not correspond to the destination')
+            self.log("hash list: %s" % hashes)
+            self.log("tohash:    %s" % tohash)
+            self.log("Hash does not correspond to the destination")
             session.remove()
             return Milter.CONTINUE
 
-        if msg['From'] and msg['From'] == _config.get('FROM_EMAIL'):
+        if msg["From"] and msg["From"] == _config.get("FROM_EMAIL"):
             self.log("Let's not process the email we send")
             session.remove()
             return Milter.CONTINUE
 
         msg_id = clean_item(msg_id)
 
-        if msg_id and '-ticket-' in msg_id:
-            self.log('Processing issue')
+        if msg_id and "-ticket-" in msg_id:
+            self.log("Processing issue")
             session.remove()
             return self.handle_ticket_email(msg, msg_id)
-        elif msg_id and '-pull-request-' in msg_id:
-            self.log('Processing pull-request')
+        elif msg_id and "-pull-request-" in msg_id:
+            self.log("Processing pull-request")
             session.remove()
             return self.handle_request_email(msg, msg_id)
         else:
-            self.log('Not a pagure ticket or pull-request email, let it go')
+            self.log("Not a pagure ticket or pull-request email, let it go")
             session.remove()
             return Milter.CONTINUE
 
     def handle_ticket_email(self, emailobj, msg_id):
-        ''' Add the email as a comment on a ticket. '''
-        uid = msg_id.split('-ticket-')[-1].split('@')[0]
+        """ Add the email as a comment on a ticket. """
+        uid = msg_id.split("-ticket-")[-1].split("@")[0]
         parent_id = None
-        if '-' in uid:
-            uid, parent_id = uid.rsplit('-', 1)
-        if '/' in uid:
-            uid = uid.split('/')[0]
-        self.log('uid %s' % uid)
-        self.log('parent_id %s' % parent_id)
+        if "-" in uid:
+            uid, parent_id = uid.rsplit("-", 1)
+        if "/" in uid:
+            uid = uid.split("/")[0]
+        self.log("uid %s" % uid)
+        self.log("parent_id %s" % parent_id)
 
         data = {
-            'objid': uid,
-            'comment': get_email_body(emailobj),
-            'useremail': clean_item(emailobj['From']),
+            "objid": uid,
+            "comment": get_email_body(emailobj),
+            "useremail": clean_item(emailobj["From"]),
         }
-        url = _config.get('APP_URL')
+        url = _config.get("APP_URL")
 
-        if url.endswith('/'):
+        if url.endswith("/"):
             url = url[:-1]
-        url = '%s/pv/ticket/comment/' % url
-        self.log('Calling URL: %s' % url)
+        url = "%s/pv/ticket/comment/" % url
+        self.log("Calling URL: %s" % url)
         req = requests.put(url, data=data)
         if req.status_code == 200:
-            self.log('Comment added')
+            self.log("Comment added")
             return Milter.ACCEPT
-        self.log('Could not add the comment to ticket to pagure')
+        self.log("Could not add the comment to ticket to pagure")
         self.log(req.text)
 
         return Milter.CONTINUE
 
     def handle_request_email(self, emailobj, msg_id):
-        ''' Add the email as a comment on a request. '''
-        uid = msg_id.split('-pull-request-')[-1].split('@')[0]
+        """ Add the email as a comment on a request. """
+        uid = msg_id.split("-pull-request-")[-1].split("@")[0]
         parent_id = None
-        if '-' in uid:
-            uid, parent_id = uid.rsplit('-', 1)
-        if '/' in uid:
-            uid = uid.split('/')[0]
-        self.log('uid %s' % uid)
-        self.log('parent_id %s' % parent_id)
+        if "-" in uid:
+            uid, parent_id = uid.rsplit("-", 1)
+        if "/" in uid:
+            uid = uid.split("/")[0]
+        self.log("uid %s" % uid)
+        self.log("parent_id %s" % parent_id)
 
         data = {
-            'objid': uid,
-            'comment': get_email_body(emailobj),
-            'useremail': clean_item(emailobj['From']),
+            "objid": uid,
+            "comment": get_email_body(emailobj),
+            "useremail": clean_item(emailobj["From"]),
         }
-        url = _config.get('APP_URL')
+        url = _config.get("APP_URL")
 
-        if url.endswith('/'):
+        if url.endswith("/"):
             url = url[:-1]
-        url = '%s/pv/pull-request/comment/' % url
-        self.log('Calling URL: %s' % url)
+        url = "%s/pv/pull-request/comment/" % url
+        self.log("Calling URL: %s" % url)
         req = requests.put(url, data=data)
         if req.status_code == 200:
-            self.log('Comment added on PR')
+            self.log("Comment added on PR")
             return Milter.ACCEPT
-        self.log('Could not add the comment to PR to pagure')
+        self.log("Could not add the comment to PR to pagure")
         self.log(req.text)
 
         return Milter.CONTINUE
@@ -270,11 +272,13 @@ def background():
         if not t:
             break
         msg, id, ts = t
-        print("%s [%d]" % (time.strftime(
-            '%Y%b%d %H:%M:%S', time.localtime(ts)), id))
+        print(
+            "%s [%d]"
+            % (time.strftime("%Y%b%d %H:%M:%S", time.localtime(ts)), id)
+        )
         # 2005Oct13 02:34:11 [1] msg1 msg2 msg3 ...
         for i in msg:
-            print(i,)
+            print(i)
         print
 
 
@@ -285,12 +289,12 @@ def main():
     timeout = 600
     # Register to have the Milter factory create instances of your class:
     Milter.factory = PagureMilter
-    print("%s pagure milter startup" % time.strftime('%Y%b%d %H:%M:%S'))
+    print("%s pagure milter startup" % time.strftime("%Y%b%d %H:%M:%S"))
     sys.stdout.flush()
     Milter.runmilter("paguremilter", socketname, timeout)
     logq.put(None)
     bt.join()
-    print("%s pagure milter shutdown" % time.strftime('%Y%b%d %H:%M:%S'))
+    print("%s pagure milter shutdown" % time.strftime("%Y%b%d %H:%M:%S"))
 
 
 if __name__ == "__main__":

+ 32 - 18
rundocserver.py

@@ -3,7 +3,7 @@
 from __future__ import unicode_literals, absolute_import
 
 # These two lines are needed to run on EL6
-__requires__ = ['jinja2 >= 2.4']
+__requires__ = ["jinja2 >= 2.4"]
 import pkg_resources
 
 import argparse
@@ -11,42 +11,56 @@ import sys
 import os
 
 
-parser = argparse.ArgumentParser(
-    description='Run the Pagure doc server')
+parser = argparse.ArgumentParser(description="Run the Pagure doc server")
 parser.add_argument(
-    '--config', '-c', dest='config',
-    help='Configuration file to use for the pagure doc server.')
+    "--config",
+    "-c",
+    dest="config",
+    help="Configuration file to use for the pagure doc server.",
+)
 parser.add_argument(
-    '--debug', dest='debug', action='store_true',
+    "--debug",
+    dest="debug",
+    action="store_true",
     default=False,
-    help='Expand the level of data returned.')
+    help="Expand the level of data returned.",
+)
 parser.add_argument(
-    '--profile', dest='profile', action='store_true',
+    "--profile",
+    dest="profile",
+    action="store_true",
     default=False,
-    help='Profile the doc server.')
+    help="Profile the doc server.",
+)
 parser.add_argument(
-    '--port', '-p', default=5001,
-    help='Port for the Pagure doc server to run on.')
+    "--port",
+    "-p",
+    default=5001,
+    help="Port for the Pagure doc server to run on.",
+)
 parser.add_argument(
-    '--host', default="127.0.0.1",
-    help='Hostname to listen on. When set to 0.0.0.0 the server is '
-    'available externally. Defaults to 127.0.0.1 making the it only '
-    'visible on localhost')
+    "--host",
+    default="127.0.0.1",
+    help="Hostname to listen on. When set to 0.0.0.0 the server is "
+    "available externally. Defaults to 127.0.0.1 making the it only "
+    "visible on localhost",
+)
 
 args = parser.parse_args()
 
 if args.config:
     config = args.config
-    if not config.startswith('/'):
+    if not config.startswith("/"):
         here = os.path.join(os.path.dirname(os.path.abspath(__file__)))
         config = os.path.join(here, config)
-    os.environ['PAGURE_CONFIG'] = config
+    os.environ["PAGURE_CONFIG"] = config
 
 from pagure.docs_server import APP
 
 if args.profile:
     from werkzeug.contrib.profiler import ProfilerMiddleware
-    APP.config['PROFILE'] = True
+
+    APP.config["PROFILE"] = True
     APP.wsgi_app = ProfilerMiddleware(APP.wsgi_app, restrictions=[30])
 
 APP.debug = True

+ 40 - 26
runserver.py

@@ -7,56 +7,69 @@ import sys
 import os
 
 
-parser = argparse.ArgumentParser(
-    description='Run the Pagure app')
+parser = argparse.ArgumentParser(description="Run the Pagure app")
 parser.add_argument(
-    '--config', '-c', dest='config',
-    help='Configuration file to use for pagure.')
+    "--config",
+    "-c",
+    dest="config",
+    help="Configuration file to use for pagure.",
+)
 parser.add_argument(
-    '--plugins',  dest='plugins',
-    help='Configuration file for pagure plugin.')
+    "--plugins", dest="plugins", help="Configuration file for pagure plugin."
+)
 parser.add_argument(
-    '--debug', dest='debug', action='store_true',
+    "--debug",
+    dest="debug",
+    action="store_true",
     default=False,
-    help='Expand the level of data returned.')
+    help="Expand the level of data returned.",
+)
 parser.add_argument(
-    '--profile', dest='profile', action='store_true',
+    "--profile",
+    dest="profile",
+    action="store_true",
     default=False,
-    help='Profile Pagure.')
+    help="Profile Pagure.",
+)
 parser.add_argument(
-    '--perf-verbose', dest='perfverbose', action='store_true',
+    "--perf-verbose",
+    dest="perfverbose",
+    action="store_true",
     default=False,
-    help='Enable per-request printing of performance statistics.')
+    help="Enable per-request printing of performance statistics.",
+)
 parser.add_argument(
-    '--port', '-p', default=5000,
-    help='Port for the Pagure to run on.')
+    "--port", "-p", default=5000, help="Port for the Pagure to run on."
+)
 parser.add_argument(
-    '--no-debug', action='store_true',
-    help='Disable debugging')
+    "--no-debug", action="store_true", help="Disable debugging"
+)
 parser.add_argument(
-    '--host', default="127.0.0.1",
-    help='Hostname to listen on. When set to 0.0.0.0 the server is available '
-    'externally. Defaults to 127.0.0.1 making the it only visible on localhost')
+    "--host",
+    default="127.0.0.1",
+    help="Hostname to listen on. When set to 0.0.0.0 the server is available "
+    "externally. Defaults to 127.0.0.1 making the it only visible on localhost",
+)
 
 args = parser.parse_args()
 
 if args.config:
     config = args.config
-    if not config.startswith('/'):
+    if not config.startswith("/"):
         here = os.path.join(os.path.dirname(os.path.abspath(__file__)))
         config = os.path.join(here, config)
-    os.environ['PAGURE_CONFIG'] = config
+    os.environ["PAGURE_CONFIG"] = config
 
 if args.plugins:
     config = args.plugins
-    if not config.startswith('/'):
+    if not config.startswith("/"):
         here = os.path.join(os.path.dirname(os.path.abspath(__file__)))
         config = os.path.join(here, config)
-    os.environ['PAGURE_PLUGIN'] = config
+    os.environ["PAGURE_PLUGIN"] = config
 
 if args.perfverbose:
-    os.environ['PAGURE_PERFREPO'] = 'true'
-    os.environ['PAGURE_PERFREPO_VERBOSE'] = 'true'
+    os.environ["PAGURE_PERFREPO"] = "true"
+    os.environ["PAGURE_PERFREPO_VERBOSE"] = "true"
 
 from pagure.flask_app import create_app
 
@@ -64,7 +77,8 @@ APP = create_app()
 
 if args.profile:
     from werkzeug.contrib.profiler import ProfilerMiddleware
-    APP.config['PROFILE'] = True
+
+    APP.config["PROFILE"] = True
     APP.wsgi_app = ProfilerMiddleware(APP.wsgi_app, restrictions=[30])
 
 APP.debug = not args.no_debug

+ 95 - 47
runtests.py

@@ -28,12 +28,13 @@ PRINTLOCK = None
 RUNNING = []
 FAILED = []
 NUMPROCS = multiprocessing.cpu_count() - 1
-if os.environ.get('BUILD_ID'):
+if os.environ.get("BUILD_ID"):
     NUMPROCS = multiprocessing.cpu_count()
 
 HERE = os.path.join(os.path.dirname(os.path.abspath(__file__)))
 LOG = logging.getLogger(__name__)
 
+
 def setup_parser():
     """ Set up the command line arguments supported and return the arguments
     """
@@ -144,7 +145,10 @@ def setup_parser():
         help="Show the error files using `less`",
     )
     parser_run.add_argument(
-        "-n", default=None, nargs="?", type=int,
+        "-n",
+        default=None,
+        nargs="?",
+        type=int,
         help="Number of failed test to show",
     )
     parser_run.set_defaults(func=do_list)
@@ -152,7 +156,8 @@ def setup_parser():