Repository: praw-dev/praw
Pull request #1684 (2021-02-21 01:17:54)

Deprecate user.me() returning None
This finishes up #1480.


Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index 53f10902..4ee3f48e 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -4,6 +4,13 @@ Change Log
 Unreleased
 ----------
 
+**Deprecated**
+
+* :meth:`.me` will no longer return ``None`` when called in :attr:`.read_only` mode 
+  starting in PRAW 8. A :py:class:`DeprecationWarning` will be issued. To switch forward
+  to the PRAW 8 behavior set ``praw8_raise_exception_on_me=True`` in your
+  ``praw.Reddit(...)`` call.
+
 7.1.4 (2021/02/07)
 ------------------
 
diff --git a/praw/exceptions.py b/praw/exceptions.py
index e739a4db..f668ef3f 100644
--- a/praw/exceptions.py
+++ b/praw/exceptions.py
@@ -214,6 +214,10 @@ class MissingRequiredAttributeException(ClientException):
     """Indicate exceptions caused by not including a required attribute."""
 
 
+class ReadOnlyException(ClientException):
+    """Raised when a method call requires :attr:`.read_only` mode to be disabled."""
+
+
 class TooLargeMediaException(ClientException):
     """Indicate exceptions from uploading media that's too large."""
 
diff --git a/praw/models/user.py b/praw/models/user.py
index 4ef8bf93..7027ff05 100644
--- a/praw/models/user.py
+++ b/praw/models/user.py
@@ -1,7 +1,9 @@
 """Provides the User class."""
 from typing import TYPE_CHECKING, Dict, Iterator, List, Optional, Union
+from warnings import warn
 
 from ..const import API_PATH
+from ..exceptions import ReadOnlyException
 from ..models import Preferences
 from ..util.cache import cachedproperty
 from .base import PRAWBase
@@ -119,8 +121,6 @@ class User(PRAWBase):
     ) -> Optional["praw.models.Redditor"]:  # pylint: disable=invalid-name
         """Return a :class:`.Redditor` instance for the authenticated user.
 
-        In :attr:`~praw.Reddit.read_only` mode, this method returns ``None``.
-
         :param use_cache: When true, and if this function has been previously called,
             returned the cached version (default: True).
 
@@ -130,9 +130,25 @@ class User(PRAWBase):
             the cached value. Prefer using separate Reddit instances, however, for
             distinct authorizations.
 
+        .. deprecated:: 7.2
+
+            In :attr:`.read_only` mode this method returns ``None``. In PRAW 8 this
+            method will raise :class:`.ReadOnlyException` when called in
+            :attr:`.read_only` mode. To operate in PRAW 8 mode, set the config variable
+            ``praw8_raise_exception_on_me`` to ``True``.
+
         """
         if self._reddit.read_only:
-            return None
+            if not self._reddit.config.custom.get("praw8_raise_exception_on_me"):
+                warn(
+                    "The `None` return value is deprecated, and will raise a"
+                    " `ReadOnlyException` beginning with PRAW 8. See documentation for"
+                    " forward compatability options.",
+                    category=DeprecationWarning,
+                    stacklevel=2,
+                )
+                return None
+            raise ReadOnlyException("`user.me()` does not work in read_only mode")
         if "_me" not in self.__dict__ or not use_cache:
             user_data = self._reddit.get(API_PATH["me"])
             self._me = Redditor(self._reddit, _data=user_data)


Test patch:
diff --git a/tests/unit/models/test_user.py b/tests/unit/models/test_user.py
index 1542fb46..c8687ed2 100644
--- a/tests/unit/models/test_user.py
+++ b/tests/unit/models/test_user.py
@@ -1,3 +1,7 @@
+import pytest
+
+from praw import Reddit
+from praw.exceptions import ReadOnlyException
 from praw.models import User
 
 from .. import UnitTest
@@ -5,6 +9,19 @@ from .. import UnitTest
 
 class TestUser(UnitTest):
     def test_me__in_read_only_mode(self):
+        self.reddit = Reddit(
+            client_id="dummy",
+            client_secret="dummy",
+            praw8_raise_exception_on_me=True,
+            user_agent="dummy",
+        )
+        self.reddit._core._requestor._http = None
+
         assert self.reddit.read_only
         user = User(self.reddit)
-        assert user.me() is None
+        with pytest.raises(ReadOnlyException):
+            user.me()
+
+    def test_me__in_read_only_mode__deprecated(self):
+        assert self.reddit.read_only
+        assert User(self.reddit).me() is None
diff --git a/tests/unit/test_deprecations.py b/tests/unit/test_deprecations.py
index 5ad72fd8..20b3be31 100644
--- a/tests/unit/test_deprecations.py
+++ b/tests/unit/test_deprecations.py
@@ -56,3 +56,7 @@ class TestDeprecation(UnitTest):
         with pytest.raises(DeprecationWarning) as excinfo:
             self.reddit.submission("1234").gild()
             assert excinfo.value.args[0] == "`.gild` has been renamed to `.award`."
+
+    def test_reddit_user_me_read_only(self):
+        with pytest.raises(DeprecationWarning):
+            self.reddit.user.me()