Skip to content

Instantly share code, notes, and snippets.

@code-of-kpp
Last active September 17, 2015 09:32
Show Gist options
  • Save code-of-kpp/43168d081dc969c40c63 to your computer and use it in GitHub Desktop.
Save code-of-kpp/43168d081dc969c40c63 to your computer and use it in GitHub Desktop.
PyCon Russia 2015 talk on setup.py
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"<style>\n",
".cm-s-ipython span.cm-keyword { color: #2306FF;}\n",
".cm-s-ipython span.cm-string { color: #0B7208;}\n",
".cm-s-ipython span.cm-comment {color: #4F6ACA;}\n",
".cm-s-ipython span.cm-operator {color: #FF22CD;}\n",
".cm-s-ipython span.cm-builtin {color: #1600BE;}\n",
".cm-s-ipython span.cm-def {color: #632B97;}\n",
".cm-s-ipython span.cm-quote {color: #93248A;}\n",
".cm-s-ipython span.cm-attribute {color: #FF0083;}\n",
"\n",
".rendered_html code { color: #64006C;}\n",
"div.input_prompt { color: #C0C0E9;}\n",
"div.output_prompt { color: #F7BCBC;}\n",
"div.output_stderr { background: #FDEBEB;}\n",
"\n",
"</style>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%%html\n",
"\n",
"<style>\n",
".cm-s-ipython span.cm-keyword { color: #2306FF;}\n",
".cm-s-ipython span.cm-string { color: #0B7208;}\n",
".cm-s-ipython span.cm-comment {color: #4F6ACA;}\n",
".cm-s-ipython span.cm-operator {color: #FF22CD;}\n",
".cm-s-ipython span.cm-builtin {color: #1600BE;}\n",
".cm-s-ipython span.cm-def {color: #632B97;}\n",
".cm-s-ipython span.cm-quote {color: #93248A;}\n",
".cm-s-ipython span.cm-attribute {color: #FF0083;}\n",
"\n",
".rendered_html code { color: #64006C;}\n",
"div.input_prompt { color: #C0C0E9;}\n",
"div.output_prompt { color: #F7BCBC;}\n",
"div.output_stderr { background: #FDEBEB;}\n",
"\n",
"</style>"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"import sys\n",
"\n",
"sys.argv = ['setup.py', '--description']"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Don't forget setup.py\n"
]
},
{
"data": {
"text/plain": [
"<setuptools.dist.Distribution at 0x7fd9b80e8048>"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from setuptools import setup\n",
"\n",
"setup(\n",
" name=\"setup-py-pycon-ru-2015\",\n",
"\n",
" description=\"Don't forget setup.py\",\n",
"\n",
" author='Konstantin Ignatov', # hello\n",
" author_email='[email protected]', \n",
"\n",
" version=\"2015.9.18\",\n",
"\n",
" packages = ['talk'],\n",
"\n",
" classifiers=[\n",
" 'Intended Audience :: Developers',\n",
" 'Topic :: Software Development :: Build Tools',\n",
"\n",
" 'Programming Language :: Python :: 2',\n",
" 'Programming Language :: Python :: 3',\n",
" ],\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"3:00"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# История\n",
"\n",
"* `distutils`: в стандартной библиотеке с Python 1.6\n",
"* `setuptools`\n",
"* `|-- distribute` (fork)\n",
"* `setuptools-7.0` (merge)\n",
"* Python Packaging Authority: [pypa.io](http://www.pypa.io)\n",
"<div style=\"overflow: hidden;\"><img style=\"margin: -140px 0px 0px 0px;\" src=\"https://pythonhosted.org/Distutils2/giphy.gif\" /></div>\n",
"* Standard?"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"https://www.pypa.io/en/latest/history/"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"/home/kpp/build/pyconru-setup-py/simple\n"
]
}
],
"source": [
"import sys\n",
"\n",
"sys.argv = ['setup.py', '--name']\n",
"\n",
"%mkdir -p simple\n",
"%cd simple"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"5:00"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Аперитив: микропроекты"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting foo.py\n"
]
}
],
"source": [
"%%file foo.py\n",
"\n",
"def foo():\n",
" print(\"I'm in your system now\")"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting setup.py\n"
]
}
],
"source": [
"%%file setup.py\n",
"\n",
"from distutils.core import setup\n",
"\n",
"setup(\n",
" name='foo',\n",
" version='1.0',\n",
" py_modules=['foo'], # foo.py is the original gist\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"foo.py setup.py\r\n"
]
}
],
"source": [
"ls *py"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"7:00"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## В принципе, можно и без `setup.py`..."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false,
"scrolled": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Processing foo.py\n",
"Writing /tmp/easy_install-x4elgo01/setup.cfg\n",
"Running setup.py -q bdist_egg --dist-dir /tmp/easy_install-x4elgo01/egg-dist-tmp-_wlf3tzo\n",
"Moving foo-1.0.dev0-py3.4.egg to /home/kpp/build/pyconru-setup-py/venv/lib/python3.4/site-packages\n",
"Adding foo 1.0.dev0 to easy-install.pth file\n",
"\n",
"Installed /home/kpp/build/pyconru-setup-py/venv/lib/python3.4/site-packages/foo-1.0.dev0-py3.4.egg\n",
"Processing dependencies for foo==1.0.dev0\n",
"Finished processing dependencies for foo==1.0.dev0\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"zip_safe flag not set; analyzing archive contents...\n"
]
}
],
"source": [
"%%bash\n",
"easy_install \"file://$(pwd)/foo.py#egg=foo-1.0dev\""
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": false,
"scrolled": true,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"I'm in your system now\n"
]
}
],
"source": [
"%%bash\n",
"cd .. # we don't want foo.py in our pwd\n",
"python -c \"import foo; foo.foo()\""
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"**Но...**"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": false,
"scrolled": true,
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Uninstalling foo-1.0.dev0:\n",
" Successfully uninstalled foo-1.0.dev0\n",
"Traceback (most recent call last):\n",
" File \"/home/kpp/build/pyconru-setup-py/venv/bin/pip\", line 11, in <module>\n",
" sys.exit(main())\n",
" File \"/home/kpp/build/pyconru-setup-py/venv/lib/python3.4/site-packages/pip/__init__.py\", line 217, in main\n",
" return command.main(cmd_args)\n",
" File \"/home/kpp/build/pyconru-setup-py/venv/lib/python3.4/site-packages/pip/basecommand.py\", line 248, in main\n",
" pip_version_check(session)\n",
" File \"/home/kpp/build/pyconru-setup-py/venv/lib/python3.4/site-packages/pip/utils/outdated.py\", line 102, in pip_version_check\n",
" installed_version = get_installed_version(\"pip\")\n",
" File \"/home/kpp/build/pyconru-setup-py/venv/lib/python3.4/site-packages/pip/utils/__init__.py\", line 858, in get_installed_version\n",
" working_set = pkg_resources.WorkingSet()\n",
" File \"/home/kpp/build/pyconru-setup-py/venv/lib/python3.4/site-packages/pip/_vendor/pkg_resources/__init__.py\", line 629, in __init__\n",
" self.add_entry(entry)\n",
" File \"/home/kpp/build/pyconru-setup-py/venv/lib/python3.4/site-packages/pip/_vendor/pkg_resources/__init__.py\", line 685, in add_entry\n",
" for dist in find_distributions(entry, True):\n",
" File \"/home/kpp/build/pyconru-setup-py/venv/lib/python3.4/site-packages/pip/_vendor/pkg_resources/__init__.py\", line 2075, in find_eggs_in_zip\n",
" if metadata.has_metadata('PKG-INFO'):\n",
" File \"/home/kpp/build/pyconru-setup-py/venv/lib/python3.4/site-packages/pip/_vendor/pkg_resources/__init__.py\", line 1605, in has_metadata\n",
" return self.egg_info and self._has(self._fn(self.egg_info, name))\n",
" File \"/home/kpp/build/pyconru-setup-py/venv/lib/python3.4/site-packages/pip/_vendor/pkg_resources/__init__.py\", line 1963, in _has\n",
" return zip_path in self.zipinfo or zip_path in self._index()\n",
" File \"/home/kpp/build/pyconru-setup-py/venv/lib/python3.4/site-packages/pip/_vendor/pkg_resources/__init__.py\", line 1843, in zipinfo\n",
" return self._zip_manifests.load(self.loader.archive)\n",
" File \"/home/kpp/build/pyconru-setup-py/venv/lib/python3.4/site-packages/pip/_vendor/pkg_resources/__init__.py\", line 1783, in load\n",
" mtime = os.stat(path).st_mtime\n",
"FileNotFoundError: [Errno 2] No such file or directory: '/home/kpp/build/pyconru-setup-py/venv/lib/python3.4/site-packages/foo-1.0.dev0-py3.4.egg'\n"
]
}
],
"source": [
"!pip uninstall -y foo"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"I'm in your system now\n"
]
}
],
"source": [
"%%bash\n",
"cd .. # go outside working directory\n",
"python -c \"import foo; foo.foo()\""
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"8:00"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Терминология\n",
"\n",
"* module / модуль\n",
" * pure Python module / чистый модуль\n",
" * extension module / модуль расширения\n",
" * package / пакет\n",
"* root package / корневой пакет:"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"['',\n",
" '/home/kpp/build/pyconru-setup-py/venv/lib/python3.4',\n",
" '/home/kpp/build/pyconru-setup-py/venv/lib/python3.4/plat-x86_64-linux-gnu',\n",
" '/home/kpp/build/pyconru-setup-py/venv/lib/python3.4/lib-dynload',\n",
" '/usr/lib/python3.4',\n",
" '/usr/lib/python3.4/plat-x86_64-linux-gnu',\n",
" '/home/kpp/build/pyconru-setup-py/venv/lib/python3.4/site-packages',\n",
" '/home/kpp/build/pyconru-setup-py/venv/lib/python3.4/site-packages/IPython/extensions',\n",
" '/home/kpp/.ipython']"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import sys\n",
"sys.path # this is a \"working set\""
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"# Терминология\n",
"* \"пакет\" с `__init__.py` и \"module distribution\"\n",
"\n",
"* distribution root: место, где лежит `setup.py`\n",
"\n",
"* source distribution\n",
"\n",
"* binary distribution"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"10:00"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Пакеты"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"/home/kpp/build/pyconru-setup-py/packs\n"
]
}
],
"source": [
"%mkdir -p ../packs\n",
"%cd ../packs"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": true,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"%%bash\n",
"rm -rf foo.egg-info temp build dist MANIFEST setup.cfg .git *.pyc */*.pyc\n",
"\n",
"mkdir -p {one,two,three}\n",
"touch {one,two,three}/__init__.py\n",
"\n",
"mkdir -p one/four\n",
"touch one/four/__init__.py\n",
"touch one/four/data.csv\n",
"\n",
"cp -f ../simple/foo.py one/four/foo.py"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Initialized empty Git repository in /home/kpp/build/pyconru-setup-py/packs/.git/\n",
"[master (root-commit) e5835e7] initial\n",
" 8 files changed, 11 insertions(+)\n",
" create mode 100644 README.txt\n",
" create mode 100644 one/__init__.py\n",
" create mode 100644 one/four/__init__.py\n",
" create mode 100644 one/four/data.csv\n",
" create mode 100644 one/four/foo.py\n",
" create mode 100644 setup.py\n",
" create mode 100644 three/__init__.py\n",
" create mode 100644 two/__init__.py\n"
]
}
],
"source": [
"%%bash\n",
"touch setup.py\n",
"touch README.txt\n",
"\n",
"git init\n",
"git add *\n",
"git commit -m \"initial\""
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"collapsed": false,
"scrolled": true,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[01;34m.\u001b[00m\n",
"├── \u001b[01;34mthree\u001b[00m\n",
"│   └── __init__.py\n",
"├── \u001b[01;34mtwo\u001b[00m\n",
"│   └── __init__.py\n",
"├── \u001b[01;34mone\u001b[00m\n",
"│   ├── \u001b[01;34mfour\u001b[00m\n",
"│   │   ├── data.csv\n",
"│   │   ├── foo.py\n",
"│   │   └── __init__.py\n",
"│   └── __init__.py\n",
"├── README.txt\n",
"└── setup.py\n"
]
}
],
"source": [
"%%bash\n",
"tree --sort=ctime -I \"*.pyc\" --noreport -C"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"collapsed": true,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"import sys\n",
"sys.argv = [\"setup.py\", \"sdist\"]"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting setup.py\n"
]
}
],
"source": [
"%%file setup.py\n",
"from distutils.core import setup\n",
"\n",
"setup(\n",
" name=\"foo\", version=\"1.0\",\n",
" packages=['one', 'two', 'three', 'one.four'],\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"running sdist\r\n",
"running check\r\n",
"warning: check: missing required meta-data: url\r\n",
"\r\n",
"warning: check: missing meta-data: either (author and author_email) or (maintainer and maintainer_email) must be supplied\r\n",
"\r\n",
"warning: sdist: manifest template 'MANIFEST.in' does not exist (using default file list)\r\n",
"\r\n",
"writing manifest file 'MANIFEST'\r\n",
"creating foo-1.0\r\n",
"creating foo-1.0/one\r\n",
"creating foo-1.0/one/four\r\n",
"creating foo-1.0/three\r\n",
"creating foo-1.0/two\r\n",
"making hard links in foo-1.0...\r\n",
"hard linking README.txt -> foo-1.0\r\n",
"hard linking setup.py -> foo-1.0\r\n",
"hard linking one/__init__.py -> foo-1.0/one\r\n",
"hard linking one/four/__init__.py -> foo-1.0/one/four\r\n",
"hard linking one/four/foo.py -> foo-1.0/one/four\r\n",
"hard linking three/__init__.py -> foo-1.0/three\r\n",
"hard linking two/__init__.py -> foo-1.0/two\r\n",
"creating dist\r\n",
"Creating tar archive\r\n",
"removing 'foo-1.0' (and everything under it)\r\n"
]
}
],
"source": [
"!python setup.py sdist"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"`Distutils` генерирует `MANIFEST`\n",
"со списком всех файлов пакета:"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"# file GENERATED by distutils, do NOT edit\r\n",
"README.txt\r\n",
"setup.py\r\n",
"one/__init__.py\r\n",
"one/four/__init__.py\r\n",
"one/four/foo.py\r\n",
"three/__init__.py\r\n",
"two/__init__.py\r\n"
]
}
],
"source": [
"%cat MANIFEST"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"11:00"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting setup.py\n"
]
}
],
"source": [
"%%file setup.py\n",
"from setuptools import setup, find_packages\n",
"\n",
"setup(\n",
" name=\"foo\",\n",
" version=\"1.0\",\n",
" packages=find_packages(),\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"rm: cannot remove ‘*/*/*.pyc’: No such file or directory\r\n"
]
}
],
"source": [
"!rm */*/*.pyc"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"running sdist\n",
"running egg_info\n",
"creating foo.egg-info\n",
"writing dependency_links to foo.egg-info/dependency_links.txt\n",
"writing top-level names to foo.egg-info/top_level.txt\n",
"writing foo.egg-info/PKG-INFO\n",
"writing manifest file 'foo.egg-info/SOURCES.txt'\n",
"writing manifest file 'foo.egg-info/SOURCES.txt'\n",
"running check\n",
"warning: check: missing required meta-data: url\n",
"\n",
"warning: check: missing meta-data: either (author and author_email) or (maintainer and maintainer_email) must be supplied\n",
"\n",
"creating foo-1.0\n",
"creating foo-1.0/foo.egg-info\n",
"creating foo-1.0/one\n",
"creating foo-1.0/one/four\n",
"creating foo-1.0/three\n",
"creating foo-1.0/two\n",
"making hard links in foo-1.0...\n",
"hard linking README.txt -> foo-1.0\n",
"hard linking setup.py -> foo-1.0\n",
"hard linking foo.egg-info/PKG-INFO -> foo-1.0/foo.egg-info\n",
"hard linking foo.egg-info/SOURCES.txt -> foo-1.0/foo.egg-info\n",
"hard linking foo.egg-info/dependency_links.txt -> foo-1.0/foo.egg-info\n",
"hard linking foo.egg-info/top_level.txt -> foo-1.0/foo.egg-info\n",
"hard linking one/__init__.py -> foo-1.0/one\n",
"hard linking one/four/__init__.py -> foo-1.0/one/four\n",
"hard linking one/four/data.csv -> foo-1.0/one/four\n",
"hard linking one/four/foo.py -> foo-1.0/one/four\n",
"hard linking three/__init__.py -> foo-1.0/three\n",
"hard linking two/__init__.py -> foo-1.0/two\n",
"Writing foo-1.0/setup.cfg\n",
"Creating tar archive\n",
"removing 'foo-1.0' (and everything under it)\n"
]
}
],
"source": [
"!python setup.py sdist"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"`Setuptools` генерирует manifest в другом месте:"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"README.txt\r\n",
"setup.py\r\n",
"foo.egg-info/PKG-INFO\r\n",
"foo.egg-info/SOURCES.txt\r\n",
"foo.egg-info/dependency_links.txt\r\n",
"foo.egg-info/top_level.txt\r\n",
"one/__init__.py\r\n",
"one/four/__init__.py\r\n",
"one/four/data.csv\r\n",
"one/four/foo.py\r\n",
"three/__init__.py\r\n",
"two/__init__.py"
]
}
],
"source": [
"%cat foo.egg-info/SOURCES.txt"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"12:00"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## Добавляем файлы данных \n",
"\n",
"Иногда программе нужны дополнительные файлы.\n",
"\n",
"В нашем примере: `one/four/data.csv` содержит константы.\n",
"\n",
"Параметры `setup.py`:\n",
"* `package_data` (из `distutils`):\n",
"```python\n",
"setup(...,\n",
" package_data={'one.four': ['*.csv']},\n",
" # package_name => list of globs\n",
" # \"\" for all packages\n",
")\n",
"```\n",
"* `include_package_data`\n",
"* `exclude_package_data`"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"Практически универсальный `setup.py`:"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting setup.py\n"
]
}
],
"source": [
"%%file setup.py\n",
"from setuptools import setup, find_packages\n",
"\n",
"setup(\n",
" name=\"foo\",\n",
" version=\"1.0\",\n",
" packages=find_packages(),\n",
" include_package_data=True,\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"Чтобы это сработало, файлы данных должны быть в VCS.\n",
"\n",
"По умолчанию `setuptools` поддерживает только SVN и CVS\n",
"\n",
"```\n",
"pip install setuptools-git\n",
"pip install setuptools-bzr\n",
"pip install setuptools-hg\n",
"...\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {
"collapsed": true,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"rm -rf foo.egg-info/"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {
"collapsed": false,
"scrolled": true,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Processing /home/kpp/build/pyconru-setup-py/packs\n",
"Installing collected packages: foo\n",
" Found existing installation: foo 1.0\n",
" Uninstalling foo-1.0:\n",
" Successfully uninstalled foo-1.0\n",
" Running setup.py install for foo\n",
"Successfully installed foo-1.0\n"
]
}
],
"source": [
"!pip install . -U"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"14:00"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"### Как использовать эти данные\n",
"\n",
"```python\n",
"os.path.join(__file__, ...)\n",
"```\n",
"будет работать не всегда"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {
"collapsed": false,
"scrolled": true,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(Requirement.parse('foo'),\n",
" {'_Requirement__hash': 393189115900593882,\n",
" 'extras': (),\n",
" 'hashCmp': ('foo', <SpecifierSet('')>, frozenset()),\n",
" 'key': 'foo',\n",
" 'project_name': 'foo',\n",
" 'specifier': <SpecifierSet('')>,\n",
" 'specs': [],\n",
" 'unsafe_name': 'foo'})"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from pkg_resources import Requirement, resource_stream, resource_filename\n",
"\n",
"req = Requirement.parse('foo') # any distrubution name\n",
"\n",
"req, req.__dict__"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"<_io.BufferedReader name='/home/kpp/build/pyconru-setup-py/venv/lib/python3.4/site-packages/one/four/data.csv'>"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"resource_stream(req, 'one/four/data.csv')"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"/home/kpp/build/pyconru-setup-py/c_exts\n"
]
}
],
"source": [
"%mkdir -p ../c_exts\n",
"%cd ../c_exts\n",
"!touch setup.py\n",
"!touch README"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"16:00"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Модули расширения"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {
"collapsed": true,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"import sys\n",
"\n",
"# workaround for IPython bug\n",
"sys.stderr.errors = None\n",
"sys.stdout.errors = None"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"running sdist\n",
"running egg_info\n",
"writing dependency_links to foo.egg-info/dependency_links.txt\n",
"writing top-level names to foo.egg-info/top_level.txt\n",
"writing foo.egg-info/PKG-INFO\n",
"reading manifest file 'foo.egg-info/SOURCES.txt'\n",
"writing manifest file 'foo.egg-info/SOURCES.txt'\n",
"running check\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"warning: check: missing required meta-data: url\n",
"\n",
"warning: check: missing meta-data: either (author and author_email) or (maintainer and maintainer_email) must be supplied\n",
"\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"creating foo-1.0\n",
"creating foo-1.0/foo.egg-info\n",
"making hard links in foo-1.0...\n",
"hard linking README -> foo-1.0\n",
"hard linking setup.py -> foo-1.0\n",
"hard linking foo.egg-info/PKG-INFO -> foo-1.0/foo.egg-info\n",
"hard linking foo.egg-info/SOURCES.txt -> foo-1.0/foo.egg-info\n",
"hard linking foo.egg-info/dependency_links.txt -> foo-1.0/foo.egg-info\n",
"hard linking foo.egg-info/top_level.txt -> foo-1.0/foo.egg-info\n",
"Writing foo-1.0/setup.cfg\n",
"Creating tar archive\n",
"removing 'foo-1.0' (and everything under it)\n"
]
},
{
"data": {
"text/plain": [
"<setuptools.dist.Distribution at 0x7fd9aa6612b0>"
]
},
"execution_count": 32,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from distutils.core import setup, Extension\n",
"\n",
"setup(\n",
" name='foo',\n",
" version='1.0',\n",
" ext_modules=[Extension('foo', ['foo.c'])],\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"+см. документацию к Cython, cffi, numpy (как найти флаги компилятора) и др."
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {
"collapsed": false,
"scrolled": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Help on class Extension in module distutils.extension:\n",
"\n",
"class Extension(builtins.object)\n",
" | Just a collection of attributes that describes an extension\n",
" | module and everything needed to build it (hopefully in a portable\n",
" | way, but there are hooks that let you be as unportable as you need).\n",
" | \n",
" | Instance attributes:\n",
" | name : string\n",
" | the full name of the extension, including any packages -- ie.\n",
" | *not* a filename or pathname, but Python dotted name\n",
" | sources : [string]\n",
" | list of source filenames, relative to the distribution root\n",
" | (where the setup script lives), in Unix form (slash-separated)\n",
" | for portability. Source files may be C, C++, SWIG (.i),\n",
" | platform-specific resource files, or whatever else is recognized\n",
" | by the \"build_ext\" command as source for a Python extension.\n",
" | include_dirs : [string]\n",
" | list of directories to search for C/C++ header files (in Unix\n",
" | form for portability)\n",
" | define_macros : [(name : string, value : string|None)]\n",
" | list of macros to define; each macro is defined using a 2-tuple,\n",
" | where 'value' is either the string to define it to or None to\n",
" | define it without a particular value (equivalent of \"#define\n",
" | FOO\" in source or -DFOO on Unix C compiler command line)\n",
" | undef_macros : [string]\n",
" | list of macros to undefine explicitly\n",
" | library_dirs : [string]\n",
" | list of directories to search for C/C++ libraries at link time\n",
" | libraries : [string]\n",
" | list of library names (not filenames or paths) to link against\n",
" | runtime_library_dirs : [string]\n",
" | list of directories to search for C/C++ libraries at run time\n",
" | (for shared extensions, this is when the extension is loaded)\n",
" | extra_objects : [string]\n",
" | list of extra files to link with (eg. object files not implied\n",
" | by 'sources', static library that must be explicitly specified,\n",
" | binary resource files, etc.)\n",
" | extra_compile_args : [string]\n",
" | any extra platform- and compiler-specific information to use\n",
" | when compiling the source files in 'sources'. For platforms and\n",
" | compilers where \"command line\" makes sense, this is typically a\n",
" | list of command-line arguments, but for other platforms it could\n",
" | be anything.\n",
" | extra_link_args : [string]\n",
" | any extra platform- and compiler-specific information to use\n",
" | when linking object files together to create the extension (or\n",
" | to create a new static Python interpreter). Similar\n",
" | interpretation as for 'extra_compile_args'.\n",
" | export_symbols : [string]\n",
" | list of symbols to be exported from a shared extension. Not\n",
" | used on all platforms, and not generally necessary for Python\n",
" | extensions, which typically export exactly one symbol: \"init\" +\n",
" | extension_name.\n",
" | swig_opts : [string]\n",
" | any extra options to pass to SWIG if a source file has the .i\n",
" | extension.\n",
" | depends : [string]\n",
" | list of files that the extension depends on\n",
" | language : string\n",
" | extension language (i.e. \"c\", \"c++\", \"objc\"). Will be detected\n",
" | from the source extensions if not provided.\n",
" | optional : boolean\n",
" | specifies that a build failure in the extension should not abort the\n",
" | build process, but simply not install the failing extension.\n",
" | \n",
" | Methods defined here:\n",
" | \n",
" | __init__(self, name, sources, include_dirs=None, define_macros=None, undef_macros=None, library_dirs=None, libraries=None, runtime_library_dirs=None, extra_objects=None, extra_compile_args=None, extra_link_args=None, export_symbols=None, swig_opts=None, depends=None, language=None, optional=None, **kw)\n",
" | # When adding arguments to this constructor, be sure to update\n",
" | # setup_keywords in core.py.\n",
" | \n",
" | ----------------------------------------------------------------------\n",
" | Data descriptors defined here:\n",
" | \n",
" | __dict__\n",
" | dictionary for instance variables (if defined)\n",
" | \n",
" | __weakref__\n",
" | list of weak references to the object (if defined)\n",
"\n"
]
}
],
"source": [
"%%python3\n",
"import distutils.core\n",
"help(distutils.core.Extension)"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true,
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## Бывает сложнее...\n",
"\n",
"* `autotools`, `autoconf`, `CMake`...\n",
"* мир (пока) не крутится вокург Python\n",
"* попробуйте отделить начинку от bindings\n",
"* обычно нужно генерировать `setup.py`\n",
"* параметр `eager_resources` в `setup()`, если расширениям нужны файлы данных"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"18:00"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true,
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Взаимодействие с дргуими пакетами-дистрибутивами\n",
"\n",
"* require / зависимость\n",
" * `install_requires`\n",
" * `setup_requires`\n",
" * `tests_require`\n",
" * `extras_require`\n",
"* через `pkg_resources`\n",
" * через `entry_points`\n",
"\n",
"* obsolete\n",
"* provides"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"/home/kpp/build/pyconru-setup-py/deps\n"
]
}
],
"source": [
"%mkdir -p ../deps\n",
"%cd ../deps\n",
"%cp ../simple/foo.py ."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"20:00"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"### О версиях\n",
"\n",
"`pip` и `setuptools` используют PEP 440, реализованый в пакете `packaging`.\n",
"```json\n",
"Final:\n",
" 0.1.1, 9.0.3, 2015.09, ...\n",
"Pre:\n",
" 1.2_a3, 2015.09_beta, 1.2rc2, ...\n",
"Post:\n",
" 1.1-post1, 2015-rev2, 0.1.r5, 10-2, ...\n",
"Dev:\n",
" 9.6-dev0, 11.15.post7.dev, ...\n",
"Epoch:\n",
" 1!0.1, 2!8.4.4, ...\n",
"Local:\n",
" 1.0+abc.5, 1.0+ubuntu-1, 2015-r7+5, ...\n",
"\n",
"9.01.0-1 == 9.1-r1 == 0!9.1.post1\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"<Version('9.1.0.post1')>"
]
},
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import pkg_resources\n",
"\n",
"v1 = pkg_resources.parse_version('9.01.0-1')\n",
"v1"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"<Version('9.1.post1')>"
]
},
"execution_count": 36,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v2 = pkg_resources.parse_version('9.1-r1')\n",
"v2"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"<Version('9.1.post1')>"
]
},
"execution_count": 37,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v3 = pkg_resources.parse_version('0!9.1.post1')\n",
"v3"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v1 == v2 == v3"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"22:00"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"### Спецификация версий в зависимостях\n",
"\n",
"```\n",
"~= == != <= >= < > ===\n",
"```\n",
"\n",
"Специальные символы:\n",
"\n",
"\n",
"```\n",
" , *\n",
"```\n",
"\n",
"Примеры:\n",
"\n",
"```\n",
" packagename == 3.1.* packagename~=3.1.0\n",
" HelloWorld ~=3.1.0, != 3.1.3\n",
"```\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"#### Не ломайте мне систему слишком жёсткими зависимостями!!!!!!!!!!!!!!!!!!!!!!!!!!!1111111111111\n",
"* Адекватно оценивайте важность своего пакета"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"<Specifier('==3.1.*')>"
]
},
"execution_count": 39,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from packaging import specifiers\n",
"\n",
"x = specifiers.Specifier('==3.1.*')\n",
"x"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"<SpecifierSet('!=3.1.1,~=3.1.0')>"
]
},
"execution_count": 40,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"y = specifiers.SpecifierSet('~=3.1.0, !=3.1.1')\n",
"y"
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 41,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"'3.1.2-post' in y"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"24:00"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"### Зависимости не из PyPI\n",
"\n",
"```python\n",
"setup(\n",
" name=\"foo\", version=\"1.0\",\n",
" \n",
" install_requires=[\n",
" \"something\",\n",
" \"related_thing\",\n",
" ],\n",
"\n",
" dependency_links=[\n",
" \"file:///path/to/something-none-any.whl\"\n",
" \"#egg=something-1.0\",\n",
"\n",
" \"git+ssh://git@gitserver/relthing.git\"\n",
" \"@master\"\n",
" \"#egg=related_thing-0.1dev\",\n",
" ],\n",
")\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"```bash\n",
"python setup.py install\n",
"\n",
"easy_install .\n",
"\n",
"easy_install git+ssh://git@gitserver/foo.git\n",
"\n",
"pip install \\\n",
" --process-dependency-links \\\n",
" --trusted-host gitserver \\\n",
" git+ssh://git@gitserver/foo.git\n",
"\n",
"```\n",
"\n",
"С выходом нового формата метаданных, вещи немного поменяются..."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"26:00"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"# Extras\n",
"\n",
"Необязательные зависимости и параметризация поведения `setup()`\n",
"\n",
"```python\n",
"setup(\n",
" name='foo', ...\n",
" extras_require={\n",
" 'tools': [], # Just add param\n",
" ':python_version==\"2.6\"': ['argparse'],\n",
" 'export': ['msgpack', 'pyYAML', ''],\n",
" }\n",
")\n",
"```\n",
"\n",
"При установке: `$ pip install . [tools]`\n",
"\n",
"В зависимостях:\n",
"```python\n",
" install_requires=[\"foo[export,tools]\"],\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"29:00"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## А как же `requirements.txt`?\n",
"\n",
"* Используется для воссоздания окружения при помощи\n",
"\n",
"```bash\n",
" pip -r requirements.txt\n",
"```\n",
"\n",
"* Каждая строка содержит аргументы для `pip`, например:\n",
"\n",
"```bash\n",
" numpy\n",
" --pre theano\n",
"```\n",
"\n",
"* API для парсинга `pip.req.req_file` постоянно меняется\n",
"\n",
"* Если всё же конвертируете в параметры `setup()`:\n",
" * убедитесь, что `requirements.txt` попадает в `sdist`"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"31:00"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Development mode\n",
"\n",
"Добавить ссылку на текущий каталог в `sys.path`, установить зависимости и скрипты:\n",
"```bash\n",
"pip install -e .\n",
"```\n",
"\n",
"Сделать `git clone` в папке `$VIRTUAL_ENV/src`, добавить ссылку в `sys.path`, установить зависимости и скрипты:\n",
"```bash\n",
"pip install -e git+http://github.com/your/project\n",
"```\n",
"\n",
"Изменения в коде сразу отражаются в скриптах и при `import`\n",
"\n",
"Параметр `-e` можно указывать в `requirements.txt`"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"33:00"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Если `setup.py` написан без `setuptools`"
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"!touch setup.py"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"running develop\n",
"running egg_info\n",
"writing foo.egg-info/PKG-INFO\n",
"deleting foo.egg-info/requires.txt\n",
"writing dependency_links to foo.egg-info/dependency_links.txt\n",
"writing entry points to foo.egg-info/entry_points.txt\n",
"writing top-level names to foo.egg-info/top_level.txt\n",
"reading manifest file 'foo.egg-info/SOURCES.txt'\n",
"writing manifest file 'foo.egg-info/SOURCES.txt'\n",
"running build_ext\n",
"Creating /home/kpp/build/pyconru-setup-py/venv/lib/python3.4/site-packages/foo.egg-link (link to .)\n",
"Adding foo 1.0 to easy-install.pth file\n",
"Installing foo_util script to /home/kpp/build/pyconru-setup-py/venv/bin\n",
"\n",
"Installed /home/kpp/build/pyconru-setup-py/deps\n",
"Processing dependencies for foo==1.0\n",
"Finished processing dependencies for foo==1.0\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"warning: manifest_maker: standard file '-c' not found\n",
"\n"
]
}
],
"source": [
"%%bash\n",
"python -c \"import setuptools; exec(open('setup.py').read())\" develop"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"34:00"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Скрипты"
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {
"collapsed": true,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"!touch README"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {
"collapsed": false,
"scrolled": true,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting main.py\n"
]
}
],
"source": [
"%%file main.py\n",
"\n",
"if __name__ == '__main__':\n",
" import foo\n",
" foo.foo()"
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"running sdist\n",
"running egg_info\n",
"writing dependency_links to foo.egg-info/dependency_links.txt\n",
"deleting foo.egg-info/entry_points.txt\n",
"writing top-level names to foo.egg-info/top_level.txt\n",
"writing foo.egg-info/PKG-INFO\n",
"reading manifest file 'foo.egg-info/SOURCES.txt'\n",
"writing manifest file 'foo.egg-info/SOURCES.txt'\n",
"running check\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"warning: check: missing required meta-data: url\n",
"\n",
"warning: check: missing meta-data: either (author and author_email) or (maintainer and maintainer_email) must be supplied\n",
"\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"creating foo-1.0\n",
"creating foo-1.0/foo.egg-info\n",
"making hard links in foo-1.0...\n",
"hard linking README -> foo-1.0\n",
"hard linking foo.py -> foo-1.0\n",
"hard linking main.py -> foo-1.0\n",
"hard linking setup.cfg -> foo-1.0\n",
"hard linking setup.py -> foo-1.0\n",
"hard linking foo.egg-info/PKG-INFO -> foo-1.0/foo.egg-info\n",
"hard linking foo.egg-info/SOURCES.txt -> foo-1.0/foo.egg-info\n",
"hard linking foo.egg-info/dependency_links.txt -> foo-1.0/foo.egg-info\n",
"hard linking foo.egg-info/top_level.txt -> foo-1.0/foo.egg-info\n",
"copying setup.cfg -> foo-1.0\n",
"Writing foo-1.0/setup.cfg\n",
"Creating tar archive\n",
"removing 'foo-1.0' (and everything under it)\n"
]
},
{
"data": {
"text/plain": [
"<setuptools.dist.Distribution at 0x7fd9aa6388d0>"
]
},
"execution_count": 46,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"setup(\n",
" name='foo', version=\"1.0\",\n",
" py_modules=['foo'],\n",
" scripts=['main.py'],\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 47,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"running sdist\n",
"running egg_info\n",
"writing dependency_links to foo.egg-info/dependency_links.txt\n",
"writing entry points to foo.egg-info/entry_points.txt\n",
"writing top-level names to foo.egg-info/top_level.txt\n",
"writing foo.egg-info/PKG-INFO\n",
"reading manifest file 'foo.egg-info/SOURCES.txt'\n",
"writing manifest file 'foo.egg-info/SOURCES.txt'\n",
"running check\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"warning: check: missing required meta-data: url\n",
"\n",
"warning: check: missing meta-data: either (author and author_email) or (maintainer and maintainer_email) must be supplied\n",
"\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"creating foo-1.0\n",
"creating foo-1.0/foo.egg-info\n",
"making hard links in foo-1.0...\n",
"hard linking README -> foo-1.0\n",
"hard linking foo.py -> foo-1.0\n",
"hard linking main.py -> foo-1.0\n",
"hard linking setup.cfg -> foo-1.0\n",
"hard linking setup.py -> foo-1.0\n",
"hard linking foo.egg-info/PKG-INFO -> foo-1.0/foo.egg-info\n",
"hard linking foo.egg-info/SOURCES.txt -> foo-1.0/foo.egg-info\n",
"hard linking foo.egg-info/dependency_links.txt -> foo-1.0/foo.egg-info\n",
"hard linking foo.egg-info/entry_points.txt -> foo-1.0/foo.egg-info\n",
"hard linking foo.egg-info/top_level.txt -> foo-1.0/foo.egg-info\n",
"copying setup.cfg -> foo-1.0\n",
"Writing foo-1.0/setup.cfg\n",
"Creating tar archive\n",
"removing 'foo-1.0' (and everything under it)\n"
]
},
{
"data": {
"text/plain": [
"<setuptools.dist.Distribution at 0x7fd9aa5c2588>"
]
},
"execution_count": 47,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"\n",
"setup(\n",
" name='foo', version=\"1.0\",\n",
" py_modules=['foo'],\n",
" entry_points={\n",
" 'console_scripts': [\n",
" 'foo_util = foo:foo',\n",
" ],\n",
" }\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"#### Extras и скрипты"
]
},
{
"cell_type": "code",
"execution_count": 48,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"running sdist\n",
"running egg_info\n",
"writing dependency_links to foo.egg-info/dependency_links.txt\n",
"writing entry points to foo.egg-info/entry_points.txt\n",
"writing top-level names to foo.egg-info/top_level.txt\n",
"writing requirements to foo.egg-info/requires.txt\n",
"writing foo.egg-info/PKG-INFO\n",
"reading manifest file 'foo.egg-info/SOURCES.txt'\n",
"writing manifest file 'foo.egg-info/SOURCES.txt'\n",
"running check\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"warning: check: missing required meta-data: url\n",
"\n",
"warning: check: missing meta-data: either (author and author_email) or (maintainer and maintainer_email) must be supplied\n",
"\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"creating foo-1.0\n",
"creating foo-1.0/foo.egg-info\n",
"making hard links in foo-1.0...\n",
"hard linking README -> foo-1.0\n",
"hard linking foo.py -> foo-1.0\n",
"hard linking main.py -> foo-1.0\n",
"hard linking setup.cfg -> foo-1.0\n",
"hard linking setup.py -> foo-1.0\n",
"hard linking foo.egg-info/PKG-INFO -> foo-1.0/foo.egg-info\n",
"hard linking foo.egg-info/SOURCES.txt -> foo-1.0/foo.egg-info\n",
"hard linking foo.egg-info/dependency_links.txt -> foo-1.0/foo.egg-info\n",
"hard linking foo.egg-info/entry_points.txt -> foo-1.0/foo.egg-info\n",
"hard linking foo.egg-info/requires.txt -> foo-1.0/foo.egg-info\n",
"hard linking foo.egg-info/top_level.txt -> foo-1.0/foo.egg-info\n",
"copying setup.cfg -> foo-1.0\n",
"Writing foo-1.0/setup.cfg\n",
"Creating tar archive\n",
"removing 'foo-1.0' (and everything under it)\n"
]
},
{
"data": {
"text/plain": [
"<setuptools.dist.Distribution at 0x7fd9aa55e588>"
]
},
"execution_count": 48,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"setup(\n",
" name='foo', version=\"1.0\",\n",
" py_modules=['foo'],\n",
" extras_require={'tools': []},\n",
" entry_points={\n",
" 'console_scripts': [\n",
" 'foo_util = foo:foo [tools]',\n",
" ],\n",
" }\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"39:00"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# entry_points"
]
},
{
"cell_type": "code",
"execution_count": 49,
"metadata": {
"collapsed": false,
"scrolled": true,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting setup.py\n"
]
}
],
"source": [
"%%file setup.py\n",
"from setuptools import setup\n",
"\n",
"setup(\n",
" name='foo', version=\"1.0\",\n",
" py_modules=['foo'],\n",
" entry_points='''\n",
" [console_scripts]\n",
" foo_util = foo:foo\n",
"\n",
" [reporting.tools]\n",
" foo_report = foo:foo\n",
" ''',\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 50,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Uninstalling foo-1.0:\n",
" Successfully uninstalled foo-1.0\n",
"Uninstalling foo-1.0:\n",
" Successfully uninstalled foo-1.0\n"
]
}
],
"source": [
"!pip uninstall foo -y\n",
"!pip uninstall foo -y"
]
},
{
"cell_type": "code",
"execution_count": 51,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Processing /home/kpp/build/pyconru-setup-py/deps\n",
"Installing collected packages: foo\n",
" Running setup.py install for foo\n",
"Successfully installed foo-1.0\n"
]
}
],
"source": [
"!pip install . -U"
]
},
{
"cell_type": "code",
"execution_count": 52,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"I'm in your system now\n"
]
}
],
"source": [
"%%bash \n",
"foo_util"
]
},
{
"cell_type": "code",
"execution_count": 53,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"#!/home/kpp/build/pyconru-setup-py/venv/bin/python3\n",
"# EASY-INSTALL-ENTRY-SCRIPT: 'foo==1.0','console_scripts','foo_util'\n",
"__requires__ = 'foo==1.0'\n",
"import sys\n",
"from pkg_resources import load_entry_point\n",
"\n",
"if __name__ == '__main__':\n",
" sys.exit(\n",
" load_entry_point('foo==1.0', 'console_scripts', 'foo_util')()\n",
" )\n"
]
}
],
"source": [
"%%bash\n",
"cat `which foo_util`"
]
},
{
"cell_type": "code",
"execution_count": 54,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Reporter foo_report:\n",
"I'm in your system now\n"
]
}
],
"source": [
"from pkg_resources import iter_entry_points\n",
"\n",
"for ep in iter_entry_points('reporting.tools'):\n",
"\n",
" print('Reporter {}:'.format(ep.name))\n",
" func = ep.load()\n",
" \n",
" func()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"43:00"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# setup.cfg\n",
"\n",
"```bash\n",
"python setup.py ... saveopts\n",
"```\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 55,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting setup.cfg\n"
]
}
],
"source": [
"%%file setup.cfg\n",
"\n",
"[bdist_wheel]\n",
"universal = 1\n",
"\n",
"[nosetests]\n",
"exe = 1\n",
"with-coverage = 1\n",
"with-tissue = 1\n",
"\n",
"[coverage:run]\n",
"omit = *numpy*\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"source": [
"45:00"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Thank you\n",
"\n",
"```\n",
"```\n",
"\n",
"Константин Игнатов\n",
"\n",
"@podshumok\n",
"\n",
"\n",
"```\n",
"```\n",
"\n",
"\n",
"Qrator Labs\n",
"\n",
"[qrator.net](http://qrator.net)"
]
},
{
"cell_type": "code",
"execution_count": 56,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# Type your question here..."
]
}
],
"metadata": {
"celltoolbar": "Slideshow",
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.4.3"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
notebook~=4.0
packaging
setuptools>18.0
pip>7.0
setuptools-git
#git+https://github.com/damianavila/RISE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment