Repository: pypi/warehouse

Issue:
Update pyramid-tm to 2.0

There's a new version of [pyramid-tm](https://pypi.python.org/pypi/pyramid-tm) available.
You are currently using **1.1.1**. I have updated it to **2.0**



These links might come in handy:  <a href="http://pypi.python.org/pypi/pyramid_tm">PyPI</a> | <a href="https://pyup.io/changelogs/pyramid-tm/">Changelog</a> | <a href="http://docs.pylonsproject.org/projects/pyramid-tm/en/latest/">Homepage</a> 



### Changelog
> 
>### 2.0

>^^^^^^^^^^^^^^^^

>Major Features
>~~~~~~~~~~~~~~

>- The ``pyramid_tm`` tween has been moved **over** the ``EXCVIEW`` tween.
>  This means the transaction is open during exception view execution.
>  See https://github.com/Pylons/pyramid_tm/pull/55

>- Added a ``pyramid_tm.is_tm_active`` and a ``tm_active`` view predicate
>  which may be useful in exception views that require access to the database.
>  See https://github.com/Pylons/pyramid_tm/pull/60

>Backward Incompatibilities
>~~~~~~~~~~~~~~~~~~~~~~~~~~

>- The ``tm.attempts`` setting has been removed and retry support has been moved
>  into a new package named ``pyramid_retry``. If you want retry support then
>  please look at that library for more information about installing and
>  enabling it. See https://github.com/Pylons/pyramid_tm/pull/55

>- The ``pyramid_tm`` tween has been moved **over** the ``EXCVIEW`` tween.
>  If you have any hacks in your application that are opening a new transaction
>  inside your exception views then it&#39;s likely you will want to remove them
>  or re-evaluate when upgrading.
>  See https://github.com/Pylons/pyramid_tm/pull/55

>- Drop support for Pyramid &lt; 1.5.

>Minor Features
>~~~~~~~~~~~~~~

>- Support for Python 3.6.







*Got merge conflicts? Close this PR and delete the branch. I'll create a new PR for you.*

Happy merging! 🤖



Discussion:
This probably needs to wait until Pyramid 1.9 is released so that we can switch to pyramid_retry to handle retry logic.

Resolving patch:
diff --git a/warehouse/config.py b/warehouse/config.py
--- a/warehouse/config.py
+++ b/warehouse/config.py
@@ -284,11 +284,14 @@ def configure(settings=None):
         renderers.JSON(sort_keys=True, separators=(",", ":")),
     )
 
+    # Configure retry support.
+    config.add_settings({"retry.attempts": 3})
+    config.include("pyramid_retry")
+
     # Configure our transaction handling so that each request gets its own
     # transaction handler and the lifetime of the transaction is tied to the
     # lifetime of the request.
     config.add_settings({
-        "tm.attempts": 3,
         "tm.manager_hook": lambda request: transaction.TransactionManager(),
         "tm.activate_hook": activate_hook,
         "tm.annotate_user": False,
diff --git a/warehouse/tasks.py b/warehouse/tasks.py
--- a/warehouse/tasks.py
+++ b/warehouse/tasks.py
@@ -21,6 +21,7 @@
 import celery
 import celery.backends.redis
 import pyramid.scripting
+import pyramid_retry
 import transaction
 import venusian
 
@@ -56,7 +57,8 @@ def run(*args, **kwargs):
                 try:
                     return original_run(*args, **kwargs)
                 except BaseException as exc:
-                    if request.tm._retryable(exc.__class__, exc):
+                    if (isinstance(exc, pyramid_retry.RetryableException)
+                            or pyramid_retry.IRetryableError.providedBy(exc)):
                         raise obj.retry(exc=exc)
                     raise
 


Test patch:
diff --git a/tests/unit/test_config.py b/tests/unit/test_config.py
--- a/tests/unit/test_config.py
+++ b/tests/unit/test_config.py
@@ -319,6 +319,7 @@ def __init__(self):
                 ),
             ]
         ] + [
+            pretend.call("pyramid_retry"),
             pretend.call("pyramid_tm"),
             pretend.call("pyramid_services"),
             pretend.call("pyramid_rpc.xmlrpc"),
@@ -365,8 +366,8 @@ def __init__(self):
     ]
     assert configurator_obj.add_settings.calls == [
         pretend.call({"jinja2.newstyle": True}),
+        pretend.call({"retry.attempts": 3}),
         pretend.call({
-            "tm.attempts": 3,
             "tm.manager_hook": mock.ANY,
             "tm.activate_hook": config.activate_hook,
             "tm.annotate_user": False,
@@ -377,7 +378,7 @@ def __init__(self):
             },
         }),
     ]
-    add_settings_dict = configurator_obj.add_settings.calls[1].args[0]
+    add_settings_dict = configurator_obj.add_settings.calls[2].args[0]
     assert add_settings_dict["tm.manager_hook"](pretend.stub()) is \
         transaction_manager
     assert configurator_obj.add_tween.calls == [
diff --git a/tests/unit/test_tasks.py b/tests/unit/test_tasks.py
--- a/tests/unit/test_tasks.py
+++ b/tests/unit/test_tasks.py
@@ -18,6 +18,7 @@
 
 from celery import Celery
 from pyramid import scripting
+from pyramid_retry import RetryableException
 
 from warehouse import tasks
 from warehouse.config import Environment
@@ -240,7 +241,7 @@ def run(arg_, *, kwarg_=None):
         assert request.tm.__exit__.calls == [pretend.call(None, None, None)]
 
     def test_run_retries_failed_transaction(self):
-        class RetryThisException(Exception):
+        class RetryThisException(RetryableException):
             pass
 
         class Retry(Exception):
@@ -259,7 +260,6 @@ def run():
             tm=pretend.stub(
                 __enter__=pretend.call_recorder(lambda *a, **kw: None),
                 __exit__=pretend.call_recorder(lambda *a, **kw: None),
-                _retryable=pretend.call_recorder(lambda *a, **kw: True),
             ),
         )
 
@@ -273,9 +273,6 @@ def run():
         assert request.tm.__exit__.calls == [
             pretend.call(Retry, mock.ANY, mock.ANY),
         ]
-        assert request.tm._retryable.calls == [
-            pretend.call(RetryThisException, mock.ANY),
-        ]
 
     def test_run_doesnt_retries_failed_transaction(self):
         class DontRetryThisException(Exception):
@@ -294,7 +291,6 @@ def run():
             tm=pretend.stub(
                 __enter__=pretend.call_recorder(lambda *a, **kw: None),
                 __exit__=pretend.call_recorder(lambda *a, **kw: None),
-                _retryable=pretend.call_recorder(lambda *a, **kw: False),
             ),
         )
 
@@ -308,9 +304,6 @@ def run():
         assert request.tm.__exit__.calls == [
             pretend.call(DontRetryThisException, mock.ANY, mock.ANY),
         ]
-        assert request.tm._retryable.calls == [
-            pretend.call(DontRetryThisException, mock.ANY),
-        ]
 
     def test_after_return_without_pyramid_env(self):
         obj = tasks.WarehouseTask()