From a4a278261460de569b4f5e8f7631d7bc259792ab Mon Sep 17 00:00:00 2001 From: Mark Price Date: Tue, 3 Jan 2012 18:51:31 -0800 Subject: [PATCH 01/17] Echo Assignment initial commit --- WebProgramming/Echo/echo_client.py | 30 +++++++++++++++++++++++ WebProgramming/Echo/echo_server.py | 39 ++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 WebProgramming/Echo/echo_client.py create mode 100644 WebProgramming/Echo/echo_server.py diff --git a/WebProgramming/Echo/echo_client.py b/WebProgramming/Echo/echo_client.py new file mode 100644 index 0000000..7794598 --- /dev/null +++ b/WebProgramming/Echo/echo_client.py @@ -0,0 +1,30 @@ +""" +echo client, usage: + + python echo_client.py + +Both host and port are optional, defaults: localhost 50000 +host must be present if you want to provide port +""" + +import socket +import sys + +host = 'localhost' +port = 50000 +size = 1024 + +nargs = len(sys.argv) +if nargs > 1: + host = sys.argv[1] +if nargs > 2: + port = int(sys.argv[2]) + +s = socket.socket(socket.AF_INET, + socket.SOCK_STREAM) +s.connect((host,port)) +s.send('Hello, world') +data = s.recv(size) +s.close() +print 'from (%s,%s) %s' % (host, port, data) + diff --git a/WebProgramming/Echo/echo_server.py b/WebProgramming/Echo/echo_server.py new file mode 100644 index 0000000..f2c2312 --- /dev/null +++ b/WebProgramming/Echo/echo_server.py @@ -0,0 +1,39 @@ +""" +echo server, usage: + + python echo_server.py + +Port is optional, default: 50000 +""" + +import socket +import sys + +host = '' +port = 50000 + +if len(sys.argv) > 1: + port = int(sys.argv[1]) + +backlog = 5 +size = 1024 + +# server's listener socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + +# Release listener socket immediately when program exits, +# avoid socket.error: [Errno 48] Address already in use +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +s.bind((host,port)) + +print 'echo_server listening on port', port +s.listen(backlog) + +while True: + client, address = s.accept() + data = client.recv(size) + if data: + client.send('uw-student: %s' % data) + print 'from %s: %s' % (address, data) + client.close() From 7f6d62b5b8e86d4d425aa939b3cdc9d9524a6393 Mon Sep 17 00:00:00 2001 From: Mark Price Date: Tue, 3 Jan 2012 19:42:28 -0800 Subject: [PATCH 02/17] Adding README per directions.txt. Changing uw-student to Mark Price --- WebProgramming/Echo/README | 0 WebProgramming/Echo/echo_server.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 WebProgramming/Echo/README diff --git a/WebProgramming/Echo/README b/WebProgramming/Echo/README new file mode 100644 index 0000000..e69de29 diff --git a/WebProgramming/Echo/echo_server.py b/WebProgramming/Echo/echo_server.py index f2c2312..933dc44 100644 --- a/WebProgramming/Echo/echo_server.py +++ b/WebProgramming/Echo/echo_server.py @@ -34,6 +34,6 @@ client, address = s.accept() data = client.recv(size) if data: - client.send('uw-student: %s' % data) + client.send('Mark Price: %s' % data) print 'from %s: %s' % (address, data) client.close() From 11fab4351deed850d629f3dd50443c73b3daf5db Mon Sep 17 00:00:00 2001 From: Mark Price Date: Tue, 3 Jan 2012 20:02:11 -0800 Subject: [PATCH 03/17] Updated Mark Price to mark665 to reflect github username --- WebProgramming/Echo/echo_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebProgramming/Echo/echo_server.py b/WebProgramming/Echo/echo_server.py index 933dc44..c6a91c4 100644 --- a/WebProgramming/Echo/echo_server.py +++ b/WebProgramming/Echo/echo_server.py @@ -34,6 +34,6 @@ client, address = s.accept() data = client.recv(size) if data: - client.send('Mark Price: %s' % data) + client.send('mark665: %s' % data) print 'from %s: %s' % (address, data) client.close() From de28fa82103d25d4787fa620cd35356fdcd80e2d Mon Sep 17 00:00:00 2001 From: Mark Price Date: Tue, 17 Jan 2012 11:40:32 -0600 Subject: [PATCH 04/17] Adding Chat and ReEcho exercised --- WebProgramming/Chat/chat_client.py | 55 ++++++++++++++++ WebProgramming/Chat/echo_server_select.py | 76 +++++++++++++++++++++++ WebProgramming/ReEcho/reecho_client.py | 34 ++++++++++ WebProgramming/ReEcho/reecho_server.py | 39 ++++++++++++ 4 files changed, 204 insertions(+) create mode 100644 WebProgramming/Chat/chat_client.py create mode 100644 WebProgramming/Chat/echo_server_select.py create mode 100644 WebProgramming/ReEcho/reecho_client.py create mode 100644 WebProgramming/ReEcho/reecho_server.py diff --git a/WebProgramming/Chat/chat_client.py b/WebProgramming/Chat/chat_client.py new file mode 100644 index 0000000..85882e2 --- /dev/null +++ b/WebProgramming/Chat/chat_client.py @@ -0,0 +1,55 @@ +""" +echo client, usage: + + python echo_client.py + +Both host and port are optional, defaults: localhost 50000 +host must be present if you want to provide port +""" + +import socket +import sys +import select + +host = 'localhost' +port = 50003 +backlog = 5 +size = 1024 +text = '' +timeout = 10 # seconds + +nargs = len(sys.argv) +if nargs > 1: + host = sys.argv[1] +if nargs > 2: + port = int(sys.argv[2]) + +serv = socket.socket(socket.AF_INET, + socket.SOCK_STREAM) +# Release listener socket immediately when program exits, +# avoid socket.error: [Errno 48] Address already in use +serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +serv.bind((host,port)) + +print 'echo_server listening on port %s, to exit type return ' % port +serv.listen(backlog) + +serv.connect((host,port)) +serv.accept() +input = [serv,sys.stdin] + +while True : + print "Enter test to send : " + inputready,outputready,exceptready = select.select(input,[],[],timeout) + + for s in inputready: + if s == sys.stdin: + text = str(raw_input()) + serv.send(text) + + data = s.recv(size) + + print '%s' % (data) +s.close() + diff --git a/WebProgramming/Chat/echo_server_select.py b/WebProgramming/Chat/echo_server_select.py new file mode 100644 index 0000000..4149ef0 --- /dev/null +++ b/WebProgramming/Chat/echo_server_select.py @@ -0,0 +1,76 @@ +""" +Based on Daniel Zappala's http://ilab.cs.byu.edu/python/code/echoserver-select.py +Add print statements to show what's going on. +Use SO_REUSEADDR to avoid 'Address already in use' errors +Add timeout +make style similar to our recho_clien + +An echo server that uses select to handle multiple clients at a time. +Entering any line of input at the terminal will exit the server. +""" + +import select +import socket +import sys +import time +import datetime + +host = '' +port = 50003 # different port than other samples, all can run on same server + +if len(sys.argv) > 1: + port = int(sys.argv[1]) + +backlog = 5 +size = 1024 + +server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + +# Release listener socket immediately when program exits, +# avoid socket.error: [Errno 48] Address already in use +server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +server.bind((host,port)) + +print 'echo_server listening on port %s, to exit type return ' % port +server.listen(backlog) + +timeout = 10 # seconds +input = [server,sys.stdin] +clients = [] +running = True +while running: + inputready,outputready,exceptready = select.select(input,[],[],timeout) + + # timeout + if not inputready: + print 'Server running at %s' % datetime.datetime.now() + + for s in inputready: + + if s == server: + # handle the server socket + client, address = server.accept() + input.append(client) + clients.append(client) + print 'accepted connection from', address + + elif s == sys.stdin: + # handle standard input + junk = sys.stdin.readline() + running = False + print 'Input %s from stdin, exiting.' % junk.strip('\n') + + elif s: # client socket + data = s.recv(size) + #print '%s: %s' % (s.getpeername(), data.strip('\n')) + if data: + for c in clients : + c.send('%s: %s' % (s.getpeername(), data)) + else: + s.close() + print 'closed connection' + input.remove(s) + clients.remove(s) + +s.close() diff --git a/WebProgramming/ReEcho/reecho_client.py b/WebProgramming/ReEcho/reecho_client.py new file mode 100644 index 0000000..c227b69 --- /dev/null +++ b/WebProgramming/ReEcho/reecho_client.py @@ -0,0 +1,34 @@ +""" +echo client, usage: + + python echo_client.py + +Both host and port are optional, defaults: localhost 50000 +host must be present if you want to provide port +""" + +import socket +import sys + +host = 'localhost' +port = 50001 +size = 1024 +text = '' + +nargs = len(sys.argv) +if nargs > 1: + host = sys.argv[1] +if nargs > 2: + port = int(sys.argv[2]) + +while True : + s = socket.socket(socket.AF_INET, + socket.SOCK_STREAM) + s.connect((host,port)) + print "Enter test to send : " + text = str(raw_input()) + s.send(text) + data = s.recv(size) + s.close() + print 'from (%s,%s) %s' % (host, port, data) + diff --git a/WebProgramming/ReEcho/reecho_server.py b/WebProgramming/ReEcho/reecho_server.py new file mode 100644 index 0000000..18a406b --- /dev/null +++ b/WebProgramming/ReEcho/reecho_server.py @@ -0,0 +1,39 @@ +""" +echo server, usage: + + python echo_server.py + +Port is optional, default: 50001 +""" + +import socket +import sys + +host = '' +port = 50001 + +if len(sys.argv) > 1: + port = int(sys.argv[1]) + +backlog = 5 +size = 1024 + +# server's listener socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + +# Release listener socket immediately when program exits, +# avoid socket.error: [Errno 48] Address already in use +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +s.bind((host,port)) + +print 'echo_server listening on port', port +s.listen(backlog) + +while True: + client, address = s.accept() + data = client.recv(size) + if data: + client.send('mark665: %s' % data) + print 'from %s: %s' % (address, data) + client.close() From 69b2b2bbe44d606f8efc84955cbcf2b64d1c21f9 Mon Sep 17 00:00:00 2001 From: Mark Price Date: Tue, 24 Jan 2012 18:40:43 -0800 Subject: [PATCH 05/17] revising reecho server to not close socket every message, added week 2 and 3 folders. --- WebProgramming/Chat/chat_client.py | 41 +++++++++++++------------- WebProgramming/ReEcho/reecho_client.py | 24 ++++++++------- WebProgramming/ReEcho/reecho_server.py | 14 +++++---- 3 files changed, 44 insertions(+), 35 deletions(-) diff --git a/WebProgramming/Chat/chat_client.py b/WebProgramming/Chat/chat_client.py index 85882e2..2d8cd8d 100644 --- a/WebProgramming/Chat/chat_client.py +++ b/WebProgramming/Chat/chat_client.py @@ -12,8 +12,7 @@ import select host = 'localhost' -port = 50003 -backlog = 5 +port = 50003 size = 1024 text = '' timeout = 10 # seconds @@ -24,32 +23,34 @@ if nargs > 2: port = int(sys.argv[2]) -serv = socket.socket(socket.AF_INET, +#open socket for sending to the server +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.connect((host,port)) + +#open socket for recieving from the server +backlog = 5 +r = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + # Release listener socket immediately when program exits, # avoid socket.error: [Errno 48] Address already in use -serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - -serv.bind((host,port)) +r.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) -print 'echo_server listening on port %s, to exit type return ' % port -serv.listen(backlog) +r.bind((host,port)) +r.listen(backlog) -serv.connect((host,port)) -serv.accept() -input = [serv,sys.stdin] +input = [r,sys.stdin] while True : print "Enter test to send : " inputready,outputready,exceptready = select.select(input,[],[],timeout) - - for s in inputready: - if s == sys.stdin: + for input in inputready: + if input == sys.stdin: text = str(raw_input()) - serv.send(text) - - data = s.recv(size) - - print '%s' % (data) -s.close() + s.send(text) + if input == r: + print r.recv(size) + +s.close() +r.close diff --git a/WebProgramming/ReEcho/reecho_client.py b/WebProgramming/ReEcho/reecho_client.py index c227b69..28f1ee0 100644 --- a/WebProgramming/ReEcho/reecho_client.py +++ b/WebProgramming/ReEcho/reecho_client.py @@ -21,14 +21,18 @@ if nargs > 2: port = int(sys.argv[2]) -while True : - s = socket.socket(socket.AF_INET, +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.connect((host,port)) - print "Enter test to send : " - text = str(raw_input()) - s.send(text) - data = s.recv(size) - s.close() - print 'from (%s,%s) %s' % (host, port, data) - +s.connect((host,port)) +print 'Connection accepted by (%s,%s)' % (host, port) +print "Enter test to send : " +while True : + text = str(raw_input('> ')) + if text : + s.send(text) + data = s.recv(size) + print data + else : + s.close() + print 'from (%s,%s) %s' % (host, port, data) + break diff --git a/WebProgramming/ReEcho/reecho_server.py b/WebProgramming/ReEcho/reecho_server.py index 18a406b..75ab120 100644 --- a/WebProgramming/ReEcho/reecho_server.py +++ b/WebProgramming/ReEcho/reecho_server.py @@ -32,8 +32,12 @@ while True: client, address = s.accept() - data = client.recv(size) - if data: - client.send('mark665: %s' % data) - print 'from %s: %s' % (address, data) - client.close() + while True : + data = client.recv(size) + if data: + client.send('mark665: %s' % data) + print 'from %s: %s' % (address, data) + else : # no data, client sent empty message + client.close() + print 'closed connection' + break From 7670acfec9e86c5f464cf25f67b1e6a30f0d3171 Mon Sep 17 00:00:00 2001 From: Mark Price Date: Tue, 24 Jan 2012 20:14:21 -0800 Subject: [PATCH 06/17] Completed chat server, variable name overloading causing problem in for statment. --- WebProgramming/Chat/chat_client.py | 36 ++++++++----------- .../{echo_server_select.py => chat_server.py} | 3 +- 2 files changed, 16 insertions(+), 23 deletions(-) rename WebProgramming/Chat/{echo_server_select.py => chat_server.py} (93%) diff --git a/WebProgramming/Chat/chat_client.py b/WebProgramming/Chat/chat_client.py index 2d8cd8d..628790e 100644 --- a/WebProgramming/Chat/chat_client.py +++ b/WebProgramming/Chat/chat_client.py @@ -28,29 +28,21 @@ socket.SOCK_STREAM) s.connect((host,port)) -#open socket for recieving from the server -backlog = 5 -r = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - -# Release listener socket immediately when program exits, -# avoid socket.error: [Errno 48] Address already in use -r.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - -r.bind((host,port)) -r.listen(backlog) - -input = [r,sys.stdin] +input = [s, sys.stdin] +print "Enter text to send : " while True : - print "Enter test to send : " inputready,outputready,exceptready = select.select(input,[],[],timeout) - for input in inputready: - if input == sys.stdin: - text = str(raw_input()) - s.send(text) - if input == r: - print r.recv(size) - -s.close() -r.close + for selectInput in inputready: + if selectInput == sys.stdin: + text = str(raw_input('> ')) + if text : + s.send(text) + else : + s.close() + break + if selectInput == s: + text = s.recv(size) + print text + diff --git a/WebProgramming/Chat/echo_server_select.py b/WebProgramming/Chat/chat_server.py similarity index 93% rename from WebProgramming/Chat/echo_server_select.py rename to WebProgramming/Chat/chat_server.py index 4149ef0..f497dd4 100644 --- a/WebProgramming/Chat/echo_server_select.py +++ b/WebProgramming/Chat/chat_server.py @@ -63,9 +63,10 @@ elif s: # client socket data = s.recv(size) - #print '%s: %s' % (s.getpeername(), data.strip('\n')) + print '%s: %s' % (s.getpeername(), data.strip('\n')) if data: for c in clients : + print 'sending : %s: %s' % (c.getpeername(), data.strip('\n')) c.send('%s: %s' % (s.getpeername(), data)) else: s.close() From 0957fe7002c327bef4ffbd62157423ac0b97862d Mon Sep 17 00:00:00 2001 From: Mark Price Date: Tue, 31 Jan 2012 18:09:42 -0800 Subject: [PATCH 07/17] added logic so clients don't recieve their own messages from the chat server. --- WebProgramming/Chat/chat_server.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/WebProgramming/Chat/chat_server.py b/WebProgramming/Chat/chat_server.py index f497dd4..166d70f 100644 --- a/WebProgramming/Chat/chat_server.py +++ b/WebProgramming/Chat/chat_server.py @@ -66,8 +66,9 @@ print '%s: %s' % (s.getpeername(), data.strip('\n')) if data: for c in clients : - print 'sending : %s: %s' % (c.getpeername(), data.strip('\n')) - c.send('%s: %s' % (s.getpeername(), data)) + if c != s : + print 'sending : %s: %s' % (c.getpeername(), data.strip('\n')) + c.send('%s: %s' % (s.getpeername(), data)) else: s.close() print 'closed connection' From 524c6dfc694b2449672c494256fdda9d2a2a5cec Mon Sep 17 00:00:00 2001 From: Mark Price Date: Tue, 31 Jan 2012 20:36:01 -0800 Subject: [PATCH 08/17] modified hello_www.py to support sending time information, added support for /date.html in thirtyminute web server --- .../thirtyMinuteWebServer/hello_www.py | 58 ++++++++ .../thirtyMinuteWebServer/print_time.py | 5 + .../thirty_minute_webserver.py | 136 ++++++++++++++++++ 3 files changed, 199 insertions(+) create mode 100644 WebProgramming/thirtyMinuteWebServer/hello_www.py create mode 100644 WebProgramming/thirtyMinuteWebServer/print_time.py create mode 100644 WebProgramming/thirtyMinuteWebServer/thirty_minute_webserver.py diff --git a/WebProgramming/thirtyMinuteWebServer/hello_www.py b/WebProgramming/thirtyMinuteWebServer/hello_www.py new file mode 100644 index 0000000..6fcc7af --- /dev/null +++ b/WebProgramming/thirtyMinuteWebServer/hello_www.py @@ -0,0 +1,58 @@ +""" +hello_www.py - minimal web server + web application +""" + +import socket +import sys +import time +import datetime + + +page = """ +HTTP/1.0 200 OK +Content-Type text/html + + + +%s + + +""" + + +def parseRecieved (text): + url = text.split() + if url[1] == "/time" : + return page % time.time() + else : + return page % "Hello World!" + pass + +host = '' +port = 8082 # different default port than thirty_minute_webserver + +# optional command line argument: port +if len(sys.argv) > 1: + port = int(sys.argv[1]) + +backlog = 5 +size = 1024 + +# server's listener socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + +# Release listener socket immediately when program exits, +# avoid socket.error: [Errno 48] Address already in use +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +s.bind((host,port)) + +print 'hello_www listening on port', port +s.listen(backlog) + +while True: # just keep serving page to any client that connects + client, address = s.accept() # create client socket + recieved = client.recv(size) # HTTP request - not too big! Just ignore contents + send = parseRecieved (recieved) + client.send(send) # HTTP response - same for any request + client.close() diff --git a/WebProgramming/thirtyMinuteWebServer/print_time.py b/WebProgramming/thirtyMinuteWebServer/print_time.py new file mode 100644 index 0000000..4d5b684 --- /dev/null +++ b/WebProgramming/thirtyMinuteWebServer/print_time.py @@ -0,0 +1,5 @@ +import time +import datetime + +print "Here is the time: %s" % time.time() +print "and again: %s" % datetime.datetime.now() diff --git a/WebProgramming/thirtyMinuteWebServer/thirty_minute_webserver.py b/WebProgramming/thirtyMinuteWebServer/thirty_minute_webserver.py new file mode 100644 index 0000000..f4fa148 --- /dev/null +++ b/WebProgramming/thirtyMinuteWebServer/thirty_minute_webserver.py @@ -0,0 +1,136 @@ +# +# ws30 -- the thirty minute web server +# author: Wilhelm Fitzpatrick (rafial@well.com) +# date: August 3rd, 2002 +# version: 1.0 +# +# Written after attending a Dave Thomas talk at PNSS and hearing about +# his "write a web server in Ruby in one hour" challenge. +# +# Actual time spent: +# 30 minutes reading socket man page +# 30 minutes coding to first page fetched +# 3 hours making it prettier & more pythonic +# +# updated for UW Internet Programming in Python, by Brian Dorsey +# + +import os, socket, sys, datetime + +defaults = ['127.0.0.1', '8080'] +mime_types = {'.jpg' : 'image/jpg', + '.gif' : 'image/gif', + '.png' : 'image/png', + '.html' : 'text/html', + '.pdf' : 'application/pdf'} +response = {} + +response[200] =\ +"""HTTP/1.0 200 Okay +Server: ws30 +Content-type: %s + +%s +""" + +response[301] =\ +"""HTTP/1.0 301 Moved +Server: ws30 +Content-type: text/plain +Location: %s + +moved +""" + +response[404] =\ +"""HTTP/1.0 404 Not Found +Server: ws30 +Content-type: text/plain + +%s not found +""" + +DIRECTORY_LISTING =\ +""" +%s + +..
+%s + + +""" + +DIRECTORY_LINE = '%s
' + +def server_socket(host, port): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.bind((host, port)) + s.listen(1) + return s + +def listen(s): + connection, client = s.accept() + return connection.makefile('r+') + +def get_request(stream): + method = None + while True: + line = stream.readline() + print line + if not line.strip(): + break + elif not method: + method, uri, protocol = line.split() + return uri + +def list_directory(uri): + entries = os.listdir('.' + uri) + entries.sort() + return DIRECTORY_LISTING % (uri, uri, '\n'.join( + [DIRECTORY_LINE % (e, e) for e in entries])) + +def get_file(path): + f = open(path) + try: + return f.read() + finally: + f.close() + +def get_content(uri): + print 'fetching:', uri + try: + path = '.' + uri + if os.path.isfile(path): + return (200, get_mime(uri), get_file(path)) + if os.path.isdir(path): + if(uri.endswith('/')): + return (200, 'text/html', list_directory(uri)) + else: + return (301, uri + '/') + if uri == "/date.html" : + return (200, "text/html", datetime.datetime.now()) + + else: return (404, uri) + except IOError, e: + return (404, e) + +def get_mime(uri): + return mime_types.get(os.path.splitext(uri)[1], 'text/plain') + +def send_response(stream, content): + stream.write(response[content[0]] % content[1:]) + +if __name__ == '__main__': + args, nargs = sys.argv[1:], len(sys.argv) - 1 + host, port = (args + defaults[-2 + nargs:])[0:2] + server = server_socket(host, int(port)) + print 'starting %s on %s...' % (host, port) + try: + while True: + stream = listen (server) + send_response(stream, get_content(get_request(stream))) + stream.close() + except KeyboardInterrupt: + print 'shutting down...' + server.close() + From 1bfb19c8e3bc6ffd2d16870a130674c5c460349a Mon Sep 17 00:00:00 2001 From: Mark Price Date: Tue, 7 Feb 2012 14:51:03 -0800 Subject: [PATCH 09/17] Thirty minute web server, not quite working executing python files, but close --- WebProgramming/{Echo => Chat}/README | 0 .../thirtyMinuteWebServer/thirty_minute_webserver.py | 5 ++++- 2 files changed, 4 insertions(+), 1 deletion(-) rename WebProgramming/{Echo => Chat}/README (100%) diff --git a/WebProgramming/Echo/README b/WebProgramming/Chat/README similarity index 100% rename from WebProgramming/Echo/README rename to WebProgramming/Chat/README diff --git a/WebProgramming/thirtyMinuteWebServer/thirty_minute_webserver.py b/WebProgramming/thirtyMinuteWebServer/thirty_minute_webserver.py index f4fa148..a8c2818 100644 --- a/WebProgramming/thirtyMinuteWebServer/thirty_minute_webserver.py +++ b/WebProgramming/thirtyMinuteWebServer/thirty_minute_webserver.py @@ -17,7 +17,7 @@ import os, socket, sys, datetime -defaults = ['127.0.0.1', '8080'] +defaults = ['127.0.0.1', '8081'] mime_types = {'.jpg' : 'image/jpg', '.gif' : 'image/gif', '.png' : 'image/png', @@ -100,6 +100,8 @@ def get_content(uri): print 'fetching:', uri try: path = '.' + uri + if (os.path.isfile(path) & (path[-3:] == ".py")) : + print "hell yea" if os.path.isfile(path): return (200, get_mime(uri), get_file(path)) if os.path.isdir(path): @@ -109,6 +111,7 @@ def get_content(uri): return (301, uri + '/') if uri == "/date.html" : return (200, "text/html", datetime.datetime.now()) + else: return (404, uri) except IOError, e: From 56bf2d8e48849b1f21137394238667edce547439 Mon Sep 17 00:00:00 2001 From: Mark Price Date: Tue, 7 Feb 2012 18:19:52 -0800 Subject: [PATCH 10/17] better, simpler solution to running code remotly --- WebProgramming/thirtyMinuteWebServer/print_time.py | 1 + .../thirtyMinuteWebServer/thirty_minute_webserver.py | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) mode change 100644 => 100755 WebProgramming/thirtyMinuteWebServer/print_time.py diff --git a/WebProgramming/thirtyMinuteWebServer/print_time.py b/WebProgramming/thirtyMinuteWebServer/print_time.py old mode 100644 new mode 100755 index 4d5b684..88e1e1d --- a/WebProgramming/thirtyMinuteWebServer/print_time.py +++ b/WebProgramming/thirtyMinuteWebServer/print_time.py @@ -1,3 +1,4 @@ +#! /Library/Frameworks/Python.framework/Versions/2.7/bin/python import time import datetime diff --git a/WebProgramming/thirtyMinuteWebServer/thirty_minute_webserver.py b/WebProgramming/thirtyMinuteWebServer/thirty_minute_webserver.py index a8c2818..8f1e4d0 100644 --- a/WebProgramming/thirtyMinuteWebServer/thirty_minute_webserver.py +++ b/WebProgramming/thirtyMinuteWebServer/thirty_minute_webserver.py @@ -17,7 +17,7 @@ import os, socket, sys, datetime -defaults = ['127.0.0.1', '8081'] +defaults = ['127.0.0.1', '8088'] mime_types = {'.jpg' : 'image/jpg', '.gif' : 'image/gif', '.png' : 'image/png', @@ -99,17 +99,18 @@ def get_file(path): def get_content(uri): print 'fetching:', uri try: - path = '.' + uri - if (os.path.isfile(path) & (path[-3:] == ".py")) : - print "hell yea" + path = '.' + uri if os.path.isfile(path): + if path.endswith ('.py'): + output = os.popen('python ' + path).read() + return (200,'text/plain', output) return (200, get_mime(uri), get_file(path)) if os.path.isdir(path): if(uri.endswith('/')): return (200, 'text/html', list_directory(uri)) else: return (301, uri + '/') - if uri == "/date.html" : + if uri.endswith ("date.html") : return (200, "text/html", datetime.datetime.now()) From 3fcd562d92cf29c7a6fee8c12f5cbd7c8dffe221 Mon Sep 17 00:00:00 2001 From: Mark Price Date: Tue, 14 Feb 2012 14:33:07 -0800 Subject: [PATCH 11/17] Adding webAPI assignment. Uses google maps api and json to retrieve addresses and neighboring houses. --- WebProgramming/Chat/hello.py | 1 + WebProgramming/Week3/.gitignore | 1 + WebProgramming/thirtyMinuteWebServer/text.txt | 1 + .../webAPIProject/displayLocation.py | 43 +++++++++++++++++++ WebProgramming/week4/Class.py | 20 +++++++++ WebProgramming/week4/scrape.py | 11 +++++ 6 files changed, 77 insertions(+) create mode 100755 WebProgramming/Chat/hello.py create mode 100644 WebProgramming/Week3/.gitignore create mode 100644 WebProgramming/thirtyMinuteWebServer/text.txt create mode 100644 WebProgramming/webAPIProject/displayLocation.py create mode 100644 WebProgramming/week4/Class.py create mode 100644 WebProgramming/week4/scrape.py diff --git a/WebProgramming/Chat/hello.py b/WebProgramming/Chat/hello.py new file mode 100755 index 0000000..da6849a --- /dev/null +++ b/WebProgramming/Chat/hello.py @@ -0,0 +1 @@ +print "hello world" diff --git a/WebProgramming/Week3/.gitignore b/WebProgramming/Week3/.gitignore new file mode 100644 index 0000000..721c463 --- /dev/null +++ b/WebProgramming/Week3/.gitignore @@ -0,0 +1 @@ +/Ubuntu.vmwarevm diff --git a/WebProgramming/thirtyMinuteWebServer/text.txt b/WebProgramming/thirtyMinuteWebServer/text.txt new file mode 100644 index 0000000..9daeafb --- /dev/null +++ b/WebProgramming/thirtyMinuteWebServer/text.txt @@ -0,0 +1 @@ +test diff --git a/WebProgramming/webAPIProject/displayLocation.py b/WebProgramming/webAPIProject/displayLocation.py new file mode 100644 index 0000000..38567cd --- /dev/null +++ b/WebProgramming/webAPIProject/displayLocation.py @@ -0,0 +1,43 @@ +''' +Created on Feb 12, 2012 + +@author: mark +Given an address, this prints the lat/long cordinates of the address, as well as the address of the house across the street. s +''' + +from pprint import pprint +import urllib2, json + +requestLatLogAddress = "http://maps.googleapis.com/maps/api/geocode/json?%s%s" +sensor = "&sensor=false" + +print "Enter street address (less city and state) :" +address = raw_input().split() +homeAddress = "address=" + "+".join(address) +print address +address[0] = str(int(address[0]) + 1) +neighborAddress = "address=" + "+".join(address) +print "Enter City : " +city = ",+" + raw_input () +print "Enter State : " +state = ",+" + raw_input () + +print address +print city +print state + +address_request = requestLatLogAddress % (homeAddress+city+state,sensor) +neighbor_request = requestLatLogAddress % (neighborAddress+city+state,sensor) + +addressResult = urllib2.urlopen(address_request) +neighborResult = urllib2.urlopen(neighbor_request) +jsonDataAddress = json.load(addressResult) +jsonDataNeighbor = json.load(neighborResult) + +print "Cordinates of your house: " +pprint("lat: " + str(jsonDataAddress['results'][0]['geometry']['location']['lat'])) +pprint("lng: " + str(jsonDataAddress['results'][0]['geometry']['location']['lng'])) + +print "Cordinates of your Neighbor's house: " +pprint("lat: " + str(jsonDataNeighbor['results'][0]['geometry']['location']['lat'])) +pprint("lng: " + str(jsonDataNeighbor['results'][0]['geometry']['location']['lng'])) diff --git a/WebProgramming/week4/Class.py b/WebProgramming/week4/Class.py new file mode 100644 index 0000000..6b1a821 --- /dev/null +++ b/WebProgramming/week4/Class.py @@ -0,0 +1,20 @@ +''' +Created on Feb 7, 2012 + +@author: mark +''' + +""" +NOTES: + +freebase.com - database intended for exclusive use as an api +""" + +import urllib2 + +result = urllib2.urlopen('http://google.com').read () +print result + + +if __name__ == '__main__': + pass \ No newline at end of file diff --git a/WebProgramming/week4/scrape.py b/WebProgramming/week4/scrape.py new file mode 100644 index 0000000..db1a5b4 --- /dev/null +++ b/WebProgramming/week4/scrape.py @@ -0,0 +1,11 @@ +''' +Created on Feb 7, 2012 + +@author: mark +''' +from pprint import pprint +import re, urllib2, sys + +url = sys.argv[1] +result = urllib2.urlopen("http://jon-jacky.github.com/uw_python/winter_2012/index.html").read () +pprint (re.findall('http://.*html',result)) \ No newline at end of file From 0595337d81d70d9058e06bf1d933bbffc71a2c08 Mon Sep 17 00:00:00 2001 From: Mark Price Date: Tue, 14 Feb 2012 14:34:27 -0800 Subject: [PATCH 12/17] adding ignore --- WebProgramming/Week3/.gitignore | 1 - 1 file changed, 1 deletion(-) delete mode 100644 WebProgramming/Week3/.gitignore diff --git a/WebProgramming/Week3/.gitignore b/WebProgramming/Week3/.gitignore deleted file mode 100644 index 721c463..0000000 --- a/WebProgramming/Week3/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/Ubuntu.vmwarevm From 2b9b735dfdd77c5eeedcaa71ceb1d48a165bced7 Mon Sep 17 00:00:00 2001 From: Mark Price Date: Tue, 14 Feb 2012 19:15:59 -0800 Subject: [PATCH 13/17] Adding CGI test directory and web API update --- .../cgiPrograming/cgi-bin/cgi_test.py | 3 ++ .../cgiPrograming/cgi-bin/echo_cgi.py | 29 +++++++++++++++++++ WebProgramming/cgiPrograming/echo_cgi.html | 18 ++++++++++++ .../webAPIProject/displayLocation.py | 1 + WebProgramming/week5/class.py | 7 +++++ 5 files changed, 58 insertions(+) create mode 100755 WebProgramming/cgiPrograming/cgi-bin/cgi_test.py create mode 100755 WebProgramming/cgiPrograming/cgi-bin/echo_cgi.py create mode 100644 WebProgramming/cgiPrograming/echo_cgi.html create mode 100644 WebProgramming/week5/class.py diff --git a/WebProgramming/cgiPrograming/cgi-bin/cgi_test.py b/WebProgramming/cgiPrograming/cgi-bin/cgi_test.py new file mode 100755 index 0000000..7805372 --- /dev/null +++ b/WebProgramming/cgiPrograming/cgi-bin/cgi_test.py @@ -0,0 +1,3 @@ +#!/usr/bin/python +import cgi +cgi.test() diff --git a/WebProgramming/cgiPrograming/cgi-bin/echo_cgi.py b/WebProgramming/cgiPrograming/cgi-bin/echo_cgi.py new file mode 100755 index 0000000..49d2249 --- /dev/null +++ b/WebProgramming/cgiPrograming/cgi-bin/echo_cgi.py @@ -0,0 +1,29 @@ +#!/usr/bin/python + +""" +Minimal CGI + forms demo + +Send HTML page that echoes message from HTTP request +Intended to be invoked via action attribute in form tag in echo_cgi.html +""" + +import cgi +import cgitb + +cgitb.enable() # so tracebacks in the web page, not the console + +form = cgi.FieldStorage() # invoke only once +message = form.getfirst('message') + +print """Content-type: text/html + + + +Echo response + + +Message: %s + + + +""" % message diff --git a/WebProgramming/cgiPrograming/echo_cgi.html b/WebProgramming/cgiPrograming/echo_cgi.html new file mode 100644 index 0000000..236943e --- /dev/null +++ b/WebProgramming/cgiPrograming/echo_cgi.html @@ -0,0 +1,18 @@ + + + + +Echo request + + +
+Message: + +
+ + diff --git a/WebProgramming/webAPIProject/displayLocation.py b/WebProgramming/webAPIProject/displayLocation.py index 38567cd..11c1284 100644 --- a/WebProgramming/webAPIProject/displayLocation.py +++ b/WebProgramming/webAPIProject/displayLocation.py @@ -31,6 +31,7 @@ addressResult = urllib2.urlopen(address_request) neighborResult = urllib2.urlopen(neighbor_request) + jsonDataAddress = json.load(addressResult) jsonDataNeighbor = json.load(neighborResult) diff --git a/WebProgramming/week5/class.py b/WebProgramming/week5/class.py new file mode 100644 index 0000000..b797b13 --- /dev/null +++ b/WebProgramming/week5/class.py @@ -0,0 +1,7 @@ +''' +Created on Feb 14, 2012 + +@author: mark + +python -m +''' From 5e4c107f640a1643609b80d81fe8961ad6ad989d Mon Sep 17 00:00:00 2001 From: Mark Price Date: Tue, 14 Feb 2012 20:23:01 -0800 Subject: [PATCH 14/17] Added wsgi Assignment, modified to display all previous messaeges (retain context) --- WebProgramming/wsgiAssignment/echo_wsgi.py | 68 +++++++++++++++++++ .../wsgiAssignment/wsgi_simple_server.py | 32 +++++++++ 2 files changed, 100 insertions(+) create mode 100644 WebProgramming/wsgiAssignment/echo_wsgi.py create mode 100644 WebProgramming/wsgiAssignment/wsgi_simple_server.py diff --git a/WebProgramming/wsgiAssignment/echo_wsgi.py b/WebProgramming/wsgiAssignment/echo_wsgi.py new file mode 100644 index 0000000..91f5516 --- /dev/null +++ b/WebProgramming/wsgiAssignment/echo_wsgi.py @@ -0,0 +1,68 @@ +""" +Minimal WSGI + forms demo, with persistence + +Send HTML page that echoes message from HTTP request +To get started, point browser at echo_wsgi.html + +Based on example in PEP 333, then add path and query processing +""" + +import urlparse + +# send one of these pages, depending on URL path + +form_page = """ +Echo request + + +
+Message: + +
+ + +""" + +message_template = """ + + +Echo response + + +Message: %s + + + +""" + +notfound_template = """ + + +404 Not Found + + +404 %s not found + + + +""" +messages = [] + +# must be named 'application' to work with our wsgi simple server +def application(environ, start_response): + status = '200 OK' + response_headers = [('Content_type', 'text/HTML')] + start_response(status, response_headers) + + # send different page depending on URL path + path = environ['PATH_INFO'] + if path == '/echo_wsgi.html': + page = form_page + elif path == '/echo_wsgi.py': + # get message from URL query string, parse_qs returns a list for each key + messages.append(urlparse.parse_qs(environ['QUERY_STRING'])['message'][0]) + page = message_template % ( + "
Previous Message : ".join(messages)) + else: + page = notfound_template % path + return [ page ] # list of strings - must return iterable, not just a string diff --git a/WebProgramming/wsgiAssignment/wsgi_simple_server.py b/WebProgramming/wsgiAssignment/wsgi_simple_server.py new file mode 100644 index 0000000..eed3d5c --- /dev/null +++ b/WebProgramming/wsgiAssignment/wsgi_simple_server.py @@ -0,0 +1,32 @@ +""" +Simple WSGI application runner, including its own WSGI server + +Usage: python simple_wsgi_server.py + +Example: python simple_wsgi_server.py test.wsgi 8080 + +Default application is wsgi_test, default port is 8000 + +The application module can be named anything, but the +application callable it provides MUST be named 'application' +""" + +import sys +from wsgiref.simple_server import make_server + +appname = 'wsgi_test' +port = 8000 + + +nargs = len(sys.argv) +if nargs > 1: + appname = sys.argv[1] +if nargs > 2: + port = int(sys.argv[2]) + +app = __import__(appname) +httpd = make_server('', port, app.application) +print "Running %s on port %s ..." % (appname, port) + +# Respond to requests until process is killed +httpd.serve_forever() From cdfa3c13dc99e5f9a41a160a95ca0f332bc99840 Mon Sep 17 00:00:00 2001 From: Mark Price Date: Tue, 28 Feb 2012 18:08:27 -0800 Subject: [PATCH 15/17] Adding Flask information, bookdb exercise, etc. --- WebProgramming/FlaskLab/echo_flask.py | 39 ++++++++++++++++ WebProgramming/FlaskLab/echo_tests.py | 37 +++++++++++++++ WebProgramming/FlaskLab/flask_lab.txt | 15 ++++++ WebProgramming/FlaskLab/templates/form.html | 10 ++++ WebProgramming/booksPage/__init__.py | 0 WebProgramming/booksPage/bookdb.py | 42 +++++++++++++++++ WebProgramming/booksPage/bookdb_test.py | 28 +++++++++++ WebProgramming/booksPage/books.py | 46 +++++++++++++++++++ WebProgramming/booksPage/books.txt | 11 +++++ WebProgramming/booksPage/templates/book.html | 15 ++++++ .../booksPage/templates/booksList.html | 15 ++++++ 11 files changed, 258 insertions(+) create mode 100644 WebProgramming/FlaskLab/echo_flask.py create mode 100644 WebProgramming/FlaskLab/echo_tests.py create mode 100644 WebProgramming/FlaskLab/flask_lab.txt create mode 100644 WebProgramming/FlaskLab/templates/form.html create mode 100644 WebProgramming/booksPage/__init__.py create mode 100644 WebProgramming/booksPage/bookdb.py create mode 100644 WebProgramming/booksPage/bookdb_test.py create mode 100644 WebProgramming/booksPage/books.py create mode 100644 WebProgramming/booksPage/books.txt create mode 100644 WebProgramming/booksPage/templates/book.html create mode 100644 WebProgramming/booksPage/templates/booksList.html diff --git a/WebProgramming/FlaskLab/echo_flask.py b/WebProgramming/FlaskLab/echo_flask.py new file mode 100644 index 0000000..6c06125 --- /dev/null +++ b/WebProgramming/FlaskLab/echo_flask.py @@ -0,0 +1,39 @@ +""" +Minimal Flask + forms demo + +Send HTML page that echoes message from HTTP request +To get started, point browser at echo_flask.html +""" + +from flask import Flask, render_template, request +import copy + +# No need for message page +# Flask converts view function return string to HTML page + +app = Flask(__name__) + +app.debug = True # development only - remove on production machines + +messages = [] + +# View functions generate HTTP responses including HTML pages and headers + +@app.route('/echo_flask.html') +def form(): + return render_template('form.html') +# return form_page + +@app.route('/echo_flask.py') +def message_page(): + # Flask Quickstart suggests request.form should work, but here it is empty + # Flask converts return string to HTML page + messages.insert(0,request.args['message']) + return render_template('response.html', messages=copy.deepcopy(messages)) +# return 'Message: %s' % ("
Previous Message : ".join(messages)) + +# No function needed for other routes - Flask will send 404 page + +if __name__ == '__main__': + app.run() + diff --git a/WebProgramming/FlaskLab/echo_tests.py b/WebProgramming/FlaskLab/echo_tests.py new file mode 100644 index 0000000..71c4bf1 --- /dev/null +++ b/WebProgramming/FlaskLab/echo_tests.py @@ -0,0 +1,37 @@ +""" +Demonstrate Flask test support: test without server +""" + +import echo_flask as e + +# Flask test support +tc = e.app.test_client() +print tc +print +print + +# should respond with 404 +r = tc.get('/') +print r +print r.data +print +print + +# should respond with form +r = tc.get('/echo_flask.html') +print r +print r.data +print +print + +# should respond with message page +r = tc.get('/echo_flask.py?message=Hello') +print r +print r.headers +print r.data +print +print + +# This will fail if application isn't working +#assert 'Hello' in r.data # demonstrate success +assert 'Goodbye' in r.data # demonstrate failure diff --git a/WebProgramming/FlaskLab/flask_lab.txt b/WebProgramming/FlaskLab/flask_lab.txt new file mode 100644 index 0000000..7742c29 --- /dev/null +++ b/WebProgramming/FlaskLab/flask_lab.txt @@ -0,0 +1,15 @@ +flask_lab.txt ++-- + +Week 7 Lab: Flask + + Install Flask on your computer + + Revise echo_flask.py to show all the messages received since startup. + Suggestion: experiment with formatting the output page. What if + you return a big string? HTML? Does the templating system help? + + To install, consult http://flask.pocoo.org/docs/installation/ + -- but I didn't take their advice. I do not recommend virtualenv + I do not have pip installed so I tried sudo easy_install Flask + worked for me, installed Flask 0.8, Jinja2 2.6, Werkzeug 0.8.3 diff --git a/WebProgramming/FlaskLab/templates/form.html b/WebProgramming/FlaskLab/templates/form.html new file mode 100644 index 0000000..fa362f0 --- /dev/null +++ b/WebProgramming/FlaskLab/templates/form.html @@ -0,0 +1,10 @@ + +Echo request + + +
+Message: + +
+ + diff --git a/WebProgramming/booksPage/__init__.py b/WebProgramming/booksPage/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/WebProgramming/booksPage/bookdb.py b/WebProgramming/booksPage/bookdb.py new file mode 100644 index 0000000..1f9a441 --- /dev/null +++ b/WebProgramming/booksPage/bookdb.py @@ -0,0 +1,42 @@ +""" +From Brian Dorsey's Internet Programming in Python, Winter 2011 +""" + +class BookDB(): + def titles(self): + titles = [dict(id=id, title=database[id]['title']) for id in database.keys()] + return titles + + def title_info(self, id): + return database[id] + + +# let's pretend we're getting this information from a database somewhere +database = { + 'id1' : {'title' : 'CherryPy Essentials: Rapid Python Web Application Development', + 'isbn' : '978-1904811848', + 'publisher' : 'Packt Publishing (March 31, 2007)', + 'author' : 'Sylvain Hellegouarch', + }, + 'id2' : {'title' : 'Python for Software Design: How to Think Like a Computer Scientist', + 'isbn' : '978-0521725965', + 'publisher' : 'Cambridge University Press; 1 edition (March 16, 2009)', + 'author' : 'Allen B. Downey', + }, + 'id3' : {'title' : 'Foundations of Python Network Programming', + 'isbn' : '978-1430230038', + 'publisher' : 'Apress; 2 edition (December 21, 2010)', + 'author' : 'John Goerzen', + }, + 'id4' : {'title' : 'Python Cookbook, Second Edition', + 'isbn' : '978-0-596-00797-3', + 'publisher' : 'O''Reilly Media', + 'author' : 'Alex Martelli, Anna Ravenscroft, David Ascher', + }, + 'id5' : {'title' : 'The Pragmatic Programmer: From Journeyman to Master', + 'isbn' : '978-0201616224', + 'publisher' : 'Addison-Wesley Professional (October 30, 1999)', + 'author' : 'Andrew Hunt, David Thomas', + }, +} + diff --git a/WebProgramming/booksPage/bookdb_test.py b/WebProgramming/booksPage/bookdb_test.py new file mode 100644 index 0000000..3d19756 --- /dev/null +++ b/WebProgramming/booksPage/bookdb_test.py @@ -0,0 +1,28 @@ +""" +From Brian Dorsey's Internet Programming in Python, Winter 2011 +""" + +import bookdb + +def test_list_books(): + books = bookdb.BookDB() + titles = books.titles() + assert len(titles) > 1 + print titles + for title in titles: + assert 'title' in title + assert 'id' in title + +def test_get_book_info(): + books = bookdb.BookDB() + titles = books.titles() + id = titles[0]['id'] + print id + info = books.title_info(id) + print info + assert 'title' in info + assert info['title'] == titles[0]['title'] + assert 'publisher' in info + assert 'isbn' in info + assert 'author' in info + diff --git a/WebProgramming/booksPage/books.py b/WebProgramming/booksPage/books.py new file mode 100644 index 0000000..35ea535 --- /dev/null +++ b/WebProgramming/booksPage/books.py @@ -0,0 +1,46 @@ +""" +Minimal Flask + forms demo + +Send HTML page that echoes message from HTTP request +To get started, point browser at echo_flask.html +""" + +from flask import Flask, render_template, request +from bookdb import BookDB + +# No need for message page +# Flask converts view function return string to HTML page + +app = Flask(__name__) + +app.debug = True # development only - remove on production machines + +booksDB = BookDB () + +# View functions generate HTTP responses including HTML pages and headers + +@app.route('/books.html') +def bookList(): + return render_template('bookslist.html',titles = booksDB.titles()) +# return form_page + +@app.route('/abook/') +def bookInfo(book_id): + return render_template('book.html', thisBook=booksDB.title_info(book_id)) + +# return from_page +#=============================================================================== +# @app.route('/echo_flask.py') +# def message_page(): +# # Flask Quickstart suggests request.form should work, but here it is empty +# # Flask converts return string to HTML page +# messages.insert(0,request.args['message']) +# return render_template('response.html', messages=copy.deepcopy(messages)) +# # return 'Message: %s' % ("
Previous Message : ".join(messages)) +#=============================================================================== + +# No function needed for other routes - Flask will send 404 page + +if __name__ == '__main__': + app.run() + diff --git a/WebProgramming/booksPage/books.txt b/WebProgramming/booksPage/books.txt new file mode 100644 index 0000000..1dda502 --- /dev/null +++ b/WebProgramming/booksPage/books.txt @@ -0,0 +1,11 @@ +books.txt ++-- + +Week 7 Assignment: Books web site + +- Write a multi page website, using bookdb.py +- Index page is a list of books, link to a detail page per book +- Each detail page displays info about one book +- Use any Python tech you’d like + +(from Brian Dorsey's Internet Programming in Python, Winter 2011) diff --git a/WebProgramming/booksPage/templates/book.html b/WebProgramming/booksPage/templates/book.html new file mode 100644 index 0000000..49df0e3 --- /dev/null +++ b/WebProgramming/booksPage/templates/book.html @@ -0,0 +1,15 @@ + +Book List + + +

{{ thisbook['title] }} :

+
+ +
+ + + diff --git a/WebProgramming/booksPage/templates/booksList.html b/WebProgramming/booksPage/templates/booksList.html new file mode 100644 index 0000000..93b0d13 --- /dev/null +++ b/WebProgramming/booksPage/templates/booksList.html @@ -0,0 +1,15 @@ + +Book List + + +

Books Available in Library :

+
+ +
+ + + From 88a6dffaedcdfc27f06b8da18e9c76af692fc0f3 Mon Sep 17 00:00:00 2001 From: Mark Price Date: Tue, 28 Feb 2012 18:22:50 -0800 Subject: [PATCH 16/17] Few little fixes --- WebProgramming/booksPage/books.py | 13 ++----------- WebProgramming/booksPage/templates/book.html | 4 ++-- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/WebProgramming/booksPage/books.py b/WebProgramming/booksPage/books.py index 35ea535..2a1a790 100644 --- a/WebProgramming/booksPage/books.py +++ b/WebProgramming/booksPage/books.py @@ -26,18 +26,9 @@ def bookList(): @app.route('/abook/') def bookInfo(book_id): - return render_template('book.html', thisBook=booksDB.title_info(book_id)) - + return render_template('book.html', thisBook = booksDB.title_info(book_id)) # return from_page -#=============================================================================== -# @app.route('/echo_flask.py') -# def message_page(): -# # Flask Quickstart suggests request.form should work, but here it is empty -# # Flask converts return string to HTML page -# messages.insert(0,request.args['message']) -# return render_template('response.html', messages=copy.deepcopy(messages)) -# # return 'Message: %s' % ("
Previous Message : ".join(messages)) -#=============================================================================== + # No function needed for other routes - Flask will send 404 page diff --git a/WebProgramming/booksPage/templates/book.html b/WebProgramming/booksPage/templates/book.html index 49df0e3..379b35c 100644 --- a/WebProgramming/booksPage/templates/book.html +++ b/WebProgramming/booksPage/templates/book.html @@ -2,11 +2,11 @@ Book List -

{{ thisbook['title] }} :

+

{{ thisBook['title'] }} :

From 7f2e59c835267add4a8a6a51c63d5f7ee729e784 Mon Sep 17 00:00:00 2001 From: Mark Price Date: Tue, 13 Mar 2012 13:21:27 -0700 Subject: [PATCH 17/17] Django books implementation --- .../FlaskLab/templates/response.html | 16 ++ WebProgramming/books/__init__.py | 0 WebProgramming/books/manage.py | 14 ++ WebProgramming/books/settings.py | 145 ++++++++++++++++++ WebProgramming/books/urls.py | 17 ++ 5 files changed, 192 insertions(+) create mode 100644 WebProgramming/FlaskLab/templates/response.html create mode 100644 WebProgramming/books/__init__.py create mode 100644 WebProgramming/books/manage.py create mode 100644 WebProgramming/books/settings.py create mode 100644 WebProgramming/books/urls.py diff --git a/WebProgramming/FlaskLab/templates/response.html b/WebProgramming/FlaskLab/templates/response.html new file mode 100644 index 0000000..9061167 --- /dev/null +++ b/WebProgramming/FlaskLab/templates/response.html @@ -0,0 +1,16 @@ + +Echo request + + +
+

+Message: +{{ messages[0] }} +

+{% for message in messages[1:] %} +

Old Message : {{ message }}

+{% endfor %} +
+ + + diff --git a/WebProgramming/books/__init__.py b/WebProgramming/books/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/WebProgramming/books/manage.py b/WebProgramming/books/manage.py new file mode 100644 index 0000000..3e4eedc --- /dev/null +++ b/WebProgramming/books/manage.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python +from django.core.management import execute_manager +import imp +try: + imp.find_module('settings') # Assumed to be in the same directory. +except ImportError: + import sys + sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n" % __file__) + sys.exit(1) + +import settings + +if __name__ == "__main__": + execute_manager(settings) diff --git a/WebProgramming/books/settings.py b/WebProgramming/books/settings.py new file mode 100644 index 0000000..b1179ee --- /dev/null +++ b/WebProgramming/books/settings.py @@ -0,0 +1,145 @@ +# Django settings for books project. + +DEBUG = True +TEMPLATE_DEBUG = DEBUG + +ADMINS = ( + # ('Your Name', 'your_email@example.com'), +) + +MANAGERS = ADMINS + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. + 'NAME': '/Users/mark/Documents/workspace/books/sqlite.db', # Or path to database file if using sqlite3. + 'USER': '', # Not used with sqlite3. + 'PASSWORD': '', # Not used with sqlite3. + 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. + 'PORT': '', # Set to empty string for default. Not used with sqlite3. + } +} + +# Local time zone for this installation. Choices can be found here: +# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name +# although not all choices may be available on all operating systems. +# On Unix systems, a value of None will cause Django to use the same +# timezone as the operating system. +# If running in a Windows environment this must be set to the same as your +# system time zone. +TIME_ZONE = 'America/Chicago' + +# Language code for this installation. All choices can be found here: +# http://www.i18nguy.com/unicode/language-identifiers.html +LANGUAGE_CODE = 'en-us' + +SITE_ID = 1 + +# If you set this to False, Django will make some optimizations so as not +# to load the internationalization machinery. +USE_I18N = True + +# If you set this to False, Django will not format dates, numbers and +# calendars according to the current locale +USE_L10N = True + +# Absolute filesystem path to the directory that will hold user-uploaded files. +# Example: "/home/media/media.lawrence.com/media/" +MEDIA_ROOT = '' + +# URL that handles the media served from MEDIA_ROOT. Make sure to use a +# trailing slash. +# Examples: "http://media.lawrence.com/media/", "http://example.com/media/" +MEDIA_URL = '' + +# Absolute path to the directory static files should be collected to. +# Don't put anything in this directory yourself; store your static files +# in apps' "static/" subdirectories and in STATICFILES_DIRS. +# Example: "/home/media/media.lawrence.com/static/" +STATIC_ROOT = '' + +# URL prefix for static files. +# Example: "http://media.lawrence.com/static/" +STATIC_URL = '/static/' + +# URL prefix for admin static files -- CSS, JavaScript and images. +# Make sure to use a trailing slash. +# Examples: "http://foo.com/static/admin/", "/static/admin/". +ADMIN_MEDIA_PREFIX = '/static/admin/' + +# Additional locations of static files +STATICFILES_DIRS = ( + # Put strings here, like "/home/html/static" or "C:/www/django/static". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. +) + +# List of finder classes that know how to find static files in +# various locations. +STATICFILES_FINDERS = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', +# 'django.contrib.staticfiles.finders.DefaultStorageFinder', +) + +# Make this unique, and don't share it with anybody. +SECRET_KEY = '!s@20740-vblpbdyi-8!9&hj%=z&!#j@69*h^4un1sy=o*2ig%' + +# List of callables that know how to import templates from various sources. +TEMPLATE_LOADERS = ( + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', +# 'django.template.loaders.eggs.Loader', +) + +MIDDLEWARE_CLASSES = ( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', +) + +ROOT_URLCONF = 'books.urls' + +TEMPLATE_DIRS = ( + # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. +) + +INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.messages', + 'django.contrib.staticfiles', + # Uncomment the next line to enable the admin: + # 'django.contrib.admin', + # Uncomment the next line to enable admin documentation: + # 'django.contrib.admindocs', +) + +# A sample logging configuration. The only tangible logging +# performed by this configuration is to send an email to +# the site admins on every HTTP 500 error. +# See http://docs.djangoproject.com/en/dev/topics/logging for +# more details on how to customize your logging configuration. +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'class': 'django.utils.log.AdminEmailHandler' + } + }, + 'loggers': { + 'django.request': { + 'handlers': ['mail_admins'], + 'level': 'ERROR', + 'propagate': True, + }, + } +} diff --git a/WebProgramming/books/urls.py b/WebProgramming/books/urls.py new file mode 100644 index 0000000..9984d96 --- /dev/null +++ b/WebProgramming/books/urls.py @@ -0,0 +1,17 @@ +from django.conf.urls.defaults import patterns, include, url + +# Uncomment the next two lines to enable the admin: +# from django.contrib import admin +# admin.autodiscover() + +urlpatterns = patterns('', + # Examples: + # url(r'^$', 'books.views.home', name='home'), + # url(r'^books/', include('books.foo.urls')), + + # Uncomment the admin/doc line below to enable admin documentation: + # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), + + # Uncomment the next line to enable the admin: + # url(r'^admin/', include(admin.site.urls)), +)