Going backwards on your questions; while it's really broad, the topic is still constrained enough.
I can tell you that the classifiers are not manipulated, but rather read from the and then written to PKG-INFO
file by the egg_info
command, which in turn looks for all egg_info.writers
entry_points which the setuptools.command.egg_info:write_pkg_info
function will do the actual writing. As far as I can tell, trying to leverage that Classifier outside will not be a great way, however you can override everything and anything you want through setuptools
so you can make your own write_pkg_info
function, figure out how to read the metadata (which you can see in the main distutils.command.upload:upload.upload_file
method) and manipulate that further before upload_file finally reads it. At this point you probably are thinking that manipulating and working with this system is going to be rather annoying.
As I mentioned though, everything can be overridden. You can make an upload command that take the public flag, like so:
from distutils.log import warn
from distutils.command.upload import upload as orig
# alternatively, for later versions of setuptools:
# from setuptools.command.upload import upload as orig
class upload(orig):
description = "customized upload command"
user_options = orig.user_options + [
('public', None,
'make package public on pypi'),
]
def initialize_options(self):
orig.initialize_options(self)
self.public = False
def run(self):
if not self.public:
warn('not public, not uploading')
return
return orig.run(self)
The accompanied setup.py
might look something like this.
from setuptools import setup
setup(
name='my_pypi_uploader',
version='0.0',
description='"safer" pypi uploader',
py_modules=['my_pypi_uploader'], # assuming above file is my_py_uploader.py
entry_points={
'distutils.commands': [
'upload = my_pypi_uploader:upload',
],
},
)
Install that as a package into your environment and the upload command will be replaced by your version. Example run:
$ python setup.py upload
running upload
not public, not uploading
Try again with the public flag
$ python setup.py upload --public
running upload
error: No dist file created in earlier command
Which is fine, since I didn't create any dist files at all. You could of course further extend that command by rewriting the upload_file
method (make a copy in your code) and change the parts to do what you want in your subclass (like injecting the private classifier there), up to you.
You might also be wondering why the class names are in lower case (violation of pep8), this is due to legacy stuff and how the help for a given command is generated.
$ python setup.py upload --help
...
Options for 'upload' command:
Using a "properly" named class (e.g. SafeUpload
; remember to also update the entry_point
in the setup.py
to point to this new class name)
$ python setup.py upload --help
...
Options for 'SafeUpload' command:
of course if this output is the intent, the standard class naming convention can be used instead.
Though to be perfectly honest, you should not specify upload at all on your production, but rather do this on your build servers as part of post-push hook, so when the project is pushed (or tagged), build is done and the file is loaded onto your private servers, and then only further manual intervention (or automatic if specific tags are pushed) will then get the package up to pypi. However the above example should get you started in what you originally set out to do.
One last thing: you can just change self.repository
to your private devpi location, if the --public
flag is not set. You could either override this before calling the orig.upload_file
method (through your customized version), or do it in run
; so rather than quitting, your code could just verify that the repository url is not the public PyPI instance. Or alternatively, manipulate the distribution metadata (i.e. the classifiers) via self.distribution.metadata
(self
being the upload
instance). You can of course create a completely new command to play with this to your hearts content (by creating a new Command
subclass, and add a new entry_point for that).