Looking for a working example of `SupportsRound`












3















There's not a lot of detailed information online about making type annotations work with __round__. I have implemented this but I still get an error on line 16 (calling round without an ndigits argument) when I run mypy:




error: Incompatible types in assignment (expression has type "int", variable has type "MyClass")




The test passes, i.e. in both calls to round I get back an object of type MyClass. But the MyPy check fails only when I call round without an argument.



Version numbers: Python 3.6.5, mypy 0.641.



from typing import Any, SupportsRound, overload

class MyClass(SupportsRound['MyClass']):

def __round__(self: 'MyClass', ndigits: int = 0) -> 'MyClass':
return self


def test_tmp() -> None:
x = MyClass()
result: MyClass

result = round(x, 0)
assert type(result) == MyClass
result = round(x)
assert type(result) == MyClass









share|improve this question





























    3















    There's not a lot of detailed information online about making type annotations work with __round__. I have implemented this but I still get an error on line 16 (calling round without an ndigits argument) when I run mypy:




    error: Incompatible types in assignment (expression has type "int", variable has type "MyClass")




    The test passes, i.e. in both calls to round I get back an object of type MyClass. But the MyPy check fails only when I call round without an argument.



    Version numbers: Python 3.6.5, mypy 0.641.



    from typing import Any, SupportsRound, overload

    class MyClass(SupportsRound['MyClass']):

    def __round__(self: 'MyClass', ndigits: int = 0) -> 'MyClass':
    return self


    def test_tmp() -> None:
    x = MyClass()
    result: MyClass

    result = round(x, 0)
    assert type(result) == MyClass
    result = round(x)
    assert type(result) == MyClass









    share|improve this question



























      3












      3








      3








      There's not a lot of detailed information online about making type annotations work with __round__. I have implemented this but I still get an error on line 16 (calling round without an ndigits argument) when I run mypy:




      error: Incompatible types in assignment (expression has type "int", variable has type "MyClass")




      The test passes, i.e. in both calls to round I get back an object of type MyClass. But the MyPy check fails only when I call round without an argument.



      Version numbers: Python 3.6.5, mypy 0.641.



      from typing import Any, SupportsRound, overload

      class MyClass(SupportsRound['MyClass']):

      def __round__(self: 'MyClass', ndigits: int = 0) -> 'MyClass':
      return self


      def test_tmp() -> None:
      x = MyClass()
      result: MyClass

      result = round(x, 0)
      assert type(result) == MyClass
      result = round(x)
      assert type(result) == MyClass









      share|improve this question
















      There's not a lot of detailed information online about making type annotations work with __round__. I have implemented this but I still get an error on line 16 (calling round without an ndigits argument) when I run mypy:




      error: Incompatible types in assignment (expression has type "int", variable has type "MyClass")




      The test passes, i.e. in both calls to round I get back an object of type MyClass. But the MyPy check fails only when I call round without an argument.



      Version numbers: Python 3.6.5, mypy 0.641.



      from typing import Any, SupportsRound, overload

      class MyClass(SupportsRound['MyClass']):

      def __round__(self: 'MyClass', ndigits: int = 0) -> 'MyClass':
      return self


      def test_tmp() -> None:
      x = MyClass()
      result: MyClass

      result = round(x, 0)
      assert type(result) == MyClass
      result = round(x)
      assert type(result) == MyClass






      python mypy






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 26 '18 at 13:16









      shadowtalker

      4,44012148




      4,44012148










      asked Nov 26 '18 at 13:12









      migwellianmigwellian

      535




      535
























          1 Answer
          1






          active

          oldest

          votes


















          1














          I believe the problem here has less to do with your use of SupportsRound and more to do with the definition of the round function. The round function is defined in typeshed, the repository of type hints for the standard library, to have the following signature:



          @overload
          def round(number: float) -> int: ...
          @overload
          def round(number: float, ndigits: None) -> int: ...
          @overload
          def round(number: float, ndigits: int) -> float: ...
          @overload
          def round(number: SupportsRound[_T]) -> int: ...
          @overload
          def round(number: SupportsRound[_T], ndigits: None) -> int: ... # type: ignore
          @overload
          def round(number: SupportsRound[_T], ndigits: int) -> _T: ...


          Note that when only one argument is provided or ndigits is None, the output is always int. This is consistent with the documented behavior of the round function in the standard library: https://docs.python.org/3/library/functions.html#round



          Unfortunately, I don't see a really clean way of working around this: I don't think the implementation of SupportsRound is really consistent with this behavior.



          Specifically, SupportsRound probably ought to have been defined to be something like so:



          @runtime
          class SupportsRound(Protocol[_T_co]):
          @abstractmethod
          @overload
          def __round__(self, ndigits: None = None) -> int: ...

          @abstractmethod
          @overload
          def __round__(self, ndigits: int) -> _T_co: ...


          Basically, force the user to handle these two cases.



          Actually changing the definition would probably be complicated though: there isn't really a clean way of updating any older versions of Python that come bundled with older versions of the typing module.



          I would recommend filing an issue about this on the typeshed issue tracker. I personally think you've discovered a genuine inconsistency/bug here, but there's possibly some nuance here that I'm missing, so I think it would be good to escalate this.






          share|improve this answer
























          • Thanks. I have filed github.com/python/typeshed/issues/2638

            – migwellian
            Nov 27 '18 at 17:01











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53481887%2flooking-for-a-working-example-of-supportsround%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          1














          I believe the problem here has less to do with your use of SupportsRound and more to do with the definition of the round function. The round function is defined in typeshed, the repository of type hints for the standard library, to have the following signature:



          @overload
          def round(number: float) -> int: ...
          @overload
          def round(number: float, ndigits: None) -> int: ...
          @overload
          def round(number: float, ndigits: int) -> float: ...
          @overload
          def round(number: SupportsRound[_T]) -> int: ...
          @overload
          def round(number: SupportsRound[_T], ndigits: None) -> int: ... # type: ignore
          @overload
          def round(number: SupportsRound[_T], ndigits: int) -> _T: ...


          Note that when only one argument is provided or ndigits is None, the output is always int. This is consistent with the documented behavior of the round function in the standard library: https://docs.python.org/3/library/functions.html#round



          Unfortunately, I don't see a really clean way of working around this: I don't think the implementation of SupportsRound is really consistent with this behavior.



          Specifically, SupportsRound probably ought to have been defined to be something like so:



          @runtime
          class SupportsRound(Protocol[_T_co]):
          @abstractmethod
          @overload
          def __round__(self, ndigits: None = None) -> int: ...

          @abstractmethod
          @overload
          def __round__(self, ndigits: int) -> _T_co: ...


          Basically, force the user to handle these two cases.



          Actually changing the definition would probably be complicated though: there isn't really a clean way of updating any older versions of Python that come bundled with older versions of the typing module.



          I would recommend filing an issue about this on the typeshed issue tracker. I personally think you've discovered a genuine inconsistency/bug here, but there's possibly some nuance here that I'm missing, so I think it would be good to escalate this.






          share|improve this answer
























          • Thanks. I have filed github.com/python/typeshed/issues/2638

            – migwellian
            Nov 27 '18 at 17:01
















          1














          I believe the problem here has less to do with your use of SupportsRound and more to do with the definition of the round function. The round function is defined in typeshed, the repository of type hints for the standard library, to have the following signature:



          @overload
          def round(number: float) -> int: ...
          @overload
          def round(number: float, ndigits: None) -> int: ...
          @overload
          def round(number: float, ndigits: int) -> float: ...
          @overload
          def round(number: SupportsRound[_T]) -> int: ...
          @overload
          def round(number: SupportsRound[_T], ndigits: None) -> int: ... # type: ignore
          @overload
          def round(number: SupportsRound[_T], ndigits: int) -> _T: ...


          Note that when only one argument is provided or ndigits is None, the output is always int. This is consistent with the documented behavior of the round function in the standard library: https://docs.python.org/3/library/functions.html#round



          Unfortunately, I don't see a really clean way of working around this: I don't think the implementation of SupportsRound is really consistent with this behavior.



          Specifically, SupportsRound probably ought to have been defined to be something like so:



          @runtime
          class SupportsRound(Protocol[_T_co]):
          @abstractmethod
          @overload
          def __round__(self, ndigits: None = None) -> int: ...

          @abstractmethod
          @overload
          def __round__(self, ndigits: int) -> _T_co: ...


          Basically, force the user to handle these two cases.



          Actually changing the definition would probably be complicated though: there isn't really a clean way of updating any older versions of Python that come bundled with older versions of the typing module.



          I would recommend filing an issue about this on the typeshed issue tracker. I personally think you've discovered a genuine inconsistency/bug here, but there's possibly some nuance here that I'm missing, so I think it would be good to escalate this.






          share|improve this answer
























          • Thanks. I have filed github.com/python/typeshed/issues/2638

            – migwellian
            Nov 27 '18 at 17:01














          1












          1








          1







          I believe the problem here has less to do with your use of SupportsRound and more to do with the definition of the round function. The round function is defined in typeshed, the repository of type hints for the standard library, to have the following signature:



          @overload
          def round(number: float) -> int: ...
          @overload
          def round(number: float, ndigits: None) -> int: ...
          @overload
          def round(number: float, ndigits: int) -> float: ...
          @overload
          def round(number: SupportsRound[_T]) -> int: ...
          @overload
          def round(number: SupportsRound[_T], ndigits: None) -> int: ... # type: ignore
          @overload
          def round(number: SupportsRound[_T], ndigits: int) -> _T: ...


          Note that when only one argument is provided or ndigits is None, the output is always int. This is consistent with the documented behavior of the round function in the standard library: https://docs.python.org/3/library/functions.html#round



          Unfortunately, I don't see a really clean way of working around this: I don't think the implementation of SupportsRound is really consistent with this behavior.



          Specifically, SupportsRound probably ought to have been defined to be something like so:



          @runtime
          class SupportsRound(Protocol[_T_co]):
          @abstractmethod
          @overload
          def __round__(self, ndigits: None = None) -> int: ...

          @abstractmethod
          @overload
          def __round__(self, ndigits: int) -> _T_co: ...


          Basically, force the user to handle these two cases.



          Actually changing the definition would probably be complicated though: there isn't really a clean way of updating any older versions of Python that come bundled with older versions of the typing module.



          I would recommend filing an issue about this on the typeshed issue tracker. I personally think you've discovered a genuine inconsistency/bug here, but there's possibly some nuance here that I'm missing, so I think it would be good to escalate this.






          share|improve this answer













          I believe the problem here has less to do with your use of SupportsRound and more to do with the definition of the round function. The round function is defined in typeshed, the repository of type hints for the standard library, to have the following signature:



          @overload
          def round(number: float) -> int: ...
          @overload
          def round(number: float, ndigits: None) -> int: ...
          @overload
          def round(number: float, ndigits: int) -> float: ...
          @overload
          def round(number: SupportsRound[_T]) -> int: ...
          @overload
          def round(number: SupportsRound[_T], ndigits: None) -> int: ... # type: ignore
          @overload
          def round(number: SupportsRound[_T], ndigits: int) -> _T: ...


          Note that when only one argument is provided or ndigits is None, the output is always int. This is consistent with the documented behavior of the round function in the standard library: https://docs.python.org/3/library/functions.html#round



          Unfortunately, I don't see a really clean way of working around this: I don't think the implementation of SupportsRound is really consistent with this behavior.



          Specifically, SupportsRound probably ought to have been defined to be something like so:



          @runtime
          class SupportsRound(Protocol[_T_co]):
          @abstractmethod
          @overload
          def __round__(self, ndigits: None = None) -> int: ...

          @abstractmethod
          @overload
          def __round__(self, ndigits: int) -> _T_co: ...


          Basically, force the user to handle these two cases.



          Actually changing the definition would probably be complicated though: there isn't really a clean way of updating any older versions of Python that come bundled with older versions of the typing module.



          I would recommend filing an issue about this on the typeshed issue tracker. I personally think you've discovered a genuine inconsistency/bug here, but there's possibly some nuance here that I'm missing, so I think it would be good to escalate this.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 27 '18 at 2:37









          Michael0x2aMichael0x2a

          22.8k1674126




          22.8k1674126













          • Thanks. I have filed github.com/python/typeshed/issues/2638

            – migwellian
            Nov 27 '18 at 17:01



















          • Thanks. I have filed github.com/python/typeshed/issues/2638

            – migwellian
            Nov 27 '18 at 17:01

















          Thanks. I have filed github.com/python/typeshed/issues/2638

          – migwellian
          Nov 27 '18 at 17:01





          Thanks. I have filed github.com/python/typeshed/issues/2638

          – migwellian
          Nov 27 '18 at 17:01




















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53481887%2flooking-for-a-working-example-of-supportsround%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

          Calculate evaluation metrics using cross_val_predict sklearn

          Insert data from modal to MySQL (multiple modal on website)