{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Example of Pythran Usage Within a Full Project\n",
    "\n",
    "This notebook covers the creation of a simple, distutils-powered, project that ships a pythran kernel.\n",
    "\n",
    "\n",
    "But first some cleanup"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "!rm -rf hello setup.py && mkdir hello"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Project layout\n",
    "\n",
    "The Pythran file is really dumb.\n",
    "The expected layout is:\n",
    "\n",
    "```\n",
    "setup.py\n",
    "hello/\n",
    "  +---- __init__.py\n",
    "  +---- hello.py\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Writing hello/hello.py\n"
     ]
    }
   ],
   "source": [
    "%%file hello/hello.py\n",
    "\n",
    "#pythran export hello()\n",
    "\n",
    "def hello():\n",
    "    \"\"\"\n",
    "    Wave hello.\n",
    "    \"\"\"\n",
    "    print(\"Hello from Pythran o/\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And so is the ``__init__.py`` file."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Writing hello/__init__.py\n"
     ]
    }
   ],
   "source": [
    "%%file hello/__init__.py\n",
    "\"\"\"\n",
    "Hello package, featuring a Pythran kernel.\n",
    "\"\"\"\n",
    "from hello import hello"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The ``setup.py`` file contains the classical metadata, plus a special header. this header basically states *if pythran is available, use it, otherwise fallback to the python file*."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Writing setup.py\n"
     ]
    }
   ],
   "source": [
    "%%file setup.py\n",
    "from distutils.core import setup\n",
    "\n",
    "try:\n",
    "    from pythran.dist import PythranExtension, PythranBuildExt\n",
    "    setup_args = {\n",
    "        'cmdclass': {\"build_ext\": PythranBuildExt},\n",
    "        'ext_modules': [PythranExtension('hello.hello', sources = ['hello/hello.py'])],\n",
    "    }\n",
    "except ImportError:\n",
    "    print(\"Not building Pythran extension\")\n",
    "    setup_args = {}\n",
    "          \n",
    "setup(name = 'hello',\n",
    "      version = '1.0',\n",
    "      description = 'Yet another demo package',\n",
    "      packages = ['hello'],\n",
    "      **setup_args)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Running ``setup.py``\n",
    "\n",
    "With the described configuration, the normal ``python setup.py`` targets should « just work ».\n",
    "\n",
    "If pythran is in the path, it is used to generate the alternative c++ extension when building a source release. Note the ``hello.cpp``!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello/hello.cpp\n",
      "hello/hello.py\n"
     ]
    }
   ],
   "source": [
    "%%sh\n",
    "rm -rf build dist\n",
    "python setup.py sdist 2>/dev/null 1>/dev/null\n",
    "tar tf dist/hello-1.0.tar.gz | grep -E 'hello/hello.(py|cpp)' -o | sort"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "But if pythran is no longer in the ``PYTHONPATH``, the installation does not fail: the regular Python source can still be used."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello/hello.py\n"
     ]
    }
   ],
   "source": [
    "%%sh\n",
    "rm -rf build dist\n",
    "PYTHONPATH= python setup.py sdist 2>/dev/null 1>/dev/null\n",
    "tar tf dist/hello-1.0.tar.gz | grep -E 'hello/hello.py' -o"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In case of binary distribution, the native module is generated alongside the original source."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello/hello.py\n"
     ]
    }
   ],
   "source": [
    "%%sh\n",
    "rm -rf build dist\n",
    "python setup.py bdist 2>/dev/null 1>/dev/null\n",
    "tar tf dist/hello-1.0.linux-x86_64.tar.gz | grep -E 'hello/hello.(py|cpp)' -o"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And if pythran is not in the ``PYTHONPATH``, this still work ``\\o/``"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello/hello.py\n"
     ]
    }
   ],
   "source": [
    "%%sh\n",
    "rm -rf build dist\n",
    "PYTHONPATH= python setup.py bdist 2>/dev/null 1>/dev/null\n",
    "tar tf dist/hello-1.0.linux-x86_64.tar.gz | grep -E 'hello/hello.py' -o"
   ]
  }
 ],
 "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.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
