Zest.releaser uses twine as an API when uploading files to pypi. It calls upload() directly. But https://github.com/pypa/twine/commit/ece3711fb7e69891b1ed8f86314a2762dbe64454, which is in the recent 1.7.x releases, broke the API as there are now two extra mandatory arguments.
So...
I've been clear on past issues that we don't consider twine.commands.* to be a public API. What I've been working towards, however, is something semi-public in twine.{exceptions,package,repository}.
If you look at how the upload command works, it roughly does:
Repository from URL and credentials (username, password)PackageFile from its filename (PackageFile.from_filename)PackageFile instance using Repository#uploadThat said, I've had neither time, nor the inclination to document these because I wouldn't consider them entirely stable APIs. I still have a desire to iterate on them and really no one else has been really asking for much of a stable API. They have accepted that we don't have one and use the internals as they see fit completely accepting that they may see breakage.
@sigmavirus24 Is there some "high level" API, which an be considered stable? What about e.g. twine.cli.dispatch()?
Rational: I need to add support for --sign or detection of signature-files (.asc) to zest.releaser. zest.releaser currently is not able to upload signatures: it implements upload following your advice above, thus uploading each file on its own, and Repository#upload will skip any .asc file.
Implementing this, I found myself re-implementing quite some parts of twine (esp. twine.commands.upload#upload and – even more important – using a lot more functions of which it is unclear whether they are stable and public. IMHO this is not the way to go. Imagine twine gaining more and more functionality and the PyPi API changing.
For example using twine.cli.dispatch() would solve this issue – if it is to be considered public. Using this function would add some overhead for parsing arguments, etc., but on the other hand it would allow to use twine like on the command-line (without the overhead of starting a new process).
@sigmavirus24 How are you feeling about this and PR #361? Worth keeping open and discussing as a feature request?
I have some sympathies with the critiques made in #361. In particular, I do agree the "hello world" of a twine API should be short and sweet. A client shouldn't need to orchestrate a series of objects to perform a basic operation. The API should provide sane defaults very similar to how the command-line interface behaves. Ideally, the programmatic API and CLI would both be built on a common foundation, something like 'actions' with 'args' where args have 'defaults'.
It seems that the main users requesting this functionality would be satisfied with a simple entry point that exposes the various twine commands via their CLI interface.
In the feature/commands-api branch, I've drafted the concept where the twine commands are exposed as functions in twine.api. To invoke upload:
import twine.api
args = [] # args as would be passed to subprocess.Popen
twine.api.upload(args)
I'm not sure if this approach is viable or where it would not be. It surely doesn't provide any high-level abstractions or sophistication around the mechanics of twine; it simply provides a shortcut to the behavior in-process. I did note that for some values of args (e.g. --help), a SystemExit is raised by the ArgumentParser. I suspect that's an ignorable behavior if it only applies to --help.
@jaraco just because folks are using that out of desperation now doesn't mean we should irrevocably make that the API. It's not something we could walk back and the api you've described is not an API I'd ever want to use as a 3rd party. (Passing in an argparse.Namespace or a list of arguments that are undocumented)
Most helpful comment
I have some sympathies with the critiques made in #361. In particular, I do agree the "hello world" of a twine API should be short and sweet. A client shouldn't need to orchestrate a series of objects to perform a basic operation. The API should provide sane defaults very similar to how the command-line interface behaves. Ideally, the programmatic API and CLI would both be built on a common foundation, something like 'actions' with 'args' where args have 'defaults'.
It seems that the main users requesting this functionality would be satisfied with a simple entry point that exposes the various twine commands via their CLI interface.