Advanced Python Training at VMWare - Day 1

Nov 20-22, 2017 Vikrant Patil

These notes will be available online at http://notes.pipal.in/2017/vmware-nov-advpython/ after this training!

© Pipal Academy LLP

Day 1 | Day 2 | Day 3

Python Distribution

We will be using following python3 distribution for this training

https://www.anaconda.com/download/

Quick Recap

In [1]:
4 + 2.0
Out[1]:
6.0
In [2]:
4 ** 1000
Out[2]:
114813069527425452423283320117768198402231770208869520047764273682576626139237031385665948631650626991844596463898746277344711896086305533142593135616665318539129989145312280000688779148240044871428926990063486244781615463646388363947317026040466353970904996558162398808944629605623311649536164221970332681344168908984458505602379484807914058900934776500429002716706625830522008132236281291761267883317206598995396418127021779858404042159853183251540889433902091920554957783589672039160081957216630582755380425583726015528348786419432054508915275783882625175435528800822842770817965453762184851149029376
In [3]:
5 /2 
Out[3]:
2.5
In [4]:
5//2
Out[4]:
2
In [5]:
"There" "are" "strings"
Out[5]:
'Therearestrings'
In [6]:
"string with ' quote"
Out[6]:
"string with ' quote"
In [7]:
'string with " quote'
Out[7]:
'string with " quote'
In [9]:
multi = """
this 
is a 
multi line 
string
"""
In [10]:
print(multi)
this 
is a 
multi line 
string

In [11]:
digits = list(range(10))
In [12]:
digits
Out[12]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [14]:
digits[0]
Out[14]:
0
In [15]:
digits[9]
Out[15]:
9
In [16]:
digits[-1]
Out[16]:
9
In [17]:
digits[-1]
Out[17]:
9
In [18]:
digits[1:6] #starts at index 1 (inclusive) and ends at 6th(exlusive)8
Out[18]:
[1, 2, 3, 4, 5]
In [19]:
digits[2:8:3]
Out[19]:
[2, 5]
In [21]:
digits[2:8] # step is 1 by default
Out[21]:
[2, 3, 4, 5, 6, 7]
In [22]:
digits[2:]
Out[22]:
[2, 3, 4, 5, 6, 7, 8, 9]
In [23]:
digits[:8]
Out[23]:
[0, 1, 2, 3, 4, 5, 6, 7]
In [24]:
digits[:]
Out[24]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [25]:
digits[:-1] #all except last
Out[25]:
[0, 1, 2, 3, 4, 5, 6, 7, 8]
In [26]:
digits[::-1] #reverse
Out[26]:
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
In [27]:
word = "madam" 
In [28]:
word == word[::-1]
Out[28]:
True
In [29]:
numbers = list(range(1,10))
In [30]:
numbers
Out[30]:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
In [31]:
numbers = range(1,10)
In [32]:
numbers
Out[32]:
range(1, 10)
In [33]:
squares = [n*n for n in numbers]
In [34]:
evens = [n for n in numbers if n%2==0]
In [35]:
evens
Out[35]:
[2, 4, 6, 8]
In [36]:
sentence = "This is some random statement"
In [38]:
words = sentence.split()
In [39]:
[word.upper() for word in words]
Out[39]:
['THIS', 'IS', 'SOME', 'RANDOM', 'STATEMENT']
In [40]:
"it" is "not english"
Out[40]:
False
In [41]:
"hell" in "hello"
Out[41]:
True
In [42]:
person = {
    "name":"Alice",
    "email":"alice@wonder.land",
    "roles":["Admin", "Staff"]
}
In [43]:
person['roles']
Out[43]:
['Admin', 'Staff']
In [44]:
[key for key in person.keys()]
Out[44]:
['name', 'email', 'roles']
In [45]:
[v for v in person.values()]
Out[45]:
['Alice', 'alice@wonder.land', ['Admin', 'Staff']]
In [46]:
for key, value in person.items():
    print(key, value)
name Alice
email alice@wonder.land
roles ['Admin', 'Staff']

Example: CSV parser

In [47]:
%%file data.csv
A1,B1,C1
A2,B2,C2
A3,B3,C3
A4,B4,C4
Writing data.csv
In [48]:
open("data.csv").readlines()
Out[48]:
['A1,B1,C1\n', 'A2,B2,C2\n', 'A3,B3,C3\n', 'A4,B4,C4']
In [51]:
[line.strip().split(",") for line in open("data.csv").readlines()]
Out[51]:
[['A1', 'B1', 'C1'],
 ['A2', 'B2', 'C2'],
 ['A3', 'B3', 'C3'],
 ['A4', 'B4', 'C4']]

problem: Write a function quicksort which sorts given list using quicksort mechanism. in quisort mechanism you define a pivot element and filter all the elements less than pivote to left side of pivote and all the elements greater than pivote are put on right side of pivot. Then you operate quicksort recursively over filtered less and greater lists.

In [52]:
def morethan(items, x):
    return [item for item in items if item>x]
In [53]:
def lessthan(items, x):
    return [item for item in items if item<=x]
In [61]:
def quicksort(seq):
    if seq:
        pivot = seq[0]
        tail = seq[1:]
        less = lessthan(tail, pivot)
        more = morethan(tail, pivot)
        return quicksort(less)+ [pivot] + quicksort(more)
    else:
        return []
In [62]:
quicksort([3,1,6,2,3,6,1,9,6])
Out[62]:
[1, 1, 2, 3, 3, 6, 6, 6, 9]
In [63]:
quicksort([])
Out[63]:
[]
In [64]:
quicksort([1,1,1,1])
Out[64]:
[1, 1, 1, 1]

Function in deapth

Positional arguments

In [1]:
def cylinder_volume(radius, height):
    return 3.14*radius**2*height
In [2]:
cylinder_volume(1.0, 10) # radius = 1, height = 10
Out[2]:
31.400000000000002
In [3]:
cylinder_volume(10, 1.0)# by mistake! ...results will bve wrong..will be very difficult to 
#debug
Out[3]:
314.0
In [4]:
cylinder_volume(radius=1,height=10)
Out[4]:
31.400000000000002
In [5]:
cylinder_volume(1, height=10)
Out[5]:
31.400000000000002
In [6]:
cylinder_volume(radius=1, 10)
  File "<ipython-input-6-2bfb29ebfe33>", line 1
    cylinder_volume(radius=1, 10)
                             ^
SyntaxError: positional argument follows keyword argument
In [7]:
cylinder_volume(height=10, radius=1)
Out[7]:
31.400000000000002

Default argument

In [8]:
def email(name, domain="vmware.com"):
    return name + "@" + domain
    
In [9]:
email("shiva")
Out[9]:
'shiva@vmware.com'
In [10]:
email("shiva", "intute.com")
Out[10]:
'shiva@intute.com'
In [11]:
email("shiva", domain="vmware.in")
Out[11]:
'shiva@vmware.in'
In [13]:
import random

def number():
    return random.random()

def func(index, randnum=number()):
    print(index, randnum)
In [14]:
for i in range(5):
    func(i)
0 0.1296526230933327
1 0.1296526230933327
2 0.1296526230933327
3 0.1296526230933327
4 0.1296526230933327
In [15]:
def func(index, randnum=None):
    if not randnum: #randnum==None
        randnum = number()
    print(index, randnum)
In [16]:
for i in range(5):
    func(i)
0 0.01375842923438031
1 0.5929248848949995
2 0.5262898203366712
3 0.28884653444054265
4 0.33417101816727857

Named only argument

In [17]:
def sumation(values, *, inital=50):
    return inital + sum(values)
In [18]:
sumation(range(1,11), inital=0)
Out[18]:
55
In [19]:
sumation(range(1,11))
Out[19]:
105
In [20]:
sumation(range(1,11), 40)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-20-01dd7e27ae5c> in <module>()
----> 1 sumation(range(1,11), 40)

TypeError: sumation() takes 1 positional argument but 2 were given

Variable number of arguments

mysum(1,2)
mysum(1,2,3,4,5)
In [21]:
def func(*args):
    pass
In [22]:
func(1)
In [23]:
func(1,2,3)
In [24]:
def func(*args):
    print(args)
In [25]:
func(1,2,3)
(1, 2, 3)
In [26]:
sum([1,2,3,4])
Out[26]:
10
In [27]:
sum((1,2,3,4))
Out[27]:
10
In [28]:
def mysum(*args):
    return sum(args)
In [29]:
def mysum_(*args):
    s = 0
    for item in args:
        s += item
    return s
In [31]:
mysum(1,2,3,4,5)
Out[31]:
15
In [32]:
",".join(["A","B","C"])
Out[32]:
'A,B,C'
In [36]:
def joinstring(*args, sep=" "):
    total = args[0]
    for item in args[1:]:
        total = total + sep + item
    return total
In [37]:
joinstring("A","B","C")
Out[37]:
'A B C'
In [38]:
joinstring("Alanzo","church","though","about","lambda","calculas")
Out[38]:
'Alanzo church though about lambda calculas'
In [39]:
def make_person(name, **kwargs):
    person = {"name":name}
    for k,v in kwargs.items():
        person[k] = v
    return person
In [40]:
make_person(name="alice",email="alice@example.com",phone="8989232983")
Out[40]:
{'email': 'alice@example.com', 'name': 'alice', 'phone': '8989232983'}
In [43]:
def f(*args,name="alice"):
    print(args)
    print(name)
In [52]:
f(1,2,3,4)
(1, 2, 3, 4)
alice
In [50]:
def f1(*args, x): # after *args there are named only arguments
    print(args, x)
In [49]:
f1(1,2,3,x="name")
(1, 2, 3) name
In [53]:
f1(1,2)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-53-d1ffa26218f6> in <module>()
----> 1 f1(1,2)

TypeError: f1() missing 1 required keyword-only argument: 'x'

Unpacking arguments

In [ ]:
 
In [55]:
def find_stats(*args):
    results ={
        'sum':mysum(*args),
        "mean":mysum(*args)/len(args),
        'max':max(args),
        'min':min(args)
    }
    return results
In [56]:
find_stats(1.,2.,1.1,1.2)
Out[56]:
{'max': 2.0, 'mean': 1.325, 'min': 1.0, 'sum': 5.3}
In [57]:
def timeseries(*values, **kwargs):
    stats = find_stats(*values)
    ploting_data = {}
    ploting_data['values'] = values
    ploting_data['stats'] = stats
    for k,v in kwargs.items():
        ploting_data[k] = v
    return ploting_data
In [59]:
timeseries(0.01,0.012,0.011,0.013,
           group="cancer",
           obesrvations="raw_intensity",
           experiment="gene",
           gene="RC33")
          
Out[59]:
{'experiment': 'gene',
 'gene': 'RC33',
 'group': 'cancer',
 'obesrvations': 'raw_intensity',
 'stats': {'max': 0.013, 'mean': 0.0115, 'min': 0.01, 'sum': 0.046},
 'values': (0.01, 0.012, 0.011, 0.013)}
In [60]:
timeseries([1,2,3,4],name="A",surname="B")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-60-aae20a095ebf> in <module>()
----> 1 timeseries([1,2,3,4],name="A",surname="B")

<ipython-input-57-e9f0320db809> in timeseries(*values, **kwargs)
      1 def timeseries(*values, **kwargs):
----> 2     stats = find_stats(*values)
      3     ploting_data = {}
      4     ploting_data['values'] = values
      5     ploting_data['stats'] = stats

<ipython-input-55-b701b0c79d24> in find_stats(*args)
      1 def find_stats(*args):
      2     results ={
----> 3         'sum':mysum(*args),
      4         "mean":mysum(*args)/len(args),
      5         'max':max(args),

<ipython-input-28-771c7fc3e5e8> in mysum(*args)
      1 def mysum(*args):
----> 2     return sum(args)

TypeError: unsupported operand type(s) for +: 'int' and 'list'
In [61]:
def f(*args, **kwargs):
    print(args)
    print(kwargs)
In [62]:
f([1,2,3,4],[1,1,1],"hello",name="name")
([1, 2, 3, 4], [1, 1, 1], 'hello')
{'name': 'name'}

Function as arguments and return values

In [63]:
def func(x):
    return x*x
In [64]:
func
Out[64]:
<function __main__.func>
In [65]:
type(func)
Out[65]:
function
In [66]:
x = 3
In [67]:
x
Out[67]:
3
In [68]:
func
Out[68]:
<function __main__.func>
In [69]:
y = x
In [70]:
y
Out[70]:
3
In [71]:
square = func
In [72]:
square
Out[72]:
<function __main__.func>
In [73]:
square == func
Out[73]:
True
In [74]:
func(3)
Out[74]:
9
In [75]:
square(4)
Out[75]:
16
In [78]:
def sum_natural(n):
    s = 0
    for i in range(1,n+1):
        s += i
    return s

def square(x):
    return x*x

def sum_squares(n):
    s = 0
    for i in range(1,n+1):
        s += square(i)
    return s

def cube(x):
    return x*x*x

def sum_cubes(n):
    s = 0
    for i in range(1,n+1):
        s += cubes(i)
    return s

def sum_func(n, f):
    s = 0
    for i in range(1, n+1):
        s += f(i)
    return s
In [79]:
sum_squares(10)
Out[79]:
385
In [80]:
sum_func(10, square)
Out[80]:
385
In [81]:
f = lambda x:x*x
In [82]:
f
Out[82]:
<function __main__.<lambda>>
In [83]:
sum_func(10, lambda x:x*x*x)
Out[83]:
3025

the series 8/(1*3) + 8/(5*7) + 8/(9*11) .... slowly converges to value of pi

In [84]:
sum_func(1000, lambda n:8/((4*n-3)*(4*n-1)))
Out[84]:
3.141092653621038
In [85]:
def make_adder(x):
    def adder(y):
        return x+y
    
    return adder
In [86]:
adder5 = make_adder(5)
In [87]:
adder5
Out[87]:
<function __main__.make_adder.<locals>.adder>
In [88]:
adder5(4)
Out[88]:
9
In [89]:
adder5(10)
Out[89]:
15
In [90]:
adder7 = make_adder(7)
In [91]:
adder7(5)
Out[91]:
12
In [92]:
adder5(6)
Out[92]:
11
In [94]:
adder5("dgfgf")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-94-2aa8f4f40181> in <module>()
----> 1 adder5("dgfgf")

<ipython-input-85-5b658f3a86e8> in adder(y)
      1 def make_adder(x):
      2     def adder(y):
----> 3         return x+y
      4 
      5     return adder

TypeError: unsupported operand type(s) for +: 'int' and 'str'
In [95]:
def make_logger(prefix):
    def logger(*args):
        print(prefix, *args)
    
    return logger
In [96]:
info = make_logger("[INFO]")
warn = make_logger("[WARNING]")
In [97]:
info("called some function", square)
[INFO] called some function <function square at 0x7ff154684488>
In [98]:
warn("Something went wrong", Exception("invalid id"))
[WARNING] Something went wrong invalid id
In [99]:
records =[
    ("A",40),
    ("B",86),
    ("C",48),
    ("D",75)
]
In [100]:
max(records)
Out[100]:
('D', 75)
In [101]:
def get_marks(record):
    return record[1]
In [102]:
max(records, key=get_marks)
Out[102]:
('B', 86)
In [106]:
import os
from os.path import getsize
In [104]:
files = os.listdir(os.getcwd())
In [107]:
max(files, key=getsize)
Out[107]:
'day1.html'
In [108]:
records = [
    ("A",90,6.6),
    ("B",100, 6.7),
    ("C",110, 7.0),
    ("D",95, 10.0)
] #column 0 is name, column1 is systolic BP, column2 is sugar
In [109]:
def column(index):
    return lambda row:row[index]
In [110]:
max(records, key=column(1))
Out[110]:
('C', 110, 7.0)
In [111]:
max(records, key=column(2))
Out[111]:
('D', 95, 10.0)
In [112]:
sentence = "Lets print longest word out of this statement"
In [114]:
words = sentence.split()
In [115]:
max(words)
Out[115]:
'word'
In [116]:
max(words, key=len)
Out[116]:
'statement'

problem: Write a function compose which will take two functions f, g as arguments. and return a function which can compute f(g(x)) given x

>>> f = lambda x:x*x
>>> g = lambda x :x-1
>>> fg = compose(f,g)
>>> fg(3)
4
>>> gf = compose(g,f)
>>> gf(3)
8
In [117]:
def compose(f,g):
    return lambda x: f(g(x))
  • problem Write a function zip_with which takes function f as argument and returns a function which zips two lists into single list by combining element by element using f

    >>> listadder = zip_with(lambda x,y:x+y)
    >>> listaddder([1,2,3],[1,1,1])
    [1,3,4]
    >>> listmulti = zip_with(lambda x,y:x*y)
    >>> listmulti([1,2,3],[2,2,2])
    [2,4,6]
  • problem Write a function fold which reduces given sequence in to a single item given a joiner function
    >>> def add(x,y):
    ...     return x+y
    >>> fold(add, [1,2,3,4,5], default=0)
    15
  • bonus problem A number x is said to be fixed point of a function f, if f(x)=x. For some functions we can locate a fixed point by beginning with an initial guess and applyting f repetedly , f(x), f(f(x)), f(f(f(x))).... Write a python function to find fixed point of a function. It should take function as argument, initial guess and accuracy(default=0.0001) for equating f(x) and x
    >>> fixed_point(math.cos, 1)
    0.73905479...
In [121]:
def list_adder(list1, list2, f):
    return [f(list1[i], list2[i]) for i in range(len(list1))]


def zip_with(f):
    def joiner(first, second):
        z = []
        for i in range(len(first)):
            v = f(first[i], second[i])
            z.append(v)
        return z
    return joiner
        
        
In [126]:
def add(x, y):
    return x+y
def mult(x,y):
    return x*y
In [124]:
listadder = zip_with(add)
In [125]:
listadder([1,1,1,1],[2,2,2,2])
Out[125]:
[3, 3, 3, 3]
In [119]:
def make_adder(x):
    def adder(y):
        return x+y
    return adder
In [120]:
adder5 = make_adder(5)
In [127]:
adder5(6)
Out[127]:
11
In [128]:
def fold(f, seq, default=0):
    acc = default
    for item in seq:
        acc = f(acc, item)
    return acc
In [129]:
fold(lambda x,y:x+y, [1,1,1,1,1])
Out[129]:
5
In [131]:
fold(lambda x,y:x*y, range(1,5), default=1)
Out[131]:
24

Decorators

In [132]:
def add(x,y):
    # print(x,y)
    return x+y

def sub(x,y):
    return x-y

def mult(x,y):
    return x*y

def double(x):
    return 2*x
In [133]:
def debug(f):
    
    def wrapper(*args):
        print(f.__qualname__, args)
        v = f(*args)
        print("returning ",f.__qualname__, v)
        return v
    
    return wrapper
In [134]:
add(3,4)
Out[134]:
7
In [135]:
add1 = debug(add)
In [136]:
add1(3,4)
add (3, 4)
returning  add 7
Out[136]:
7
In [137]:
add = debug(add)
In [138]:
add(4,5)
add (4, 5)
returning  add 9
Out[138]:
9
In [139]:
@debug
def fib(n):
    if n in [1,2]:
        return 1
    else:
        return fib(n-1) + fib(n-2)
In [140]:
fib(5)
fib (5,)
fib (4,)
fib (3,)
fib (2,)
returning  fib 1
fib (1,)
returning  fib 1
returning  fib 2
fib (2,)
returning  fib 1
returning  fib 3
fib (3,)
fib (2,)
returning  fib 1
fib (1,)
returning  fib 1
returning  fib 2
returning  fib 5
Out[140]:
5

Lets build some advanced debugger which gives us complete trace of a function call

In [142]:
%%file trace.py
import os
level = 0

def log(*args):
    if os.getenv("DEBUG")=="true":
        print(*args)

def trace(f):
    
    def g(*args):
        global level 
        log("| "*level + "|--" +f.__qualname__, args)
        level += 1
        value = f(*args)
        level -= 1
        log("| "*level + "|--" + "return", value)
        return value
    
    return g
Writing trace.py
In [143]:
%%file sum.py

from trace import trace

@trace
def square(x):
    return x*x

@trace
def sumofsquares(x,y):
    return square(x) + square(y)

if __name__ == "__main__":
    print(sumofsquares(3,4))
Writing sum.py
In [144]:
!python sum.py
25
In [145]:
!DEBUG=true python sum.py
|--sumofsquares (3, 4)
| |--square (3,)
| |--return 9
| |--square (4,)
| |--return 16
|--return 25
25
In [147]:
%%file fib.py
import sys
from trace import trace

@trace
def fib(n):
    """
    computes nth fibonacci number
    """
    if n in [1,2]:
        return 1
    else:
        return fib(n-1)+fib(n-2)

    
def main():
    n = int(sys.argv[1])
    fib(n)
    
if __name__ == "__main__":
    main()
Overwriting fib.py
In [148]:
!DEBUG=true python fib.py 5
|--fib (5,)
| |--fib (4,)
| | |--fib (3,)
| | | |--fib (2,)
| | | |--return 1
| | | |--fib (1,)
| | | |--return 1
| | |--return 2
| | |--fib (2,)
| | |--return 1
| |--return 3
| |--fib (3,)
| | |--fib (2,)
| | |--return 1
| | |--fib (1,)
| | |--return 1
| |--return 2
|--return 5
In [153]:
!DEBUG=true python fib.py 8 | grep "fib (2,)" | wc -l
13
In [154]:
%%file memoize.py

def memoize(f):
    cache ={}
    
    def g(*args):
        if args not in cache:
            cache[args] = f(*args)
        return cache[args]
    
    return g
Writing memoize.py
In [157]:
%%file sq1.py
from memoize import memoize

@memoize
def square(x):
    print("Calling function square({})".format(x))
    return x*x

if __name__ == "__main__":
    print(square(2))
    print(square(2))
Overwriting sq1.py
In [158]:
!python sq1.py
Calling function square(2)
4
4
In [161]:
%%file fib1.py
import sys
from trace import trace
from memoize import memoize

@memoize
@trace
def fib(n):
    """
    computes nth fibonacci number
    """
    if n in [1,2]:
        return 1
    else:
        return fib(n-1)+fib(n-2)

    
def main():
    n = int(sys.argv[1])
    fib(n)
    
if __name__ == "__main__":
    main()
Overwriting fib1.py
In [162]:
!DEBUG=true python fib1.py 8
|--fib (8,)
| |--fib (7,)
| | |--fib (6,)
| | | |--fib (5,)
| | | | |--fib (4,)
| | | | | |--fib (3,)
| | | | | | |--fib (2,)
| | | | | | |--return 1
| | | | | | |--fib (1,)
| | | | | | |--return 1
| | | | | |--return 2
| | | | |--return 3
| | | |--return 5
| | |--return 8
| |--return 13
|--return 21
In [164]:
!time -p python fib.py 30
real 14.25
user 14.25
sys 0.00
In [165]:
!time -p python fib1.py 30
real 0.06
user 0.04
sys 0.01

Testing Python Programs

In [166]:
%%file sq1.py

def square(x):
    return x*x

def test():
    print(square(3))

if __name__ == "__main__":
    test()
Overwriting sq1.py
In [167]:
!python sq1.py
9
In [172]:
%%file sq2.py

def square(x):
    return x*x

def test():
    if square(3)==9:
        print("passed")

if __name__ == "__main__":
    test()
Overwriting sq2.py
In [173]:
!python sq2.py
passed
In [182]:
%%file sq3.py

def square(x):
    return x*x

def test_square():
    assert square(0) == 0
    assert square(-1) == 1
    assert square(3) == square(-3)
    assert square(3) == 9
    assert square(1) == 0
    
if __name__ == "__main__":
    test_square()
Overwriting sq3.py
In [183]:
!python sq3.py
Traceback (most recent call last):
  File "sq3.py", line 13, in <module>
    test_square()
  File "sq3.py", line 10, in test_square
    assert square(1) == 0
AssertionError

py.test is third party tool which makes use of this fact about how assert statement works and is used for automated testing

pip3 install pytest
In [185]:
!pytest sq3.py
============================= test session starts ==============================
platform linux -- Python 3.6.1, pytest-3.0.7, py-1.4.33, pluggy-0.4.0
rootdir: /home/vikrant/trainings/2017/vmware-nov-advpython, inifile:
collected 1 items 

sq3.py F

=================================== FAILURES ===================================
_________________________________ test_square __________________________________

    def test_square():
        assert square(0) == 0
        assert square(-1) == 1
        assert square(3) == square(-3)
        assert square(3) == 9
>       assert square(1) == 0
E       assert 1 == 0
E        +  where 1 = square(1)

sq3.py:10: AssertionError
=========================== 1 failed in 0.05 seconds ===========================
In [186]:
%%file weekday.py
import datetime

def now():
    return datetime.datetime.now()

def weekday():
    t = now()
    return t.strftime("%A")

if __name__ == "__main__":
    print(weekday())
Writing weekday.py
In [187]:
!python weekday.py
Monday
In [188]:
%%file test_weekday.py
import weekday
import datetime

def test_weekday(monkeypatch):
    faketime = 2010, 1, 1
    def fakenow():
        return datetime.datetime(*faketime)
    
    monkeypatch.setattr(weekday, "now", fakenow)
    
    faketime = 2010, 1, 1
    assert weekday.weekday() == "Friday"
    
    faketime = 2010, 1, 2
    assert weekday.weekday() == "Saturday"
    
Writing test_weekday.py
In [189]:
!pytest test_weekday.py
============================= test session starts ==============================
platform linux -- Python 3.6.1, pytest-3.0.7, py-1.4.33, pluggy-0.4.0
rootdir: /home/vikrant/trainings/2017/vmware-nov-advpython, inifile:
collected 1 items 

test_weekday.py .

=========================== 1 passed in 0.01 seconds ===========================
In [190]:
%%file module.py

def add(x,y):
    return x+y
    
print("hello")
Writing module.py
In [191]:
!python module.py
hello
In [192]:
import module
hello
In [193]:
%%file backup.py

def add(x,y):
    return x+y
    
def backup():
    print("called backup")
    delete(dirpath)
    mkdir(newdir)
    cp(src, dest)
    
backup()
Writing backup.py
In [194]:
!python backup.py
called backup
Traceback (most recent call last):
  File "backup.py", line 11, in <module>
    backup()
  File "backup.py", line 7, in backup
    delete(dirpath)
NameError: name 'delete' is not defined
In [196]:
from backup import backup
called backup
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-196-0ace622975b6> in <module>()
----> 1 from backup import backup

/home/vikrant/trainings/2017/vmware-nov-advpython/backup.py in <module>()
      9     cp(src, dest)
     10 
---> 11 backup()

/home/vikrant/trainings/2017/vmware-nov-advpython/backup.py in backup()
      5 def backup():
      6     print("called backup")
----> 7     delete(dirpath)
      8     mkdir(newdir)
      9     cp(src, dest)

NameError: name 'delete' is not defined
In [197]:
%%file backup1.py

def add(x,y):
    return x+y
    
def backup():
    print("called backup")
    delete(dirpath)
    mkdir(newdir)
    cp(src, dest)

print(__name__)
Writing backup1.py
In [198]:
!python backup1.py
__main__
In [200]:
from backup1 import backup
backup1
In [201]:
%%file backup2.py
def add(x,y):
    return x+y
    
def backup():
    print("called backup")
    delete(dirpath)
    mkdir(newdir)
    cp(src, dest)

if __name__ == "__main__":
    backup()
if __name__ == "backup2":
    print("I am a module not script")
Writing backup2.py
In [202]:
!python backup2.py
called backup
Traceback (most recent call last):
  File "backup2.py", line 11, in <module>
    backup()
  File "backup2.py", line 6, in backup
    delete(dirpath)
NameError: name 'delete' is not defined
In [203]:
import backup2
I am a module not script
In [204]:
from backup2 import backup
In [ ]: