Repository: falconry/falcon
Pull request #1463 (2019-02-28 16:24:08)

refactor(Response): Restore the stream_len alias
Restore the stream_len alias since it was only deprecated as of 2.0, not 1.4, and we should allow at least one release cycle before removing deprecated parts of the interface.

codecov[bot]: # [Codecov](https://codecov.io/gh/falconry/falcon/pull/1463?src=pr&el=h1) Report
> Merging [#1463](https://codecov.io/gh/falconry/falcon/pull/1463?src=pr&el=desc) into [master](https://codecov.io/gh/falconry/falcon/commit/4fd9de5c8a3f8a71f59b375bb374082312e673e8?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/falconry/falcon/pull/1463/graphs/tree.svg?width=650&token=zOtkfNQ3h6&height=150&src=pr)](https://codecov.io/gh/falconry/falcon/pull/1463?src=pr&el=tree)

```diff
@@          Coverage Diff           @@
##           master   #1463   +/-   ##
======================================
  Coverage     100%    100%           
======================================
  Files          39      39           
  Lines        2613    2609    -4     
  Branches      414     414           
======================================
- Hits         2613    2609    -4
```


| [Impacted Files](https://codecov.io/gh/falconry/falcon/pull/1463?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [falcon/response.py](https://codecov.io/gh/falconry/falcon/pull/1463/diff?src=pr&el=tree#diff-ZmFsY29uL3Jlc3BvbnNlLnB5) | `100% <100%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/falconry/falcon/pull/1463?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/falconry/falcon/pull/1463?src=pr&el=footer). Last update [4fd9de5...abe964f](https://codecov.io/gh/falconry/falcon/pull/1463?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

codecov[bot]: # [Codecov](https://codecov.io/gh/falconry/falcon/pull/1463?src=pr&el=h1) Report
> Merging [#1463](https://codecov.io/gh/falconry/falcon/pull/1463?src=pr&el=desc) into [master](https://codecov.io/gh/falconry/falcon/commit/4fd9de5c8a3f8a71f59b375bb374082312e673e8?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/falconry/falcon/pull/1463/graphs/tree.svg?width=650&token=zOtkfNQ3h6&height=150&src=pr)](https://codecov.io/gh/falconry/falcon/pull/1463?src=pr&el=tree)

```diff
@@          Coverage Diff           @@
##           master   #1463   +/-   ##
======================================
  Coverage     100%    100%           
======================================
  Files          39      39           
  Lines        2613    2609    -4     
  Branches      414     414           
======================================
- Hits         2613    2609    -4
```


| [Impacted Files](https://codecov.io/gh/falconry/falcon/pull/1463?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [falcon/response.py](https://codecov.io/gh/falconry/falcon/pull/1463/diff?src=pr&el=tree#diff-ZmFsY29uL3Jlc3BvbnNlLnB5) | `100% <100%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/falconry/falcon/pull/1463?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/falconry/falcon/pull/1463?src=pr&el=footer). Last update [4fd9de5...abe964f](https://codecov.io/gh/falconry/falcon/pull/1463?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

vytas7: I have just remembered Hug gate in our Travis setup, was this breaking change the only thing blocking it, or did we have more?
kgriffs: Let's try re-enabling the hug gate.
vytas7: Ah, I guess we'll have to forget the Hug gate for now, it seems Hug is building heavily upon older signatures of hooks, middlewares, and error handlers which where removed in https://github.com/falconry/falcon/commit/6bb2ac770ff12ef2419e30c122a23356d3251cca

Patch:
diff --git a/.travis.yml b/.travis.yml
index 077d2a0..3dada4e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -41,8 +41,7 @@ matrix:
           env: TOXENV=py37_smoke_cython
         - python: 2.7
           env: TOXENV=docs
-        # TODO(kgriffs): Re-enable once we have mitigated the stream_len
-        #   breaking change in hug.
+        # TODO(kgriffs): Re-enable once Hug is compatible with Falcon 2.0
         # - python: 3.6
         #   env: TOXENV=hug
         - python: 3.7
diff --git a/falcon/response.py b/falcon/response.py
index 28e37a2..5709821 100644
--- a/falcon/response.py
+++ b/falcon/response.py
@@ -38,10 +38,11 @@ CookieError = compat.http_cookies.CookieError
 
 GMT_TIMEZONE = TimezoneGMT()
 
-_STREAM_LEN_REMOVED_MSG = (
-    'The deprecated stream_len property was removed in Falcon 2.0. '
-    'Please use Response.set_stream() or Response.content_length instead.'
-)
+# TODO(kgriffs): Uncomment when 3.0 development opens
+# _STREAM_LEN_REMOVED_MSG = (
+#     'The deprecated stream_len property was removed in Falcon 3.0. '
+#     'Please use Response.set_stream() or Response.content_length instead.'
+# )
 
 
 class Response(object):
@@ -112,6 +113,8 @@ class Response(object):
                 resource cleanup, it can implement a close() method to do so.
                 The close() method will be called upon completion of the request.
 
+        stream_len (int): Deprecated alias for :attr:`content_length`.
+
         context (dict): Dictionary to hold any data about the response which is
             specific to your app. Falcon itself will not interact with this
             attribute after it has been initialized.
@@ -249,17 +252,19 @@ class Response(object):
         # just be thrown away.
         self._data = None
 
-    @property
-    def stream_len(self):
-        # NOTE(kgriffs): Provide some additional information by raising the
-        #   error explicitly.
-        raise AttributeError(_STREAM_LEN_REMOVED_MSG)
+    # TODO(kgriffs): Uncomment when 3.0 development opens
+    # @property
+    # def stream_len(self):
+    #     # NOTE(kgriffs): Provide some additional information by raising the
+    #     #   error explicitly.
+    #     raise AttributeError(_STREAM_LEN_REMOVED_MSG)
 
-    @stream_len.setter
-    def stream_len(self, value):
-        # NOTE(kgriffs): We explicitly disallow setting the deprecated attribute
-        #   so that apps relying on it do not fail silently.
-        raise AttributeError(_STREAM_LEN_REMOVED_MSG)
+    # TODO(kgriffs): Uncomment when 3.0 development opens
+    # @stream_len.setter
+    # def stream_len(self, value):
+    #     # NOTE(kgriffs): We explicitly disallow setting the deprecated attribute
+    #     #   so that apps relying on it do not fail silently.
+    #     raise AttributeError(_STREAM_LEN_REMOVED_MSG)
 
     def __repr__(self):
         return '<%s: %s>' % (self.__class__.__name__, self.status)
@@ -827,6 +832,9 @@ class Response(object):
         """,
     )
 
+    # TODO(kgriffs): Remove deprecated alias once development opens for 3.0
+    stream_len = content_length
+
     content_range = header_property(
         'Content-Range',
         """A tuple to use in constructing a value for the Content-Range header.


Test patch:
diff --git a/tests/test_headers.py b/tests/test_headers.py
index 215334f..a855f2b 100644
--- a/tests/test_headers.py
+++ b/tests/test_headers.py
@@ -212,7 +212,8 @@ class ContentLengthHeaderResource(object):
         self._body = body
 
     def on_get(self, req, resp):
-        resp.content_length = self._content_length
+        # NOTE(kgriffs): Use stream_len for now to cover the deprecated alias
+        resp.stream_len = self._content_length
         resp.body = self._body
 
 
diff --git a/tests/test_response.py b/tests/test_response.py
index 80b59b5..8c61664 100644
--- a/tests/test_response.py
+++ b/tests/test_response.py
@@ -51,11 +51,12 @@ def test_response_attempt_to_set_read_only_headers():
     assert headers['x-things3'] == 'thing-3a, thing-3b'
 
 
-def test_response_removed_stream_len():
-    resp = falcon.Response()
+# TODO(kgriffs): Uncomment when 3.0 development opens
+# def test_response_removed_stream_len():
+#     resp = falcon.Response()
 
-    with pytest.raises(AttributeError):
-        resp.stream_len = 128
+#     with pytest.raises(AttributeError):
+#         resp.stream_len = 128
 
-    with pytest.raises(AttributeError):
-        resp.stream_len
+#     with pytest.raises(AttributeError):
+#         resp.stream_len