Repository: scrapy/scrapy
Pull request #6512 (2024-10-26 19:42:19)

Deprecate `scrapy.twisted_version`
fix: #6509

wRAR: No idea what do these pytest errors mean.
Laerte: > No idea what do these pytest errors mean.

So because we defined ``__getattr__``
 the default behavior is to raise a `AttributeError` exception but It was returning None instead, that's why was failing, fixed.

Ref: https://github.com/pytest-dev/pytest/issues/4631
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/scrapy/scrapy/pull/6512?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=scrapy) Report
Attention: Patch coverage is `25.00000%` with `6 lines` in your changes missing coverage. Please review.
> Project coverage is 84.87%. Comparing base [(`1138a5c`)](https://app.codecov.io/gh/scrapy/scrapy/commit/1138a5cf9945d4346c92da17e002e6da7a5c1883?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=scrapy) to head [(`58a433f`)](https://app.codecov.io/gh/scrapy/scrapy/commit/58a433f8e2c6e5bae57d530cf3abd09fa70247c9?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=scrapy).
> Report is 31 commits behind head on master.

| [Files with missing lines](https://app.codecov.io/gh/scrapy/scrapy/pull/6512?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=scrapy) | Patch % | Lines |
|---|---|---|
| [scrapy/\_\_init\_\_.py](https://app.codecov.io/gh/scrapy/scrapy/pull/6512?src=pr&el=tree&filepath=scrapy%2F__init__.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=scrapy#diff-c2NyYXB5L19faW5pdF9fLnB5) | 25.00% | [5 Missing and 1 partial :warning: ](https://app.codecov.io/gh/scrapy/scrapy/pull/6512?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=scrapy) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master    #6512      +/-   ##
==========================================
- Coverage   89.46%   84.87%   -4.60%     
==========================================
  Files         162      162              
  Lines       12086    12079       -7     
  Branches     1559     1559              
==========================================
- Hits        10813    10252     -561     
- Misses        958     1544     +586     
+ Partials      315      283      -32     
```

| [Files with missing lines](https://app.codecov.io/gh/scrapy/scrapy/pull/6512?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=scrapy) | Coverage Δ | |
|---|---|---|
| [scrapy/\_\_init\_\_.py](https://app.codecov.io/gh/scrapy/scrapy/pull/6512?src=pr&el=tree&filepath=scrapy%2F__init__.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=scrapy#diff-c2NyYXB5L19faW5pdF9fLnB5) | `68.42% <25.00%> (-31.58%)` | :arrow_down: |

... and [34 files with indirect coverage changes](https://app.codecov.io/gh/scrapy/scrapy/pull/6512/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=scrapy)

</details>
Laerte: @wRAR Added tests for test coverage 
Gallaecio: ```
scrapy/pipelines/media.py:209: error: Cannot assign to a method  [method-assign]
```
Gallaecio: > ```
> scrapy/pipelines/media.py:209: error: Cannot assign to a method  [method-assign]
> ```

Nevermind, it seems that might have been introduced by https://github.com/scrapy/scrapy/pull/6510.
wRAR: Thanks!

Patch:
diff --git a/scrapy/__init__.py b/scrapy/__init__.py
index 1c1a5c2cc..921296502 100644
--- a/scrapy/__init__.py
+++ b/scrapy/__init__.py
@@ -6,8 +6,6 @@ import pkgutil
 import sys
 import warnings
 
-from twisted import version as _txv
-
 # Declare top-level shortcuts
 from scrapy.http import FormRequest, Request
 from scrapy.item import Field, Item
@@ -17,7 +15,6 @@ from scrapy.spiders import Spider
 __all__ = [
     "__version__",
     "version_info",
-    "twisted_version",
     "Spider",
     "Request",
     "FormRequest",
@@ -30,7 +27,23 @@ __all__ = [
 # Scrapy and Twisted versions
 __version__ = (pkgutil.get_data(__package__, "VERSION") or b"").decode("ascii").strip()
 version_info = tuple(int(v) if v.isdigit() else v for v in __version__.split("."))
-twisted_version = (_txv.major, _txv.minor, _txv.micro)
+
+
+def __getattr__(name: str):
+    if name == "twisted_version":
+        import warnings
+
+        from twisted import version as _txv
+
+        from scrapy.exceptions import ScrapyDeprecationWarning
+
+        warnings.warn(
+            "The scrapy.twisted_version attribute is deprecated, use twisted.version instead",
+            ScrapyDeprecationWarning,
+        )
+        return _txv.major, _txv.minor, _txv.micro
+
+    raise AttributeError
 
 
 # Ignore noisy twisted deprecation warnings


Test patch:
diff --git a/tests/test_scrapy__getattr__.py b/tests/test_scrapy__getattr__.py
new file mode 100644
index 000000000..979c42267
--- /dev/null
+++ b/tests/test_scrapy__getattr__.py
@@ -0,0 +1,13 @@
+import warnings
+
+
+def test_deprecated_twisted_version():
+    with warnings.catch_warnings(record=True) as warns:
+        from scrapy import twisted_version
+
+        assert twisted_version is not None
+        assert isinstance(twisted_version, tuple)
+        assert (
+            "The scrapy.twisted_version attribute is deprecated, use twisted.version instead"
+            in warns[0].message.args
+        )