Skip to content

typing improvements#184

Open
jap wants to merge 6 commits into
pyauth:mainfrom
jap:typing-improvements
Open

typing improvements#184
jap wants to merge 6 commits into
pyauth:mainfrom
jap:typing-improvements

Conversation

@jap

@jap jap commented Sep 15, 2025

Copy link
Copy Markdown

This series of commits brings some typing improvements, but also adds the option to return the timecode that matched when verifying a TOTP, which is a feature in passlib.totp but that project appears to no longer be maintained.

  • Add option to return the timecode that matched when verifying TOTP.
  • typing: accept float for timestamp values
  • typing: add explicit isinstance asserts to tests
  • typing: don't construct TOTP instances with a secret that is bytes
  • tests: make the Timecop more pythonic
  • refactor: remove testing of stdlib code
  • lint: perform typing checks on test.py as well

@jap
jap marked this pull request as ready for review September 15, 2025 12:11
@jap
jap force-pushed the typing-improvements branch from 8143db2 to acd7917 Compare September 17, 2025 10:52
@kislyuk

kislyuk commented Jan 3, 2026

Copy link
Copy Markdown
Member

Thanks for the PR! Unfortunately it can't be merged in its current form.

  • The feature to return the timecode can't be added to the existing method, because I won't be breaking the API for that method. It should be added as a separate, new method.
  • The typing changes and the functional changes should be separated into distinct PRs.
  • This package's linters are set up to follow a line length of 120 characters. Any changes that merely reformat code to shorten the line length need to be reverted.

@jap

jap commented Jun 26, 2026

Copy link
Copy Markdown
Author

moved the return-timestamp bit to #191, if that looks ok I can also redo some of the typing bits.

kislyuk pushed a commit that referenced this pull request Jun 28, 2026
…mecode (#191)

This contains the part of #184 that implements a method
`verify_and_return_timecode` for TOTP.

As its name suggests, this method verifies the given OTP, and if it
matches, it will return the matching timecode.

This can be used to prevent replay attacks, by storing the timecode on
successful authentication, and ensuring that it always increases.
@jap
jap force-pushed the typing-improvements branch from acd7917 to 0b0cad4 Compare June 29, 2026 07:38
@codecov-commenter

codecov-commenter commented Jun 29, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (main@cc15683). Learn more about missing BASE report.
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #184   +/-   ##
=======================================
  Coverage        ?   91.34%           
=======================================
  Files           ?        8           
  Lines           ?      231           
  Branches        ?       54           
=======================================
  Hits            ?      211           
  Misses          ?        9           
  Partials        ?       11           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jap

jap commented Jun 29, 2026

Copy link
Copy Markdown
Author

Thanks for merging #191 !
I rebased this branch on top of current main (and undid some formatter damage); could you give this another look?

Comment thread src/pyotp/totp.py Outdated
super().__init__(s=s, digits=digits, digest=digest, name=name, issuer=issuer)

def at(self, for_time: Union[int, datetime.datetime], counter_offset: int = 0) -> str:
def at(self, for_time: Union[float, datetime.datetime], counter_offset: int = 0) -> str:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I don't understand. Why are you putting float here? The behavior of the algorithm is undefined for non-integer timestamps so I don't think the API should accept floats.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i believe the commit message explains the reasoning? (it also links to docs about this.) note that tests already do pass floats. note that time.time() also returns a float.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This package was first developed when type hints were not really a thing. Yes, it accepts floats and at this time it does not raise an error and attempts to do the least surprising thing when a float is passed in. But that does not mean it's a good idea to pass in a float. Passing a float to an algorithm that is only defined on integers is meaningless and should be assumed to lead to dangerously undefined behavior.

This is also why exhaustively typing the test suite is not a big priority; the test suite may deliberately violate type specs to test behavior that the type checker errors on. In this case the correct solution is to set a # type: ignore[...] on the call in the test suite that passes a float, instead of relaxing the type annotation.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey @kislyuk and @jap 👋🏼 seems like the latest push should address everything? would be great to have this merged… and into a release!

@jap
jap force-pushed the typing-improvements branch from 0b0cad4 to 9ee7c03 Compare July 6, 2026 12:37
jap added 5 commits July 6, 2026 14:37
This allows mypy to infer that the called methods actually exist.

Note that two self.assertIsInstance got replaced by these; the tests
will still fail on type mismatch.
This accidentally worked but the typing police does not like it.
This removes a bunch of test calls against compare_digest which is
imported from the standard library, and not exposed to users of this
library.

Mypy also did not like this.
@jap
jap force-pushed the typing-improvements branch from 9ee7c03 to 506616c Compare July 6, 2026 12:37
@jap
jap force-pushed the typing-improvements branch from 506616c to 62e8753 Compare July 6, 2026 12:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants