<commit_before><commit_msg>Added example notebook for python2 to python3 differences<commit_after>{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Coding in Python3\n",
    "\n",
    "So now that PmagPy has made the conversion to python3, for at least a short time the command line programs will be supported in both Python2 and Python3 using the library future which can be installed by in your favorite package manager (canopy, anaconda) or using this code in the command line `pip install future`. This is not true for the GUIs, however, which due to their dependency on the wxpython library must be in one language or the other. For the sake of future proofing the library all GUI related code needs to be in Python3 as soon many of the scientific libraries (ipython, matplotlib, pandas) required by PmagPy are dropping support for Python2. A full list of libraries dropping support for Python2 by 2020 can be found [here](http://www.python3statement.org/).\n",
    "\n",
    "## Python3 vs. Python2\n",
    "\n",
    "There are a number of differences between the two programming languages, which while not completely unrelated are disparate. This guide will go over those changes most relevant to PmagPy development as follows:\n",
    "\n",
    "- [Print function vs print statement](#print_explanation)\n",
    "- [Relative imports](#import_explanation)\n",
    "- [Exception raising/catching](#exception_explanation)\n",
    "- [Strings](#string_explanation)\n",
    "- [Generator vs. List vs. Iterable Objects(range, map, filter, {}.keys(), {}.values, {}.items())](#generator_list_explanation)\n",
    "- [input vs. raw_input](#input_explanation)\n",
    "- [Division](#division_explanation)\n",
    "\n",
    "This is by no means a full list of the differences between the languages and a more comprehensive list can be found [here](http://sebastianraschka.com/Articles/2014_python_2_3_key_diff.html). The goal of this list is to be concise and simple for those developing PmagPy rather than thorough.\n",
    "\n",
    "**Note:** if you already have Python2 code you would like to see incorporated into the GUI see [Converting Python2 Code](#converting_python2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Print Function vs. Print Statement\n",
    "<a id='print_explanation'></a>\n",
    "\n",
    "This is the most simple of the differences between Python2 and Python3 and the most commonly encountered. Simply the print statement in Python3 is only a function not a statement like in Python2. This means that there is no special syntax for print and it must be called as a function would. This also means that there are key word arguments for print to allow better manipulation of text."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "ename": "SyntaxError",
     "evalue": "Missing parentheses in call to 'print' (<ipython-input-5-4a3be0654a6d>, line 3)",
     "output_type": "error",
     "traceback": [
      "\u001b[0;36m  File \u001b[0;32m\"<ipython-input-5-4a3be0654a6d>\"\u001b[0;36m, line \u001b[0;32m3\u001b[0m\n\u001b[0;31m    print \"hello world\"\u001b[0m\n\u001b[0m                      ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m Missing parentheses in call to 'print'\n"
     ]
    }
   ],
   "source": [
    "#python2 syntax, now throws an error\n",
    "\n",
    "print \"hello world\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello world\n"
     ]
    }
   ],
   "source": [
    "#python3 syntax, this also works in python2 (2.5+) though in python3 this is the only option\n",
    "\n",
    "print(\"hello world\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on built-in function print in module builtins:\n",
      "\n",
      "print(...)\n",
      "    print(value, ..., sep=' ', end='\\n', file=sys.stdout, flush=False)\n",
      "    \n",
      "    Prints the values to a stream, or to sys.stdout by default.\n",
      "    Optional keyword arguments:\n",
      "    file:  a file-like object (stream); defaults to the current sys.stdout.\n",
      "    sep:   string inserted between values, default a space.\n",
      "    end:   string appended after the last value, default a newline.\n",
      "    flush: whether to forcibly flush the stream.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "#documentation on the python3 print function\n",
    "help(print)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Relative Imports\n",
    "<a id='import_explanation'></a>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exception Raising/Catching\n",
    "<a id='exception_explanation'></a>\n",
    "\n",
    "This is simply a syntax change in the raising and catching syntax."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "ename": "SyntaxError",
     "evalue": "invalid syntax (<ipython-input-20-a9d830369f4b>, line 3)",
     "output_type": "error",
     "traceback": [
      "\u001b[0;36m  File \u001b[0;32m\"<ipython-input-20-a9d830369f4b>\"\u001b[0;36m, line \u001b[0;32m3\u001b[0m\n\u001b[0;31m    raise ValueError, \"Expected a diblock was given type(%s)\"%str(type(\"\"))\u001b[0m\n\u001b[0m                    ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n"
     ]
    }
   ],
   "source": [
    "#Python2 rasing an error\n",
    "\n",
    "raise TypeError, \"Expected a diblock was given type(%s)\"%str(type(\"\")) #gives SyntaxError no the TypeError we wanted"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "Expected a diblock was given type(<class 'str'>)",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-22-9806db9f401a>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;31m#Python3 raising an error\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Expected a diblock was given type(%s)\"\u001b[0m\u001b[0;34m%\u001b[0m\u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtype\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m: Expected a diblock was given type(<class 'str'>)"
     ]
    }
   ],
   "source": [
    "#Python3 raising an error\n",
    "\n",
    "raise TypeError(\"Expected a diblock was given type(%s)\"%str(type(\"\")))#gives the appropriate TypeError"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "ename": "SyntaxError",
     "evalue": "invalid syntax (<ipython-input-23-fa8feca3e57f>, line 5)",
     "output_type": "error",
     "traceback": [
      "\u001b[0;36m  File \u001b[0;32m\"<ipython-input-23-fa8feca3e57f>\"\u001b[0;36m, line \u001b[0;32m5\u001b[0m\n\u001b[0;31m    except RuntimeError, err:\u001b[0m\n\u001b[0m                       ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n"
     ]
    }
   ],
   "source": [
    "#Python2 catching an error\n",
    "\n",
    "try:\n",
    "    raise RuntimeError; print(\"obviously not caught\")\n",
    "except RuntimeError, err:\n",
    "    print(err, \"caught the error: note there's no message for the error\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " caught the error: note there's no message for the error\n"
     ]
    }
   ],
   "source": [
    "#Python3 catching an error\n",
    "\n",
    "try:\n",
    "    raise RuntimeError; print(\"obviously not caught\")\n",
    "except RuntimeError as err:\n",
    "    print(err, \"caught the error: note there's no message for the error\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Strings\n",
    "<a id='string_explanation'></a>\n",
    "\n",
    "One of the most unnoticed and important changes between Python2 and Python3 is the difference in Strings and how they are encoded. **Def:** encoded - the manner in which the bits are organized to represent a given piece of information to the computer, in this case string characters. Python2 used ASCII strings by default and had a class Unicode, where as Python3 uses Unicode as the main string class (str) and has two other string classes byte and bytearray which are used to represent binary data. This mostly causes a problem in PmagPy when reading binary data using open(file,'b') as it will now be read in as a byte object which cannot be manipulated like a string. This can be seen in the 2G binary conversion script in the programs directory. This can also be a problem when using libraries like json as the library may read in using a different encoding like ASCII and need to be decoded to turn into the correct string. An example of this can be seen in data_model3 in the pmagpy directory. This is rather case by case and something only occasionally run into, hopefully the work arounds in data_model3 and the 2G binary conversion script can help you overcome most of these issues."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "strings are now utf-8 μnicoΔé! <class 'str'>\n",
      "b'bytes are a thing now too and when turned into a string keep this b in front' <class 'bytes'>\n"
     ]
    }
   ],
   "source": [
    "#Some Python3 examples of Unicode vs. Bytes\n",
    "\n",
    "print('strings are now utf-8 \\u03BCnico\\u0394é!', type(''))\n",
    "\n",
    "print(b'bytes are a thing now too and when turned into a string keep this b in front', type(b' bytes for storing data'))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Generators vs. Lists vs. Tuples\n",
    "<a id='generator_list_explanation'></a>\n",
    "\n",
    "This is a pain in the rear of a change. As the python vision is to be as explicit as possible and make objects for everything, Python3 is extremely explicit on what things are what objects and there are a lot more objects. For instance in Python2 range(4) returns a list [0,1,2,3] where as in Python3 range(4) returns a range object which is iterable and decended from the generator class, but does not have the same methods as a list so you cannot try append to it, and has more methods than the generator class."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "python3 range output\n",
      "range(0, 4) <class 'range'> \n",
      "\n",
      "casting range object to list to simulate python2 output\n",
      "[0, 1, 2, 3] <class 'list'>\n"
     ]
    }
   ],
   "source": [
    "print(\"python3 range output\")\n",
    "p3r=range(4)\n",
    "print(p3r,type(p3r),'\\n')\n",
    "\n",
    "print(\"casting range object to list to simulate python2 output\")\n",
    "p2r=list(range(4))\n",
    "print(p2r,type(p2r))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "python3 map output\n",
      "<map object at 0x7f08ec5a8630> <class 'map'>\n",
      "[1, 2, 3, 4] <class 'list'> \n",
      "\n",
      "python3 filter output\n",
      "<filter object at 0x7f08ec5a8828> <class 'filter'>\n",
      "[0, 2] <class 'list'> \n",
      "\n",
      "python3 dictionary methods with new classes for output\n",
      "{'thing3': 3.75, 'thing1': 1, 'thing2': 'hello world', 5.47: 'another value'} <class 'dict'> \n",
      "\n",
      "dict_keys(['thing3', 'thing1', 'thing2', 5.47]) <class 'dict_keys'>\n",
      "['thing3', 'thing1', 'thing2', 5.47] <class 'list'> \n",
      "\n",
      "dict_values([3.75, 1, 'hello world', 'another value']) <class 'dict_values'>\n",
      "[3.75, 1, 'hello world', 'another value'] <class 'list'> \n",
      "\n",
      "dict_items([('thing3', 3.75), ('thing1', 1), ('thing2', 'hello world'), (5.47, 'another value')]) <class 'dict_items'>\n",
      "[('thing3', 3.75), ('thing1', 1), ('thing2', 'hello world'), (5.47, 'another value')] <class 'list'> \n",
      "\n"
     ]
    }
   ],
   "source": [
    "#Other examples\n",
    "\n",
    "print(\"python3 map output\")\n",
    "p3m = map(lambda x: x+1, range(4))\n",
    "print(p3m, type(p3m))\n",
    "print(list(p3m),type(list(p3m)),'\\n')\n",
    "\n",
    "print(\"python3 filter output\")\n",
    "p3f = filter(lambda x: (x%2)==0, range(4))\n",
    "print(p3f, type(p3f))\n",
    "print(list(p3f),type(list(p3f)),'\\n')\n",
    "\n",
    "print(\"python3 dictionary methods with new classes for output\")\n",
    "p3d = {\"thing1\": 1, \"thing2\": \"hello world\", \"thing3\": 3.75, 5.47: \"another value\"}\n",
    "print(p3d, type(p3d),'\\n')\n",
    "\n",
    "p3dk = p3d.keys()\n",
    "p3dv = p3d.values()\n",
    "p3di = p3d.items()\n",
    "\n",
    "print(p3dk, type(p3dk))\n",
    "print(list(p3dk),type(list(p3dk)),'\\n')\n",
    "\n",
    "print(p3dv, type(p3dv))\n",
    "print(list(p3dv),type(list(p3dv)),'\\n')\n",
    "\n",
    "print(p3di, type(p3di))\n",
    "print(list(p3di),type(list(p3di)),'\\n')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Explination of the difference between Generators, Lists, and Tuples\n",
    "\n",
    "**Note:** If you plan to just turn all of the new above mentioned data types into lists then you can probably safely skip this, but the bellow ilistrates important distinctions between the different iterable types in both Python2 and Python3 and should help you write clearer code with the right objects used for all cases.\n",
    "\n",
    "This difference brings up a conversation on the 3 different types of objects which contains sets of data as they can be found in both Python2 and Python3: generators, lists, and tuples. Generators are objects which have a current state and a defined next operation (i.e. x=0, x+1) this allows you to define infinite sets or large sets without storing all the data in memory. Lists are built-in arrays which contain each piece of data in RAM and can access them as requested by the user (i.e. [0,2,3,4,5]), most importantly lists are mutable so their values can be changed even in different namespaces than they were created. Tuples are nearly identical to lists, however, they are imutable and they must be recreated to change even a single value. This distinction is more important in Python3 than Python2 as many of the data types returned from the built-in functions above are decended from the generator class or the tuple class instead of just returning a list as Python2 does. Here are some examples of a basic generator, list, and tuple."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<generator object make_gen at 0x7f08ec5954c8> <class 'generator'>\n",
      "0\n",
      "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\n",
      "21\n",
      "True \n",
      "\n",
      "range(0, 20) <class 'range'>\n",
      "0\n",
      "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]\n",
      "0\n",
      "False \n",
      "\n"
     ]
    }
   ],
   "source": [
    "def make_gen():\n",
    "    x=0\n",
    "    while True:\n",
    "        yield x\n",
    "        x+=1\n",
    "gen=make_gen() #makes a generator that returns all non-negative integers\n",
    "print(gen, type(gen))\n",
    "print(next(gen)) #note in Python2 this was done gen.next() though in Python3 next is an external function not a method\n",
    "print([next(gen) for _ in range(20)])\n",
    "print(next(gen))\n",
    "print(hasattr(gen,'__next__'),'\\n')\n",
    "\n",
    "ran20 = range(20) #returns a range object which is related to a generator, but different as it has no next, remembers data, and can be indexed\n",
    "print(ran20, type(ran20))\n",
    "print(ran20[0])\n",
    "print(list(ran20))\n",
    "print(ran20[0])\n",
    "print(hasattr(ran20,'__next__'),'\\n') #this means you can't call next(ran20)\n",
    "#manipulating this object and remembering it's difference is often quite a pain so it is sometimes better to just turn it into a list\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A =  [0, 1, 2, 3, 4]\n",
      "B =  [0, 1, 2, 3, 4]\n",
      "C =  [0, 1, 2, 3, 4] \n",
      "\n",
      "A =  ['haha', 1, 2, 3, 4]\n",
      "B =  ['haha', 1, 2, 3, 4]\n",
      "C =  [0, 1, 2, 3, 4] \n",
      "\n",
      "A =  ['haha', 1, 5.938, 3, 4]\n",
      "B =  ['haha', 1, 5.938, 3, 4]\n",
      "C =  [0, 1, 2, 3, 4] \n",
      "\n",
      "A =  ['haha', 1, 5.938, 3, 4]\n",
      "B =  ['haha', 1, 5.938, 3, 4]\n",
      "C =  [0, 1, 2, 3, True] \n",
      "\n",
      "A is B:  True\n",
      "A is C:  False\n",
      "A==B==C:  True\n"
     ]
    }
   ],
   "source": [
    "#This is meant to demonstrate how lists mutate and show the difference betweeen tuples and lists\n",
    "A = list(range(5)) #creates a list of the first 5 non-negative integers\n",
    "B = A #makes B point to A\n",
    "C = list(A) #makes a copy of A in C\n",
    "print(\"A = \", A)\n",
    "print(\"B = \", B)\n",
    "print(\"C = \", C, '\\n')\n",
    "\n",
    "B[0] = \"haha\" #Notice how a change to B also changes A\n",
    "print(\"A = \", A)\n",
    "print(\"B = \", B)\n",
    "print(\"C = \", C, '\\n')\n",
    "\n",
    "A[2] = 5.938 #and vice versa\n",
    "print(\"A = \", A)\n",
    "print(\"B = \", B)\n",
    "print(\"C = \", C, '\\n')\n",
    "\n",
    "C[4] = True #Though C which is a copy not a pointer is not changed\n",
    "print(\"A = \", A)\n",
    "print(\"B = \", B)\n",
    "print(\"C = \", C, '\\n')\n",
    "\n",
    "#you can check these kind of things using the \"is\" statement without needing to go through all the above changes\n",
    "\n",
    "A = list(range(5)) #creates a list of the first 5 non-negative integers\n",
    "B = A #makes B point to A\n",
    "C = list(A) #makes a copy of A in C\n",
    "\n",
    "print(\"A is B: \", A is B)\n",
    "print(\"A is C: \", A is C)\n",
    "print(\"A==B==C: \", A==B==C)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A =  (0, 1, 2, 3, 4)\n",
      "B =  (0, 1, 2, 3, 4)\n",
      "C =  (0, 1, 2, 3, 4) \n",
      "\n",
      "A is B:  True\n",
      "A is C:  True\n",
      "A==B==C:  True\n"
     ]
    },
    {
     "ename": "TypeError",
     "evalue": "'tuple' object does not support item assignment",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-78-67ccc7d4566f>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m     12\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"A==B==C: \"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mA\u001b[0m\u001b[0;34m==\u001b[0m\u001b[0mB\u001b[0m\u001b[0;34m==\u001b[0m\u001b[0mC\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     13\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 14\u001b[0;31m \u001b[0mB\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"haha\"\u001b[0m \u001b[0;31m#And ERROR, because you can't do this to a tuple which prevents the headache above from developing\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment"
     ]
    }
   ],
   "source": [
    "#Trying the above exercise again with Tuples to demonstrate immutability\n",
    "A = tuple(range(5)) #creates a list of the first 5 non-negative integers\n",
    "B = A #makes B point to A\n",
    "C = tuple(A) #makes C point to A (doesn't copy because it doesn't have to as tuples can't be changed)\n",
    "print(\"A = \", A)\n",
    "print(\"B = \", B)\n",
    "print(\"C = \", C, '\\n')\n",
    "\n",
    "#again we can use is to determine what is a copy and what is identical\n",
    "print(\"A is B: \", A is B)\n",
    "print(\"A is C: \", A is C) #in this case all are identical as there is no need to make a copy of a tuple as it can't change\n",
    "print(\"A==B==C: \", A==B==C)\n",
    "\n",
    "B[0] = \"haha\" #And ERROR, because you can't do this to a tuple which prevents the headache above from developing"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### input vs. raw_input\n",
    "<a id='input_explanation'></a>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Division\n",
    "<a id='division_explanation'></a>\n",
    "\n",
    "This is a rather subtle change to Python and can often go unnoticed as it doesn't raise an error. The main change is that in Python2 int/int = int every time, however in python3 int/int = int_or_float. Here are some various examples of both division (/) and whole number division (//)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "3 / 2 = 1\n",
      "3 // 2 = 1\n",
      "3 / 2.0 = 1.5\n",
      "3 // 2.0 = 1.0\n",
      "\n"
     ]
    }
   ],
   "source": [
    "#Python2 example output\n",
    "\n",
    "example=\\\n",
    "\"\"\"\n",
    "3 / 2 = 1\n",
    "3 // 2 = 1\n",
    "3 / 2.0 = 1.5\n",
    "3 // 2.0 = 1.0\n",
    "\"\"\"\n",
    "\n",
    "print(example)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3 / 2 = 1.5\n",
      "3 // 2 = 1\n",
      "3 / 2.0 = 1.5\n",
      "3 // 2.0 = 1.0\n"
     ]
    }
   ],
   "source": [
    "#Python3 test of Python2 example code\n",
    "\n",
    "print(\"3 / 2 =\", 3 / 2)\n",
    "print(\"3 // 2 =\", 3 // 2)\n",
    "print(\"3 / 2.0 =\", 3 / 2.0)\n",
    "print(\"3 // 2.0 =\", 3 // 2.0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='converting_python2'></a>\n",
    "## Converting Python2 Code\n",
    "\n",
    "If you already have a script or function you would like to have incorporated into PmagPy and need it converted into Python3 or Python2/3 here are a few links with explanations of this process.\n",
    "\n",
    "[Python2 to Python2/3](http://python-future.org/futurize.html) This is the appropriate action if you have a command line script or a library function you would like to contribute.\n",
    "\n",
    "[Python2 to Python3](https://docs.python.org/2/library/2to3.html) This is the correct method to use if you have any code related to the GUIs or that uses a GUI library like wxpython."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='resources'></a>\n",
    "## Resources\n",
    "\n",
    "- [Python3 Documentation](https://docs.python.org/3/)\n",
    "- [Python2/3 Cheat Sheet](http://python-future.org/compatible_idioms.html)"
   ]
  },
  {
   "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.4.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
{'fraction_non_alphanumeric': 0.1878314152166228, 'fraction_numerical': 0.0551474920460348, 'mean_word_length': 2.6861155349645287, 'pattern_counts': {'":': 200, '<': 53, '<?xml version=': 0, '>': 55, 'https://': 2, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 7, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2345992', 'n_tokens_mistral': 10308, 'n_tokens_neox': 9443, 'n_words': 2667}