├── .gitignore
├── .project
├── .pydevproject
├── README
├── basic_examples
├── extra_stuff.py
├── my_module.py
├── python_booleans.py
├── python_control.py
├── python_conversions.py
├── python_dictionary.py
├── python_exceptions.py
├── python_files.py
├── python_functions.py
├── python_lists.py
├── python_logical_lines.py
├── python_modules.py
├── python_numbers.py
├── python_objects.py
├── python_os_module.py
├── python_read.py
├── python_sequences.py
├── python_star_args_and_kwargs.py
├── python_string_interpolation.py
├── python_strings.py
├── python_tuples.py
└── python_write.py
├── mini_projects
└── adaptive_backup.py
└── tdd
├── TDDWithPython.odp
├── iostubbing
├── all_tests.py
├── test_write_user_details.py
├── test_write_user_details_iostub.py
├── test_write_user_details_istub.py
├── test_write_user_details_mock.py
├── write_user_details.py
└── write_user_details_di.py
├── tdd_python_plan.txt
└── transformations
├── MailerProg.py
├── Msg2Xml.py
├── TestMailerProg.py
├── VerifyServers.py
├── email1.msg
├── email2.msg
├── email3.msg
├── email4.msg
└── email5.msg
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 |
3 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | python-examples
4 |
5 |
6 |
7 |
8 |
9 | org.python.pydev.PyDevBuilder
10 |
11 |
12 |
13 |
14 | org.eclipse.wst.common.project.facet.core.builder
15 |
16 |
17 |
18 |
19 |
20 | org.eclipse.wst.common.project.facet.core.nature
21 | org.python.pydev.pythonNature
22 |
23 |
24 |
--------------------------------------------------------------------------------
/.pydevproject:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Default
6 | python 2.7
7 |
8 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | **About**
2 |
3 | This project contains a series of Python examples to help someone new to Python learn how to program in Python.
4 |
5 | I am listing the order in which you may want to read these examples. The order below starts with simple concepts, moving on to more advanced ones.
6 |
7 | **Introduction To Python**
8 |
9 | - python_strings.py
10 | - python_numbers.py
11 | - python_booleans.py
12 | - python_conversions.py
13 | - using_modules.py
14 | - string_interpolation.py
15 | - python_lists.py
16 | - python_dictionary.py
17 | - python_tupes.py
18 | - python_sequences,py
19 | - python_functions.py
20 | - python_logical_lines.py
21 | - python_string_interpolation.py
22 | - python_modules.py
23 | - python_os_module.py
24 | - python_star_args_and_kwargs.py
25 | - python_objects.py
26 |
27 | **TDD With Python**
28 |
29 | Slides for introduction to TDD With Python
30 |
31 | Code Samples
32 |
33 | - write_user_details.py
34 | - test_write_user_details.py
35 | - test_write_user_details_istub.py
36 | - test_write_user_details_iostub.py
37 | - write_user_details_di.py
38 | - test_write_user_details_mock.py
39 |
--------------------------------------------------------------------------------
/basic_examples/extra_stuff.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | import os
4 |
5 | #If there is only one statement that would have gone in the block then it can
6 | #be specified in the same line
7 | if os.name == 'posix': print 'You are cool'
8 |
9 | def say_hello(): return 'hello'
10 | print say_hello()
11 |
12 | #List comprehensions
13 | class Employee:
14 |
15 | def __str__(self):
16 | return self.name + ' ' + str(self.salary)
17 |
18 | def __init__(self, name, salary):
19 | self.name = name
20 | self.salary = salary
21 |
22 |
23 | employees = []
24 | employees.append(Employee('Tom', 30000))
25 | employees.append(Employee('Satish', 40000))
26 | employees.append(Employee('Harry', 50000))
27 |
28 | #Let's get a list of all employees whose salaries are greater than 30000
29 | #using list comprehensions
30 | sal_more_than_40k = [e for e in employees if e.salary > 40000]
31 | print 'Listing ' + str(len(sal_more_than_40k)) + ' employees with sal > 40k'
32 | for emp in sal_more_than_40k:
33 | print emp
34 |
35 | #Now let's get something similar using lambda expressions
36 | sal_more_than_30k = filter(lambda e : e.salary > 30000, employees)
37 | print "Listing " + str(len(sal_more_than_30k)) + " employees with sal > 30k"
38 | for emp in sal_more_than_30k:
39 | print emp
40 |
41 | #`` and repr return a canonical form of an object in the form if a string
42 | #We can control what repr returns with the __repr__() method
43 | print repr(sal_more_than_30k)
44 | print `sal_more_than_30k`
45 | eval(repr(sal_more_than_30k))
46 |
--------------------------------------------------------------------------------
/basic_examples/my_module.py:
--------------------------------------------------------------------------------
1 | def sayHello():
2 | print 'Hello'
3 |
4 | print 'Module ', __name__, ' initialized'
5 |
--------------------------------------------------------------------------------
/basic_examples/python_booleans.py:
--------------------------------------------------------------------------------
1 | print "Python has 10 type of booleans", True, " and ", False
2 | print "They are normally the result of comparisons"
3 |
4 | num = 8
5 | if num < 10:
6 | print num, " is less than 10"
7 | else:
8 | print num, " is not less than 10"
9 |
10 |
11 | print "What we just saw are conditional statements.
12 | print "It's ok if you do not understand them, we will look into them in greater details very soon."
13 |
--------------------------------------------------------------------------------
/basic_examples/python_control.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | age = int(raw_input('Enter your age '))
4 | #If else statements in Python
5 | if age < 6:
6 | print 'Hello little one'
7 | elif age >= 6 and age < 10:
8 | print 'Are you enjoying school?'
9 | elif age >= 10 and age < 13:
10 | print 'You are a Tween now'
11 | elif age >= 13 and age < 20:
12 | print 'Now you are officially a teenager'
13 | else:
14 | print 'Welcome to the real world'
15 |
16 | #PYTHON DOES NOT HAVE A SWITCH STATEMENT
17 |
18 | #Python while loop
19 | number = age
20 | fact = 1
21 | st = 'abc'
22 | while(age < 2):
23 | fact = fact * age
24 | age = age - 1
25 | else:
26 | print 'Python while loops have a redundant else'
27 | print 'factorial of your age is: ', fact
28 |
29 | #The for loop in Python essentially iterates over a sequence. This is very
30 | #similar to the for(i : collection) loop in Java
31 | print 'printing all integers from 1 to 5'
32 | for i in range(1,5):
33 | print i
34 |
35 | #We can also have a stepping factpr in the iteration
36 | print 'printing alternate numbers from 1 to 10'
37 | for i in range(1,11, 2):
38 | print i
39 |
40 | #Python also has the break and continue statements which work just like in Java
41 |
--------------------------------------------------------------------------------
/basic_examples/python_conversions.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | #num is of type int
4 | num = 8
5 | #eight is of type str
6 | eight = str(num)
7 | print "eight is of type ", type(eight)
8 |
9 | #num8 is of type int
10 | num8 = int(eight)
11 | print "num8 is of type ", type(num8)
12 |
13 | t = True
14 | strt = str(t)
15 | print "strt is of type ", type(strt)
--------------------------------------------------------------------------------
/basic_examples/python_dictionary.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | #A Python dictionary is a collection which contains key value pairs, where the
4 | #key must be an immutable object
5 |
6 | # you can also run this in the interpretor
7 |
8 | phonebook = {'joe':'568-564-1109', 'ashish':'657-097-7862'}
9 |
10 | print "\nPrinting the phonebook"
11 | print phonebook
12 | print "\nPrinting joe's phone number"
13 | phonebook['joe']
14 |
15 | print "\nAdding an element to the phonebook"
16 | phonebook['joel'] = '657'
17 | print "\nPrinting the phone number of the newly added contact joel"
18 | print phonebook['joel']
19 |
20 | print "\nItearating across the phonebook with it's keys"
21 | for k in phonebook.keys():
22 | print k, phonebook[k]
23 |
24 | print "\nHere's how we remove an element from the dictionary - removing 'joel'"
25 | del(phonebook['joel'])
26 |
27 | print "\nIterating across the phonebook with key and value"
28 | for k, v in phonebook.items():
29 | print k, v
30 |
31 |
32 |
--------------------------------------------------------------------------------
/basic_examples/python_exceptions.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | class MyMethodNotImplementedError(Exception):
4 | def __init__(self):
5 | Exception.__init__(self)
6 |
7 | #We will raise an Error if this method is called. The purpose is to show which
8 | #Error to use to signal that a method os not yet implemented and also to show
9 | #how to raise Exceptions
10 | def some_method():
11 | raise NotImplementedError
12 |
13 | def another_method():
14 | raise MyMethodNotImplementedError()
15 |
16 | try:
17 | some_method()
18 | except NotImplementedError, e:
19 | print 'Method is not implemented ', e
20 |
21 | another_method()
22 |
--------------------------------------------------------------------------------
/basic_examples/python_files.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | import os
4 |
5 | def read_file(name):
6 | print 'printing contents of file ' + name
7 | f = None
8 | #We use try...finally to ensure that the file is closed even if there
9 | #is a problem while processing it
10 | try:
11 | f = file(name, 'r')
12 | line = f.readline()
13 | while(len(line) != 0):
14 | print line, #notice the , to prevent printing a newline character
15 | line = f.readline()
16 | finally:
17 | if f != None:
18 | f.close()
19 |
20 | def create_module(name):
21 | print 'creating module ' + name
22 | f = None
23 | #We use try...finally to ensure that the file is closed even if there
24 | #is a problem while processing it
25 | try:
26 | f = file(name, 'w')
27 | #Notice that a newline is not inserted automatically
28 | #There is no println in Python
29 | f.write('#!/usr/bin/python\n')
30 | f.write('# Filename : ' + name + '\n')
31 | f.write("'''Class comment to be completed.'''\n")
32 | f.write('\n')
33 | f.write('def __init__():\n')
34 | f.write('\n')
35 | f.write('def __str__():\n')
36 | f.write('\n')
37 | finally:
38 | if f != None:
39 | f.close()
40 |
41 | name = '/home/pshah/tmp/tmp.py'
42 | #Use exceptions to make the program fail gracefully and provide a meaningful
43 | #message to the user
44 | try:
45 | create_module('/home/pshah/tmp1/tmp.py')
46 | read_file(name)
47 | #Remove the file so we do not pollute the disk
48 | os.remove(name)
49 | except Exception, e:
50 | print 'An error ocurred in this program ', e
51 |
--------------------------------------------------------------------------------
/basic_examples/python_functions.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | maxCalled = 0
4 | minCalled = 0
5 |
6 |
7 |
8 |
9 | def max_val(a,b):
10 | '''Returns the maximum of the specified arguments.
11 |
12 | Arguments must be numbers'''
13 |
14 | global maxCalled
15 | maxCalled = maxCalled + 1
16 |
17 | if(a > b):
18 | return a
19 | elif(b > a):
20 | return b
21 | else:
22 | return a
23 |
24 | def min_val(a,b):
25 | '''Returns the minimum of the specified arguments.
26 |
27 | Arguments must be numbers'''
28 |
29 | global minCalled
30 | minCalled = minCalled + 1
31 |
32 | if(a < b):
33 | return a
34 | elif(b < a):
35 | return b
36 | else:
37 | return a
38 |
39 | def print_usage(init_msg, max_val=True, min_val=True):
40 | global maxCalled, minCalled
41 | print init_msg
42 | if max_val:
43 | print 'functin max_val was called', maxCalled, ' times'
44 | if min_val:
45 | print 'function min_val was called', minCalled, ' times'
46 |
47 |
48 | print 'Calling function max_val'
49 | print max_val.__doc__
50 | max_val(1,4)
51 | max_val(2,b=1)
52 | max_val(b=4,a=3)
53 |
54 | print 'Calling function min_val'
55 | print min_val.__doc__
56 | min_val(1,4)
57 | min_val(2,4)
58 | min_val(4,b=9)
59 |
60 | print_usage('The usage of functions min_val and max_val')
61 |
--------------------------------------------------------------------------------
/basic_examples/python_lists.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | jvm_langs = ['Java', 'Jython', 'Groovy', 'Scala', 'Jruby']
4 |
5 | #How many JVM langs do you know ?
6 | print 'I know of ', jvm_langs.__len__(), 'langs that can run on the JVM'
7 |
8 | #It's not a good idea to directly us __xxx__ methods
9 | #A better way is. Remember there is usually a top level function which
10 | #is the idoimatic way to access the __xxx__method
11 | print 'I know of ', len(jvm_langs), 'langs that can run on the JVM'
12 |
13 | print 'Oops I forgot Clojure'
14 | jvm_langs.append('Clojure')
15 |
16 | #Let's iterate across the list
17 | for lang in jvm_langs:
18 | print lang
19 |
20 | #Can we get the 3rd element of the list ?
21 | print "The 3rd JVM language is ", jvm_langs[2]
22 | print "The first 3 JVM languages are ", jvm_langs[:3]
23 | print "The 2nd to 4th JVM languages are ", jvm_langs[1:4]
24 |
25 | print "let's sort these languages"
26 | jvm_langs.sort()
27 | print jvm_langs
28 |
29 |
30 |
--------------------------------------------------------------------------------
/basic_examples/python_logical_lines.py:
--------------------------------------------------------------------------------
1 | #This physical like is also a logical line
2 | i = 3
3 | print i
4 |
5 | #This physical line actually contrains two logical lines
6 | i = 8; j = 0
7 | print i + j
8 |
9 | #Now we show multiple physical lines that represent one logical line
10 | print "this line may appear to be have a newline\
11 | but in reality it does not"
12 |
--------------------------------------------------------------------------------
/basic_examples/python_modules.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | import sys
4 | import my_module
5 |
6 | #printing all the command line arguments provided to this program
7 | print "cmd args to this program are '", sys.argv, "'"
8 |
9 | print 'The PYTHONPATH is ', sys.path
10 |
11 | #Let's call a function from my_module
12 | my_module.sayHello()
13 |
--------------------------------------------------------------------------------
/basic_examples/python_numbers.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | print "8 is an integer ", 8
4 |
5 | num = 8
6 | print "8 is an integer and 'num' is a variable referring to an integer", num
7 |
8 | print "8/4 is 2. let's check ", num/4
9 | print "But why is 8/3 also 2 ? ", num/3
10 | print """
11 | Maybe because when integers are divided, the result is also an integer.
12 | Which means the result is truncated. Maybe if we used floats we might get
13 | a better answer.
14 | """
15 |
16 | num = 8.0
17 | print "8.0/3.0 = ", num/3.0
18 |
19 | print """
20 | ok great. BTW I hope you realized how we were able to assign 'num' to a float
21 | after assigning it to an int. This is because Python is not a statically
22 | typed language. We could have assigned 'num' to a String as well.
23 | """
24 |
25 | #What is the default type of numbers in Python... compare this with Groovy
26 | max64BitInt = 2**64 - 1
27 | bigNum = max64BitInt + 126
28 | print 'This is a big number ', bigNum
29 |
30 | #Python has the floor dividion operator as well as the power operator
31 | #I do not think Java has any of these. Groovy probably has the power op
32 | print '4//3 = ', 4//3
33 |
34 | #See the GroovyNumbers program and verify that all concepts appear here as well
35 |
--------------------------------------------------------------------------------
/basic_examples/python_objects.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | class InvoiceItem:
4 | '''An item within the invoice'''
5 | def __str__(self):
6 | return self.text + ' ' + str(self.amt)
7 |
8 | def __init__(self, **kwargs):
9 | self.text = ''
10 | self.amt = 0
11 | if kwargs['text'] != None:
12 | self.text = kwargs['text']
13 | if kwargs['amt'] != None:
14 | self.amt = kwargs['amt']
15 |
16 | class Invoice:
17 | # This is a static variable
18 | my_company_name = "DIYComputerScience"
19 |
20 | # This is a static method
21 | @staticmethod
22 | def get_service_tax_per():
23 | return 12.5
24 |
25 | '''An invoice.'''
26 | def __str__(self):
27 | return self.number + ' ' + str(self.amt())
28 |
29 | def __init__(self, **kwargs):
30 | self.number = ''
31 | self.client = ''
32 | self.date = ''
33 | self.invoice_items = []
34 |
35 | def add_invoice_item(self, invoice_entry):
36 | self.invoice_items.append(invoice_entry)
37 |
38 | def amt(self):
39 | amt = 0
40 | for item in self.invoice_items:
41 | amt = amt + item.amt
42 | return amt
43 |
44 | invoice = Invoice()
45 | invoice.number = '20080422_01'
46 | invoice.client = 'Sun Microsystems'
47 | invoice.date = '22/04/2008'
48 |
49 | invoice_item = InvoiceItem(text='consulting April', amt=2000)
50 | invoice.add_invoice_item(invoice_item)
51 |
52 | print invoice
53 |
--------------------------------------------------------------------------------
/basic_examples/python_os_module.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | #The os module exposes various operating system related details and
4 | #functionality. In this module we will explore some of the more commonly
5 | #needed functionality
6 |
7 | import os
8 |
9 | print 'Your operating system: ', os.name
10 | print 'Your username: ', os.getlogin()
11 | print 'Your current working directory is: ', os.getcwd()
12 | print 'Your system path is: ', os.getenv('PATH')
13 |
--------------------------------------------------------------------------------
/basic_examples/python_read.py:
--------------------------------------------------------------------------------
1 | # from sys module import a member called 'argv'
2 | from sys import argv
3 | #unpack
4 | script, filename = argv
5 | fp = open(filename)
6 | print "Reading file %r " % fp
7 | print fp.read()
8 | fp.close()
9 |
--------------------------------------------------------------------------------
/basic_examples/python_sequences.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | #Note: lists, tuples, and strings are all sequences in Python. Sequences allow
4 | #indexing and slicing operations
5 | #When a sequence is sliced the resulting object is a brand new object
6 |
7 | jvm_langs = ['Java', 'Jython', 'Groovy', 'JRuby', 'Scala', 'Clojure']
8 | print 'The first JVM language was ', jvm_langs[0]
9 |
10 | #Let's slice the list. Slicing can be done with positive and negative indexes
11 | print 'The second and third JVM languages are ', jvm_langs[1:3]
12 | print 'The last 2 JVM languages are ', jvm_langs[-2:]
13 | print 'The first 2 JVM languages are ', jvm_langs[:2]
14 |
15 | name = 'Parag Shah'
16 | print 'The first name is ', name[0:5]
17 |
--------------------------------------------------------------------------------
/basic_examples/python_star_args_and_kwargs.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | def add_all(*list_of_nums):
4 | sum = 0
5 | for num in list_of_nums:
6 | sum = sum + num
7 | print 'sum ', ' + '.join(str(n) for n in list_of_nums), ' = ', sum
8 |
9 | add_all(2,3,4)
10 |
11 | nums = (2,3,4)
12 | add_all(*nums)
13 |
14 | nums = [2,3,4]
15 | add_all(*nums)
16 |
17 | def add_all_msg(*args, **kwargs):
18 | print kwargs['before']
19 | add_all(*args)
20 | print kwargs['after']
21 |
22 | add_all_msg(2,3,4,before='adding numbers', after='added all numbers')
23 |
--------------------------------------------------------------------------------
/basic_examples/python_string_interpolation.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | from string import Template
4 |
5 | greeting = 'Hello'
6 | name = 'John'
7 |
8 | print("%s %s how are you?" %(greeting, name))
9 |
10 | print "%(greeting)s %(name)s how are you?" % locals()
11 |
12 | print Template('$greeting $name how are you?').substitute(locals())
13 |
14 | #For Python 3.0
15 | #print("{greeting} {name} how are you?".format(**locals()))
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/basic_examples/python_strings.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | #Note: Python strings are immutable
4 |
5 | #Strings can be enclosed in single quotes
6 | print 'Hello World in single quotes'
7 |
8 | #Strings can also be enclosed in double quotes
9 | print "Hello World in double quotes"
10 |
11 | #Strings can also be enclosed in triple quotes
12 | print """ This is a multiline string
13 | Such strings are also possible in Groovy.
14 | These strings can contain ' as well as " quotes """
15 |
16 | #Strings can be continued on the next line
17 | print "This string is continued on the\
18 | next line (in the source) but a newline is not added"
19 |
20 | #Raw strings
21 | print r"The newline character is represented with \n"
22 |
23 | #The following is a unicode string, but here it is a literal.
24 | #How do we specify that a string read from a file should be held
25 | #as a unicode string. Also the +uXXXX notation does not work in
26 | #Python
27 | print u"This is a unicode string u0600"
28 |
29 | #See how the strings are concatenated
30 | print 'hello ' 'world'
31 |
32 | #Notice how the print statement accepts , separated values
33 | print '2 + 3 = ', (2+3)
34 |
35 | #Getting the length of a string
36 | greeting = "Hello my dear friend how are you?"
37 | print "the length of string '" ,greeting, "' is ", len(greeting)
38 |
39 | #Let's check if the string contains the word 'Hello'
40 | if('Hello' in greeting):
41 | print 'This greeting seems to be in English'
42 |
43 | if(greeting.find('Hello') != -1):
44 | print 'This greeting seems to be in English'
45 |
--------------------------------------------------------------------------------
/basic_examples/python_tuples.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | #Note: Python tuples are immutable just like strings
4 |
5 | jvm_langs = ('Java', 'Jython', 'JRuby')
6 | print jvm_langs
7 |
8 | print 'Oops I forgot Scala and Groovy but I cannot add to an existing tuple'
9 |
10 | jvm_langs_revised = ('Scala', 'Groovy', 'Clojure', jvm_langs)
11 | #Notice that the earlier sequence is retained and not flattened
12 | print jvm_langs_revised
13 |
14 |
--------------------------------------------------------------------------------
/basic_examples/python_write.py:
--------------------------------------------------------------------------------
1 | # from sys module import a member called 'argv'
2 | from sys import argv
3 | #unpack
4 | script, filename = argv
5 | fp = open(filename, "w")
6 | print "Writing to file %r " % fp
7 | fp.write("Hello World")
8 | fp.close()
9 |
--------------------------------------------------------------------------------
/mini_projects/adaptive_backup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # Filename : adaptive_backup.py
3 |
4 | import os
5 | import time
6 | import tarfile
7 |
8 | #List of directories and files to backup
9 | bk_src = ['/home/pshah/Documents',
10 | '/home/pshah/Templates']
11 |
12 | #Directory where the backup will be stored
13 | bk_dest = '/home/pshah/bk/'
14 |
15 | bk_fn = bk_dest + time.strftime('%Y%m%d%H%M%S') + '.tgz'
16 | zip_cmd = "zip -qr '%s' %s" % (bk_fn, ' '.join(bk_src))
17 |
18 | tar_file = tarfile.open(bk_fn, 'w:gz')
19 | for file in bk_src:
20 | tar_file.add(file)
21 | tar_file.close()
22 |
23 |
--------------------------------------------------------------------------------
/tdd/TDDWithPython.odp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adaptives/python-examples/ae5e003151be8fcb3a0bfb8924a8e8d5a1d71a81/tdd/TDDWithPython.odp
--------------------------------------------------------------------------------
/tdd/iostubbing/all_tests.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | import test_write_user_details
3 | import test_write_user_details_istub
4 |
5 | suite1 = unittest.TestLoader().loadTestsFromTestCase(test_write_user_details.TestUserDetails)
6 | suite1.addTests(unittest.TestLoader().loadTestsFromTestCase(test_write_user_details_istub.TestUserDetails))
7 |
8 | unittest.TextTestRunner(verbosity=2).run(suite1)
--------------------------------------------------------------------------------
/tdd/iostubbing/test_write_user_details.py:
--------------------------------------------------------------------------------
1 | import unittest
2 |
3 | class TestUserDetails(unittest.TestCase):
4 |
5 | def setUp(self):
6 | super(TestUserDetails, self).setUp()
7 |
8 |
9 | def tearDown(self):
10 | super(TestUserDetails, self).tearDown()
11 |
12 |
13 | def test_output_file_contents(self):
14 | fp = open('Priyanka.txt')
15 | name = fp.readline()
16 | age = fp.readline()
17 | city = fp.readline()
18 | self.assertEqual(name[0:len(name)-1], 'Name : Priyanka')
19 | self.assertEqual(age[0:len(age)-1], 'Age : 33')
20 | self.assertEqual(city[0:len(city)-1], 'City : Mumbai')
21 |
22 | if __name__ == "__main__":
23 | unittest.main()
--------------------------------------------------------------------------------
/tdd/iostubbing/test_write_user_details_iostub.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | import write_user_details
3 | import sys
4 |
5 | def gen_open_stub(output_stub):
6 | def open(fpath, mode):
7 | return output_stub
8 | return open
9 |
10 | class InputStub(object):
11 | def __init__(self, values):
12 | self.values = values
13 | self.cnt = 0
14 |
15 | def readline(self):
16 | if self.cnt < len(self.values):
17 | ret_val = self.values[self.cnt]
18 | self.cnt += 1
19 | return ret_val
20 | else:
21 | raise StopError()
22 |
23 | class OutputStub(object):
24 | def __init__(self):
25 | self.values = []
26 |
27 | def write(self, value):
28 | self.values.append(value)
29 |
30 | def close(self):
31 | self.closed = True
32 |
33 |
34 | class TestUserDetails(unittest.TestCase):
35 |
36 | def test_output_file_contents(self):
37 | values = ['Priyanka', '33', 'Mumbai']
38 | output_stub = OutputStub()
39 | write_user_details.open = gen_open_stub(output_stub)
40 | sys.stdin = InputStub(values)
41 | write_user_details.accept_and_write()
42 | name = output_stub.values[0]
43 | age = output_stub.values[1]
44 | city = output_stub.values[2]
45 | self.assertEqual(name[0:len(name)-1], 'Name : Priyanka')
46 | self.assertEqual(age[0:len(age)-1], 'Age : 33')
47 | self.assertEqual(city[0:len(city)-1], 'City : Mumbai')
48 |
49 | if __name__ == "__main__":
50 | unittest.main()
--------------------------------------------------------------------------------
/tdd/iostubbing/test_write_user_details_istub.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | import write_user_details
3 | import sys
4 |
5 | class InputStub(object):
6 | def __init__(self, values):
7 | self.values = values
8 | self.cnt = 0
9 |
10 | def readline(self):
11 | if self.cnt < len(self.values):
12 | ret_val = self.values[self.cnt]
13 | self.cnt += 1
14 | return ret_val
15 | else:
16 | raise StopError()
17 |
18 | class TestUserDetails(unittest.TestCase):
19 |
20 | def test_output_file_contents(self):
21 | values = ['Priyanka', '33', 'Mumbai']
22 | sys.stdin = InputStub(values)
23 | write_user_details.accept_and_write()
24 | fp = open('Priyanka.txt')
25 | name = fp.readline()
26 | age = fp.readline()
27 | city = fp.readline()
28 | self.assertEqual(name[0:len(name)-1], 'Name : Priyanka')
29 | self.assertEqual(age[0:len(age)-1], 'Age : 33')
30 | self.assertEqual(city[0:len(city)-1], 'City : Mumbai')
31 |
32 | if __name__ == "__main__":
33 | unittest.main()
--------------------------------------------------------------------------------
/tdd/iostubbing/test_write_user_details_mock.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | import write_user_details_di
3 | import sys
4 | import pymock
5 |
6 | class TestUserDetails(pymock.PyMockTestCase):
7 |
8 | def test_output_file_contents(self):
9 | #mock the input proxy
10 | raw_input_provider = self.mock()
11 | mock_raw_input = raw_input_provider.raw_input
12 | self.expectAndReturn(mock_raw_input('What is your name ? '), 'Joe')
13 | self.expectAndReturn(mock_raw_input('What is your age ? '), '40')
14 | self.expectAndReturn(mock_raw_input('Which city do you stay in ? '), 'Pune')
15 |
16 | #mock the file handle
17 | mock_opener_interface = self.mock()
18 | mock_file = self.mock()
19 | self.expectAndReturn(mock_opener_interface.open('Joe.txt', 'w'), mock_file)
20 | mock_file.write('Name : Joe\n')
21 | mock_file.write('Age : 40\n')
22 | mock_file.write('City : Pune\n')
23 | mock_file.close()
24 |
25 | #replay
26 | self.replay()
27 |
28 | #call the actual method
29 | write_user_details_di.accept_and_write(iproxy=raw_input_provider.raw_input, opener=mock_opener_interface.open)
30 |
31 | #verify
32 | self.verify()
33 |
34 |
35 | if __name__ == "__main__":
36 | unittest.main()
--------------------------------------------------------------------------------
/tdd/iostubbing/write_user_details.py:
--------------------------------------------------------------------------------
1 | """
2 | In this file we accept some details from the user and write them
3 | to a file.
4 | """
5 |
6 | def accept_and_write():
7 | name = raw_input('What is your name ? ')
8 | age = raw_input('What is your age ? ')
9 | city = raw_input('Which city do you stay in ? ')
10 |
11 | fp = open(name+'.txt', 'w')
12 | fp.write("Name : %s\n" % name)
13 | fp.write("Age : %s\n" % age)
14 | fp.write("City : %s\n" % city)
15 | fp.close()
16 |
17 | if __name__ == "__main__":
18 | accept_and_write()
19 |
--------------------------------------------------------------------------------
/tdd/iostubbing/write_user_details_di.py:
--------------------------------------------------------------------------------
1 | """
2 | In this file we accept some details from the user and write them
3 | to a file.
4 | """
5 |
6 | class InputProxy():
7 | def raw_input(self, msg):
8 | return raw_input(msg)
9 |
10 |
11 | def accept_and_write(iproxy=raw_input, opener=open):
12 | name = iproxy('What is your name ? ')
13 | age = iproxy('What is your age ? ')
14 | city = iproxy('Which city do you stay in ? ')
15 |
16 | fp = opener(name+'.txt', 'w')
17 | fp.write("Name : %s\n" % name)
18 | fp.write("Age : %s\n" % age)
19 | fp.write("City : %s\n" % city)
20 | fp.close()
--------------------------------------------------------------------------------
/tdd/tdd_python_plan.txt:
--------------------------------------------------------------------------------
1 | There are two ways to us the PyMock framework. As standalone or as a unittest testcase. If used in standalone mode, we need to create a controller, and when used as a unittest testcase, the controller is created automatically for us.
2 |
3 | Stana
4 |
5 |
6 | =============================================
7 | 1. Explain and run write_user_details.py
8 | 2. Explaina and Test the output file with test_write_user_details.py
9 | 3. Explain the drawbacks of the plumbing we have to do with this type of test. Explain why we need to automate the accepting of UserInput
10 | 4. Explain and run test_write_user_details_istub.py and show it's benefits. This is a one step process. However, we are still writing to a file. This too is not good.
11 | 5. Explain and run test_write_user_details_iostub.py
12 | 6. This is good but we cannot wrote stubs for everything in a large project. It will take too long to do it
13 | 7. Here is where mocking comes in. Explain and run test_write_user_details_mock.py
14 | 8. We cannot manually run so many test cases. Here is where test suites come in the picture
15 | 9. unittest also supports test discovery
16 | python -m unittest discover
17 |
18 |
19 | class MyTestCase(unittest.TestCase):
20 |
21 | @unittest.skip("demonstrating skipping")
22 | def test_nothing(self):
23 | self.fail("shouldn't happen")
24 |
25 | @unittest.skipIf(mylib.__version__ < (1, 3),
26 | "not supported in this library version")
27 | def test_format(self):
28 | # Tests that work for only a certain version of the library.
29 | pass
30 |
31 | @unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
32 | def test_windows_support(self):
33 | # windows specific testing code
34 | pass
35 |
36 | @unittest.skip("showing class skipping")
37 | class MySkippedTestCase(unittest.TestCase):
38 | def test_not_run(self):
39 | pass
40 |
41 | class ExpectedFailureTestCase(unittest.TestCase):
42 | @unittest.expectedFailure
43 | def test_fail(self):
44 | self.assertEqual(1, 0, "broken")
45 |
46 | Resources:
47 | ==========
48 | Python unittest http://docs.python.org/library/unittest.html
49 |
--------------------------------------------------------------------------------
/tdd/transformations/MailerProg.py:
--------------------------------------------------------------------------------
1 | import os
2 | import re
3 |
4 | """
5 | def find_msg_files(d):
6 | msg_files = []
7 | for f in os.listdir(d):
8 | if f.endswith('.msg'):
9 | msg_files.append(f)
10 | return msg_files
11 | """
12 |
13 | def get_all_msgs():
14 | msgs = []
15 | msg_file_names = find_msg_files('c:/temp')
16 | for msg_file_name in msg_file_names:
17 | msgs.append(parse_msg_file(msg_file_name))
18 | return msgs
19 |
20 | def find_msg_files(d):
21 | return [f for f in os.listdir(d) if f.endswith('.msg')]
22 |
23 | def parse_msg_file(fname):
24 | fp = open(fname, 'r')
25 | reading_body = False
26 | ffrom = ""
27 | to = ""
28 | cc = ""
29 | tstamp = ""
30 | mime = ""
31 | body = ""
32 | for line in fp.readlines():
33 | if reading_body:
34 | body += line
35 | else:
36 | if line.startswith('to: '):
37 | to = line[len('to: '):]
38 | to = __remove_newline_chars(to)
39 | elif line.startswith('from: '):
40 | ffrom = line[len('from: '):]
41 | ffrom = __remove_newline_chars(ffrom)
42 | elif line.startswith('cc: '):
43 | cc = line[len('cc: '):]
44 | cc = __remove_newline_chars(cc)
45 | elif line.startswith('tstamp: '):
46 | tstamp = line[len('tstamp: '):]
47 | tstamp = __remove_newline_chars(tstamp)
48 | elif line.startswith('mime: '):
49 | mime = line[len('mime: '):]
50 | mime = __remove_newline_chars(mime)
51 | elif line.startswith('body:'):
52 | reading_body = True
53 |
54 | return Msg(to=to, ffrom=ffrom, cc=cc, tstamp=tstamp, mime=mime, body=body)
55 |
56 | def __remove_newline_chars(s):
57 | s = s.replace('\n','')
58 | s = s.replace('\r', '')
59 | return s
60 |
61 | class Msg(object):
62 | def __init__(self, ffrom="", to="", cc="", tstamp="", mime="", body=""):
63 | self.ffrom = ffrom
64 | self.to = []
65 | self.cc = []
66 | self.tstamp = tstamp
67 | self.mime = mime
68 | self.body = body
69 | self.to = re.split(',\s*', to)
70 | if '' in self.to:
71 | self.to.remove('')
72 | self.cc = re.split(',\s*', cc)
73 | if '' in self.cc:
74 | self.cc.remove('')
75 |
76 | def __str__(self):
77 | return """
78 | from: %s
79 | to: %s
80 | cc: %s
81 | mime: %s
82 | tstamp: %s
83 | body: %s""" % (self.ffrom, self.to, self.cc, self.mime, self.tstamp, self.body)
84 |
85 |
86 |
87 |
88 | if "__main__" == __name__:
89 | print find_msg_files('c:/temp')
90 |
--------------------------------------------------------------------------------
/tdd/transformations/Msg2Xml.py:
--------------------------------------------------------------------------------
1 | from xml.etree.ElementTree import Element, SubElement, Comment, tostring
2 |
3 | top = Element('top')
4 |
5 | comment = Comment('Generated for PyMOTW')
6 | top.append(comment)
7 |
8 | child = SubElement(top, 'child')
9 | child.text = 'This child contains text.'
10 |
11 | child_with_tail = SubElement(top, 'child_with_tail')
12 | child_with_tail.text = 'This child has regular text.'
13 | child_with_tail.tail = 'And "tail" text.'
14 |
15 | child_with_entity_ref = SubElement(top, 'child_with_entity_ref')
16 | child_with_entity_ref.text = 'This & that'
17 |
18 | print tostring(top)
--------------------------------------------------------------------------------
/tdd/transformations/TestMailerProg.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | import MailerProg
3 | import os
4 |
5 | class TestMailerProg(unittest.TestCase):
6 |
7 | def setUp(self):
8 | super(TestMailerProg, self).setUp()
9 |
10 | def tearDown(self):
11 | super(TestMailerProg, self).tearDown()
12 |
13 | def test_find_msg_files(self):
14 | fqn = os.path.abspath(__file__)
15 | msg_files = MailerProg.find_msg_files(fqn[0:fqn.rfind('/')])
16 | self.assertEqual(5, len(msg_files))
17 | self.assertTrue('email1.msg' in msg_files)
18 | self.assertTrue('email2.msg' in msg_files)
19 | self.assertTrue('email3.msg' in msg_files)
20 | self.assertTrue('email4.msg' in msg_files)
21 | self.assertTrue('email5.msg' in msg_files)
22 |
23 | def test_parse_msg_file(self):
24 | fqn = os.path.abspath(__file__)
25 | curr_dir = fqn[0:fqn.rfind('/')]
26 | msg = MailerProg.parse_msg_file(os.path.join(curr_dir,'email1.msg'))
27 | self.assertEqual(msg.to[0], 'user1@domaina.com')
28 |
29 |
30 | if __name__ == "__main__":
31 | unittest.main()
32 |
--------------------------------------------------------------------------------
/tdd/transformations/VerifyServers.py:
--------------------------------------------------------------------------------
1 | import urllib2
2 |
3 | servers = ['http://localhost:8080']
4 |
5 | for server in servers:
6 | try:
7 | urllib.urlopen(server)
8 | except urllib2.HTTPError, e:
9 | send_mail(e)
10 | except urllib2.URLError, e:
11 | send_mail(e)
12 |
13 | def send_mail(e):
14 | #send an email to the admin with the details of this exception
15 | pass
--------------------------------------------------------------------------------
/tdd/transformations/email1.msg:
--------------------------------------------------------------------------------
1 | to: user1@domaina.com
2 | from: user1@domainb.com
3 | mime: plain/text
4 | tstamp: 26 June, 2012
5 | body:
6 | Hi there how are you ?
7 | --
8 | Thanks
9 |
10 |
--------------------------------------------------------------------------------
/tdd/transformations/email2.msg:
--------------------------------------------------------------------------------
1 | to: user2@domaina.com
2 | from: user1@domainc.com
3 | cc: user1@domainb.com
4 | mime: plain/text
5 | tstamp: 26 June, 2012
6 | body:
7 | Hi there how are you ?
8 | --
9 | Thanks
10 |
11 |
--------------------------------------------------------------------------------
/tdd/transformations/email3.msg:
--------------------------------------------------------------------------------
1 | to: user4@domaina.com
2 | from: user1@domainc.com
3 | mime: plain/text
4 | tstamp: 26 June, 2012
5 | body:
6 | Hi there how are you ?
7 | --
8 | Thanks
9 |
10 |
--------------------------------------------------------------------------------
/tdd/transformations/email4.msg:
--------------------------------------------------------------------------------
1 | to: user3@domaina.com
2 | from: user1@domainc.com
3 | cc: user1@domainb.com
4 | mime: plain/text
5 | tstamp: 26 June, 2012
6 | body:
7 | Hi there how are you ?
8 | --
9 | Thanks
10 |
--------------------------------------------------------------------------------
/tdd/transformations/email5.msg:
--------------------------------------------------------------------------------
1 | to: user3@domaina.com
2 | from: user4@domainc.com
3 | cc: user5@domainb.com
4 | mime: plain/text
5 | tstamp: 26 June, 2012
6 | body:
7 | Hi there how are you ?
8 | --
9 | Thanks
10 |
--------------------------------------------------------------------------------