Как выбрать переменную для скрипта Python из командной строки?

Мне нужно запустить тестовый скрипт python для разных сред (разные URL-адреса). И мне нужно определить, какую переменную использовать из командной строки. В дальнейшем этот параметр будет использоваться в работе Jenkins.

script.py:

class TestLogin(unittest.TestCase):

    @allure.step
    def test_LoginValidation(self):

        devURL = "http://url1/admin/login/"
        stagingURL = "http://url2/admin/login/"
        prodURL = "https://url3/admin/login"

        driver.maximize_window()
        driver.implicitly_wait(10)
        driver.get(url)

        lp = LoginPage(driver)
        lp.login("login", "password")


        time.sleep(2)
        driver.quit()

В командной строке мне нужно написать

python script.py stagingURL

В результате в методе test_LoginValidation в driver.get (URL) будет использоваться url, который я определил в командной строке.

Если вы хотите создать интерфейс командной строки только для параметризации модульного теста, вы можете рассмотреть возможность использования @pytest.mark.parametrize, который позволяет определять несколько наборов аргументов и фикстур в тестовой функции или классе. Вы можете посмотреть мой ответ для более подробной информации. Кроме того, я добавил фиктивный пример того, как реализовать cli с помощью python click.

Raoslaw Szamszur 26.11.2018 13:22
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
1
581
4

Ответы 4

Вы ищете argparse. Это должно позволить вам делать именно то, что вы ищете, например:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('url', help = 'The URL to use for ...', type = str)

Это устанавливает URL-адрес в качестве обязательного аргумента, передаваемого функции, и устанавливает для него тип str (это поведение по умолчанию, но явное указание - это хорошо).

Затем вы можете извлечь аргументы, используя:

args = parser.parse_args()
specified_url = args.url

Отсюда вы можете продолжить как обычно. Если вы хотите сделать аргумент необязательным, но со значением по умолчанию, это также можно сделать с помощью argparse.

Использование переменных среды работает, но отладить его намного сложнее, особенно если вы ожидаете, что этот сценарий будет запускаться другой частью программного обеспечения. Argparse намного надежнее.

В этом ответе поможет пример.

Adam Smith 26.11.2018 12:22

Для этого можно использовать argparse:

import argparse

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Description')

    parser.add_argument('--dev',
                        dest='dev',
                        action='store_true',
                        help = "Help message")

    parser.add_argument('--stage',
                        dest='stage',
                        action='store_true',
                        help = "Help message")

    parser.add_argument('--prod',
                        dest='prod',
                        action='store_true',
                        help = "Help message")

    parser.set_defaults(dev=True,
                        stage=False,
                        action=False)

    args = parser.parse_args()

    url = None
    if args.dev:
        url = "http://url1/admin/login/"
    if args.stage:
        url = "http://url2/admin/login/"
    if args.prod:
        url = "https://url3/admin/login"

    # do something with the url

Это один из способов сделать это. Вы создаете некоторые параметры arg --dev, --stage, --prod, и по умолчанию для --dev установлено значение true. Вы также можете не иметь значения по умолчанию (просто установите dev=False).

Итак, в следующий раз вы можете запустить:

python program.py --dev
python program.py --stage
python program.py --prod

Возможно, вы захотите обработать случай, когда передано более одного флага.

Вы также можете сделать это так:

import argparse

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Description')

    parser.add_argument("--env", 
                        choices = {"dev", "stage", "prod"}, 
                        help = "Some help message.")

    args = parser.parse_args()

    url = None
    if args.env == "dev":
        url = "http://url1/admin/login/"
    elif args.env == "stage":
        url = "http://url2/admin/login/"
    elif args.env == "prod":
        url = "https://url3/admin/login"
    else:
        print("Please specify the environment using --env flag.")

    if url is not None:
        print(url)

Пример:

$ python3 test2.py
Please specify the environment using --env flag.

$ python3 test2.py --env prod
https://url3/admin/login

$ python3 test2.py --env stage
http://url2/admin/login/

$ python3 test2.py --env dev
http://url1/admin/login/

$ python3 test2.py --env wrong
usage: test2.py [-h] [--env {stage,dev,prod}]
test2.py: error: argument --env: invalid choice: 'wrong' (choose from 'stage', 'dev', 'prod')

Вы можете узнать больше о argparseздесь.

Могу порекомендовать пакет click для создания CLI. Это действительно просто, хорошо документировано, имеет множество опций и, на мой взгляд, намного проще в использовании, чем argparse.

Пустой пример:

import click

@click.command()
@click.option(
    '--count',
    default=1,
    help='Number of greetings.'
)
@click.option(
    '--name',
    prompt='Your name',
    help='The person to greet.'
)
def hello(**options):
    """Simple program that greets NAME for a total of COUNT times."""
    for x in range(options['count']):
        click.echo('Hello %s!' % options['name'])

if __name__ == '__main__':
    hello()

И как это выглядит при запуске:

$ python hello.py --count=3
Your name: John
Hello John!
Hello John!
Hello John!

Он автоматически генерирует красиво отформатированные справочные страницы:

$ python hello.py --help
Usage: hello.py [OPTIONS]

  Simple program that greets NAME for a total of COUNT times.

Options:
  --count INTEGER  Number of greetings.
  --name TEXT      The person to greet.
  --help           Show this message and exit.

Вы можете получить библиотеку прямо из PyPI:

pip install click

Если вы хотите создать интерфейс командной строки только для параметризации модульного теста, вы можете рассмотреть возможность использования @pytest.mark.parametrize, который позволяет определять несколько наборов аргументов и фикстур в тестовой функции или классе.

Пример:

import pytest

class TestLogin(object):

    @pytest.mark.parametrize("url", [
        "http://url1/admin/login/",
        "http://url2/admin/login/",
        "https://url3/admin/login",
    ])
    def test_LoginValidation(self, url):
        driver.maximize_window()
        driver.implicitly_wait(10)
        driver.get(url)

        lp = LoginPage(driver)
        lp.login("login", "password")


        time.sleep(2)
        driver.quit()

Возможно, стоит включить в click фрагмент переключатели функций, который здесь и следует использовать.

Adam Smith 26.11.2018 12:43

@AdamSmith Спасибо за ответ! Я не хотел, чтобы пост был слишком длинным, поэтому я больше не добавлял фрагментов (это уже хорошо задокументировано). Вместо этого я предоставил альтернативное решение, которое также должно решить вариант использования OP.

Raoslaw Szamszur 26.11.2018 13:04

В Jenkins это почти наверняка легче сделать, чем в Python. Вдобавок кажется логичным, что ваш конвейер DevOps контролирует расположение URI разработки, подготовки и выпуска (по крайней мере, в той мере, в какой это целесообразно).

def targetUrl = ''
switch (env.TARGET) {
    case 'dev':
        targetUrl = "http://url1/admin/login/"
        break
    // etc
}

sh "python script.py ${targetUrl}"

затем попросите скрипт python взглянуть на sys.argv[1] (который является первым переданным ему аргументом) и напрямую использовать этот URL.

Другие вопросы по теме