111 votes

Comment spécifier plusieurs auteur(s) / email(s) dans setup.py

Nous avons écrit un petit wrapper pour une application Twitter et nous avons publié ces informations sur le site http://pypi.python.org . Mais setup.py ne contient qu'un seul champ pour spécifier l'email / le nom de l'auteur. Comment puis-je spécifier plusieurs contributeurs / liste d'emails, pour les champs suivants puisque nous aimerions que ce paquet soit listé sous nos noms, de la même manière qu'il apparaît dans http://rubygems.org .

author='foo',
author_email='foo.bar@gmail.com',

112voto

modocache Points 2140

Pour autant que je sache, setuptools ne permet pas d'utiliser une liste de chaînes pour spécifier plusieurs auteurs. Le mieux est de lister les auteurs dans une seule chaîne :

author='Foo Bar, Spam Eggs',
author_email='foobar@baz.com, spameggs@joe.org',

Je ne suis pas sûr que PyPI valide le code author_email Vous risquez donc d'avoir des problèmes avec ce champ. Quoi qu'il en soit, je vous recommande de les limiter à un seul auteur et de mentionner tous les contributeurs dans la documentation ou la description.

Quelques sources :

Cela a été enregistré comme un bogue En fait, il semble que la prise en charge de plusieurs auteurs n'ait pas été mise en œuvre. Ici est une solution alternative. Ici est une idée pour fournir une adresse électronique de contact pour un projet avec plusieurs auteurs.

3voto

Rob Truxal Points 1134

Je ne fais que reprendre la réponse de @modocache, au cas où vous souhaiteriez des précisions.

Tout au long de cette réponse, je ferai référence à une version python3.6 de l'application FOO-PYTHON-ENV\Lib\distutils\dist.py fichier

Pour rappel, il n'est pas possible d'utiliser une liste dans la rubrique author domaine. Voici pourquoi :

Spoiler : Deux méthodes appartenant à la catégorie DistributionMetadata sont la raison

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

C'est ici que vous rencontrerez une erreur si vous essayez d'insérer une liste dans le champ author domaine :

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)...*#

& Voici l'ensemble :

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

1voto

Mike T Points 7385

Envisager d'utiliser flit pour construire le paquet, car ce système de construction prend en charge plusieurs auteurs et mainteneurs. Stockez ces métadonnées dans pyproject.toml comme suit :

[build-system]
requires = ["flit_core >=3.2,<4"]
build-backend = "flit_core.buildapi"

[project]
...
authors = [
    {name = "First1 Last1", email = "name1@foo.bar"},
    {name = "First2 Last2", email = "name2@foo.bar"},
]
maintainers = [
    {name = "First1 Last1", email = "name1@foo.bar"},
    {name = "First2 Last2", email = "name2@foo.bar"},
]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X