IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

setup.py et "tests_require" / "extras_require": comment les utiliser ? [Python 3.X]


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Développeur informatique
    Inscrit en
    Mars 2008
    Messages
    80
    Détails du profil
    Informations personnelles :
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2008
    Messages : 80
    Par défaut setup.py et "tests_require" / "extras_require": comment les utiliser ?
    Bonjour à tous,

    J'ai créé un script "setup.py" de base afin de me faire la main sur le packaging de projets Python.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
     
    # See: https://setuptools.readthedocs.io/en/latest/setuptools.html
    #
    # Note: please keep in mind that this script will be executed within 2
    #       environments:
    #          1. the "source environment": the project where the distribution is
    #             generated.
    #          2. the "installation environment": the project where the distribution
    #             is installed.
    #       Within the second environment, the files will be searched within the
    #       distribution archive.
     
    import setuptools
    from typing import List
    import os
    import re
    import sys
     
     
    # See: https://docs.python.org/3.6/distutils/setupscript.html
    # WARNING: make sure to declare the file "data/description.md" as a "data file"
    # (see key "data_files").
    __DIR__ = os.path.dirname(os.path.abspath(__file__))
    long_description_path = os.path.join(__DIR__, 'data', 'description.md')
     
    with open(long_description_path, "r") as fh:
        long_description = fh.read()
     
    # Get the list of packages under the directory "lib".
    #
    # Please note that, since Python 3.3 the presence of the file "__init__.py" in
    # the package directory is not mandatory anymore. See "Implicit Namespace
    # Packages" at https://www.python.org/dev/peps/pep-0420/
    #
    # However, for "setuptools.find_packages()" to work, you must create a file
    # called "__init__.py" in the package directory.
    #
    # See: https://setuptools.readthedocs.io/en/latest/setuptools.html
    #
    # If you use implicit namespace packages (since Python 3.3), then you can use
    # the method "setuptools.find_namespace_packages()".
     
    use_implicit_namespace_packages = False
     
    if use_implicit_namespace_packages:
        # No package initializer "__init__.py" is required (since Python 3.3).
        packages = setuptools.find_namespace_packages(where=os.path.join(__DIR__,
                                                                         'lib'))
    else:
        # Package initializers "__init__.py" are required.
        packages = setuptools.find_packages(where=os.path.join(__DIR__, 'lib'))
     
    print('Packages:\n\n' + '\n'.join([f'* {p}' for p in packages]) + "\n\n")
    print(f'Installation prefix: "{sys.prefix}".' + "\n\n")
     
    # Load the requirements.
    # Please note that the requirement files must be generated prior to this
    #    operation:
    #    * pipenv lock --requirements > requirements.txt
    #    * pipenv lock --requirements --dev > requirements-test.txt
    #
    # See the sections "[dev-packages]" and "[packages]" of the "Pipfile".
    #
    # Please note that "pipenv" and "setup.py" don't use the same terms.
     
     
    def load_requirements(name: str) -> List[str]:
        """Load a given requirement file and generate the corresponding data
        structure that represents the requirements.
     
        :param name: name of the requirement file to load.
        :return: the corresponding data structure that represents the requirements.
        """
        dependencies: List[str] = []
        dep_matcher = re.compile('^[^=<>\\s]+\\s*[=<>]+\\s*[^=<>\\s]+$')
        with open(name, 'r') as fd:
            for line in fd.read().split("\n"):
                line.strip()
                if dep_matcher.match(line):
                    dependencies.append(line)
        return dependencies
     
     
    install_requirements = load_requirements('requirements.txt')
    test_requirements = load_requirements('requirements-dev.txt')
     
    setuptools.setup(
        author="Me",
        author_email="me@example.com",
        # The key "packages" lists the *names* of the packages.
        # It does not list the package directories.
        # The paths to the directories are defined by the key "package_dir".
        packages=packages,
        # See https://docs.python.org/3.6/distutils/setupscript.html#listing-whole-packages
        # Here, we say that all the package directories are located in the directory
        # "src". It is possible to assign specific directories for specific
        # packages.
        package_dir={'': 'lib'},
        name="Hello_World",
        version="0.0.1",
        description="Say hello to the World.",
        long_description=long_description,
        long_description_content_type="text/markdown",
        # See: https://docs.python.org/3.6/distutils/setupscript.html#installing-scripts
        # This key simply tells the installer that it must replace the path to the
        # interpreter after the "#!" (if present) by the path to the current
        # interpreter (or the one passed through the command line), in the specified
        # list of files.
        scripts=['bin/hello_world.py'],
        classifiers=[
            "Programming Language :: Python :: 3",
            "Operating System :: OS Independent"
        ],
        # See: https://python-packaging.readthedocs.io/en/latest/command-line-scripts.html
        # Once the package is installed, the console script "hello" will be
        # available. To see the list of all entry points for a given package you
        # can use the command bellow:
        #
        #    pipenv run pip show hello_world
        entry_points={
            'console_scripts': [
                'hello = my_package.my_module:main',
            ]
        },
        # Data files: files that must be included into the archive that is the
        # wheel.
        #
        # See: https://docs.python.org/3.6/distutils/setupscript.html#installing-additional-files
        #
        # Make sure to add all files used by the script "setup.py". In this case:
        # - requirements.txt
        # - requirements-dev.txt
        # - data/description.md
        #
        # "data_files" is an array of tuples. Each tuple contains 2 elements.
        # - The first element of the tuple (ex: "data") represents the target
        #   directory.
        # - The second element of the tuple ( zx: "data/description.md") represents
        #   the file that will be copied into the distribution.
        data_files=[('', ['requirements.txt', 'requirements-dev.txt']),
                    ('data', ['data/description.md'])],
        # List the requirements for the nominal use and for the development environment.
        install_requires=install_requirements,
        # List the requirements for the development environment.
        tests_require=test_requirements,
        extras_require={
            "dev": ['clint="*"']
        }
    )
    Je peux créer une archive pour distribuer les sources du projet:

    Je peux installer le projet:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    pip install /path/to/Hello_World-0.0.1.tar.gz
    pip show Hello-World --files
    python -c "import my_package.my_module; print(my_package.my_module.__file__)"
    Tout va bien dans le meilleur des mondes... Mais QUID des paramètres "tests_require" et "extras_require" ???

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
        tests_require=test_requirements,
        extras_require={
            "dev": ['clint="*"']
        }
    Comment "activer" l'utilisation de ces paramètres ?

    Avez-vous une idée ?

    Merci

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 743
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 743
    Par défaut
    Salut,

    Citation Envoyé par WinNew Voir le message
    Comment "activer" l'utilisation de ces paramètres ?
    L'exemple donné dans la documentation n'est il pas suffisant?

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Membre confirmé
    Profil pro
    Développeur informatique
    Inscrit en
    Mars 2008
    Messages
    80
    Détails du profil
    Informations personnelles :
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2008
    Messages : 80
    Par défaut
    @wiztricks

    Bonjour,

    J'avais effectivement lu cette partie de la documentation. Toutefois, après quelques essais je n'étais pas parvenu à "en tirer quelque chose".

    J'ai passé la journée d'hier à "creuser" la question. Et j'ai finalement réussi à mener à bien la tâche que je souhaitais réaliser.

    Je vais indiquer ici la manipulation.

    Tout d'abord, un conseil : si vous souhaitez tester des manipulations sur des packages, je vous conseille d'éviter d'utiliser le nom "hello_world" pour vos packages. En effet, un package qui porte ce nom existe. Du coup, cela risque de produire des "effets de bord" qui vont vous faire perdre du temps.

    Donc, je suppose que vous avez créé un package nommé "my_hello_world", via le fichier "setup.py" suivant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
     
    # See: https://setuptools.readthedocs.io/en/latest/setuptools.html
    #
    # Note: please keep in mind that this script will be executed within 2
    #       environments:
    #          1. the "source environment": the project where the distribution is
    #             generated.
    #          2. the "installation environment": the project where the distribution
    #             is installed.
    #       Within the second environment, the files will be searched within the
    #       distribution archive.
     
    import setuptools
    from typing import List
    import os
    import re
    import sys
     
     
    # See: https://docs.python.org/3.6/distutils/setupscript.html
    # WARNING: make sure to declare the file "data/description.md" as a "data file"
    # (see key "data_files").
    __DIR__ = os.path.dirname(os.path.abspath(__file__))
    long_description_path = os.path.join(__DIR__, 'data', 'description.md')
     
    with open(long_description_path, "r") as fh:
        long_description = fh.read()
     
    # Get the list of packages under the directory "lib".
    #
    # Please note that, since Python 3.3 the presence of the file "__init__.py" in
    # the package directory is not mandatory anymore. See "Implicit Namespace
    # Packages" at https://www.python.org/dev/peps/pep-0420/
    #
    # However, for "setuptools.find_packages()" to work, you must create a file
    # called "__init__.py" in the package directory.
    #
    # See: https://setuptools.readthedocs.io/en/latest/setuptools.html
    #
    # If you use implicit namespace packages (since Python 3.3), then you can use
    # the method "setuptools.find_namespace_packages()".
     
    use_implicit_namespace_packages = False
     
    if use_implicit_namespace_packages:
        # No package initializer "__init__.py" is required (since Python 3.3).
        packages = setuptools.find_namespace_packages(where=os.path.join(__DIR__,
                                                                         'lib'))
    else:
        # Package initializers "__init__.py" are required.
        packages = setuptools.find_packages(where=os.path.join(__DIR__, 'lib'))
     
    print('Packages:\n\n' + '\n'.join([f'* {p}' for p in packages]) + "\n\n")
    print(f'Installation prefix: "{sys.prefix}".' + "\n\n")
     
    # Load the requirements.
    # Please note that the requirement files must be generated prior to this
    #    operation:
    #    * pipenv lock --requirements > requirements.txt
    #    * pipenv lock --requirements --dev > requirements-test.txt
    #
    # See the sections "[dev-packages]" and "[packages]" of the "Pipfile".
    #
    # Please note that "pipenv" and "setup.py" don't use the same terms.
     
     
    def load_requirements(name: str) -> List[str]:
        """Load a given requirement file and generate the corresponding data
        structure that represents the requirements.
     
        :param name: name of the requirement file to load.
        :return: the corresponding data structure that represents the requirements.
        """
        dependencies: List[str] = []
        dep_matcher = re.compile('^[^=<>\\s]+\\s*[=<>]+\\s*[^=<>\\s]+$')
        with open(name, 'r') as fd:
            for line in fd.read().split("\n"):
                line.strip()
                if dep_matcher.match(line):
                    dependencies.append(line)
        return dependencies
     
     
    install_requirements = load_requirements('requirements.txt')
    test_requirements = load_requirements('requirements-dev.txt')
     
    setuptools.setup(
        author="Me",
        author_email="me@example.com",
        # The key "packages" lists the *names* of the packages.
        # It does not list the package directories.
        # The paths to the directories are defined by the key "package_dir".
        packages=packages,
        # See https://docs.python.org/3.6/distutils/setupscript.html#listing-whole-packages
        # Here, we say that all the package directories are located in the directory
        # "src". It is possible to assign specific directories for specific
        # packages.
        package_dir={'': 'lib'},
        # **WARNING**: do NOT use the name "hello_world" !!!
        # A package with the same name already exists !!!
        name="my_hello_world",
        version="0.1",
        description="Say hello to the World.",
        long_description=long_description,
        long_description_content_type="text/markdown",
        # See: https://docs.python.org/3.6/distutils/setupscript.html#installing-scripts
        # This key simply tells the installer that it must replace the path to the
        # interpreter after the "#!" (if present) by the path to the current
        # interpreter (or the one passed through the command line), in the specified
        # list of files.
        scripts=['bin/hello_world.py'],
        classifiers=[
            "Programming Language :: Python :: 3",
            "Operating System :: OS Independent"
        ],
        # See: https://python-packaging.readthedocs.io/en/latest/command-line-scripts.html
        # Once the package is installed, the console script "hello" will be
        # available. To see the list of all entry points for a given package you
        # can use the command bellow:
        #
        #    pipenv run pip show hello_world
        entry_points={
            'console_scripts': [
                'hello = my_package.my_module:main',
            ]
        },
        # Data files: files that must be included into the archive that is the
        # wheel.
        #
        # See: https://docs.python.org/3.6/distutils/setupscript.html#installing-additional-files
        #
        # Make sure to add all files used by the script "setup.py". In this case:
        # - requirements.txt
        # - requirements-dev.txt
        # - data/description.md
        #
        # "data_files" is an array of tuples. Each tuple contains 2 elements.
        # - The first element of the tuple (ex: "data") represents the target
        #   directory.
        # - The second element of the tuple ( zx: "data/description.md") represents
        #   the file that will be copied into the distribution.
        data_files=[('', ['requirements.txt', 'requirements-dev.txt']),
                    ('data', ['data/description.md'])],
        # List the requirements for the nominal use and for the development environment.
        install_requires=install_requirements,
        # List the requirements for the development environment.
        tests_require=test_requirements,
        extras_require={
            "dev": ["clint==0.5.1"]
        }
    )
    Veuillez noter la présence du paramètre extras_require.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        extras_require={
            "dev": ["clint==0.5.1"]
        }
    Vous avez généré le "wheel":

    Du coup, vous avez produit un fichier: dist/my_hello_world-0.1.tar.gz

    Vous souhaitez installer votre super package, en activant "l'option" "dev":

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    pip install --no-cache-dir --find-links=/path/to/my_hello_world-0.1.tar.gz  "my_hello_world [dev]"
    Note: l'option "--no-cache-dir" n'est pas indispensable!

    Voilà :-)

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Les doubles quotes dans les fprintf
    Par Changedman dans le forum C
    Réponses: 30
    Dernier message: 22/02/2007, 12h07
  2. Réponses: 15
    Dernier message: 21/02/2007, 17h29

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo