diff --git a/.project b/.project new file mode 100644 index 00000000..afb89d22 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + IPP + + + + + + org.python.pydev.PyDevBuilder + + + + + + org.python.pydev.pythonNature + + diff --git a/.pydevproject b/.pydevproject new file mode 100644 index 00000000..b7acad2c --- /dev/null +++ b/.pydevproject @@ -0,0 +1,10 @@ + + + + + +/IPP + +python 2.7 +Default + diff --git a/assignments/week01/athome/addserver.py b/assignments/week01/athome/addserver.py new file mode 100644 index 00000000..c5ba4eca --- /dev/null +++ b/assignments/week01/athome/addserver.py @@ -0,0 +1,31 @@ +import socket +import sys + +# Create a TCP/IP socket +#aserver = socket.socket( 2, 1, 0) #Edit due to class example +aserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_IP) + +# Bind the socket to the port +server_address = ('127.0.0.1', 50000) +aserver.bind(server_address) +# Listen for incoming connections +aserver.listen(2) #listen(num) is the number of sequential connections allowed + +while True: +# Wait for a connection + con, cli = aserver.accept() + + try: + # Receive the data and send it back + msg = con.recv(1024) + + a, b = (int(msg.split()[0]), int(msg.split()[1])) + thesum = str(a + b) + out = con.sendall(thesum) + + finally: + # Clean up the connection + con.close() + +aserver.close() + \ No newline at end of file diff --git a/assignments/week01/athome/client.py b/assignments/week01/athome/client.py new file mode 100644 index 00000000..e4f4beb8 --- /dev/null +++ b/assignments/week01/athome/client.py @@ -0,0 +1,26 @@ +import socket +import sys + +# Create a TCP/IP socket +client = socket.socket(2,1,0) +# Connect the socket to the port where the server is listening +server_address = ('127.0.0.1', 50000) +#server_address = ('208.85.148.104',50000) +#server_address = ('block647050-tha.blueboxgrid.com',50000) + +client.connect(server_address) + +try: + # Send data + message = raw_input("Enter two numbers separated by a space: ") + #message = '2 5' + out = client.sendall(message) + response = client.recv(1024) + # print the response + print response + +finally: + # close the socket to clean up + client.close() + + diff --git a/assignments/week01/lab/echo_client.py b/assignments/week01/lab/echo_client.py index b8898436..96e063c8 100644 --- a/assignments/week01/lab/echo_client.py +++ b/assignments/week01/lab/echo_client.py @@ -2,15 +2,23 @@ import sys # Create a TCP/IP socket - +client = socket.socket(2,1,0) # Connect the socket to the port where the server is listening -server_address = ('localhost', 50000) +#server_address = ('127.0.0.1', 50000) +server_address = ('208.85.148.104',50000) +#server_address = ('block647050-tha.blueboxgrid.com',50000) +client.connect(server_address) try: # Send data - message = 'This is the message. It will be repeated.' - + message = 'This is the message. It may be repeated.' + out = client.sendall(message) + response = client.recv(1024) # print the response - + print response + finally: # close the socket to clean up + client.close() + + diff --git a/assignments/week01/lab/echo_server.py b/assignments/week01/lab/echo_server.py index e2c52fc6..22ab3ca0 100644 --- a/assignments/week01/lab/echo_server.py +++ b/assignments/week01/lab/echo_server.py @@ -2,18 +2,25 @@ import sys # Create a TCP/IP socket +aserver = socket.socket( 2, 1, 0) # Bind the socket to the port -server_address = ('localhost', 50000) - +server_address = ('127.0.0.1', 50000) +aserver.bind(server_address) # Listen for incoming connections +aserver.listen(2) #listen(num) is the number of sequential connections allowed while True: - # Wait for a connection - +# Wait for a connection + con, cli = aserver.accept() + try: # Receive the data and send it back - - + msg = con.recv(1024) + print msg + out = con.sendall('YES, received') + finally: # Clean up the connection + con.close() + \ No newline at end of file diff --git a/assignments/week02/lab/Sample_Scene_Balls.jpg b/assignments/week02/lab/Sample_Scene_Balls.jpg new file mode 100644 index 00000000..1c0ccade Binary files /dev/null and b/assignments/week02/lab/Sample_Scene_Balls.jpg differ diff --git a/assignments/week02/lab/favicon.ico b/assignments/week02/lab/favicon.ico new file mode 100644 index 00000000..c1b77883 Binary files /dev/null and b/assignments/week02/lab/favicon.ico differ diff --git a/assignments/week02/lab/http_serve1.py b/assignments/week02/lab/http_serve1.py new file mode 100644 index 00000000..1d16050c --- /dev/null +++ b/assignments/week02/lab/http_serve1.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +import socket +import email + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +def ok_response(body): + return ( "HTTP/1.1 200 OK\r\n" + + "Content-Type: text/html\r\n" + + "Date: %s\r\n"%(email.Utils.formatdate()) + + "\r\n" + + body ) + + + +f = open('tiny_html.html') +html = f.read() + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + data = client.recv(size) + if data: # if the connection was closed there would be no data + print "received: %s, sending back tiny_html"%data + client.send(ok_response(html)) + client.close() \ No newline at end of file diff --git a/assignments/week02/lab/http_serve2.py b/assignments/week02/lab/http_serve2.py new file mode 100644 index 00000000..1d16050c --- /dev/null +++ b/assignments/week02/lab/http_serve2.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +import socket +import email + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +def ok_response(body): + return ( "HTTP/1.1 200 OK\r\n" + + "Content-Type: text/html\r\n" + + "Date: %s\r\n"%(email.Utils.formatdate()) + + "\r\n" + + body ) + + + +f = open('tiny_html.html') +html = f.read() + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + data = client.recv(size) + if data: # if the connection was closed there would be no data + print "received: %s, sending back tiny_html"%data + client.send(ok_response(html)) + client.close() \ No newline at end of file diff --git a/assignments/week02/lab/http_serve3.py b/assignments/week02/lab/http_serve3.py new file mode 100644 index 00000000..57af36b1 --- /dev/null +++ b/assignments/week02/lab/http_serve3.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +import socket +import email + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +def ok_response(body): + return ( "HTTP/1.1 200 OK\r\n" + + "Content-Type: text/html\r\n" + + "Date: %s\r\n"%(email.Utils.formatdate()) + + "\r\n" + + body ) + + +def parse_request(request): + line1 = request.split('\r\n')[0].split() + requesttype = line1[0] + uri = line1[1] + return requesttype, uri + +f = open('tiny_html.html') +html = f.read() + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + data = client.recv(size) + req, uri = parse_request(data) + + print req, uri + + if req != 'GET': + raise ValueError, "The request was not of type GET" + + if data: # if the connection was closed there would be no data + + client.send(html) + client.close() + + + diff --git a/assignments/week02/lab/http_serve4.py b/assignments/week02/lab/http_serve4.py new file mode 100644 index 00000000..5a12db2c --- /dev/null +++ b/assignments/week02/lab/http_serve4.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +import socket +import email, os + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +def ok_response(body): + return ( "HTTP/1.1 200 OK\r\n" + + "Content-Type: text/html\r\n" + + "Date: %s\r\n"%(email.Utils.formatdate()) + + "\r\n" + + body ) + + +def parse_request(request): + line1 = request.split('\r\n')[0].split() + requesttype = line1[0] + uri = line1[1] + return requesttype, uri + +def resolve_uri(uri): + #strip any leading / + if uri.startswith('/'): uri = uri[1:] + #if directory + if os.path.isdir(uri): + list_content = os.listdir(uri) + return ok_response('\r\n'.join(list_content)) + #if a file + #if not found + + else: raise ValueError, 'URI not found' + + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + data = client.recv(size) + req, uri = parse_request(data) + + print req, uri + + if req != 'GET': + raise ValueError, "The request was not of type GET" + + if data: # if the connection was closed there would be no data + print data, '\r\n' + client.send(resolve_uri(uri)) + client.close() + + + diff --git a/assignments/week02/lab/http_serve5.py b/assignments/week02/lab/http_serve5.py new file mode 100644 index 00000000..3ec64355 --- /dev/null +++ b/assignments/week02/lab/http_serve5.py @@ -0,0 +1,69 @@ + #!/usr/bin/env python + +import socket +import email, os, time + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once +headers = {'jpg':'image', 'jpeg':'image', 'gif':'image','png':'image', 'ico':'image', 'html':'html', 'txt':'text'} +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +def ok_response(body, ty='text/html'): + return ( "HTTP/1.1 200 OK\r\n" + #+ "Content-Type: %s\r\n"%ty + + "Date: %s\r\n"%(email.Utils.formatdate()) + + "\r\n" + + body ) + +def parse_request(request): + line1 = request.split('\r\n')[0].split() + requesttype = line1[0] + uri = line1[1] + return requesttype, uri + +def resolve_uri(uri): + #strip any leading / + if uri.startswith('/'): uri = uri[1:] + #if directory + if os.path.isdir(uri): + list_content = os.listdir(uri) + return ok_response('\r\n'.join(list_content)) + #if a file + if os.path.isfile(uri): + ctype = uri.split('.')[-1] + return ok_response(uri, headers[ctype]+'/'+ctype) + + else: raise ValueError, 'URI not found' + + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + + try: + data = client.recv(size) + req, uri = parse_request(data) + + print req, uri + + if req != 'GET': + raise ValueError, "The request was not of type GET" + + if data: # if the connection was closed there would be no data + #print data, '\r\n' + tosend = resolve_uri(uri) + print tosend + client.send(tosend) + client.close() + + except: + time.sleep(0.1) + diff --git a/assignments/week02/lab/test.py b/assignments/week02/lab/test.py new file mode 100644 index 00000000..973121ee --- /dev/null +++ b/assignments/week02/lab/test.py @@ -0,0 +1,53 @@ + #!/usr/bin/env python + +import socket +import email, os, time + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +xx = ''' + + +

This is a header

+

+ and this is some regular text +

+

+ and some more + +

+ + +''' + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + + try: + data = client.recv(size) + + + if data: # if the connection was closed there would be no data + #print data, '\r\n' + print xx + client.send(xx) + client.close() + + except: + time.sleep(0.1) + + + +#balls \ No newline at end of file diff --git a/assignments/week02/lab/tiny_html.html b/assignments/week02/lab/tiny_html.html index 8d4ec08c..d113b802 100755 --- a/assignments/week02/lab/tiny_html.html +++ b/assignments/week02/lab/tiny_html.html @@ -6,6 +6,7 @@

This is a header

and some more + Pulpit rock

diff --git a/assignments/week02/lab/web/Sample_Scene_Balls.jpg b/assignments/week02/lab/web/Sample_Scene_Balls.jpg new file mode 100644 index 00000000..1c0ccade Binary files /dev/null and b/assignments/week02/lab/web/Sample_Scene_Balls.jpg differ diff --git a/assignments/week03/distribute-0.6.31.tar.gz b/assignments/week03/distribute-0.6.31.tar.gz new file mode 100644 index 00000000..a8257463 Binary files /dev/null and b/assignments/week03/distribute-0.6.31.tar.gz differ diff --git a/assignments/week03/find_feeds.py b/assignments/week03/find_feeds.py new file mode 100644 index 00000000..026e7eb5 --- /dev/null +++ b/assignments/week03/find_feeds.py @@ -0,0 +1,55 @@ +fh = open('C:\\Users\\Tyler\\bloglist.html') +from bs4 import BeautifulSoup + +parsed = BeautifulSoup(fh) + + + +'''' + +for e in entries: + anchor = e.find('a') + paragraph = e.find('p', 'discreet') + title = anchor.text.strip() + url = anchor.attrs['href'] + print title + print url + try: + print paragraph.text.strip() + except AttributeError: + print 'Uncategorized' + print + ''' + +def my_function(parsed): + '''parse out url and title of entry, add to list dependent on topic''' + pgsql = [] + django = [] + other = [] + + entries = parsed.find_all('div', class_='feedEntry') + print len(entries), 'entries' + + for xx in entries: + anchor = xx.find('a') + url = anchor.attrs['href'] + title = anchor.attrs['title'] + paragraph = xx.find('p', 'discreet').text.strip() + + print type(paragraph) + + if 'Postgre' in paragraph: + pgsql.append({'title':title, 'url':url}) + elif 'Django' in paragraph: + django.append({'title':title, 'url':url}) + else: other.append({'title':title, 'url':url}) + + return pgsql, django, other + + +a, b, c = my_function(parsed) +print a +print +print b +print +print c \ No newline at end of file diff --git a/assignments/week03/geocoding.py b/assignments/week03/geocoding.py new file mode 100644 index 00000000..312e9d78 --- /dev/null +++ b/assignments/week03/geocoding.py @@ -0,0 +1,15 @@ +import urllib +import urllib2 +from pprint import pprint +import json + +base = 'http://maps.googleapis.com/maps/api/geocode/json' +addr = '1325 4th Ave, Seattle, WA 98101' +data = {'address': addr, 'sensor': 'false' } + +query = urllib.urlencode(data) +print data +print json.dumps(data) +res = urllib2.urlopen('?'.join([base, query])) +response = json.load(res) +pprint(response) \ No newline at end of file diff --git a/assignments/week03/soupenv/Scripts/activate b/assignments/week03/soupenv/Scripts/activate new file mode 100644 index 00000000..0f00e3da --- /dev/null +++ b/assignments/week03/soupenv/Scripts/activate @@ -0,0 +1,80 @@ +# This file must be used with "source bin/activate" *from bash* +# you cannot run it directly + +deactivate () { + unset pydoc + + # reset old environment variables + if [ -n "$_OLD_VIRTUAL_PATH" ] ; then + PATH="$_OLD_VIRTUAL_PATH" + export PATH + unset _OLD_VIRTUAL_PATH + fi + if [ -n "$_OLD_VIRTUAL_PYTHONHOME" ] ; then + PYTHONHOME="$_OLD_VIRTUAL_PYTHONHOME" + export PYTHONHOME + unset _OLD_VIRTUAL_PYTHONHOME + fi + + # This should detect bash and zsh, which have a hash command that must + # be called to get it to forget past commands. Without forgetting + # past commands the $PATH changes we made may not be respected + if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then + hash -r 2>/dev/null + fi + + if [ -n "$_OLD_VIRTUAL_PS1" ] ; then + PS1="$_OLD_VIRTUAL_PS1" + export PS1 + unset _OLD_VIRTUAL_PS1 + fi + + unset VIRTUAL_ENV + if [ ! "$1" = "nondestructive" ] ; then + # Self destruct! + unset -f deactivate + fi +} + +# unset irrelevant variables +deactivate nondestructive + +VIRTUAL_ENV="$(if [ "$OSTYPE" "==" "cygwin" ]; then cygpath -u 'C:\Users\Tyler\training.python_web\assignments\week03\soupenv'; else echo '/C/Users/Tyler/training.python_web/assignments/week03/soupenv'; fi;)" +export VIRTUAL_ENV + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/Scripts:$PATH" +export PATH + +# unset PYTHONHOME if set +# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) +# could use `if (set -u; : $PYTHONHOME) ;` in bash +if [ -n "$PYTHONHOME" ] ; then + _OLD_VIRTUAL_PYTHONHOME="$PYTHONHOME" + unset PYTHONHOME +fi + +if [ -z "$VIRTUAL_ENV_DISABLE_PROMPT" ] ; then + _OLD_VIRTUAL_PS1="$PS1" + if [ "x" != x ] ; then + PS1="$PS1" + else + if [ "`basename \"$VIRTUAL_ENV\"`" = "__" ] ; then + # special case for Aspen magic directories + # see http://www.zetadev.com/software/aspen/ + PS1="[`basename \`dirname \"$VIRTUAL_ENV\"\``] $PS1" + else + PS1="(`basename \"$VIRTUAL_ENV\"`)$PS1" + fi + fi + export PS1 +fi + +alias pydoc="python -m pydoc" + +# This should detect bash and zsh, which have a hash command that must +# be called to get it to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then + hash -r 2>/dev/null +fi diff --git a/assignments/week03/soupenv/Scripts/activate.bat b/assignments/week03/soupenv/Scripts/activate.bat new file mode 100644 index 00000000..ff29cb29 --- /dev/null +++ b/assignments/week03/soupenv/Scripts/activate.bat @@ -0,0 +1,26 @@ +@echo off +set "VIRTUAL_ENV=C:\Users\Tyler\training.python_web\assignments\week03\soupenv" + +if defined _OLD_VIRTUAL_PROMPT ( + set "PROMPT=%_OLD_VIRTUAL_PROMPT%" +) else ( + if not defined PROMPT ( + set "PROMPT=$P$G" + ) + set "_OLD_VIRTUAL_PROMPT=%PROMPT%" +) +set "PROMPT=(soupenv) %PROMPT%" + +if not defined _OLD_VIRTUAL_PYTHONHOME ( + set "_OLD_VIRTUAL_PYTHONHOME=%PYTHONHOME%" +) +set PYTHONHOME= + +if defined _OLD_VIRTUAL_PATH ( + set "PATH=%_OLD_VIRTUAL_PATH%" +) else ( + set "_OLD_VIRTUAL_PATH=%PATH%" +) +set "PATH=%VIRTUAL_ENV%\Scripts;%PATH%" + +:END diff --git a/assignments/week03/soupenv/Scripts/activate.ps1 b/assignments/week03/soupenv/Scripts/activate.ps1 new file mode 100644 index 00000000..e40ca1bf --- /dev/null +++ b/assignments/week03/soupenv/Scripts/activate.ps1 @@ -0,0 +1,148 @@ +# This file must be dot sourced from PoSh; you cannot run it +# directly. Do this: . ./activate.ps1 + +# FIXME: clean up unused vars. +$script:THIS_PATH = $myinvocation.mycommand.path +$script:BASE_DIR = split-path (resolve-path "$THIS_PATH/..") -Parent +$script:DIR_NAME = split-path $BASE_DIR -Leaf + +function global:deactivate ( [switch] $NonDestructive ){ + + if ( test-path variable:_OLD_VIRTUAL_PATH ) { + $env:PATH = $variable:_OLD_VIRTUAL_PATH + remove-variable "_OLD_VIRTUAL_PATH" -scope global + } + + if ( test-path function:_old_virtual_prompt ) { + $function:prompt = $function:_old_virtual_prompt + remove-item function:\_old_virtual_prompt + } + + if ($env:VIRTUAL_ENV) { + $old_env = split-path $env:VIRTUAL_ENV -leaf + remove-item env:VIRTUAL_ENV -erroraction silentlycontinue + } + + if ( !$NonDestructive ) { + # Self destruct! + remove-item function:deactivate + } +} + +# unset irrelevant variables +deactivate -nondestructive + +$VIRTUAL_ENV = $BASE_DIR +$env:VIRTUAL_ENV = $VIRTUAL_ENV + +$global:_OLD_VIRTUAL_PATH = $env:PATH +$env:PATH = "$env:VIRTUAL_ENV/Scripts;" + $env:PATH +function global:_old_virtual_prompt { "" } +$function:_old_virtual_prompt = $function:prompt +function global:prompt { + # Add a prefix to the current prompt, but don't discard it. + write-host "($(split-path $env:VIRTUAL_ENV -leaf)) " -nonewline + & $function:_old_virtual_prompt +} + +# SIG # Begin signature block +# MIISeAYJKoZIhvcNAQcCoIISaTCCEmUCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB +# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR +# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUS5reBwSg3zOUwhXf2jPChZzf +# yPmggg6tMIIGcDCCBFigAwIBAgIBJDANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQG +# EwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERp +# Z2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2Vy +# dGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDcxMDI0MjIwMTQ2WhcNMTcxMDI0MjIw +# MTQ2WjCBjDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzAp +# BgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxODA2BgNV +# BAMTL1N0YXJ0Q29tIENsYXNzIDIgUHJpbWFyeSBJbnRlcm1lZGlhdGUgT2JqZWN0 +# IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyiOLIjUemqAbPJ1J +# 0D8MlzgWKbr4fYlbRVjvhHDtfhFN6RQxq0PjTQxRgWzwFQNKJCdU5ftKoM5N4YSj +# Id6ZNavcSa6/McVnhDAQm+8H3HWoD030NVOxbjgD/Ih3HaV3/z9159nnvyxQEckR +# ZfpJB2Kfk6aHqW3JnSvRe+XVZSufDVCe/vtxGSEwKCaNrsLc9pboUoYIC3oyzWoU +# TZ65+c0H4paR8c8eK/mC914mBo6N0dQ512/bkSdaeY9YaQpGtW/h/W/FkbQRT3sC +# pttLVlIjnkuY4r9+zvqhToPjxcfDYEf+XD8VGkAqle8Aa8hQ+M1qGdQjAye8OzbV +# uUOw7wIDAQABo4IB6TCCAeUwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +# AQYwHQYDVR0OBBYEFNBOD0CZbLhLGW87KLjg44gHNKq3MB8GA1UdIwQYMBaAFE4L +# 7xqkQFulF2mHMMo0aEPQQa7yMD0GCCsGAQUFBwEBBDEwLzAtBggrBgEFBQcwAoYh +# aHR0cDovL3d3dy5zdGFydHNzbC5jb20vc2ZzY2EuY3J0MFsGA1UdHwRUMFIwJ6Al +# oCOGIWh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3Nmc2NhLmNybDAnoCWgI4YhaHR0 +# cDovL2NybC5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMIGABgNVHSAEeTB3MHUGCysG +# AQQBgbU3AQIBMGYwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29t +# L3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t +# L2ludGVybWVkaWF0ZS5wZGYwEQYJYIZIAYb4QgEBBAQDAgABMFAGCWCGSAGG+EIB +# DQRDFkFTdGFydENvbSBDbGFzcyAyIFByaW1hcnkgSW50ZXJtZWRpYXRlIE9iamVj +# dCBTaWduaW5nIENlcnRpZmljYXRlczANBgkqhkiG9w0BAQUFAAOCAgEAcnMLA3Va +# N4OIE9l4QT5OEtZy5PByBit3oHiqQpgVEQo7DHRsjXD5H/IyTivpMikaaeRxIv95 +# baRd4hoUcMwDj4JIjC3WA9FoNFV31SMljEZa66G8RQECdMSSufgfDYu1XQ+cUKxh +# D3EtLGGcFGjjML7EQv2Iol741rEsycXwIXcryxeiMbU2TPi7X3elbwQMc4JFlJ4B +# y9FhBzuZB1DV2sN2irGVbC3G/1+S2doPDjL1CaElwRa/T0qkq2vvPxUgryAoCppU +# FKViw5yoGYC+z1GaesWWiP1eFKAL0wI7IgSvLzU3y1Vp7vsYaxOVBqZtebFTWRHt +# XjCsFrrQBngt0d33QbQRI5mwgzEp7XJ9xu5d6RVWM4TPRUsd+DDZpBHm9mszvi9g +# VFb2ZG7qRRXCSqys4+u/NLBPbXi/m/lU00cODQTlC/euwjk9HQtRrXQ/zqsBJS6U +# J+eLGw1qOfj+HVBl/ZQpfoLk7IoWlRQvRL1s7oirEaqPZUIWY/grXq9r6jDKAp3L +# ZdKQpPOnnogtqlU4f7/kLjEJhrrc98mrOWmVMK/BuFRAfQ5oDUMnVmCzAzLMjKfG +# cVW/iMew41yfhgKbwpfzm3LBr1Zv+pEBgcgW6onRLSAn3XHM0eNtz+AkxH6rRf6B +# 2mYhLEEGLapH8R1AMAo4BbVFOZR5kXcMCwowggg1MIIHHaADAgECAgIEuDANBgkq +# hkiG9w0BAQUFADCBjDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0 +# ZC4xKzApBgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcx +# ODA2BgNVBAMTL1N0YXJ0Q29tIENsYXNzIDIgUHJpbWFyeSBJbnRlcm1lZGlhdGUg +# T2JqZWN0IENBMB4XDTExMTIwMzE1MzQxOVoXDTEzMTIwMzE0NTgwN1owgYwxIDAe +# BgNVBA0TFzU4MTc5Ni1HaDd4Zkp4a3hRU0lPNEUwMQswCQYDVQQGEwJERTEPMA0G +# A1UECBMGQmVybGluMQ8wDQYDVQQHEwZCZXJsaW4xFjAUBgNVBAMTDUphbm5pcyBM +# ZWlkZWwxITAfBgkqhkiG9w0BCQEWEmphbm5pc0BsZWlkZWwuaW5mbzCCAiIwDQYJ +# KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMcPeABYdN7nPq/AkZ/EkyUBGx/l2Yui +# Lfm8ZdLG0ulMb/kQL3fRY7sUjYPyn9S6PhqqlFnNoGHJvbbReCdUC9SIQYmOEjEA +# raHfb7MZU10NjO4U2DdGucj2zuO5tYxKizizOJF0e4yRQZVxpUGdvkW/+GLjCNK5 +# L7mIv3Z1dagxDKHYZT74HXiS4VFUwHF1k36CwfM2vsetdm46bdgSwV+BCMmZICYT +# IJAS9UQHD7kP4rik3bFWjUx08NtYYFAVOd/HwBnemUmJe4j3IhZHr0k1+eDG8hDH +# KVvPgLJIoEjC4iMFk5GWsg5z2ngk0LLu3JZMtckHsnnmBPHQK8a3opUNd8hdMNJx +# gOwKjQt2JZSGUdIEFCKVDqj0FmdnDMPfwy+FNRtpBMl1sz78dUFhSrnM0D8NXrqa +# 4rG+2FoOXlmm1rb6AFtpjAKksHRpYcPk2DPGWp/1sWB+dUQkS3gOmwFzyqeTuXpT +# 0juqd3iAxOGx1VRFQ1VHLLf3AzV4wljBau26I+tu7iXxesVucSdsdQu293jwc2kN +# xK2JyHCoZH+RyytrwS0qw8t7rMOukU9gwP8mn3X6mgWlVUODMcHTULjSiCEtvyZ/ +# aafcwjUbt4ReEcnmuZtWIha86MTCX7U7e+cnpWG4sIHPnvVTaz9rm8RyBkIxtFCB +# nQ3FnoQgyxeJAgMBAAGjggOdMIIDmTAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIH +# gDAuBgNVHSUBAf8EJDAiBggrBgEFBQcDAwYKKwYBBAGCNwIBFQYKKwYBBAGCNwoD +# DTAdBgNVHQ4EFgQUWyCgrIWo8Ifvvm1/YTQIeMU9nc8wHwYDVR0jBBgwFoAU0E4P +# QJlsuEsZbzsouODjiAc0qrcwggIhBgNVHSAEggIYMIICFDCCAhAGCysGAQQBgbU3 +# AQICMIIB/zAuBggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNzbC5jb20vcG9s +# aWN5LnBkZjA0BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFydHNzbC5jb20vaW50 +# ZXJtZWRpYXRlLnBkZjCB9wYIKwYBBQUHAgIwgeowJxYgU3RhcnRDb20gQ2VydGlm +# aWNhdGlvbiBBdXRob3JpdHkwAwIBARqBvlRoaXMgY2VydGlmaWNhdGUgd2FzIGlz +# c3VlZCBhY2NvcmRpbmcgdG8gdGhlIENsYXNzIDIgVmFsaWRhdGlvbiByZXF1aXJl +# bWVudHMgb2YgdGhlIFN0YXJ0Q29tIENBIHBvbGljeSwgcmVsaWFuY2Ugb25seSBm +# b3IgdGhlIGludGVuZGVkIHB1cnBvc2UgaW4gY29tcGxpYW5jZSBvZiB0aGUgcmVs +# eWluZyBwYXJ0eSBvYmxpZ2F0aW9ucy4wgZwGCCsGAQUFBwICMIGPMCcWIFN0YXJ0 +# Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MAMCAQIaZExpYWJpbGl0eSBhbmQg +# d2FycmFudGllcyBhcmUgbGltaXRlZCEgU2VlIHNlY3Rpb24gIkxlZ2FsIGFuZCBM +# aW1pdGF0aW9ucyIgb2YgdGhlIFN0YXJ0Q29tIENBIHBvbGljeS4wNgYDVR0fBC8w +# LTAroCmgJ4YlaHR0cDovL2NybC5zdGFydHNzbC5jb20vY3J0YzItY3JsLmNybDCB +# iQYIKwYBBQUHAQEEfTB7MDcGCCsGAQUFBzABhitodHRwOi8vb2NzcC5zdGFydHNz +# bC5jb20vc3ViL2NsYXNzMi9jb2RlL2NhMEAGCCsGAQUFBzAChjRodHRwOi8vYWlh +# LnN0YXJ0c3NsLmNvbS9jZXJ0cy9zdWIuY2xhc3MyLmNvZGUuY2EuY3J0MCMGA1Ud +# EgQcMBqGGGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tLzANBgkqhkiG9w0BAQUFAAOC +# AQEAhrzEV6zwoEtKjnFRhCsjwiPykVpo5Eiye77Ve801rQDiRKgSCCiW6g3HqedL +# OtaSs65Sj2pm3Viea4KR0TECLcbCTgsdaHqw2x1yXwWBQWZEaV6EB05lIwfr94P1 +# SFpV43zkuc+bbmA3+CRK45LOcCNH5Tqq7VGTCAK5iM7tvHwFlbQRl+I6VEL2mjpF +# NsuRjDOVrv/9qw/a22YJ9R7Y1D0vUSs3IqZx2KMUaYDP7H2mSRxJO2nADQZBtriF +# gTyfD3lYV12MlIi5CQwe3QC6DrrfSMP33i5Wa/OFJiQ27WPxmScYVhiqozpImFT4 +# PU9goiBv9RKXdgTmZE1PN0NQ5jGCAzUwggMxAgEBMIGTMIGMMQswCQYDVQQGEwJJ +# TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0 +# YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg +# MiBQcmltYXJ5IEludGVybWVkaWF0ZSBPYmplY3QgQ0ECAgS4MAkGBSsOAwIaBQCg +# eDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEE +# AYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJ +# BDEWBBRVGw0FDSiaIi38dWteRUAg/9Pr6DANBgkqhkiG9w0BAQEFAASCAgCInvOZ +# FdaNFzbf6trmFDZKMojyx3UjKMCqNjHVBbuKY0qXwFC/ElYDV1ShJ2CBZbdurydO +# OQ6cIQ0KREOCwmX/xB49IlLHHUxNhEkVv7HGU3EKAFf9IBt9Yr7jikiR9cjIsfHK +# 4cjkoKJL7g28yEpLLkHt1eo37f1Ga9lDWEa5Zq3U5yX+IwXhrUBm1h8Xr033FhTR +# VEpuSz6LHtbrL/zgJnCzJ2ahjtJoYevdcWiNXffosJHFaSfYDDbiNsPRDH/1avmb +# 5j/7BhP8BcBaR6Fp8tFbNGIcWHHGcjqLMnTc4w13b7b4pDhypqElBa4+lCmwdvv9 +# GydYtRgPz8GHeoBoKj30YBlMzRIfFYaIFGIC4Ai3UEXkuH9TxYohVbGm/W0Kl4Lb +# RJ1FwiVcLcTOJdgNId2vQvKc+jtNrjcg5SP9h2v/C4aTx8tyc6tE3TOPh2f9b8DL +# S+SbVArJpuJqrPTxDDoO1QNjTgLcdVYeZDE+r/NjaGZ6cMSd8db3EaG3ijD/0bud +# SItbm/OlNVbQOFRR76D+ZNgPcU5iNZ3bmvQQIg6aSB9MHUpIE/SeCkNl9YeVk1/1 +# GFULgNMRmIYP4KLvu9ylh5Gu3hvD5VNhH6+FlXANwFy07uXks5uF8mfZVxVCnodG +# xkNCx+6PsrA5Z7WP4pXcmYnMn97npP/Q9EHJWw== +# SIG # End signature block diff --git a/assignments/week03/soupenv/Scripts/activate_this.py b/assignments/week03/soupenv/Scripts/activate_this.py new file mode 100644 index 00000000..ea12c28a --- /dev/null +++ b/assignments/week03/soupenv/Scripts/activate_this.py @@ -0,0 +1,34 @@ +"""By using execfile(this_file, dict(__file__=this_file)) you will +activate this virtualenv environment. + +This can be used when you must use an existing Python interpreter, not +the virtualenv bin/python +""" + +try: + __file__ +except NameError: + raise AssertionError( + "You must run this like execfile('path/to/activate_this.py', dict(__file__='path/to/activate_this.py'))") +import sys +import os + +old_os_path = os.environ['PATH'] +os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + os.pathsep + old_os_path +base = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +if sys.platform == 'win32': + site_packages = os.path.join(base, 'Lib', 'site-packages') +else: + site_packages = os.path.join(base, 'lib', 'python%s' % sys.version[:3], 'site-packages') +prev_sys_path = list(sys.path) +import site +site.addsitedir(site_packages) +sys.real_prefix = sys.prefix +sys.prefix = base +# Move the added items to the front of the path: +new_sys_path = [] +for item in list(sys.path): + if item not in prev_sys_path: + new_sys_path.append(item) + sys.path.remove(item) +sys.path[:0] = new_sys_path diff --git a/assignments/week03/soupenv/Scripts/deactivate.bat b/assignments/week03/soupenv/Scripts/deactivate.bat new file mode 100644 index 00000000..52aabe5e --- /dev/null +++ b/assignments/week03/soupenv/Scripts/deactivate.bat @@ -0,0 +1,18 @@ +@echo off + +if defined _OLD_VIRTUAL_PROMPT ( + set "PROMPT=%_OLD_VIRTUAL_PROMPT%" + set _OLD_VIRTUAL_PROMPT= +) + +if defined _OLD_VIRTUAL_PYTHONHOME ( + set "PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME%" + set _OLD_VIRTUAL_PYTHONHOME= +) + +if defined _OLD_VIRTUAL_PATH ( + set "PATH=%_OLD_VIRTUAL_PATH%" + set _OLD_VIRTUAL_PATH= +) + +:END diff --git a/assignments/week03/soupenv/Scripts/easy_install-2.7-script.py b/assignments/week03/soupenv/Scripts/easy_install-2.7-script.py new file mode 100644 index 00000000..6b7ab961 --- /dev/null +++ b/assignments/week03/soupenv/Scripts/easy_install-2.7-script.py @@ -0,0 +1,10 @@ +#!C:\Users\Tyler\training.python_web\assignments\week03\soupenv\Scripts\python.exe +# EASY-INSTALL-ENTRY-SCRIPT: 'distribute==0.6.31','console_scripts','easy_install-2.7' +__requires__ = 'distribute==0.6.31' +import sys +from pkg_resources import load_entry_point + +if __name__ == '__main__': + sys.exit( + load_entry_point('distribute==0.6.31', 'console_scripts', 'easy_install-2.7')() + ) diff --git a/assignments/week03/soupenv/Scripts/easy_install-2.7.exe b/assignments/week03/soupenv/Scripts/easy_install-2.7.exe new file mode 100644 index 00000000..9b7717b7 Binary files /dev/null and b/assignments/week03/soupenv/Scripts/easy_install-2.7.exe differ diff --git a/assignments/week03/soupenv/Scripts/easy_install-script.py b/assignments/week03/soupenv/Scripts/easy_install-script.py new file mode 100644 index 00000000..77af6a88 --- /dev/null +++ b/assignments/week03/soupenv/Scripts/easy_install-script.py @@ -0,0 +1,10 @@ +#!C:\Users\Tyler\training.python_web\assignments\week03\soupenv\Scripts\python.exe +# EASY-INSTALL-ENTRY-SCRIPT: 'distribute==0.6.31','console_scripts','easy_install' +__requires__ = 'distribute==0.6.31' +import sys +from pkg_resources import load_entry_point + +if __name__ == '__main__': + sys.exit( + load_entry_point('distribute==0.6.31', 'console_scripts', 'easy_install')() + ) diff --git a/assignments/week03/soupenv/Scripts/easy_install.exe b/assignments/week03/soupenv/Scripts/easy_install.exe new file mode 100644 index 00000000..9b7717b7 Binary files /dev/null and b/assignments/week03/soupenv/Scripts/easy_install.exe differ diff --git a/assignments/week03/soupenv/Scripts/ipcluster-script.py b/assignments/week03/soupenv/Scripts/ipcluster-script.py new file mode 100644 index 00000000..739cd816 --- /dev/null +++ b/assignments/week03/soupenv/Scripts/ipcluster-script.py @@ -0,0 +1,10 @@ +#!C:\Users\Tyler\training.python_web\assignments\week03\soupenv\Scripts\python.exe +# EASY-INSTALL-ENTRY-SCRIPT: 'ipython==0.13.1','console_scripts','ipcluster' +__requires__ = 'ipython==0.13.1' +import sys +from pkg_resources import load_entry_point + +if __name__ == '__main__': + sys.exit( + load_entry_point('ipython==0.13.1', 'console_scripts', 'ipcluster')() + ) diff --git a/assignments/week03/soupenv/Scripts/ipcluster.exe b/assignments/week03/soupenv/Scripts/ipcluster.exe new file mode 100644 index 00000000..9b7717b7 Binary files /dev/null and b/assignments/week03/soupenv/Scripts/ipcluster.exe differ diff --git a/assignments/week03/soupenv/Scripts/ipcontroller-script.py b/assignments/week03/soupenv/Scripts/ipcontroller-script.py new file mode 100644 index 00000000..41f8de89 --- /dev/null +++ b/assignments/week03/soupenv/Scripts/ipcontroller-script.py @@ -0,0 +1,10 @@ +#!C:\Users\Tyler\training.python_web\assignments\week03\soupenv\Scripts\python.exe +# EASY-INSTALL-ENTRY-SCRIPT: 'ipython==0.13.1','console_scripts','ipcontroller' +__requires__ = 'ipython==0.13.1' +import sys +from pkg_resources import load_entry_point + +if __name__ == '__main__': + sys.exit( + load_entry_point('ipython==0.13.1', 'console_scripts', 'ipcontroller')() + ) diff --git a/assignments/week03/soupenv/Scripts/ipcontroller.exe b/assignments/week03/soupenv/Scripts/ipcontroller.exe new file mode 100644 index 00000000..9b7717b7 Binary files /dev/null and b/assignments/week03/soupenv/Scripts/ipcontroller.exe differ diff --git a/assignments/week03/soupenv/Scripts/ipengine-script.py b/assignments/week03/soupenv/Scripts/ipengine-script.py new file mode 100644 index 00000000..120311f3 --- /dev/null +++ b/assignments/week03/soupenv/Scripts/ipengine-script.py @@ -0,0 +1,10 @@ +#!C:\Users\Tyler\training.python_web\assignments\week03\soupenv\Scripts\python.exe +# EASY-INSTALL-ENTRY-SCRIPT: 'ipython==0.13.1','console_scripts','ipengine' +__requires__ = 'ipython==0.13.1' +import sys +from pkg_resources import load_entry_point + +if __name__ == '__main__': + sys.exit( + load_entry_point('ipython==0.13.1', 'console_scripts', 'ipengine')() + ) diff --git a/assignments/week03/soupenv/Scripts/ipengine.exe b/assignments/week03/soupenv/Scripts/ipengine.exe new file mode 100644 index 00000000..9b7717b7 Binary files /dev/null and b/assignments/week03/soupenv/Scripts/ipengine.exe differ diff --git a/assignments/week03/soupenv/Scripts/iplogger-script.py b/assignments/week03/soupenv/Scripts/iplogger-script.py new file mode 100644 index 00000000..fe5ff1b0 --- /dev/null +++ b/assignments/week03/soupenv/Scripts/iplogger-script.py @@ -0,0 +1,10 @@ +#!C:\Users\Tyler\training.python_web\assignments\week03\soupenv\Scripts\python.exe +# EASY-INSTALL-ENTRY-SCRIPT: 'ipython==0.13.1','console_scripts','iplogger' +__requires__ = 'ipython==0.13.1' +import sys +from pkg_resources import load_entry_point + +if __name__ == '__main__': + sys.exit( + load_entry_point('ipython==0.13.1', 'console_scripts', 'iplogger')() + ) diff --git a/assignments/week03/soupenv/Scripts/iplogger.exe b/assignments/week03/soupenv/Scripts/iplogger.exe new file mode 100644 index 00000000..9b7717b7 Binary files /dev/null and b/assignments/week03/soupenv/Scripts/iplogger.exe differ diff --git a/assignments/week03/soupenv/Scripts/iptest-script.py b/assignments/week03/soupenv/Scripts/iptest-script.py new file mode 100644 index 00000000..83bf6450 --- /dev/null +++ b/assignments/week03/soupenv/Scripts/iptest-script.py @@ -0,0 +1,10 @@ +#!C:\Users\Tyler\training.python_web\assignments\week03\soupenv\Scripts\python.exe +# EASY-INSTALL-ENTRY-SCRIPT: 'ipython==0.13.1','console_scripts','iptest' +__requires__ = 'ipython==0.13.1' +import sys +from pkg_resources import load_entry_point + +if __name__ == '__main__': + sys.exit( + load_entry_point('ipython==0.13.1', 'console_scripts', 'iptest')() + ) diff --git a/assignments/week03/soupenv/Scripts/iptest.exe b/assignments/week03/soupenv/Scripts/iptest.exe new file mode 100644 index 00000000..9b7717b7 Binary files /dev/null and b/assignments/week03/soupenv/Scripts/iptest.exe differ diff --git a/assignments/week03/soupenv/Scripts/ipython-script.py b/assignments/week03/soupenv/Scripts/ipython-script.py new file mode 100644 index 00000000..3cfe1f07 --- /dev/null +++ b/assignments/week03/soupenv/Scripts/ipython-script.py @@ -0,0 +1,10 @@ +#!C:\Users\Tyler\training.python_web\assignments\week03\soupenv\Scripts\python.exe +# EASY-INSTALL-ENTRY-SCRIPT: 'ipython==0.13.1','console_scripts','ipython' +__requires__ = 'ipython==0.13.1' +import sys +from pkg_resources import load_entry_point + +if __name__ == '__main__': + sys.exit( + load_entry_point('ipython==0.13.1', 'console_scripts', 'ipython')() + ) diff --git a/assignments/week03/soupenv/Scripts/ipython.exe b/assignments/week03/soupenv/Scripts/ipython.exe new file mode 100644 index 00000000..9b7717b7 Binary files /dev/null and b/assignments/week03/soupenv/Scripts/ipython.exe differ diff --git a/assignments/week03/soupenv/Scripts/irunner-script.py b/assignments/week03/soupenv/Scripts/irunner-script.py new file mode 100644 index 00000000..cd14817e --- /dev/null +++ b/assignments/week03/soupenv/Scripts/irunner-script.py @@ -0,0 +1,10 @@ +#!C:\Users\Tyler\training.python_web\assignments\week03\soupenv\Scripts\python.exe +# EASY-INSTALL-ENTRY-SCRIPT: 'ipython==0.13.1','console_scripts','irunner' +__requires__ = 'ipython==0.13.1' +import sys +from pkg_resources import load_entry_point + +if __name__ == '__main__': + sys.exit( + load_entry_point('ipython==0.13.1', 'console_scripts', 'irunner')() + ) diff --git a/assignments/week03/soupenv/Scripts/irunner.exe b/assignments/week03/soupenv/Scripts/irunner.exe new file mode 100644 index 00000000..9b7717b7 Binary files /dev/null and b/assignments/week03/soupenv/Scripts/irunner.exe differ diff --git a/assignments/week03/soupenv/Scripts/pip-2.7-script.py b/assignments/week03/soupenv/Scripts/pip-2.7-script.py new file mode 100644 index 00000000..f98a697b --- /dev/null +++ b/assignments/week03/soupenv/Scripts/pip-2.7-script.py @@ -0,0 +1,10 @@ +#!C:\Users\Tyler\training.python_web\assignments\week03\soupenv\Scripts\python.exe +# EASY-INSTALL-ENTRY-SCRIPT: 'pip==1.2.1','console_scripts','pip-2.7' +__requires__ = 'pip==1.2.1' +import sys +from pkg_resources import load_entry_point + +if __name__ == '__main__': + sys.exit( + load_entry_point('pip==1.2.1', 'console_scripts', 'pip-2.7')() + ) diff --git a/assignments/week03/soupenv/Scripts/pip-2.7.exe b/assignments/week03/soupenv/Scripts/pip-2.7.exe new file mode 100644 index 00000000..9b7717b7 Binary files /dev/null and b/assignments/week03/soupenv/Scripts/pip-2.7.exe differ diff --git a/assignments/week03/soupenv/Scripts/pip-script.py b/assignments/week03/soupenv/Scripts/pip-script.py new file mode 100644 index 00000000..5bb581b1 --- /dev/null +++ b/assignments/week03/soupenv/Scripts/pip-script.py @@ -0,0 +1,10 @@ +#!C:\Users\Tyler\training.python_web\assignments\week03\soupenv\Scripts\python.exe +# EASY-INSTALL-ENTRY-SCRIPT: 'pip==1.2.1','console_scripts','pip' +__requires__ = 'pip==1.2.1' +import sys +from pkg_resources import load_entry_point + +if __name__ == '__main__': + sys.exit( + load_entry_point('pip==1.2.1', 'console_scripts', 'pip')() + ) diff --git a/assignments/week03/soupenv/Scripts/pip.exe b/assignments/week03/soupenv/Scripts/pip.exe new file mode 100644 index 00000000..9b7717b7 Binary files /dev/null and b/assignments/week03/soupenv/Scripts/pip.exe differ diff --git a/assignments/week03/soupenv/Scripts/pycolor-script.py b/assignments/week03/soupenv/Scripts/pycolor-script.py new file mode 100644 index 00000000..5cabff2c --- /dev/null +++ b/assignments/week03/soupenv/Scripts/pycolor-script.py @@ -0,0 +1,10 @@ +#!C:\Users\Tyler\training.python_web\assignments\week03\soupenv\Scripts\python.exe +# EASY-INSTALL-ENTRY-SCRIPT: 'ipython==0.13.1','console_scripts','pycolor' +__requires__ = 'ipython==0.13.1' +import sys +from pkg_resources import load_entry_point + +if __name__ == '__main__': + sys.exit( + load_entry_point('ipython==0.13.1', 'console_scripts', 'pycolor')() + ) diff --git a/assignments/week03/soupenv/Scripts/pycolor.exe b/assignments/week03/soupenv/Scripts/pycolor.exe new file mode 100644 index 00000000..9b7717b7 Binary files /dev/null and b/assignments/week03/soupenv/Scripts/pycolor.exe differ diff --git a/assignments/week03/soupenv/Scripts/python.exe b/assignments/week03/soupenv/Scripts/python.exe new file mode 100644 index 00000000..f68a605b Binary files /dev/null and b/assignments/week03/soupenv/Scripts/python.exe differ diff --git a/assignments/week03/soupenv/Scripts/pythonw.exe b/assignments/week03/soupenv/Scripts/pythonw.exe new file mode 100644 index 00000000..42f32179 Binary files /dev/null and b/assignments/week03/soupenv/Scripts/pythonw.exe differ diff --git a/assignments/week03/soupenv/share/doc/ipython/examples/core/appconfig.py b/assignments/week03/soupenv/share/doc/ipython/examples/core/appconfig.py new file mode 100644 index 00000000..a6b41c16 --- /dev/null +++ b/assignments/week03/soupenv/share/doc/ipython/examples/core/appconfig.py @@ -0,0 +1,101 @@ +"""A simple example of how to use IPython.config.application.Application. + +This should serve as a simple example that shows how the IPython config +system works. The main classes are: + +* IPython.config.configurable.Configurable +* IPython.config.configurable.SingletonConfigurable +* IPython.config.loader.Config +* IPython.config.application.Application + +To see the command line option help, run this program from the command line:: + + $ python appconfig.py -h + +To make one of your classes configurable (from the command line and config +files) inherit from Configurable and declare class attributes as traits (see +classes Foo and Bar below). To make the traits configurable, you will need +to set the following options: + +* ``config``: set to ``True`` to make the attribute configurable. +* ``shortname``: by default, configurable attributes are set using the syntax + "Classname.attributename". At the command line, this is a bit verbose, so + we allow "shortnames" to be declared. Setting a shortname is optional, but + when you do this, you can set the option at the command line using the + syntax: "shortname=value". +* ``help``: set the help string to display a help message when the ``-h`` + option is given at the command line. The help string should be valid ReST. + +When the config attribute of an Application is updated, it will fire all of +the trait's events for all of the config=True attributes. +""" + +import sys + +from IPython.config.configurable import Configurable +from IPython.config.application import Application +from IPython.utils.traitlets import ( + Bool, Unicode, Int, Float, List, Dict +) + + +class Foo(Configurable): + """A class that has configurable, typed attributes. + + """ + + i = Int(0, config=True, help="The integer i.") + j = Int(1, config=True, help="The integer j.") + name = Unicode(u'Brian', config=True, help="First name.") + + +class Bar(Configurable): + + enabled = Bool(True, config=True, help="Enable bar.") + + +class MyApp(Application): + + name = Unicode(u'myapp') + running = Bool(False, config=True, + help="Is the app running?") + classes = List([Bar, Foo]) + config_file = Unicode(u'', config=True, + help="Load this config file") + + aliases = Dict(dict(i='Foo.i',j='Foo.j',name='Foo.name', running='MyApp.running', + enabled='Bar.enabled', log_level='MyApp.log_level')) + + flags = Dict(dict(enable=({'Bar': {'enabled' : True}}, "Enable Bar"), + disable=({'Bar': {'enabled' : False}}, "Disable Bar"), + debug=({'MyApp':{'log_level':10}}, "Set loglevel to DEBUG") + )) + + def init_foo(self): + # Pass config to other classes for them to inherit the config. + self.foo = Foo(config=self.config) + + def init_bar(self): + # Pass config to other classes for them to inherit the config. + self.bar = Bar(config=self.config) + + def initialize(self, argv=None): + self.parse_command_line(argv) + if self.config_file: + self.load_config_file(self.config_file) + self.init_foo() + self.init_bar() + + def start(self): + print "app.config:" + print self.config + + +def main(): + app = MyApp() + app.initialize() + app.start() + + +if __name__ == "__main__": + main() diff --git a/assignments/week03/soupenv/share/doc/ipython/examples/core/display.py b/assignments/week03/soupenv/share/doc/ipython/examples/core/display.py new file mode 100644 index 00000000..2d5ca500 --- /dev/null +++ b/assignments/week03/soupenv/share/doc/ipython/examples/core/display.py @@ -0,0 +1,27 @@ +"""Code that shows off the IPython display logic. +""" + +from IPython.lib.latextools import latex_to_png +from IPython.core.display import ( + display, display_pretty, display_html, + display_svg, display_json, display_png +) + +class Circle(object): + + def __init__(self, radius): + self.radius = radius + + def _repr_pretty_(self, p, cycle): + p.text(u"\u25CB") + + def _repr_html_(self): + return "

Cirle: radius=%s

" % self.radius + + def _repr_svg_(self): + return """ + +""" + + def _repr_png_(self): + return latex_to_png('$\circle$') diff --git a/assignments/week03/soupenv/share/doc/ipython/examples/core/example-embed-short.py b/assignments/week03/soupenv/share/doc/ipython/examples/core/example-embed-short.py new file mode 100644 index 00000000..09bd449d --- /dev/null +++ b/assignments/week03/soupenv/share/doc/ipython/examples/core/example-embed-short.py @@ -0,0 +1,47 @@ +"""Quick code snippets for embedding IPython into other programs. + +See example-embed.py for full details, this file has the bare minimum code for +cut and paste use once you understand how to use the system.""" + +#--------------------------------------------------------------------------- +# This code loads IPython but modifies a few things if it detects it's running +# embedded in another IPython session (helps avoid confusion) + +try: + get_ipython +except NameError: + banner=exit_msg='' +else: + banner = '*** Nested interpreter ***' + exit_msg = '*** Back in main IPython ***' + +# First import the embed function +from IPython.frontend.terminal.embed import InteractiveShellEmbed +# Now create the IPython shell instance. Put ipshell() anywhere in your code +# where you want it to open. +ipshell = InteractiveShellEmbed(banner1=banner, exit_msg=exit_msg) + +#--------------------------------------------------------------------------- +# This code will load an embeddable IPython shell always with no changes for +# nested embededings. + +from IPython import embed +# Now embed() will open IPython anywhere in the code. + +#--------------------------------------------------------------------------- +# This code loads an embeddable shell only if NOT running inside +# IPython. Inside IPython, the embeddable shell variable ipshell is just a +# dummy function. + +try: + get_ipython +except NameError: + from IPython.frontend.terminal.embed import InteractiveShellEmbed + ipshell = InteractiveShellEmbed() + # Now ipshell() will open IPython anywhere in the code +else: + # Define a dummy ipshell() so the same code doesn't crash inside an + # interactive IPython + def ipshell(): pass + +#******************* End of file ******************** diff --git a/assignments/week03/soupenv/share/doc/ipython/examples/core/example-embed.py b/assignments/week03/soupenv/share/doc/ipython/examples/core/example-embed.py new file mode 100644 index 00000000..43b42788 --- /dev/null +++ b/assignments/week03/soupenv/share/doc/ipython/examples/core/example-embed.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python + +"""An example of how to embed an IPython shell into a running program. + +Please see the documentation in the IPython.Shell module for more details. + +The accompanying file example-embed-short.py has quick code fragments for +embedding which you can cut and paste in your code once you understand how +things work. + +The code in this file is deliberately extra-verbose, meant for learning.""" +from __future__ import print_function + +# The basics to get you going: + +# IPython sets the __IPYTHON__ variable so you can know if you have nested +# copies running. + +# Try running this code both at the command line and from inside IPython (with +# %run example-embed.py) +from IPython.config.loader import Config +try: + get_ipython +except NameError: + nested = 0 + cfg = Config() + prompt_config = cfg.PromptManager + prompt_config.in_template = 'In <\\#>: ' + prompt_config.in2_template = ' .\\D.: ' + prompt_config.out_template = 'Out<\\#>: ' +else: + print("Running nested copies of IPython.") + print("The prompts for the nested copy have been modified") + cfg = Config() + nested = 1 + +# First import the embeddable shell class +from IPython.frontend.terminal.embed import InteractiveShellEmbed + +# Now create an instance of the embeddable shell. The first argument is a +# string with options exactly as you would type them if you were starting +# IPython at the system command line. Any parameters you want to define for +# configuration can thus be specified here. +ipshell = InteractiveShellEmbed(config=cfg, + banner1 = 'Dropping into IPython', + exit_msg = 'Leaving Interpreter, back to program.') + +# Make a second instance, you can have as many as you want. +cfg2 = cfg.copy() +prompt_config = cfg2.PromptManager +prompt_config.in_template = 'In2<\\#>: ' +if not nested: + prompt_config.in_template = 'In2<\\#>: ' + prompt_config.in2_template = ' .\\D.: ' + prompt_config.out_template = 'Out<\\#>: ' +ipshell2 = InteractiveShellEmbed(config=cfg, + banner1 = 'Second IPython instance.') + +print('\nHello. This is printed from the main controller program.\n') + +# You can then call ipshell() anywhere you need it (with an optional +# message): +ipshell('***Called from top level. ' + 'Hit Ctrl-D to exit interpreter and continue program.\n' + 'Note that if you use %kill_embedded, you can fully deactivate\n' + 'This embedded instance so it will never turn on again') + +print('\nBack in caller program, moving along...\n') + +#--------------------------------------------------------------------------- +# More details: + +# InteractiveShellEmbed instances don't print the standard system banner and +# messages. The IPython banner (which actually may contain initialization +# messages) is available as get_ipython().banner in case you want it. + +# InteractiveShellEmbed instances print the following information everytime they +# start: + +# - A global startup banner. + +# - A call-specific header string, which you can use to indicate where in the +# execution flow the shell is starting. + +# They also print an exit message every time they exit. + +# Both the startup banner and the exit message default to None, and can be set +# either at the instance constructor or at any other time with the +# by setting the banner and exit_msg attributes. + +# The shell instance can be also put in 'dummy' mode globally or on a per-call +# basis. This gives you fine control for debugging without having to change +# code all over the place. + +# The code below illustrates all this. + + +# This is how the global banner and exit_msg can be reset at any point +ipshell.banner = 'Entering interpreter - New Banner' +ipshell.exit_msg = 'Leaving interpreter - New exit_msg' + +def foo(m): + s = 'spam' + ipshell('***In foo(). Try %whos, or print s or m:') + print('foo says m = ',m) + +def bar(n): + s = 'eggs' + ipshell('***In bar(). Try %whos, or print s or n:') + print('bar says n = ',n) + +# Some calls to the above functions which will trigger IPython: +print('Main program calling foo("eggs")\n') +foo('eggs') + +# The shell can be put in 'dummy' mode where calls to it silently return. This +# allows you, for example, to globally turn off debugging for a program with a +# single call. +ipshell.dummy_mode = True +print('\nTrying to call IPython which is now "dummy":') +ipshell() +print('Nothing happened...') +# The global 'dummy' mode can still be overridden for a single call +print('\nOverriding dummy mode manually:') +ipshell(dummy=False) + +# Reactivate the IPython shell +ipshell.dummy_mode = False + +print('You can even have multiple embedded instances:') +ipshell2() + +print('\nMain program calling bar("spam")\n') +bar('spam') + +print('Main program finished. Bye!') + +#********************** End of file *********************** diff --git a/assignments/week03/soupenv/share/doc/ipython/examples/core/example-gnuplot.py b/assignments/week03/soupenv/share/doc/ipython/examples/core/example-gnuplot.py new file mode 100644 index 00000000..37aa5b41 --- /dev/null +++ b/assignments/week03/soupenv/share/doc/ipython/examples/core/example-gnuplot.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python +""" +Example code showing how to use Gnuplot and an embedded IPython shell. +""" + +from Numeric import * +from IPython.numutils import * +from IPython.Shell import IPShellEmbed + +# Arguments to start IPython shell with. Load numeric profile. +ipargs = ['-profile','numeric'] +ipshell = IPShellEmbed(ipargs) + +# Compute sin(x) over the 0..2pi range at 200 points +x = frange(0,2*pi,npts=200) +y = sin(x) + +# In the 'numeric' profile, IPython has an internal gnuplot instance: +g = ipshell.IP.gnuplot + +# Change some defaults +g('set style data lines') + +# Or also call a multi-line set of gnuplot commands on it: +g(""" +set xrange [0:pi] # Set the visible range to half the data only +set title 'Half sine' # Global gnuplot labels +set xlabel 'theta' +set ylabel 'sin(theta)' +""") + +# Now start an embedded ipython. +ipshell('Starting the embedded IPython.\n' + 'Try calling plot(x,y), or @gpc for direct access to Gnuplot"\n') + +#********************** End of file ********************* diff --git a/assignments/week03/soupenv/share/doc/ipython/examples/core/ipython-get-history.py b/assignments/week03/soupenv/share/doc/ipython/examples/core/ipython-get-history.py new file mode 100644 index 00000000..d6d51ec6 --- /dev/null +++ b/assignments/week03/soupenv/share/doc/ipython/examples/core/ipython-get-history.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +"""Extract a session from the IPython input history. + +Usage: + ipython-get-history.py sessionnumber [outputfile] + +If outputfile is not given, the relevant history is written to stdout. If +outputfile has a .py extension, the translated history (without IPython's +special syntax) will be extracted. + +Example: + ./ipython-get-history.py 57 record.ipy + + +This script is a simple demonstration of HistoryAccessor. It should be possible +to build much more flexible and powerful tools to browse and pull from the +history database. +""" +import sys +import codecs + +from IPython.core.history import HistoryAccessor + +session_number = int(sys.argv[1]) +if len(sys.argv) > 2: + dest = open(sys.argv[2], "w") + raw = not sys.argv[2].endswith('.py') +else: + dest = sys.stdout + raw = True +dest.write("# coding: utf-8\n") + +# Profiles other than 'default' can be specified here with a profile= argument: +hist = HistoryAccessor() + +for session, lineno, cell in hist.get_range(session=session_number, raw=raw): + # To use this in Python 3, remove the .encode() here: + dest.write(cell.encode('utf-8') + '\n') diff --git a/assignments/week03/soupenv/share/doc/ipython/examples/core/ipython-qtconsole.desktop b/assignments/week03/soupenv/share/doc/ipython/examples/core/ipython-qtconsole.desktop new file mode 100644 index 00000000..ea636165 --- /dev/null +++ b/assignments/week03/soupenv/share/doc/ipython/examples/core/ipython-qtconsole.desktop @@ -0,0 +1,24 @@ +# If you want ipython to appear in a linux app launcher ("start menu"), install this by doing: +# sudo desktop-file-install ipython-qtconsole.desktop + +[Desktop Entry] +Comment=Enhanced interactive Python qtconsole +Exec=ipython qtconsole +GenericName[en_US]=Python shell +GenericName=Python shell +Icon=gnome-netstatus-idle +Name[en_US]=IPython Qt console +Name=IPython Qt console +Categories=Development;Utility; +StartupNotify=false +Terminal=false +Type=Application +Actions=Pylab;Pylabinline; + +[Desktop Action Pylab] +Name=Pylab +Exec=ipython qtconsole --pylab + +[Desktop Action Pylabinline] +Name=Pylab (inline plots) +Exec=ipython qtconsole --pylab=inline diff --git a/assignments/week03/soupenv/share/doc/ipython/examples/core/ipython-sh.desktop b/assignments/week03/soupenv/share/doc/ipython/examples/core/ipython-sh.desktop new file mode 100644 index 00000000..e47a3ebf --- /dev/null +++ b/assignments/week03/soupenv/share/doc/ipython/examples/core/ipython-sh.desktop @@ -0,0 +1,15 @@ +# If you want ipython to appear in a linux app launcher ("start menu"), install this by doing: +# sudo desktop-file-install ipython-sh.desktop + +[Desktop Entry] +Comment=Perform shell-like tasks in interactive ipython session +Exec=ipython --profile=pysh +GenericName[en_US]=IPython shell mode +GenericName=IPython shell mode +Icon=gnome-netstatus-idle +Name[en_US]=ipython-sh +Name=ipython-sh +Categories=Development;Utility; +StartupNotify=false +Terminal=true +Type=Application diff --git a/assignments/week03/soupenv/share/doc/ipython/examples/core/ipython.desktop b/assignments/week03/soupenv/share/doc/ipython/examples/core/ipython.desktop new file mode 100644 index 00000000..4d9d3108 --- /dev/null +++ b/assignments/week03/soupenv/share/doc/ipython/examples/core/ipython.desktop @@ -0,0 +1,15 @@ +# If you want ipython to appear in a linux app launcher ("start menu"), install this by doing: +# sudo desktop-file-install ipython.desktop + +[Desktop Entry] +Comment=Enhanced interactive Python shell +Exec=ipython +GenericName[en_US]=IPython +GenericName=IPython +Icon=gnome-netstatus-idle +Name[en_US]=ipython +Name=ipython +Categories=Development;Utility; +StartupNotify=false +Terminal=true +Type=Application diff --git a/assignments/week03/soupenv/share/doc/ipython/examples/core/ipython_here_shell_extension.reg b/assignments/week03/soupenv/share/doc/ipython/examples/core/ipython_here_shell_extension.reg new file mode 100644 index 00000000..934a3ac2 --- /dev/null +++ b/assignments/week03/soupenv/share/doc/ipython/examples/core/ipython_here_shell_extension.reg @@ -0,0 +1,6 @@ + Windows Registry Editor Version 5.00 + +[HKEY_CLASSES_ROOT\Directory\shell\IPython here] + +[HKEY_CLASSES_ROOT\Directory\shell\IPython here\Command] +@="cmd.exe /C ipython.py -p sh -i -c \"%cd %1\"" \ No newline at end of file diff --git a/assignments/week03/soupenv/share/doc/ipython/examples/core/leo_bridge_demo.leo b/assignments/week03/soupenv/share/doc/ipython/examples/core/leo_bridge_demo.leo new file mode 100644 index 00000000..052a9302 --- /dev/null +++ b/assignments/week03/soupenv/share/doc/ipython/examples/core/leo_bridge_demo.leo @@ -0,0 +1,552 @@ + + + + + + + + + + + +Documentation +@nosent ILeo_doc.txt +Documentation +Introduction +Installation +Accessing IPython from Leo +Accessing Leo nodes from IPython +Cl definitions +Special node types +Custom push +Code snippets +Acknowledgements and history + + + +@chapters +@settings +@@string ipython_argv = ipython -pylab +@enabled-plugins + +@ipy-startup +b +Some classes P +File-like access +csv data +String list +slist to leo + + +Class tests +csvr +tempfile +rfile +strlist + +IPython script push tests +Direct variables +bar + +pylab tests +Generate testarr +testarr +Call plotter on testarr + +test stuff +@ipy-results +foo + +spam + + +? +?Direct children of this node will be pushed at ipython bridge startup + +This node itself will *not* be pushed +print "world" +def rfile(body,n): + """ @cl rfile + + produces a StringIO (file like obj of the rest of the body) """ + + import StringIO + return StringIO.StringIO(body) + +def tmpfile(body,n): + """ @cl tmpfile + + Produces a temporary file, with node body as contents + + """ + import tempfile + h, fname = tempfile.mkstemp() + f = open(fname,'w') + f.write(body) + f.close() + return fname + +@cl tmpfile + +Hello +? +@cl rfile +These +lines +should +be +readable +@others +def csvdata(body,n): + import csv + d = csv.Sniffer().sniff(body) + reader = csv.reader(body.splitlines(), dialect = d) + return reader +@cl csvdata + +a,b,b +1,2,2 + +@cl +"hello world" +import IPython.genutils +def slist(body,n): + return IPython.genutils.SList(body.splitlines()) + +@cl slist +hello +world +on +many +lines + +import ipy_leo +@ipy_leo.format_for_leo.when_type(IPython.genutils.SList) +def format_slist(obj): + return "@cl slist\n" + obj.n + +? +@wrap +@nocolor +# test ipython script 'cleanup' with complex blocks +1+2 +print "hello" +3+4 + +def f(x): + return x.upper() + + +if 0: + print "foo" +else: + print "bar" + +def g(): + pass + +g() + +if 1: + if 1: + print "hello" + + print "world" + +if 1: + print "hello" + + print "word" +else: + print "foo" + + print "bar" + print "baz" + +try: + raise Exception +except: + print "exc ok" + +@cl rfile +hello +world +and whatever +@others + + +ipython.py + +Introduction +============ + +The purpose of ILeo, or leo-ipython bridge, is being a two-way communication +channel between Leo and IPython. The level of integration is much deeper than +conventional integration in IDEs; most notably, you are able to store *data* in +Leo nodes, in addition to mere program code. The possibilities of this are +endless, and this degree of integration has not been seen previously in the python +world. + +IPython users are accustomed to using things like %edit to produce non-trivial +functions/classes (i.e. something that they don't want to enter directly on the +interactive prompt, but creating a proper script/module involves too much +overhead). In ILeo, this task consists just going to the Leo window, creating a node +and writing the code there, and pressing alt+I (push-to-ipython). + +Obviously, you can save the Leo document as usual - this is a great advantage +of ILeo over using %edit, you can save your experimental scripts all at one +time, without having to organize them into script/module files (before you +really want to, of course!) + + +Installation +============ + +You need at least Leo 4.4.7, and the development version of IPython (ILeo +will be incorporated to IPython 0.8.3). + +You can get IPython from Launchpad by installing bzr and doing + +bzr branch lp:ipython + +and running "setup.py install". + +You need to enable the 'ipython.py' plugin in Leo: + +- Help -> Open LeoSettings.leo + +- Edit @settings-->Plugins-->@enabled-plugins, add/uncomment 'ipython.py' + +- Alternatively, you can add @settings-->@enabled-plugins with body ipython.py to your leo document. + +- Restart Leo. Be sure that you have the console window open (start leo.py from console, or double-click leo.py on windows) + +- Press alt+5 OR alt-x start-ipython to launch IPython in the console that +started leo. You can start entering IPython commands normally, and Leo will keep +running at the same time. + + +Accessing IPython from Leo +========================== + +IPython code +------------ + +Just enter IPython commands on a Leo node and press alt-I to execute +push-to-ipython in order to execute the script in IPython. 'commands' is +interpreted loosely here - you can enter function and class definitions, in +addition to the things you would usually enter at IPython prompt - calculations, +system commands etc. + +Everything that would be legal to enter on IPython prompt is legal to execute +from ILeo. + +Results will be shows in Leo log window for convenience, in addition to the console. + +Suppose that a node had the following contents: +{{{ +1+2 +print "hello" +3+4 + +def f(x): + return x.upper() + +f('hello world') +}}} + +If you press alt+I on that node, you will see the following in Leo log window (IPython tab): + +{{{ +In: 1+2 +<2> 3 +In: 3+4 +<4> 7 +In: f('hello world') +<6> 'HELLO WORLD' +}}} + +(numbers like <6> mean IPython output history indices; the actual object can be +referenced with _6 as usual in IPython). + + +Plain Python code +----------------- + +If the headline of the node ends with capital P, alt-I will not run the code +through IPython translation mechanism but use the direct python 'exec' statement +(in IPython user namespace) to execute the code. It wont be shown in IPython +history, and sometimes it is safer (and more efficient) to execute things as +plain Python statements. Large class definitions are good candidates for P +nodes. + + +Accessing Leo nodes from IPython +================================ + +The real fun starts when you start entering text to leo nodes, and are using +that as data (input/output) for your IPython work. + +Accessing Leo nodes happens through the variable 'wb' (short for "WorkBook") +that exist in the IPython user namespace. Nodes that are directly accessible are +the ones that have simple names which could also be Python variable names; +'foo_1' will be accessible directly from IPython, whereas 'my scripts' will not. +If you want to access a node with arbitrary headline, add a child node '@a foo' +(@a stands for 'anchor'). Then, the parent of '@a foo' is accessible through +'wb.foo'. + +You can see what nodes are accessible be entering (in IPython) wb.<TAB>. Example: + +[C:leo/src]|12> wb. +wb.b wb.tempfile wb.rfile wb.NewHeadline +wb.bar wb.Docs wb.strlist wb.csvr +[C:leo/src]|12> wb.tempfile + <12> <ipy_leo.LeoNode object at 0x044B6D90> + +So here, we meet the 'LeoNode' class that is your key to manipulating Leo +content from IPython! + +LeoNode +------- + +Suppose that we had a node with headline 'spam' and body: + +['12',2222+32] + +we can access it from IPython (or from scripts entered into other Leo nodes!) by doing: + +C:leo/src]|19> wb.spam.v + <19> ['12', 2254] + +'v' attribute stands for 'value', which means the node contents will be run +through 'eval' and everything you would be able to enter into IPython prompt +will be converted to objects. This mechanism can be extended far beyond direct +evaluation (see '@cl definitions'). + +'v' attribute also has a setter, i.e. you can do: + +wb.spam.v = "mystring" + +Which will result in the node 'spam' having the following text: + +'mystring' + +What assignment to 'v' does can be configured through generic functions +('simplegeneric' module, will be explained later). + +Besides v, you can set the body text directly through + +wb.spam.b = "some\nstring", + +headline by + +wb.spam.h = 'new_headline' + +(obviously you must access the node through wb.new_headline from that point +onwards), and access the contents as string list (IPython SList) through +'wb.spam.l'. + +If you do 'wb.foo.v = 12' when node named 'foo' does not exist, the node titled +'foo' will be automatically created and assigned body 12. + +LeoNode also supports go() that focuses the node in the Leo window, and ipush() +that simulates pressing alt+I on the node. + +You can access unknownAttributes by .uA property dictionary. Unknown attributes +allow you to store arbitrary (pickleable) python objects in the Leo nodes; the +attributes are stored when you save the .leo document, and recreated when you +open the document again. The attributes are not visible anywhere, but can be +used for domain-specific metatada. Example: + + [C:leo/src]|12> wb.spam.uA['coords'] = (12,222) + [C:leo/src]|13> wb.spam.uA + <13> {'coords': (12, 222)} + +Accessing children with iteration and dict notation +--------------------------------------------------- + +Sometimes, you may want to treat a node as a 'database', where the nodes +children represent elements in the database. You can create a new child node for +node 'spam', with headline 'foo bar' like this: + + wb.spam['foo bar'] = "Hello" + +And assign a new value for it by doing + + wb.spam['foo bar'].v = "Hello again" + +Note how you can't use .v when you first create the node - i.e. the node needs +to be initialized by simple assignment, that will be interpreted as assignment +to '.v'. This is a conscious design choice. + +If you try to do wb.spam['bar'] = 'Hello', ILeo will assign '@k bar' as the +headline for the child instead, because 'bar' is a legal python name (and as +such would be incorporated in the workbook namespace). This is done to avoid +crowding the workbook namespace with extraneous items. The item will still be +accessible as wb.spam['bar'] + +LeoNodes are iterable, so to see the headlines of all the children of 'spam' do: + + for n in wb.spam: + print n.h + + +@cl definitions +=============== + +If the first line in the body text is of the form '@cl sometext', IPython will +evaluate 'sometext' and call the result with the rest of the body when you do +'wb.foo.v'. An example is in place here. Suppose that we have defined a class (I +use the term class in a non-python sense here) + +{{{ +def rfile(body,node): + """ @cl rfile + + produces a StringIO (file like obj) of the rest of the body """ + + import StringIO + return StringIO.StringIO(body) +}}} + +(note that node is ignored here - but it could be used to access headline, +children etc.), + +Now, let's say you have node 'spam' with text + +{{{ +@cl rfile +hello +world +and whatever +}}} + +Now, in IPython, we can do this: + +{{{ +[C:leo/src]|22> f = wb.spam.v +[C:leo/src]|23> f + <23> <StringIO.StringIO instance at 0x04E7E490> +[C:leo/src]|24> f.readline() + <24> u'hello\n' +[C:leo/src]|25> f.readline() + <25> u'world\n' +[C:leo/src]|26> f.readline() + <26> u'and whatever' +[C:leo/src]|27> f.readline() + <27> u'' +}}} + +You should declare new @cl types to make ILeo as convenient your problem domain +as possible. For example, a "@cl etree" could return the elementtree object for +xml content. + + +Special node types +================== + +@ipy-startup +------------ + +If this node exist, the *direct children* of this will be pushed to IPython when +ILeo is started (you press alt+5). Use it to push your own @cl definitions etc. +The contents of of the node itself will be ignored. + +@ipy-results +------------ + +When you create a new node (wb.foo.v = 'stuff'), the node foo will be created as +a child of this node. If @ipy-results does not exist, the new node will be created after the currently selected node. + +@a nodes +-------- + +You can attach these as children of existing nodes to provide a way to access +nodes with arbitrary headlines, or to provide aliases to other nodes. If +multiple @a nodes are attached as children of a node, all the names can be used +to access the same object. + + +Acknowledgements & History +========================== + +This idea got started when I (Ville) saw this post by Edward Ream (the author of +Leo) on IPython developer mailing list: + + http://lists.ipython.scipy.org/pipermail/ipython-dev/2008-January/003551.html + +I was using FreeMind as mind mapping software, and so I had an immediate use +case for Leo (which, incidentally, is superior to FreeMind as mind mapper). The +wheels started rolling, I got obsessed with the power of this concept +(everything clicked together), and Edwards excitement paralleled mine. +Everything was mind-bogglingly easy/trivial, something that is typical of all +revolutionary technologies (think Python here). + +The discussion that "built" ILeo is here: + http://sourceforge.net/forum/forum.php?thread_id=1911662&forum_id=10226 + +? + +Declaring custom push-to-ipython handlers +========================================= + +Sometimes, you might want to configure what alt+I on a node does. You can do +that by creating your own push function and expose it using +ipy_leo.expose_ileo_push(f, priority). The function should check whether the +node should by handled by the function and raise IPython.ipapi.TryNext if it +will not do the handling, giving the next function in the chain a chance to see +whether it should handle the push. + +This example would print an uppercase version of node body if the node headline ends +with U (yes, this is completely useless!): + +{{{ +def push_upcase(node): + if not node.h.endswith('U'): + raise TryNext + print node.b.upper() + +ipy_leo.expose_ileo_push(push_upcase, 12) +}}} + +(the priority should be between 0-100 - typically, you don't need to care about +it and can usually omit the argument altogether) + + +Example code snippets +===================== + +Get list of all headlines of all the nodes in leo: + + [node.h for node in wb] + +Create node with headline 'baz', empty body: + wb.baz + +Create 10 child nodes for baz, where i is headline and 'Hello ' + i is body: + + for i in range(10): + wb.baz[i] = 'Hello %d' % i + + + + +12 +array([[ 0, 1, 2], + [ 3, 4, 5], + [ 6, 7, 8], + [ 9, 10, 11]]) +# press alt+i here to plot testarr + +plot(wb.testarr.v) + +Quickstart: + easy_install numpy + easy_install matplotlib + +Make sure you have '@string ipython-argv = ipython -pylab' in @settings. We currently recommend using TkAgg as the backend (it's also the default) +#press alt+i here to generate an array for plotter + +wb.testarr.v = arange(12).reshape(4,3) + + diff --git a/assignments/week03/soupenv/share/doc/ipython/examples/core/new-embed.py b/assignments/week03/soupenv/share/doc/ipython/examples/core/new-embed.py new file mode 100644 index 00000000..cc9ff4ea --- /dev/null +++ b/assignments/week03/soupenv/share/doc/ipython/examples/core/new-embed.py @@ -0,0 +1,17 @@ +# This shows how to use the new top-level embed function. It is a simpler +# API that manages the creation of the embedded shell. + +from IPython import embed + +a = 10 +b = 20 + +embed(header='First time', banner1='') + +c = 30 +d = 40 + +try: + raise Exception('adsfasdf') +except: + embed(header='The second time') diff --git a/assignments/week03/soupenv/share/doc/ipython/examples/core/seteditor.py b/assignments/week03/soupenv/share/doc/ipython/examples/core/seteditor.py new file mode 100644 index 00000000..a2cde04b --- /dev/null +++ b/assignments/week03/soupenv/share/doc/ipython/examples/core/seteditor.py @@ -0,0 +1,15 @@ +import os + + +editor = r'q:/opt/np/notepad++.exe' + + +e = os.environ + +e['EDITOR'] = editor +e['VISUAL'] = editor + + + + + diff --git a/assignments/week03/soupenv/share/doc/ipython/examples/notebooks/00_notebook_tour.ipynb b/assignments/week03/soupenv/share/doc/ipython/examples/notebooks/00_notebook_tour.ipynb new file mode 100644 index 00000000..dbe7c27e --- /dev/null +++ b/assignments/week03/soupenv/share/doc/ipython/examples/notebooks/00_notebook_tour.ipynb @@ -0,0 +1,1195 @@ +{ + "metadata": { + "name": "00_notebook_tour" + }, + "nbformat": 3, + "nbformat_minor": 0, + "worksheets": [ + { + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# A brief tour of the IPython notebook\n", + "\n", + "This document will give you a brief tour of the capabilities of the IPython notebook. \n", + "You can view its contents by scrolling around, or execute each cell by typing `Shift-Enter`.\n", + "After you conclude this brief high-level tour, you should read the accompanying notebook \n", + "titled `01_notebook_introduction`, which takes a more step-by-step approach to the features of the\n", + "system. \n", + "\n", + "The rest of the notebooks in this directory illustrate various other aspects and \n", + "capabilities of the IPython notebook; some of them may require additional libraries to be executed.\n", + "\n", + "**NOTE:** This notebook *must* be run from its own directory, so you must ``cd``\n", + "to this directory and then start the notebook, but do *not* use the ``--notebook-dir``\n", + "option to run it from another location.\n", + "\n", + "The first thing you need to know is that you are still controlling the same old IPython you're used to,\n", + "so things like shell aliases and magic commands still work:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "pwd" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "pyout", + "prompt_number": 1, + "text": [ + "u'/Users/minrk/dev/ip/mine/docs/examples/notebooks'" + ] + } + ], + "prompt_number": 1 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "ls" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "00_notebook_tour.ipynb callbacks.ipynb python-logo.svg\r\n", + "01_notebook_introduction.ipynb cython_extension.ipynb rmagic_extension.ipynb\r\n", + "Animations_and_Progress.ipynb display_protocol.ipynb sympy.ipynb\r\n", + "Capturing Output.ipynb formatting.ipynb sympy_quantum_computing.ipynb\r\n", + "Script Magics.ipynb octavemagic_extension.ipynb trapezoid_rule.ipynb\r\n", + "animation.m4v progbar.ipynb\r\n" + ] + } + ], + "prompt_number": 2 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "message = 'The IPython notebook is great!'\n", + "# note: the echo command does not run on Windows, it's a unix command.\n", + "!echo $message" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "The IPython notebook is great!\r\n" + ] + } + ], + "prompt_number": 3 + }, + { + "cell_type": "heading", + "level": 2, + "metadata": {}, + "source": [ + "Plots with matplotlib" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "IPython adds an 'inline' matplotlib backend,\n", + "which embeds any matplotlib figures into the notebook." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "%pylab inline" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\n", + "Welcome to pylab, a matplotlib-based Python environment [backend: module://IPython.zmq.pylab.backend_inline].\n", + "For more information, type 'help(pylab)'.\n" + ] + } + ], + "prompt_number": 4 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "x = linspace(0, 3*pi, 500)\n", + "plot(x, sin(x**2))\n", + "title('A simple chirp');" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "display_data", + "png": "iVBORw0KGgoAAAANSUhEUgAAAX0AAAEICAYAAACzliQjAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJztfXt0VdWd/+fmwSvhlUDeAcSECREFFWtLi8YKWlBTrS8c\nq1StZVppO21XZ3XNrJnqmqmF6XSpa9EquqYVOlZp+6tCUfHZKK2ltIpohcqjonnwCOQBeSc35/fH\n7s49OTmP/Tzn3GR/1sqCJGc/7s09n/05n+93f3fCsiwLBgYGBgZjAhlRT8DAwMDAIDwY0jcwMDAY\nQzCkb2BgYDCGYEjfwMDAYAzBkL6BgYHBGIIhfQMDA4MxBEP6BmmPJ554AldeeaWWvr/whS/g3//9\n35X2ee+99+K2227z/P2CBQvw+uuvKx3TwIDCkL5B5KipqUFeXh76+vqE2t9666144YUXFM+KIJFI\nIJFIKO/TD3/5y19wySWXKB3TwIDCkL5BpDhy5Ah2796NgoICbNu2LerpuEL1/kWZ/pLJpMKZGIxF\nGNI3iBSbN2/GsmXLcNttt2HTpk2+1z7++OM4++yzMWXKFMydOxc///nPh36+dOnSoesyMjLw8MMP\no7KyElOmTMF//Md/4PDhw/jEJz6BadOmYdWqVejv7wcA1NXVoaysDN///vcxc+ZMnHXWWUP9umH7\n9u1YtGgRpk+fjk9+8pN49913Pa997733sHz5cuTn56OoqAjf//73ARCl39fXh9WrV2PKlClYsGAB\n3nzzzaF2c+bMwauvvgqAWEE33HADbrvtNkydOhWPP/740M9WrVqFKVOm4MILL8Q777wT8E4bGBAY\n0jeIFJs3b8bNN9+Mm266CS+88AJOnDjhel1nZye+/vWvY8eOHTh9+jT+8Ic/YNGiRZ79vvjii9iz\nZw927dqF9evX4+6778aTTz6Jjz76CO+++y6efPLJoWuPHz+OU6dOoampCZs2bcKXvvQlHDx4cESf\ne/bswV133YXHHnsMLS0tWLNmDWpra11tqTNnzmDZsmVYuXIljh49ikOHDuHyyy8HQJT+tm3bcMst\nt6C9vR21tbVYu3btUFun/bNt2zbceOONaG9vx6233jr0s5tuugmtra34x3/8R1x77bUYGBjweacN\nDAgM6RtEht/97ndobGxEbW0tKisrUV1d7auyMzIy8O6776K7uxuFhYWorq72vPZf/uVfkJubi+rq\n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\n" + } + ], + "prompt_number": 5 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can paste blocks of input with prompt markers, such as those from\n", + "[the official Python tutorial](http://docs.python.org/tutorial/interpreter.html#interactive-mode)" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + ">>> the_world_is_flat = 1\n", + ">>> if the_world_is_flat:\n", + "... print \"Be careful not to fall off!\"" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "Be careful not to fall off!\n" + ] + } + ], + "prompt_number": 6 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Errors are shown in informative ways:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "%run non_existent_file" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stderr", + "text": [ + "ERROR: File `u'non_existent_file.py'` not found." + ] + } + ], + "prompt_number": 7 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "x = 1\n", + "y = 4\n", + "z = y/(1-x)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "ename": "ZeroDivisionError", + "evalue": "integer division or modulo by zero", + "output_type": "pyerr", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0mx\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[0my\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m4\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mz\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m/\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m-\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[1;31mZeroDivisionError\u001b[0m: integer division or modulo by zero" + ] + } + ], + "prompt_number": 8 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When IPython needs to display additional information (such as providing details on an object via `x?`\n", + "it will automatically invoke a pager at the bottom of the screen:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "magic" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 18 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Non-blocking output of kernel\n", + "\n", + "If you execute the next cell, you will see the output arriving as it is generated, not all at the end." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import time, sys\n", + "for i in range(8):\n", + " print i,\n", + " time.sleep(0.5)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "0 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "1 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "2 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "3 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "4 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "5 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "6 " + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "7\n" + ] + } + ], + "prompt_number": 19 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Clean crash and restart\n", + "\n", + "We call the low-level system libc.time routine with the wrong argument via\n", + "ctypes to segfault the Python interpreter:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import sys\n", + "from ctypes import CDLL\n", + "# This will crash a Linux or Mac system; equivalent calls can be made on Windows\n", + "dll = 'dylib' if sys.platform == 'darwin' else '.so.6'\n", + "libc = CDLL(\"libc.%s\" % dll) \n", + "libc.time(-1) # BOOM!!" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": "*" + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Markdown cells can contain formatted text and code\n", + "\n", + "You can *italicize*, **boldface**\n", + "\n", + "* build\n", + "* lists\n", + "\n", + "and embed code meant for illustration instead of execution in Python:\n", + "\n", + " def f(x):\n", + " \"\"\"a docstring\"\"\"\n", + " return x**2\n", + "\n", + "or other languages:\n", + "\n", + " if (i=0; i" + ] + } + ], + "prompt_number": 1 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "An image can also be displayed from raw data or a url" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "Image(url='http://python.org/images/python-logo.gif')" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "html": [ + "" + ], + "output_type": "pyout", + "prompt_number": 2, + "text": [ + "" + ] + } + ], + "prompt_number": 2 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "SVG images are also supported out of the box (since modern browsers do a good job of rendering them):" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "from IPython.display import SVG\n", + "SVG(filename='python-logo.svg')" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "pyout", + "prompt_number": 3, + "svg": [ + "\n", + " \n", + " \n", + " \n", + " image/svg+xml\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "" + ], + "text": [ + "" + ] + } + ], + "prompt_number": 3 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Embedded vs Non-embedded Images" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As of IPython 0.13, images are embedded by default for compatibility with QtConsole, and the ability to still be displayed offline.\n", + "\n", + "Let's look at the differences:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "# by default Image data are embedded\n", + "Embed = Image( 'http://www.google.fr/images/srpr/logo3w.png')\n", + "\n", + "# if kwarg `url` is given, the embedding is assumed to be false\n", + "SoftLinked = Image(url='http://www.google.fr/images/srpr/logo3w.png')\n", + "\n", + "# In each case, embed can be specified explicitly with the `embed` kwarg\n", + "# ForceEmbed = Image(url='http://www.google.fr/images/srpr/logo3w.png', embed=True)" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 4 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Today's Google doodle, (at the time I created this notebook). This should also work in the Qtconsole.\n", + "Drawback is that the saved notebook will be larger, but the image will still be present offline." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "Embed" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "pyout", + "png": "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\n", + "prompt_number": 5, + "text": [ + "" + ] + } + ], + "prompt_number": 5 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Today's Google doodle, visible only with an active internet connexion, that should be different from the previous one. This will not work on Qtconsole.\n", + "Notebook saved with this kind of image will be lighter and always reflect the current version of the source, but the image won't display offline." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "SoftLinked" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "html": [ + "" + ], + "output_type": "pyout", + "prompt_number": 6, + "text": [ + "" + ] + } + ], + "prompt_number": 6 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Of course, if you re-run this notebook, the two doodles will be the same again.\n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Video" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And more exotic objects can also be displayed, as long as their representation supports \n", + "the IPython display protocol.\n", + "\n", + "For example, videos hosted externally on YouTube are easy to load (and writing a similar wrapper for other\n", + "hosted content is trivial):" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "from IPython.display import YouTubeVideo\n", + "# a talk about IPython at Sage Days at U. Washington, Seattle.\n", + "# Video credit: William Stein.\n", + "YouTubeVideo('1j_HxD4iLn8')" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "html": [ + "\n", + " \n", + " " + ], + "output_type": "pyout", + "prompt_number": 7, + "text": [ + "" + ] + } + ], + "prompt_number": 7 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using the nascent video capabilities of modern browsers, you may also be able to display local\n", + "videos. At the moment this doesn't work very well in all browsers, so it may or may not work for you;\n", + "we will continue testing this and looking for ways to make it more robust. \n", + "\n", + "The following cell loads a local file called `animation.m4v`, encodes the raw video as base64 for http\n", + "transport, and uses the HTML5 video tag to load it. On Chrome 15 it works correctly, displaying a control\n", + "bar at the bottom with a play/pause button and a location slider." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "from IPython.display import HTML\n", + "video = open(\"animation.m4v\", \"rb\").read()\n", + "video_encoded = video.encode(\"base64\")\n", + "video_tag = '