factory_boy icon indicating copy to clipboard operation
factory_boy copied to clipboard

feat: Add basic typing support

Open last-partizan opened this issue 3 years ago • 13 comments

This PR adds basic type hinting support

Refs #468

last-partizan avatar Jan 12 '22 16:01 last-partizan

@rbarrois

hmm, i think, to properly test type annotations, we should add pyright and/or mypy to CI, run it over example file, and compare that to expected output.

But there is simpler option, we can do something like this:

def x() -> int:
    ...

assert x.__annotations__ == {"returns": int}

In theory, this should be enough to ensure we get expected annotations.

as for linking with Meta: model, yes, i don't see any way to do it.

Also, i see some failing CI checks, i'll try to fix it.

last-partizan avatar Jan 19 '22 22:01 last-partizan

Oh, looks like all errors is from 3.6 version, lefetime of which is ended three weeks ago.

Maybe better solution in this case, is to remove old version from CI? But i'll try to find other solutions, maybe any ideas?

last-partizan avatar Jan 19 '22 22:01 last-partizan

I haven't found easy workarounds for this, so i created PR for removing 3.6 from CI, and adding 3.10 and django-4.0.

last-partizan avatar Jan 24 '22 16:01 last-partizan

Thanks, an other huge step would be to type the kwargs. To be able to do UserFactory.create(xxx=yy) and have autocompletion on xxx.

I have no idea on how to do that, and even if it could be possible with python? 🤔

mathieutu avatar Feb 11 '22 17:02 mathieutu

I think, it could be implemented. Python 3.10 added ParamSpec, and it could be used with older versions of python via typing-extensions, so i think it could be possible.

last-partizan avatar Feb 11 '22 19:02 last-partizan

I found a way to properly type even calls to factory, turned out it was pretty simple.

Now types are correct with both possible ways to call a factory:

BookFactory() -> Book
BookFactory.create() -> Book

But, this all requires python 3.6 at least.

last-partizan avatar Feb 11 '22 20:02 last-partizan

I think, it could be implemented. Python 3.10 added ParamSpec, and it could be used with older versions of python via typing-extensions, so i think it could be possible.

I would love to see that!

mathieutu avatar Feb 11 '22 20:02 mathieutu

I found a way to properly type even calls to factory, turned out it was pretty simple.

Turned out it doesn't work. Reverted changes back to only typing create, build, etc...

Now i'm trying to test it.

last-partizan avatar Feb 16 '22 16:02 last-partizan

As for testing type annotations, i found one way to do it:

And it looks like this: https://github.com/smarie/python-decopatch/pull/27/files

  • Install pyright
  • Run it in json mode, compare results to snapshot

I could add similar tests for this package. (In this PR or next, preferrably next)

last-partizan avatar Feb 23 '22 14:02 last-partizan

I fund myself today thinking it would be great to have types in my factories. Can we merge this, or we need to add tests first?

last-partizan avatar May 18 '22 16:05 last-partizan

I started a project, types-factory-boy, to add type annotations to factory boy. It is in early stage, and it most probably needs a plugin to automatically discover and create type annotations automatically (otherwise you would have to type annotate basically every attribute), but I think it's a start.

youtux avatar Jun 03 '22 17:06 youtux

When it comes to testing types and type annotations. I'd suggest: https://github.com/TypedDjango/pytest-mypy-plugins

Although it's a pytest plugin, so those tests needs to be run with pytest. Should be possible to add that as an individual job in CI etc.

Have a look at django-stubs https://github.com/typeddjango/django-stubs/tree/master/tests/typecheck for reference of how to use it and/or set it up.

flaeppe avatar Jul 14 '22 20:07 flaeppe

@youtux great project, thank you.

After pyright fixed a bug with invalid init annotations and default values in 1.1.264, default factory_boy is throwing type errors sometimes (Maybe declaration for example).

Your project fixed it.

last-partizan avatar Aug 04 '22 14:08 last-partizan

Is this ready for review again?

jeffwidman avatar Nov 02 '22 16:11 jeffwidman

In basic form, yes.

But, we have https://github.com/youtux/types-factory-boy now, and i can try to merge it into this project with merge_pyi.

But, i think it's better to leave this PR in minimal form, maybe add tests for types in the next PR. And then - merge types-factory-boy for more complete type coverage.

last-partizan avatar Nov 04 '22 11:11 last-partizan

~I think there was some misunderstanding here, as I don't understand @last-partizan message about merging types-factory-boy into this codebase.~

~types-factory-boy contains annotations for factory_boy lib (which I don't control), not for pytest_factoryboy (that I manage).~

EDIT: scrap that, I thought I was writing in the pytest_factoryboy project.

youtux avatar Nov 05 '22 14:11 youtux

I made some progress in types-factory-boy. Now there is a mypy plugin that automatically adds the typevar information of the Factory[T] baseclass.

So, instead of writing this:

class AuthorFactory(Factory[Author]):
    class Meta:
        model = Author
reveal_type(AuthorFactory.create())  # foo.Author

we can write this:

class AuthorFactory(Factory):  # No need to specify the typevar for Factory[...], it's inferred from Meta.model
    class Meta:
        model = Author
reveal_type(AuthorFactory.create())  # foo.Author

youtux avatar Nov 06 '22 01:11 youtux

Any updates on whether this PR will be merged?

palgorhythm avatar Mar 30 '23 00:03 palgorhythm

Updated it to include tests for typing.

last-partizan avatar Apr 14 '23 17:04 last-partizan

@rbarrois please, take a look. I've added tests for types based on pytest-mypy-plugins.

last-partizan avatar Apr 15 '23 09:04 last-partizan

any news ?

WaYdotNET avatar Jun 08 '23 06:06 WaYdotNET

Should stub/stub_batch be typed to return StubObject? Still better than Any. Other than that, having this PR merged would be really useful, as you can't really make use of the type stubs as from the implementation side (and not the stubs file), the factory class doesn't inherit from Generic or define any __class_getitem__ class method

Viicos avatar Oct 12 '23 13:10 Viicos

Should stub/stub_batch be typed to return StubObject? Still better than Any. Other than that, having this PR merged would be really useful, as you can't really make use of the type stubs as from the implementation side (and not the stubs file), the factory class doesn't inherit from Generic or define any __class_getitem__ class method

I'm not sure. StubObject is generic container, and from type-checking perspective it's empty, so you cannot access any attributes.

last-partizan avatar Oct 14 '23 08:10 last-partizan

I'm not sure. StubObject is generic container, and from type-checking perspective it's empty, so you cannot access any attributes.

Yes but at least people would know what object it is, instead of Any currently (as I believe no type checker can infer the return type considering it is making subcalls to _generate)

Viicos avatar Oct 14 '23 10:10 Viicos

@Viicos i think it's better to leave it as is, at least for now. This PR is focused on just basic typing support.

After merging this, you can improve typing for StubFactory.

last-partizan avatar Oct 15 '23 13:10 last-partizan

Gentle bump @francoisfreitag considering how many people requested it

Viicos avatar Dec 03 '23 20:12 Viicos

I don’t see opposition to merging this work. I offered a small fixes as a PR. Once these fixes are correct, and integrated into this PR, I think we can merge it.

In the meantime, @rbarrois’ opinion is very welcome :)

francoisfreitag avatar Dec 11 '23 11:12 francoisfreitag

Oh, I missed that PR. Fixes accepted!

last-partizan avatar Dec 11 '23 11:12 last-partizan

Can you rebase one last time before merging, please? :pray:

francoisfreitag avatar Jan 18 '24 08:01 francoisfreitag

Sure, rebased already, but looks like typing tests aren't running in CI.

Almost ready.

last-partizan avatar Jan 18 '24 10:01 last-partizan