Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to specify multiple author(s) / email(s) in setup.py

Tags:

python

pypi

We wrote a small wrapper to a twitter app and published this information to http://pypi.python.org. But setup.py just contained a single field for specifying email / name of the author. How do I specify multiple contributors / email list, to the following fields since we would like this package to be listed under our names, much similar to how it shows up in http://rubygems.org.

author='foo',
author_email='[email protected]',
like image 659
priya Avatar asked Apr 03 '12 19:04

priya


People also ask

How do you add multiple authors in setup py?

Your best bet is to list the authors in a single string: author='Foo Bar, Spam Eggs', author_email='[email protected], [email protected]', I'm not sure if PyPI validates the author_email field, so you may run into trouble with that one.

What is Package_dir in setup py?

package_dir = {'': 'lib'} in your setup script. The keys to this dictionary are package names, and an empty package name stands for the root package. The values are directory names relative to your distribution root.

What is Python Setuptools used for?

Setuptools is a collection of enhancements to the Python distutils that allow developers to more easily build and distribute Python packages, especially ones that have dependencies on other packages. Packages built and distributed using setuptools look to the user like ordinary Python packages based on the distutils .


2 Answers

As far as I know, setuptools doesn't support using a list of strings in order to specify multiple authors. Your best bet is to list the authors in a single string:

author='Foo Bar, Spam Eggs',
author_email='[email protected], [email protected]',

I'm not sure if PyPI validates the author_email field, so you may run into trouble with that one. In any case, I would recommend you limit these to a single author and mention all contributors in the documentation or description.

Some sources:

This has been registered as a bug, actually, but it seems like support for multiple authors was not implemented. Here is an alternative solution. Here is an idea for how to provide a contact email for a project with multiple authors.

like image 136
modocache Avatar answered Sep 24 '22 22:09

modocache


I'm sort of just piggybacking off of @modocache's answer, in case you want some specifics.

Throughout this answer, I'll be refering to a python3.6 version of the FOO-PYTHON-ENV\Lib\distutils\dist.py file

To reiterate, you cannot use a list in the author field. Here's why:

Spoiler: Two methods belonging to the DistributionMetadata class are the reason --

def _read_field(name):
    value = msg[name]
    if value == 'UNKNOWN':
        return None
    return value

def _read_list(name):
    values = msg.get_all(name, None)
    if values == []:
        return None
    return values

Here's where you'll hit an error if you try to stick a list in the author field:

class DistributionMetadata:

#*...(R E D A C T E D)...*#

    def read_pkg_file(self, file):
        """Reads the metadata values from a file object."""
    #*...(R E D A C T E D)...*#
        # ####################################
        # Note the usage of _read_field() here
        # ####################################
        self.name = _read_field('name')
        self.version = _read_field('version')
        self.description = _read_field('summary')
        # we are filling author only.
        self.author = _read_field('author')
        self.maintainer = None
        self.author_email = _read_field('author-email')
        self.maintainer_email = None
        self.url = _read_field('home-page')
        self.license = _read_field('license')
    #*...(R E D A C T E D)...*#
        # ###################################
        # Note the usage of _read_list() here
        # ###################################
        self.platforms = _read_list('platform')
        self.classifiers = _read_list('classifier')
    #*...(R E D A C T E D)...*#

& Here's the whole thing:

class DistributionMetadata:
        """Dummy class to hold the distribution meta-data: name, version,
        author, and so forth.
        """

        _METHOD_BASENAMES = ("name", "version", "author", "author_email",
                     "maintainer", "maintainer_email", "url",
                     "license", "description", "long_description",
                     "keywords", "platforms", "fullname", "contact",
                     "contact_email", "classifiers", "download_url",
                     # PEP 314
                     "provides", "requires", "obsoletes",
                     )

    def __init__(self, path=None):
        if path is not None:
            self.read_pkg_file(open(path))
        else:
            self.name = None
            self.version = None
            self.author = None
            self.author_email = None
            self.maintainer = None
            self.maintainer_email = None
            self.url = None
            self.license = None
            self.description = None
            self.long_description = None
            self.keywords = None
            self.platforms = None
            self.classifiers = None
            self.download_url = None
            # PEP 314
            self.provides = None
            self.requires = None
            self.obsoletes = None

    def read_pkg_file(self, file):
        """Reads the metadata values from a file object."""
        msg = message_from_file(file)

        def _read_field(name):
            value = msg[name]
            if value == 'UNKNOWN':
                return None
            return value

        def _read_list(name):
            values = msg.get_all(name, None)
            if values == []:
                return None
            return values

        metadata_version = msg['metadata-version']
        self.name = _read_field('name')
        self.version = _read_field('version')
        self.description = _read_field('summary')
        # we are filling author only.
        self.author = _read_field('author')
        self.maintainer = None
        self.author_email = _read_field('author-email')
        self.maintainer_email = None
        self.url = _read_field('home-page')
        self.license = _read_field('license')

        if 'download-url' in msg:
            self.download_url = _read_field('download-url')
        else:
            self.download_url = None

        self.long_description = _read_field('description')
        self.description = _read_field('summary')

        if 'keywords' in msg:
            self.keywords = _read_field('keywords').split(',')

        self.platforms = _read_list('platform')
        self.classifiers = _read_list('classifier')

        # PEP 314 - these fields only exist in 1.1
        if metadata_version == '1.1':
            self.requires = _read_list('requires')
            self.provides = _read_list('provides')
            self.obsoletes = _read_list('obsoletes')
        else:
            self.requires = None
            self.provides = None
            self.obsoletes = None
like image 30
Rob Truxal Avatar answered Sep 26 '22 22:09

Rob Truxal