Единственным на моей памяти исключением является node.js, авторы которой разработали «с чистого листа» на удивление удачную систему управления зависимостями. Ну, как удачную? Проблем там тоже много, начиная автовыполняемыми скриптами и заканчивая переходом от древовидной к flat структуре в 3-й версии. Но по сравнению с тем, что на тот момент было в других языках, нода — это прорыв.
Совсем недавно экосистема пополнилась новой утилитой rnpm, которая позволяет одной командой устанавливать React Native зависимости. В которых, на секундочку, может быть бинарный код для android и ios. Для разных архитектур. И все это работает из коробки. Мы в Voximplant хорошо знакомы с этой штукой: с ее помощью ставится наш собственный React Native SDK.
Вашему вниманию предлагаем интересную статью, опубликованную всего два дня назад, в которой очень подробно рассказывается про управление зависимостями в Python. Про историю развития. Про проблемы. И, что самое ценное — про то, как сообщество их решает. Под катом адаптированный для Хабра перевод и возможность обсудить печальную тему зависимостей. И не только для Python.
Окай, ребята. Похоже, прошли те времена, когда мы могли рассказывать друг другу, насколько все плохо с зависимостями в Python. Сейчас расскажу, почему.
Потому что мы починили работу с зависимостями. Если ты разработчик и создаешь или используешь Python библиотеки, то теперь это делается легко и без боли. Я говорю это, потому что в течении долгого времени средства Python для работы с зависимостями были… с проблемами. Это уже не так, но многие люди продолжают читать о «проблемах с зависимостями у Python» и думают, что ничего не поменялось. Пора все рассказать.
Небольшой исторический экскурс. С зависимостями у Python дело обстояло примерно так…
Рассвет
Python увидел свет в те времена, когда добавление зависимости означало долгое путешествие в киберспейс. Для начала нужно было дождаться освобождения телефонной линии. Затем позвонить провайдеру. Позвонить по модему, что характерно. После боя с SLIP или PPP клиентом можно было задать вопрос в одну из групп, знает ли кто-нибудь хороший gopher-сайт, где можно найти библиотеку для решения стоящей перед тобой задачи. После чего можно было отключиться от интернета и подождать несколько десятков часов: вдруг кто-нибудь да ответит. Если повезло, то можно было поставить закачку на ночь.
Никакого pip search тогда не было!
Для того времени подход Python к управлению зависимостями был удивительно прозорливым. Директива ‘import’ и расширяемая система загрузки модулей позволяла подключать зависимости откуда угодно.
Вместе с версией 2.0 Python (октябрь 2000 года) состоялся релиз Distutils. С его помощью разработчики смогли абстрактно описывать их коллекции модулей и создавать пригодные для распространения коллекции модулей и пакетов. И снова, это было очень, очень прозорливое решение. В те времена ни о чем подобном не было и речи.
Перематываем время к 2004 году. Создание setuptools для решения типовых задач, с которыми сталкиваются разработчики open source при распространении своих модулей через интернет. В 2005 была добавлена утилита easy_install для автоматического определения зависимостей и скачивания их в нужные директории.
Темные века
К сожалению, вместе с простыми механизмами описания зависимостей, setuptols притащили с собой чудовищное количество сложности. Автор посчитал, что директива ‘import’ должна работать немного по-другому, и установка setuptools изменила ее поведение. По сравнению с обычной директивой ‘import’, версия setuptools поддерживала работу с несколькими версиями одной и той же зависимости в рамках одной программы. Тогда это казалось замечательной идеей. Но время показало, что это не так. Более того, схожая идея возможности установки нескольких версий библиотеки на один компьютер (а не одновременно для одной программы) является важной и нужной штукой.
В дополнение к этому идеологическому отходу от стандартной семантики Python, setuptools имела проблемы с майнтейнером. Точнее, с отсутствием майнтейнеров. Она стала критичной частью Python экосистемы как раз в тот момент, когда автор решил заняться другими проектами – совершенно несвязанными с программированием. Довольно долго никто не мог договориться, кто и как будет поддерживать проект. Который, к тому времени, с одной стороны был уже форкнут, а с другой стороны, во многих дистрибутивах «окаменела» старая и глючная версия.
С 2008 по 2012 года управление зависимостями в Python представляло из себя не лучшее зрелище. Пользоваться им было по меньшей мере болезненно. Было непонятно, какие библиотеки и утилиты использовать, в какие стоит инвестировать свое внимание и изучать. Ручное управление зависимостями было утомительно, тогда как автоматизация требовала множество слабо документированных обходных путей.
Это еще не говоря о многочисленных дырах безопасности в разных частях тулчейна. Не было возможности запаковать и распространить Python библиотеку с нативным кодом так, чтобы у пользователя не было необходимости иметь на своем компьютере полностью настроенный компилятор.
В то же самое время все большую популярность стали завоевывать новые языки и экосистемы, в которых управление зависимостями было реализовано более-менее правильно с самого начала и которые имели лучшую поддержку распространения бинарных файлов. Эти решения выучили свой урок на ошибках Python и Perl.
И, наконец, Python Package Index. Сайт, хранящий и распространяющий все open source библиотеки, созданные сообществом Python. Не более чем proof-of-concept, который был запущен слишком рано, не имел никаких ресурсов для развития своей инфраструктуры и слишком часто становился оффлайн.
Все складывалось не лучшим образом для Python.
Интерлюдия
Вот мы и подошли к тому моменту, когда говорят, что “управление зависимостями в Python — #$@#@@!”. Большинство таких высказываний — устаревшая информация, описывающая этот период времени. Множество блогпостов с жалобами, высоко ранжируемые поисковыми системами по запросу “проблемы”. Те, кто использовал Python в это время и перешел на использование других языков, часто ворчат о том, как ужасно было управлять зависимостями, насколько сломана была экосистема и как часто лежал PyPI. Хуже всего, в сети есть множество советов по обходным путям решения проблем, которые уже давно не нужны, но все еще показываются поисковыми системами в топе выдачи. Следование таким советам ломает пользователям рабочее окружение и только усугубляет ситуацию.
Восставшие из пепла
И посредине этого великого полома ряд разработчиков героически, молча, медленно все чинили, по одному вгрызаясь в багрепорты. Стартовал проект ‘pip’, многочисленные мейнтейнеры которого убрали большую часть сложности, что принесла ‘easy_install’, и исправили многие ее недостатки. Donald Stufft взялся сразу за Pip и PyPI, исправив старые уязвимости и сделав систему более устойчивой. Daniel Holth написал PEP для формата ‘wheel’, который позволяет распространять бинарный код вместе с библиотеками. То есть, другими словами, позволяет пользователями без настроенного компилятора “C” устанавливать пакеты, которые в противном случае потребуют этот компилятор для сборки.
В 2013 году setuptools снова объединился со своим форком distribute, что позволило вендорам операционных систем обновить системы работы с зависимостями и дать пользователям современные инструменты. Модуль “ensurepip” был включен в Python Core дистрибьюцию для версий 2.7 и 3.3, что позволило пользователям с более-менее современной версией Python одной командой получить себе работающее окружение для работы с зависимостями.
Новый Ренессанс
Я не буду рассказывать про современные приемы работы с зависимостями. Этому посвящен отдельный вебсайт. Но я покажу, насколько это сейчас просто. Для любой современной версии Python, если вы хотите получить работающее окружение без админских прав, все что вам нужно это:
$ python -m ensurepip --user
$ python -m pip install --user --upgrade pip
$ python -m pip install --user --upgrade virtualenv
Для каждого проекта вы можете создать собственную «песочницу» virtualenv:
$ python -m virtualenv lets-go
$ . ./lets-go/bin/activate
(lets-go) $ _
Это все. Можно использовать pip, чтобы устанавливать любые зависимостями. Для установки большинства вам даже не потребуется компилятор! Более того, эти заклинания не зависят от версии Python: они будут работать с Python 2, Python 3, PyPy и даже Jython (примечание переводчика: сюрприз, да?).
На самом деле, часто вам даже не потребуется шаг с ‘ensurepip’, так как ‘pip’ будет уже установлен и настроен! Тем не менее, лучше выполнить это простое заклинание, вреда оно не нанесет.
Более продвинутые операции над зависимостями тоже упростились. Нужен компилятор «C»? Создатели операционных систем плотно работали с сообществом, чтобы сделать настройку компилятора максимально безболезненной:
$ apt install build-essential python-dev # ubuntu
$ xcode-select --install # macOS
$ dnf install @development-tools python-devel # fedora
C:\> REM windows
C:\> start https://www.microsoft.com/en-us/download/details.aspx?id=44266
Ладно-ладно, последний шаг не такой уж безболезненный. Но компилятор хотя бы есть, бесплатен и устанавливается простым скачиванием с сайта! Хотите загрузить что-нибудь на PyPI? Для большинства проектов это будет вот настолько просто:
$ pip install twine
$ python setup.py sdist bdist_wheel
$ twine upload dist/*
Хотите собрать бинарные пакеты wheels? И для этого есть приложение (docker container, разумеется).
Что важно, можно уверенно говорить о высоком онлайне PyPI. А еще у них со дня на день будет новый, полностью переделанный сайт (примечание переводчика: еще один сюрприз).
Я много занимаюсь Python разработкой, и могу сказать, что самая серьезная проблема, с которой я столкнулся за последний год, решилась удалением закешированных файлов. Я использую современный тулчейн каждый день, и он работает!
Работа, которая нам предстоит
Текущая ситуация уже неплоха. Но ее нельзя назвать «замечательной». Что бы я еще хотел от нашей экосистемы:
- Тулзы для установки на компьютеры конечных пользователей могут быть лучше.
- Pip не повредит графический пользовательский интерфейс, чтобы его можно было использовать без заклинаний командной строки (примечание переводчика: и тут Остапа понесло…)
- Нужны тулзы для автоматического создания и обновления “setup.py”. Ну или что-нибудь вроде “setup.python.json” или чего-нибудь подобного, чтобы не было необходимости писать код только ради пары строк метаданных.
- Сообщения об ошибках, когда не получается собрать что-то сишным компилятором, должны быть более понятны и содержать инструкции для пользователя.
- PyPI должен автоматически собирать «wheels» для всех платформ по факту загрузки sdists пакета. Да, это большая и амбициозная задача, но подумайте, насколько она упростит работу с зависимостями!
Я могу так долго продолжать. Есть множество способов улучшить работу с зависимостями в Python.
Послесловие
Что я хотел сказать этим лонгридом. Ситуация с зависимостями в Python далека от идеала, но уже нельзя говорить, что у других языков программирования все «намного лучше». Для Go продолжаются обсуждения разных вариантов управления зависимостей и ситуация с “CGo” далека от идеала. У Node собственные горячо обсуждаемые проблемы с культурой управления зависимостями и тулчейном. Hackage крут и все такое, но время сборки достигает поистине астрономических значений. Как обычно, у Rust с Cargo все почти идеально – но ведь никто из читающих эти строки не использует Rust?
Не хочу сказать, что работа с зависимостями в этих языках как-то особо плоха. На самом деле у них все очень неплохо, особенно если сравнивать это со средней температурой по больнице пару лет назад; наблюдается постоянный прогресс и видимые для конечного пользователя улучшения.
По моему мнению, любое утверждение о том, что в каком-то языке работа с зависимостями намного лучше чем в Python, скорее всего устарело. Сейчас зависимостями в Python уже можно пользоваться, и это не больно.. Конечно, может быть ещё лучше, но над улучшением работают множество программистов, и все основные барьеры, которые препятствовали дальнейшему развитию, они уже успешно убрали.
Пользуйтесь virtualenv! Хакните себе немного setup.py! Если последний раз вы работали с зависимостями в Python давно – попробуйте сейчас. Обещаю, все стало намного лучше.
Комментарии (71)
iroln
16.08.2016 15:18+1Нужны тулзы для автоматического создания и обновления “setup.py”. Ну или что-нибудь вроде “setup.python.json” или чего-нибудь подобного, чтобы не было необходимости писать код только ради пары строк метаданных.
На самом деле давно уже предлагают вообще избавиться от setup.py. Вот недавно даже PEP написали: https://www.python.org/dev/peps/pep-0518/
Лично моё мнение: wheel-пакеты — это лучшее, что случилось с инфраструктурой зависимостей Python за последнее время. Думаю, направление выбрано верное.
markhor
16.08.2016 15:30Черт, TOML… Ничему питонистов жизнь не учит. Когда CPython решали на какую систему контроля версий переезжать, тоже было несколько вариантов, все тщательно обсудили и выбрали… то что выбрали. И теперь закономерно огребли проблем и (ура! 2016 год на дворе) решили все-таки переехать на GitHub. Думаю, и здесь глядишь через год-другой формат поменяют на JSON/YAML когда окажется что никто его не использует.
P.S. я сам питонист.iroln
16.08.2016 15:46+2Они там приводят аргументы в защиту TOML, что он простой, гибкий и human-usable, что он используется в Cargo и т. д. JSON им кажется плохо читаемым, а YAML слишком сложным. Причем они не настаивают прямо вот на TOML (хотя и рекомендуют) и приводят примеры конфигураций также и на JSON/YAML. В любом случае, в Python из коробки сейчас есть только JSON.
nikolay_karelin
16.08.2016 15:53+11) Когда они переезжали (PEP датирован 2009 годом), Mercurial был гораздо проще для пользователей других систем контроля версий, чем Git, и GitHub (заработал в 2008-м) еще не был таким обязательным ;)
2) Wheel — это zip-архив, как и многие другие схожие форматы (ну, вспомним хотя бы jar). Метеданные внутри архива — это другое дело, там JSON/YAML был бы в тему, но скорее всего формата ключ: значение на очень многие задачи будет хватать.
nikolay_karelin
16.08.2016 15:23+2Небольшое упущение: Python 3.x и компиляция под Windows требует немного другого подхода. Детали здесь: https://wiki.python.org/moin/WindowsCompilers
Остальное — оч-ч-чень интересно, надо пробовать и разбираться в деталях.
sshikov
16.08.2016 18:55+1уже нельзя говорить, что у других языков программирования все «намного лучше»
Вот не обобщали бы на всех-то… это всегда выходит неправда.
eyeofhell
17.08.2016 07:36У кого сейчас намного лучше, если не секрет?
sshikov
17.08.2016 09:40+1Ну если по-простому — то почти у всех языков на платформе JVM намного лучше. Скажем, до groovy grapes Python еще далеко по удобству. Это вовсе не значит, что у Python все плохо — просто есть к чему стремиться. Я прекрасно понимаю, что если у вас зависимость это скажем native бинарники, а не portable код на Python — то этого не так просто добиться.
Скажем, вы можете написать:
!/usr/groovy/latest/bin/groovy
@Grapes([
@GrabConfig(systemClassLoader=true)
, Grab(group='net.sourceforge.jtds', module='jtds', version='1.3.1')
, Grab(group='org.postgresql', module='postgresql', version='9.3-1100-jdbc41')
, Grab(group='com.sybase', module='jconn3', version='6.05')
])
import groovy.sql.*
import net.sourceforge.jtds.jdbcx.*
т.е. динамически подключить зависимость (в данном случае — драйвер базы данных), и тут же ее импортировать и использовать.
Grab
17.08.2016 21:10+2Пришла оповещалка о том, что кто-то меня упомянул — значит опять про Grapes пишут :)
Mayflower
16.08.2016 21:25Как правило, создатели нового языка программирования уделяют этому не очень много внимания… Единственным на моей памяти исключением является node.js
Немного непонятно почему здесь авторы node.js приравнены к авторам языка Javascript. Или это одни и те же люди?
Fedcomp
16.08.2016 23:51> Как обычно, у Rust с Cargo все почти идеально
Кроме того что многие зависимости рассчитывают на nightly или по крайней мере unstable.
ozkriff
17.08.2016 10:56+1но ведь никто из читающих эти строки не использует Rust?
Ну уж нет, как минимум один гордый растафарианин (или как там договорились самоназываться?) читает это. Пускай и только в хобби-проекте использую)
vladshulkevich
17.08.2016 14:01+3Выполнял тестовое задание перед интервью, использовал numpy, получил отзыв:
«Минусы:
1. Поставить библиотеку для обработки статистики оказалось делом не тривиальным (пришлось покопаться в инете), в итоге нужно скачать отсюда пакет (numpy-1.11.1+mkl-cp27-cp27m-win32.whl) для установки numpy и выполнить команду «pip install numpy-1.11.1+mkl-cp27-cp27m-win32.whl» в папке где лежит пакет.
»
Понимаете, не тривиальное это дело, собранное колесо поставить. А вы говорите зависимости.Meklon
17.08.2016 15:20А почему нельзя стандартно что-то вроде apt-get install python3-numpy-dev?
iroln
17.08.2016 16:28Собрать numpy на Windows из исходников — нетривиальная задача. Поэтому есть неофициальные собранные пакеты с MKL. Без MKL есть официальные wheel-пакеты на PyPI, поэтому не понятно, что за сложности были у тех, кто давал тестовое задание. Возможно, это было давно, когда официальных wheel-пакетов ещё не было.
Сейчас, если не нужна производительность MKL, можно просто делать так:
pip install numpy
А почему нельзя стандартно что-то вроде apt-get install python3-numpy-dev?
В репах обычно старая версия
Meklon
17.08.2016 16:41Насчет старой версии согласен, но субъективно, далеко не всегда bleeding edge нужен. По крайней мере, я редко с таким сталкивался.
dimm_ddr
17.08.2016 23:45pip install numpy
На винде это легко выливается в танцы с поиском и установкой нужного компилятора. Особенно на 64 битной системе. Может быть вот прямо сейчас это изменилось в лучшую сторону, но еще этой весной все было очень плохо.iroln
17.08.2016 23:50Я выше пишу:
Собрать numpy на Windows из исходников — нетривиальная задача.
Сейчас на PyPI уже лежат официальные собранные wheel-пакеты под винду: https://pypi.python.org/pypi/numpy
Компилятор не нужен, там уже собранные бинарники в пакете.
Другое дело, что они собраны без MKL, а MKL сильно улучшает производительность вычислений над массивами.
vladkens
20.08.2016 12:11Куда лучше было бы реализовать pip по принципу npm или composer, где пакеты качаются в специальную директорию с кодом проекта, для питона, например, site-packages, а sys.path первым путем поиска записывать локальную директорию, чтобы нормально импорт работал.
Что касается virtualenv, как по мне это главная проблема в питоне. Virtualenv – софт с плохим дизайном, который даже не пытается решать проблемы предоставляя сложное решение с хаком консоли и копированием половины питона и при этом не позволяя выбирать в проекте версию интерпритатора. Чтобы использовать другой питон нужно ставить pyenv, который тоже имеет фатальный недостаток – отсутствие кроссплатформенности. Если бедный разработчик хочет чтобы его проект работал и под виндой тоже, есть и такие два пакета: pywin и anyenv. Ну и так дальше в глубь ада.
В общем количество альтернативных реализаций virtualenv показывает на проблемы инструмента, которые пока никто не решает.nikolay_karelin
21.08.2016 21:48Согласен: пытался пользоваться как virtualenv, так conda (из научного дистрибутива Anaconda) — больше проблем нежели чем решений.
Наверное, на сегодняшний день лучше все путями шаманить… Печаль.
Meklon
Спасибо. Хотел попросить консультации у опытных питонистов. Я пилю научный проект с довольно узким применением — ссылка на GitHub. Как правильнее завернуть это безобразие для облегчения использования? Плюс у меня еще и две опциональные библиотеки — seaborn и pandas. И как будет выглядеть процесс установки и запуска? Сейчас задумано клонирование репозитория и запуск из консоли с чем-то вроде
Direvius
Напишите setup.py для вашего проекта, там можно будет указать и зависимости, и точку входа (команда ляжет куда-то в /usr/bin), и многое другое. Как пример привожу собственный setup.py, документация тут.
После написания setup.py ваш проект можно будет загрузить на pypi.python.org и ставить оттуда вот так:
pip install (project name)
Или можно ставить прямо из мастер (или любой другой) ветки вашего репозитория:
pip install https://api.github.com/repos/meklon/DAB_analyzer/tarball/master
Meklon
О. Прекрасно. То есть по факту можно будет запускать как я написал выше, но не важно из какого локального каталога?
Direvius
Даже python3 не надо будет писать. Примерно так:
dab_deconv_area -p /home/meklon/Data/sample/test/ -t 35 -e 89 -s -a
Meklon
Полный восторг) спасибо. Пошел читать документацию.
Meklon
Кстати, хотел еще попросить бросить взгляд на документацию на гитхабе. Этого достаточно для пользователя?
Direvius
Я думаю вполне — я бы разобрался.
Meklon
Отлично, спасибо.
Meklon
Кстати, а что с Windows? Сейчас утилита вроде как кроссплатформенная и относительно всеядна в плане версий python. pip install тоже как-то реализуется? Я переживаю, потому, что основной пользователь — биолог-исследователь. Хочется проще.
iroln
Вы можете сделать standalone-сборку своей программы, например, с помощью cx_freeze.
Для Windows ещё есть неофициальные сборки wheel-пакетов: http://www.lfd.uci.edu/~gohlke/pythonlibs/
Meklon
Попробую, спасибо. GUI очень писать не хочется, надеюсь мануал к консоли будет достаточно понятен. Одного коллегу я консультировал, но он сам линуксоид.
iroln
По хорошему, проект должен иметь такую структуру:
То есть разработку проекта надо вести снизу-вверх. Сначала пишется библиотека, а потом над ней утилиты и приложения.
Meklon
Я очень старался писать аккуратно и следуя PEP 8, но с архитектурой, кажется, накосячил. Собственно, я до этого вообще софт не писал ибо врач. Надо думать. Мне явно потребуется расширять функциональность, но миллион ключей в консоли уже тяжело ложатся на принцип KISS. Хотя и позволяют запилить какой-нибудь скрипт на баше поверх.
synedra
Миллион ключей — не обязательно проблема. В биоинформатике многие уважаемые программы запускаются исключительно (или по крайней мере преимущественно) одной командой с горой ключей. Причина, я полагаю, в том, что если команда всего одна — то гораздо проще вставить программу в пайплайн, не заморачиваясь общением с её интерфейсом. Но при этом анализ должен очень точно настраиваться под нужды пользователя, так что команда получается гигантская.
Всем этим в консоли, конечно, пользуется скорее специально обученный биоинформатик, а не просто биолог без навыков программирования/линуксоводства. У меня один коллега вообще здорово удивился, увидев локальный BLAST. Но если вы в любом случае не собираетесь делать полноценный GUI — то тонна ключей лучше, чем что-то интерактивное на curses или, избави Господи, текстовое меню в консоли.
Meklon
Вы только что избавили меня от ошибки с меню консольным) принцип программы в выделении из среза, окрашенного несколькими красителями только одного. Например, DAB-хромогена из пары DAB+гематоксилин. И потом считает пакетно площадь надпорогового по интенсивности окрашивания. Я хочу ввести возможность выбирать свой вектор красителя, вместо захардкоженного. Если не делать меню, то это корректнее делать дополнительным файлом с NumPy массивами красителей? Как корректнее импортировать и выбирать?
В голову приходит вариант импорта по номеру вектора в файле. Что-то типа ключа --vector 3, где 3 это, например, массив с вектором эозина.
alsii
Ни в коей мере не считаю себя специалистом по Python, но рискну вставить свои 5 копеек. Мне кажется в Вашем случае разумно будет сделать файл с настройками. В первом приближении настройки — это просто список ключей с их значениями. В /etc/dab_deconf_area.conf можно положить настройки по умолчанию.
Чтобы не напрягать пользователя можно сделать ключ --save, который будет сохранять все настройки, с которыми запущена программа куда-нибудь в ~/dab_deconf_area/default.conf.
Можно еще сделать сохраниене настроек (пресетов?) под разными именами, например так: --save preset-name сохраняет в ~/dab_deconf_area/preset-name.conf. --preset preset-name загружает пресет и запускает обработку с данными пресета. Можно сделать так, что сохраненные в пресете значения будут иметь приоритет над тем, что в ~/dab_deconf_area/default.conf, а те над /etc/dab_deconf_area.conf. Ну и ключи указанные в командной строке имеют наивысший приоритет. Если вы сделаете ключ --dry-run, который прогонять программу «всухую», без реальной обработки, то пользователь сможет копировать пресеты с изменениями:
dab_deconf_area --dry-run --preset preset1 --ke1 new_value --save preset2 # Копируем preset1 в preset2, но меняем значение ключа key1.
Что-то я уже много написал, а у меня еще столько идей :) Пожалуй остановлюсь, а то меня реально понесло :)
Да, и никто не запрещает редактировать файлы настроек руками. А если сделать короткие варианты ключей: --preset = -p, --save = -s, то пользователи будут благодарны.
Meklon
Дефолтные значения в коде. Как наиболее распространенные и оптимальные. Там преимущественно надо пороги крутить, если снимки нетипичные по экспозиции/интенсивности окраски. Основная идея сделать более универсальный инструмент для оценки любого красителя. Сейчас хардкодом вбит вектор именно нашего лабораторного DAB-хромогена.
kinazarov
А может сделать понятнее, например с промежуточным словарем типа {eozyne: 3}
И тогда команда будет --vector «eozyne»
Meklon
Про словарь не думал, спасибо.
Meklon
Ме бы еще понять, как проще всего внешний конфиг парсить из программы. В идеале можно выводить в консоль список найденных векторов по ключу вроде --stain_list.
kinazarov
На выбор могу предложить несколько вариантов:
pickle
ConfigParser 1 2
или даже такой вариант как помесь кода и данных в виде обычного импортируемого модуля, который одновременно является файлом конфигурации.
А также использовать (например sqlite) для хранения очереди пакетов входных и обработанных данных для потоковой обработки результатов серии экспериментов.
Один относительно простой модуль (возможно с ncurses-подобной менюхой) регистрирует данные в БД для обработки ядром, которое их по очереди берет из БД и туда же отдает данные после обработки.
Таким образом можно будет заранее исключить необходимость создания пакетных файлов для выполнения одной и той же программы но для разных каталогов с исходными данными и разными ключами для каждого каталога.
Meklon
То, что надо, спасибо. Какие-то особые грабли ожидаются, с учетом того, что мои вектора для крастелей это NumPy массивы?
Хранение напрямую в виде человекочитаемых переменных сразу Python выглядит весьма разумно. Хотя несколько неожиданно)
iroln
numpy-массивы можно писать в файлы и читать из файлов. Вот документация: http://docs.scipy.org/doc/numpy/reference/routines.io.html
Вдруг пригодится.
Meklon
Спасибо.
Direvius
Я бы посоветовал не делать эти массивы бинарными, а сделать человекочитаемыми, например CSV, JSON или YAML. Они у вас небольшие и на производительности это не скажется. При этом с точки зрения программирования — файлы в этих форматах вы прочитаете одной строкой на питоне.
Direvius
Чтобы подкрепить слова делом, прислал PR =)
kinazarov
Для такого способа вот подсказка: создаешь в каталоге с программой еще один каталог (например «configs»). В нем пустой файл с именем __init__.py и нужное количество модулей, которые одновременно являются конфигами. А потом можно удобно использовать синтаксис импорта пакетов примерно так:
import configs.parameter_set_bender_experiment_keelallhumans
пример
Meklon
О. прекрасно. То есть после импорта у меня в Global Scope подтянутся переменные, которые были объявлены как константы в configs.parameter_set_bender_experiment_keelallhumans?
kinazarov
Не в глобал. Они будут доступны как
Для импорта в глобал чуть-чуть иначе:
Meklon
Ага. А <parameter_name> может быть переменной, полученной из args.parser? По идее аргументом из консоли выбирают вектор.
Meklon
Кажется понял. Не распихивать векторы по отдельным переменным, а сделать один словарь stain_vectors, откуда уже дергать по индексу, полученному при парсинге аргументов командной строки. И индексы словаря можно будет выбрасывать спокойно в --help где-то. Огромное спасибо) тяжело без опыта разработки. Стараешься без лапши запутанной писать, но по мере разрастания проекта все начинает дико усложняется. Особенно ужасает непрерывно меняющееся техническое задание.
kinazarov
Вот поэтому ядро с набором функций которые собственно числа перемалывают надо хранить в одном наборе модулей а все параметры/данные — в других наборах модулей.
И вот тебе еще пара мыслишек:
1. Сперва в глобал грузишь
а потом специфичный конфиг для нужного набора данных
2. Для уже загруженного барахла можно дополнительно менять один-два параметра, которые ты передашь из командной строки так же как ты и раньше делал. Или даже вот такой финт ушами
Meklon
Короче, пошел рисовать архитектуру)
Direvius
если вы сделаете конфиги в виде питонячих файлов, пользователям будет сложно модифицировать ваши конфиги — они встанут вместе с вашей библиотекой глубоко в систему. Я считаю, что лучше сделать в человекочитаемом общепринятом формате: JSON, YAML, TOML, INI. Все они парсятся одной строкой на питоне, после подключения соответствующих библиотек.
Meklon
Да, я уже почитал документацию. Раздражают различия Windows/Linux. Проще Windows сделать вторичным.
Meklon
Мне еще нужно, чтобы конфиг легко читался и редактировался руками.
cadmi
> основной пользователь — биолог-исследователь
Python всё еще торт :) В 1997 на третьем курсе физфака я, писавший до того на Perl, был вынужден познакомиться с Python, потому что на нём была написана реализация формата хранения результатов экспериментов в кристаллографии :) Уже тогда он в хвост и гриву использовался научным сообществом. В отличие от personal home pages, только-только начавших стесняться своего названия и ставших акронимом. И лексического анализатора, созданного для тех, кому стало мало awk и sed :)
А ведь еще даже не было SciPy :)
Meklon
Python прекрасен. Я, блин, врач по образованию. Но понятно же. На редкость удобный язык. Да, небыстрый. Но подпилив кое-где, используя NumPy и прочие быстрые библиотеки, все отлично работает. Все равно я ему данные не смогу лопатой подбрасывать с такой скоростью, с какой он считает. Я еще заморочился с multiprocessing, доволен как слон. Особенно дома в 4 потока бодро молотит. Но даже на рабочем Celeron у меня один сэмпл-фотография обрабатывается в среднем за 800 мс.
Taragolis
Могу посоветовать совет собрать virtualenv со всеми зависимостями, потом уже в ней
pip freeze > all_requirements.txt
Руками вычистить опциональный пакеты и обозвать requirements.txt
Залить в репу и дальше уже тем кто ставит надо будет выполнить:
pip install -r requirements.txt
или
pip install -r all_requirements.txt
Meklon
Как вариант. На Ubuntu и деривативах зависимости через apt-get заливаются. У меня вполне типовые библиотеки.
Taragolis
То что я предложил больше подходит для venv, ну и когда нужна версия библиотеки отличная от той, что есть в репозитории дистрибутива.
Сам придерживаюсь такого правила:
Глобально — apt
Virtualenv — pip
Meklon
Видимо, был не прав. Я pip через did запускаю.
ilgarm
Можете также взглянуть на PyBuilder — попытка сделать maven-like систему сборки для Python-a. Может быть пригодится…
Meklon
Посмотрю, спасибо.