Skip to content
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

Expose most of trio._util and trio._deprecate for the benefit of the Trio ecosystem #1504

Open
oremanj opened this issue May 10, 2020 · 3 comments

Comments

@oremanj
Copy link
Member

oremanj commented May 10, 2020

Trio has great tools for dealing with some of the minutiae of making a polished Python package in general, but they're private; libraries that depend on Trio need to copy-paste or reimplement these tools if they want to offer equivalent functionality. If they reimplement, they probably won't do as good of a job.

I think we should add a new public Trio submodule (trio.libtools?) which provides:

  • From trio._util: Final, NoPublicConstructor, generic_function, fixup_module_metadata, async_wraps, ConflictDetector
  • A factory for creating modules like trio._deprecate, substituting a project's own deprecation warning, issue URL, and name.
@oremanj
Copy link
Member Author

oremanj commented May 12, 2020

Also useful: extract and publicize the logic from Runner.spawn_impl() for "either get a coroutine from this async function+args or raise an error explaining why it's not in the form I wanted" and "turn this function/name into a string". They're very useful for duck-nurseries (I have a hack in tricycle.open_service_nursery() working around the absence of the error-reporting one), and I think would find other uses too (#1513 made me think of this).

@njsmith
Copy link
Member

njsmith commented May 12, 2020

extract and publicize the logic from Runner.spawn_impl() for "either get a coroutine from this async function+args or raise an error explaining why it's not in the form I wanted"

Heh, I was just wondering whether to comment on #1513 to suggest this before I saw your post :-). Maybe trio.lowlevel.trio_async_fn_to_coroutine_object(afn, *args, **kwargs)?

A factory for creating modules like trio._deprecate, substituting a project's own deprecation warning, issue URL, and name.

trio._deprecate is definitely a substantial piece of code, and it would make a ton of sense to extract into a standalone library. The reason I haven't yet is just because, y'know, making sure an interface is general enough to make public takes some work, and there are a lot of different ways that different projects like to approach to deprecation (e.g. there are multiple existing deprecation-helper libraries on PyPI already but I didn't like any of the ones I found). If someone wants to take this on though then I'd be supportive :-). Making it part of trio's public interface would feel weird though. Even just within python-trio, we have lots of libraries that might need to deprecate things but that don't otherwise depend on trio :-)

From trio._util: Final, NoPublicConstructor, generic_function, fixup_module_metadata, async_wraps, ConflictDetector

These I'm not as sure about. They're all pretty simple one-off things; the kind of code where the implementation is shorter than the documentation? And I'm reluctant to clutter Trio's API with random Python utilities. generic_function should maybe be in some typing library. async_wraps isn't really a generically reusable thing right now (maybe a more useful version would be some kind of @trio.to_thread.asyncify decorator?). Final and NoPublicConstructor are generally useful, but Final should be replaced by a @final decorator now that we dropped 3.5 support, and I'm not sure where a good place to put them would be...

ConflictDetector is the only thing here that feels like it might be a logical part of Trio's API, but even so I hesitate since it's such a trivial helper...

@oremanj
Copy link
Member Author

oremanj commented May 15, 2020

You're right that most of these are simple to copy or reimplement. The idea I'm driving at here is that we'll have a better and more polished-feeling ecosystem if all (or almost all) Trio libraries do these things the same way. They're not really about async I/O; the only reason to put them in Trio is because every Trio library already depends on Trio. I guess they do add to our public API surface area, but I feel like if we put them in a clearly delineated submodule of "helpers for writing Trio libraries that act like Trio in particular ways", they'll be easily ignorable by people who don't care about that.

The only ones I feel strongly about are ConflictDetector, fixup_module_metadata, and deprecations. ConflictDetector can easily go in trio.lowlevel on its own. For the others, I guess a different package might be a better choice. The name tradition appears available on PyPI...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants