{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Modules and Packaging\n", "====\n", "\n", "At some point, you will want to organize and distribute your code library for the whole world to share, preferably on PyPI so that it is pip installable." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## References\n", "\n", "This notebook shows a bare-bones version of creating and distributing a project to PyPI. Please follow the instructions in the official documentations. For convenience, you can use the sample project as a template. \n", "\n", "- [Packaging and Distributing Projects](https://packaging.python.org/tutorials/distributing-packages/)\n", "- [A sample Python project](https://github.com/pypa/sampleproject)\n", "\n", "For more about how to organize the structure of your package \n", "\n", "- [Official tutorial on packages](https://docs.python.org/3/tutorial/modules.html#packages)\n", "\n", "If you are still confused about what `__init__.py` does, this [blog post](and the mysterious `__init__.py`, see) might help." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Install packages we will use for packaging" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Requirement already up-to-date: pip in /usr/local/lib/python2.7/site-packages\n", "Requirement already satisfied: twine in /usr/local/lib/python2.7/site-packages\n", "Requirement already satisfied: setuptools>=0.7.0 in /usr/local/lib/python2.7/site-packages (from twine)\n", "Requirement already satisfied: pkginfo>=1.4.2 in /usr/local/lib/python2.7/site-packages (from twine)\n", "Requirement already satisfied: requests-toolbelt>=0.8.0 in /usr/local/lib/python2.7/site-packages (from twine)\n", "Requirement already satisfied: tqdm>=4.14 in /usr/local/lib/python2.7/site-packages (from twine)\n", "Requirement already satisfied: requests!=2.15,!=2.16,>=2.5.0 in /usr/local/lib/python2.7/site-packages (from twine)\n" ] } ], "source": [ "! pip install -U pip\n", "! pip install twine" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Modules\n", "\n", "In Pythoh, any `.py` file is a module in that it can be imported. Because the interpreter runs the entrie file when a moudle is imported, it is traditional to use a guard to ignore code that should only run when the file is executed as a script." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Overwriting foo.py\n" ] } ], "source": [ "%%file foo.py\n", "\"\"\"\n", "When this file is imported with `import foo`,\n", "only `useful_func1()` and `useful_func()` are loaded, \n", "and the test code `assert ...` is ignored. However,\n", "when we run foo.py as a script `python foo.py`, then\n", "the two assert statements are run.\n", "Most commonly, the code under `if __naem__ == '__main__':`\n", "consists of simple examples or test cases for the functions\n", "defined in the moule.\n", "\"\"\"\n", "\n", "def useful_func1():\n", " pass\n", "\n", "def useful_fucn2():\n", " pass\n", "\n", "if __name__ == '__main__':\n", " assert(useful_func1() is None)\n", " assert(useful_fucn2() is None)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Organization of files in a module\n", "\n", "When the number of files you write grow large, you will probably want to orgnize them into their own directory structure. To make a folder a module, you just need to include a file named `__init__.py` in the folder. This file can be empty. For example, here is a module named `pkg` with sub-modules `sub1` and `sub2`.\n", "\n", "```\n", "./pkg:\n", "__init__.py\tfoo.py\t\tsub1\t\tsub2\n", "\n", "./pkg/sub1:\n", "__init__.py\t\tmore_sub1_stuff.py\tsub1_stuff.py\n", "\n", "./pkg/sub2:\n", "__init__.py\tsub2_stuff.py\n", "```\n" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import pkg.foo as foo" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "foo.f1()" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import pkg" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pkg.foo.f1()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### How to import a module at the same level\n", "\n", "Within a package, we need to use absolute path names for importing other modules in the same directory. This prevents confusion as to whether you want to import a system moudle with the same name. For example, `foo.sub1.more_sub1_stuff.py` imports functions from `foo.sub1.sub1_stuff.py`" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "from pkg.sub1.sub1_stuff import g1, g2\r\n", "\r\n", "def g3():\r\n", " return 'g3 uses %s, %s' % (g1(), g2())\r\n", "\r\n" ] } ], "source": [ "! cat pkg/sub1/more_sub1_stuff.py" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'g3 uses g1, g2'" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from pkg.sub1.more_sub1_stuff import g3\n", "\n", "g3()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### How to import a moudle at a different level\n", "\n", "Again, just use absolute paths. For example, `sub2_stuff.py` in the `sub2` directory uses functions from `sub1_stuff.py` in the `sub1` directory:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "from pkg.sub1.sub1_stuff import g1, g2\r\n", "\r\n", "def h1():\r\n", " return g1()\r\n", "\r\n", "def h2():\r\n", " return g1() + g2()\r\n" ] } ], "source": [ "! cat pkg/sub2/sub2_stuff.py" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'g1g2'" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from pkg.sub2.sub2_stuff import h2\n", "\n", "h2()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Distributing your package\n", "\n", "Suppose we want to distribute our code as a library (for example, on PyPI so that it cnn be installed with `pip`). Let's create an `sta663-` (the username part is just to avoid name conflicts) library containing the `pkg` package and some other files:\n", "\n", "- `README.md`: some information about the library\n", "- `sta663.py`: a standalone module\n", "- `run_sta663.py`: a script (intended for use as `python run_sta663.py`)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "MANIFEST \u001b[34mdist\u001b[m\u001b[m sta663.py\r\n", "README.txt \u001b[34mpkg\u001b[m\u001b[m \u001b[34msta663_cliburn.egg-info\u001b[m\u001b[m\r\n", "__init__.py run_sta663.py \u001b[34msub1\u001b[m\u001b[m\r\n", "\u001b[34m__pycache__\u001b[m\u001b[m setup.py \u001b[34msub2\u001b[m\u001b[m\r\n", "\u001b[34mbuild\u001b[m\u001b[m \u001b[34msta663.egg-info\u001b[m\u001b[m\r\n", "\r\n", "sta663/__pycache__:\r\n", "__init__.cpython-36.pyc sta663.cpython-36.pyc\r\n", "\r\n", "sta663/build:\r\n", "\u001b[34mbdist.macosx-10.12-x86_64\u001b[m\u001b[m \u001b[34mlib\u001b[m\u001b[m \u001b[34mscripts-3.6\u001b[m\u001b[m\r\n", "\r\n", "sta663/build/bdist.macosx-10.12-x86_64:\r\n", "\r\n", "sta663/build/lib:\r\n", "\u001b[34mpkg\u001b[m\u001b[m sta663.py\r\n", "\r\n", "sta663/build/lib/pkg:\r\n", "__init__.py foo.py \u001b[34msub1\u001b[m\u001b[m \u001b[34msub2\u001b[m\u001b[m\r\n", "\r\n", "sta663/build/lib/pkg/sub1:\r\n", "__init__.py more_sub1_stuff.py sub1_stuff.py\r\n", "\r\n", "sta663/build/lib/pkg/sub2:\r\n", "__init__.py sub2_stuff.py\r\n", "\r\n", "sta663/build/scripts-3.6:\r\n", "\u001b[31mrun_sta663.py\u001b[m\u001b[m\r\n", "\r\n", "sta663/dist:\r\n", "sta663_cliburn-1.0-py3.6.egg\r\n", "\r\n", "sta663/pkg:\r\n", "__init__.py \u001b[34m__pycache__\u001b[m\u001b[m foo.py \u001b[34msub1\u001b[m\u001b[m \u001b[34msub2\u001b[m\u001b[m\r\n", "\r\n", "sta663/pkg/__pycache__:\r\n", "__init__.cpython-36.pyc foo.cpython-36.pyc\r\n", "\r\n", "sta663/pkg/sub1:\r\n", "__init__.py \u001b[34m__pycache__\u001b[m\u001b[m sub1_stuff.py\r\n", "__init__.py~ more_sub1_stuff.py\r\n", "\r\n", "sta663/pkg/sub1/__pycache__:\r\n", "__init__.cpython-36.pyc sub1_stuff.cpython-36.pyc\r\n", "\r\n", "sta663/pkg/sub2:\r\n", "__init__.py __init__.py~ sub2_stuff.py\r\n", "\r\n", "sta663/sta663.egg-info:\r\n", "PKG-INFO dependency_links.txt\r\n", "SOURCES.txt top_level.txt\r\n", "\r\n", "sta663/sta663_cliburn.egg-info:\r\n", "PKG-INFO dependency_links.txt\r\n", "SOURCES.txt top_level.txt\r\n", "\r\n", "sta663/sub1:\r\n", "__intit__.py __intit__.py~\r\n", "\r\n", "sta663/sub2:\r\n", "__iniit__.py __iniit__.py~\r\n" ] } ], "source": [ "! ls -R sta663" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "import pkg.foo as foo\r\n", "from pkg.sub1.more_sub1_stuff import g3\r\n", "from pkg.sub2.sub2_stuff import h2\r\n", "\r\n", "print foo.f1()\r\n", "print g3()\r\n", "print h2()\r\n" ] } ], "source": [ "! cat sta663/run_sta663.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Using distutils\n", "\n", "All we need to do is to write a `setup.py` file." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Overwriting sta663/setup.py\n" ] } ], "source": [ "%%file sta663/setup.py\n", "from setuptools import setup\n", "\n", "setup(name = \"sta663-cliburn\",\n", " version = \"1.0\",\n", " author='Cliburn Chan',\n", " author_email='cliburn.chan@duke.edu',\n", " url='http://people.duke.edu/~ccc14/sta-663-2018/',\n", " py_modules = ['sta663'],\n", " packages=setuptools.find_packages(),\n", " scripts = ['run_sta663.py'],\n", " python_requires='>=3',\n", " )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Build a source archive for distribution" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "/Users/cliburn/_teach/sta-663-2018/project/Packaging\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "Traceback (most recent call last):\n", " File \"setup.py\", line 9, in \n", " packages=setuptools.find_packages(),\n", "NameError: name 'setuptools' is not defined\n" ] } ], "source": [ "%%bash\n", "\n", "cd sta663\n", "python setup.py sdist\n", "cd -" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "MANIFEST \u001b[34mdist\u001b[m\u001b[m sta663.py\r\n", "README.txt \u001b[34mpkg\u001b[m\u001b[m \u001b[34msta663_cliburn.egg-info\u001b[m\u001b[m\r\n", "__init__.py run_sta663.py \u001b[34msub1\u001b[m\u001b[m\r\n", "\u001b[34m__pycache__\u001b[m\u001b[m setup.py \u001b[34msub2\u001b[m\u001b[m\r\n", "\u001b[34mbuild\u001b[m\u001b[m \u001b[34msta663.egg-info\u001b[m\u001b[m\r\n", "\r\n", "sta663/__pycache__:\r\n", "__init__.cpython-36.pyc sta663.cpython-36.pyc\r\n", "\r\n", "sta663/build:\r\n", "\u001b[34mbdist.macosx-10.12-x86_64\u001b[m\u001b[m \u001b[34mlib\u001b[m\u001b[m \u001b[34mscripts-3.6\u001b[m\u001b[m\r\n", "\r\n", "sta663/build/bdist.macosx-10.12-x86_64:\r\n", "\r\n", "sta663/build/lib:\r\n", "\u001b[34mpkg\u001b[m\u001b[m sta663.py\r\n", "\r\n", "sta663/build/lib/pkg:\r\n", "__init__.py foo.py \u001b[34msub1\u001b[m\u001b[m \u001b[34msub2\u001b[m\u001b[m\r\n", "\r\n", "sta663/build/lib/pkg/sub1:\r\n", "__init__.py more_sub1_stuff.py sub1_stuff.py\r\n", "\r\n", "sta663/build/lib/pkg/sub2:\r\n", "__init__.py sub2_stuff.py\r\n", "\r\n", "sta663/build/scripts-3.6:\r\n", "\u001b[31mrun_sta663.py\u001b[m\u001b[m\r\n", "\r\n", "sta663/dist:\r\n", "sta663_cliburn-1.0-py3.6.egg\r\n", "\r\n", "sta663/pkg:\r\n", "__init__.py \u001b[34m__pycache__\u001b[m\u001b[m foo.py \u001b[34msub1\u001b[m\u001b[m \u001b[34msub2\u001b[m\u001b[m\r\n", "\r\n", "sta663/pkg/__pycache__:\r\n", "__init__.cpython-36.pyc foo.cpython-36.pyc\r\n", "\r\n", "sta663/pkg/sub1:\r\n", "__init__.py \u001b[34m__pycache__\u001b[m\u001b[m sub1_stuff.py\r\n", "__init__.py~ more_sub1_stuff.py\r\n", "\r\n", "sta663/pkg/sub1/__pycache__:\r\n", "__init__.cpython-36.pyc sub1_stuff.cpython-36.pyc\r\n", "\r\n", "sta663/pkg/sub2:\r\n", "__init__.py __init__.py~ sub2_stuff.py\r\n", "\r\n", "sta663/sta663.egg-info:\r\n", "PKG-INFO dependency_links.txt\r\n", "SOURCES.txt top_level.txt\r\n", "\r\n", "sta663/sta663_cliburn.egg-info:\r\n", "PKG-INFO dependency_links.txt\r\n", "SOURCES.txt top_level.txt\r\n", "\r\n", "sta663/sub1:\r\n", "__intit__.py __intit__.py~\r\n", "\r\n", "sta663/sub2:\r\n", "__iniit__.py __iniit__.py~\r\n" ] } ], "source": [ "! ls -R sta663" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Distribution\n", "\n", "You can now distribute `sta663-1.0.tar.gz` to somebody else for installation in the usual way." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "running install\n", "running bdist_egg\n", "running egg_info\n", "writing sta663.egg-info/PKG-INFO\n", "writing top-level names to sta663.egg-info/top_level.txt\n", "writing dependency_links to sta663.egg-info/dependency_links.txt\n", "reading manifest file 'sta663.egg-info/SOURCES.txt'\n", "writing manifest file 'sta663.egg-info/SOURCES.txt'\n", "installing library code to build/bdist.macosx-10.12-x86_64/egg\n", "running install_lib\n", "running build_py\n", "creating build/bdist.macosx-10.12-x86_64/egg\n", "copying build/lib/sta663.py -> build/bdist.macosx-10.12-x86_64/egg\n", "creating build/bdist.macosx-10.12-x86_64/egg/pkg\n", "creating build/bdist.macosx-10.12-x86_64/egg/pkg/sub1\n", "copying build/lib/pkg/sub1/__init__.py -> build/bdist.macosx-10.12-x86_64/egg/pkg/sub1\n", "copying build/lib/pkg/sub1/more_sub1_stuff.py -> build/bdist.macosx-10.12-x86_64/egg/pkg/sub1\n", "copying build/lib/pkg/sub1/sub1_stuff.py -> build/bdist.macosx-10.12-x86_64/egg/pkg/sub1\n", "copying build/lib/pkg/__init__.py -> build/bdist.macosx-10.12-x86_64/egg/pkg\n", "creating build/bdist.macosx-10.12-x86_64/egg/pkg/sub2\n", "copying build/lib/pkg/sub2/__init__.py -> build/bdist.macosx-10.12-x86_64/egg/pkg/sub2\n", "copying build/lib/pkg/sub2/sub2_stuff.py -> build/bdist.macosx-10.12-x86_64/egg/pkg/sub2\n", "copying build/lib/pkg/foo.py -> build/bdist.macosx-10.12-x86_64/egg/pkg\n", "byte-compiling build/bdist.macosx-10.12-x86_64/egg/sta663.py to sta663.pyc\n", "byte-compiling build/bdist.macosx-10.12-x86_64/egg/pkg/sub1/__init__.py to __init__.pyc\n", "byte-compiling build/bdist.macosx-10.12-x86_64/egg/pkg/sub1/more_sub1_stuff.py to more_sub1_stuff.pyc\n", "byte-compiling build/bdist.macosx-10.12-x86_64/egg/pkg/sub1/sub1_stuff.py to sub1_stuff.pyc\n", "byte-compiling build/bdist.macosx-10.12-x86_64/egg/pkg/__init__.py to __init__.pyc\n", "byte-compiling build/bdist.macosx-10.12-x86_64/egg/pkg/sub2/__init__.py to __init__.pyc\n", "byte-compiling build/bdist.macosx-10.12-x86_64/egg/pkg/sub2/sub2_stuff.py to sub2_stuff.pyc\n", "byte-compiling build/bdist.macosx-10.12-x86_64/egg/pkg/foo.py to foo.pyc\n", "creating build/bdist.macosx-10.12-x86_64/egg/EGG-INFO\n", "installing scripts to build/bdist.macosx-10.12-x86_64/egg/EGG-INFO/scripts\n", "running install_scripts\n", "running build_scripts\n", "creating build/bdist.macosx-10.12-x86_64/egg/EGG-INFO/scripts\n", "copying build/scripts-2.7/run_sta663.py -> build/bdist.macosx-10.12-x86_64/egg/EGG-INFO/scripts\n", "changing mode of build/bdist.macosx-10.12-x86_64/egg/EGG-INFO/scripts/run_sta663.py to 755\n", "copying sta663.egg-info/PKG-INFO -> build/bdist.macosx-10.12-x86_64/egg/EGG-INFO\n", "copying sta663.egg-info/SOURCES.txt -> build/bdist.macosx-10.12-x86_64/egg/EGG-INFO\n", "copying sta663.egg-info/dependency_links.txt -> build/bdist.macosx-10.12-x86_64/egg/EGG-INFO\n", "copying sta663.egg-info/top_level.txt -> build/bdist.macosx-10.12-x86_64/egg/EGG-INFO\n", "creating 'dist/sta663-1.0-py2.7.egg' and adding 'build/bdist.macosx-10.12-x86_64/egg' to it\n", "removing 'build/bdist.macosx-10.12-x86_64/egg' (and everything under it)\n", "Processing sta663-1.0-py2.7.egg\n", "Removing /usr/local/lib/python2.7/site-packages/sta663-1.0-py2.7.egg\n", "Copying sta663-1.0-py2.7.egg to /usr/local/lib/python2.7/site-packages\n", "sta663 1.0 is already the active version in easy-install.pth\n", "Installing run_sta663.py script to /usr/local/bin\n", "\n", "Installed /usr/local/lib/python2.7/site-packages/sta663-1.0-py2.7.egg\n", "Processing dependencies for sta663==1.0\n", "Finished processing dependencies for sta663==1.0\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "zip_safe flag not set; analyzing archive contents...\n" ] } ], "source": [ "%%bash\n", "\n", "cp sta663/dist/sta663_cliburn-1.0-py3.6.egg /tmp\n", "cd /tmp\n", "tar xzf sta663_cliburn-1.0-py3.6.egg \n", "cd sta663-1.0\n", "python setup.py install" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### See `__init__.py` to understand what can be imported from where" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "import pkg\r\n", "from pkg.sub1.sub1_stuff import g1\r\n", " \r\n" ] } ], "source": [ "! cat sta663/__init__.py" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "! cat sta663/pkg/__init__.py" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "from sta663.pkg.sub1.sub1_stuff import g1, g2\r\n", "from sta663.pkg.sub1.more_sub1_stuff import g3\r\n" ] } ], "source": [ "! cat sta663/pkg/sub1/__init__.py" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "from sta663.pkg.sub2.sub2_stuff import h1, h2\r\n" ] } ], "source": [ "! cat sta663/pkg/sub2/__init__.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Using imports from the `sta663` package" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import sta663" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['g1', 'pkg']" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[x for x in dir(sta663) if not x.startswith('__')]" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'g1'" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sta663.g1()" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "collapsed": true }, "outputs": [], "source": [ "from sta663 import pkg" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['sub1', 'sub2']" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[x for x in dir(pkg) if not x.startswith('__')]" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "from sta663.pkg import sub1, sub2" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['g1', 'g2', 'g3', 'more_sub1_stuff', 'sub1_stuff']" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[x for x in dir(sub1) if not x.startswith('__')]" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['h1', 'h2', 'sub2_stuff']" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[x for x in dir(sub2) if not x.startswith('__')]" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "('g1', 'g2', 'g3 uses g1, g2')" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sub1.g1(), sub1.g2(), sub1.g3()" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "('g1', 'g1g2')" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sub2.h1(), sub2.h2()" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'g1'" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sta663.pkg.sub2.sub2_stuff.h1()" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'g1g2'" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sta663.pkg.sub2.sub2_stuff.h2()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Distributing to PyPI\n", "\n", "For testing, please upload to TestPyPI which is cleaned on a regular basis. See instructions at \n", "https://packaging.python.org/guides/using-testpypi/#using-test-pypi\n", "\n", "- **Note 1**: You need to confirm your email address after registration.\n", "- **Note 2**: You can easily delete any uploaded packages by logging in at https://test.pypi.org.\n", "\n", "When your package is ready for public release, you can upload to PyPI. See instructions at\n", "https://packaging.python.org/tutorials/distributing-packages/#id78" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Uploading distributions to https://test.pypi.org/legacy/\n", "Uploading sta663_cliburn-1.0-py3.6.egg\n", "\r", " 0%| | 0.00/7.57K [00:00=3' but the running Python is 2.7.13\n" ] } ], "source": [ "%%bash\n", "\n", "pip install --index-url https://test.pypi.org/simple/ sta663" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "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.6.1" } }, "nbformat": 4, "nbformat_minor": 1 }