-
-
Notifications
You must be signed in to change notification settings - Fork 672
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Type not yet supported: <class 'datetime.datetime'> when using freezegun
#282
Comments
Hi, I did not use pytest-freezer beforehand and I have no knowledge of how it works internally. def test_data(
# freezer,
):
# freezer.move_to("2020-06-01")
result = runner.invoke(app,)
print(result.stdout)
assert "Data for 2020-Jun" in result.stdout Raises
def test_data(
# freezer,
):
# freezer.move_to("2020-06-01")
result = runner.invoke(app, ["2020-06"])
print(result.stdout)
assert "Data for 2020-Jun" in result.stdout passes
def test_data(
freezer,
):
# freezer.move_to("2020-06-01")
result = runner.invoke(app, ["2020-06"])
print(result.stdout)
assert "Data for 2020-Jun" in result.stdout Raises the One thing to point here is that def main(something: int): You would have to invoke this with string anyway runner.invoke(main, "4") When running runner.invoke(main, 4) I am getting: E + where '' = <Result TypeError("'int' object is not iterable")>.stdout So the module expects a string anyway. Have you maybe checked out if this works with |
Sorry for the clunky sample code there. It should be what I intended now. The main change of the sample code is that typer.Argument now has a default value. Doing The only idea I have is that since freezer/freezegun "changes" |
I did some print debugging within typer code and the line def get_click_type(
*, annotation: Any, parameter_info: ParameterInfo
) -> click.ParamType: In the body, it performs a series of I added two magic lines: def get_click_type(
*, annotation: Any, parameter_info: ParameterInfo
) -> click.ParamType:
print("annonotation: ", annotation)
print("the datetime: ", datetime)
and this gives me such a result: annonotation: <class 'datetime.datetime'>
the datetime: <class 'freezegun.api.FakeDatetime'> Now one of the |
I did one more check to confirm the observation: Only main dependencies are I have two files:
import datetime
def datetime_annotated(
some_date: datetime.datetime
) -> None:
print(some_date) and from main import datetime_annotated
import datetime
def test_datetime_annotation_is_datetime(
freezer
):
annotations = datetime_annotated.__annotations__
some_date_annotation = annotations["some_date"]
assert datetime.datetime == some_date_annotation Result of the run is failure: test_datetime.py:9 (test_datetime_annotation_is_datetime)
<class 'freezegun.api.FakeDatetime'> != <class 'datetime.datetime'>
Expected :<class 'datetime.datetime'>
Actual :<class 'freezegun.api.FakeDatetime'> It means that freezegun substitutes the Below also test without from freezegun import freeze_time
from main import datetime_annotated
import datetime
@freeze_time("2020-06-24")
def test_datetime_annotation_is_datetime(
):
annotations = datetime_annotated.__annotations__
some_date_annotation = annotations["some_date"]
assert datetime.datetime == some_date_annotation Result is the same as with |
Before I open an issue over at
In freezegun/api.py#L345 |
I am no maintainer but in my opinion handling a case, where some library substitutes some object at runtime and forgets about annotations does not justify a change in the library that does not depend on it. I have a possible solution for you, however! With three files:
from datetime import datetime
import typer
app = typer.Typer()
@app.command()
def data(
year_month: datetime = typer.Argument(
f"{datetime.now().strftime('%Y-%m')}",
formats=["%Y-%m"])
):
print("Year-month: ", year_month)
typer.echo(f"Data for {year_month:%Y-%b}")
def datetime_annotated(
some_date: datetime
) -> None:
print(some_date)
if __name__ == "__main__":
app()
import datetime
from freezegun import freeze_time
from typer.testing import CliRunner
from main import app, datetime_annotated
from monkey_patch_typer import monkey_patch_commands, patch_annotations
runner = CliRunner()
def test_data(
freezer,
):
freezer.move_to("2020-06-01")
result = runner.invoke(monkey_patch_commands(app), )
assert "Data for 2021-May" in result.stdout
def test_data_with_argument(
freezer,
):
freezer.move_to("2020-06-01")
result = runner.invoke(monkey_patch_commands(app,), ["2520-07"])
assert "Data for 2520-Jul" in result.stdout
@freeze_time("2020-06-24")
def test_datetime_annotation_is_datetime(
):
patch_annotations(datetime_annotated)
assert datetime.datetime == datetime_annotated.__annotations__['some_date']
To use from datetime import datetime
from typing import Callable, Dict
import typer
def patch_annotations(function: Callable):
annotations: Dict = function.__annotations__
new_annotations = {}
for key, value in annotations.items():
# This if below is redundant
if value == datetime:
print("That would be impressive")
else:
print("Yes, as expected")
# Since above is always in the `else` department, we have to find other way to determine
# the type
if str(value) == "<class 'datetime.datetime'>":
value = datetime
new_annotations |= {key: value}
function.__annotations__ = new_annotations
def monkey_patch_commands(some_app: typer.Typer) -> typer.Typer:
registered_commands = some_app.registered_commands
for command in registered_commands:
print(command.callback.__annotations__)
patch_annotations(command.callback)
return some_app You can further improve the snippet by handling the |
freezegun
freezegun
Hey there! Sorry for the delay. Yep, that's not a supported type, it's something dependent on that package (I haven't used it), nevertheless, I think you can probably do it with a custom type, this is somewhat new: https://typer.tiangolo.com/tutorial/parameter-types/custom-types/ |
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
Describe the bug
Typer doesn't support freezegun's
FakeDateTime
. I am getting aRuntimeError: Type not yet supported: <class 'datetime.datetime'>
when I usefreezegun
to freeze the time for testing purposes and havedatetime
type in my argument.To Reproduce
main.py
with:pytest-freezegun
Complete Stacktrace
Expected behaviour
Freezing times in tests are common. I expect that the test pass.
Environment
The text was updated successfully, but these errors were encountered: