Jan 24, 2020

Alembic Basics

Alembic

alembic revision --autogenerate
alembic history

alembic stamp head
alembic stamp <rev_no>

alembic upgrade head
alembic downgrade base


Jan 12, 2020

pytest Tutorial 3 - pycharm options


  • pytest.ini
    • You can define default options like -v, -m, -x etc.,
    • [pyest]
    • addopts = -v
  • Auto-run options
    • When you make some changes, it auto-run
    • You can set interval of 2, 3, 5 secs etc.,
    • You can find this in settings gear icon in Pycharm
  • Make default pytest
    • By default it is pointed to unittest in Pycharm
    • You can change to pytest in PyCharm test configurations under
    • Tools -> Python Integrated Tools -> Default Test Runner
  • Run configuration for individual files
    • For each file, you can set -v, -m options
    • Run -> Default Configurations -> Additional Arguments
    • -v
  • Set options Globally for all instead of individual files
    • Run -> Edit Configurations -> Defaults -> Python Tests -> py.test
    • Add it here in Additional Arguments
    • This will apply to all the test files
  • Window -> Edit Tabs -> Split Vertically
    • You need to work test cases looking at your code files/Readme.
    • This will help in view both files vertically at the same time

pytest in classes

import pytest

class TestSomeStuff():
    def test_one(self):
         assert 1 == 1
   
    def test_two(self):
         assert 2 == 2

    def test_three(self):
         assert 3 == 3

class TestOtherStuff():
    def test_eleven(self):
         assert 11 == 11
   
    def test_twenty_two(self):
         assert 22 == 22

    def test_thirty_three(self):
         assert 33 == 33

We can run as all the tests a different suites as classes.
TestSomeStuff
TestOtherStuff


Jan 11, 2020

pytest Tutorial 2 -Fixtures


student.py

import json

class StudentDB:
   def __init__(self):
        self.__data = None

   def connect(self, data_file):
        with open(data_file) as json_file:
            self.__data = json.loads(data_file)

   def get_data(self, name):
        for student in self.__data['students']:
             if student['name'] == name:
                 return student

test_student.py

from student import StudentDB
import pytest

# Fixture is more like a replacement for writing both setup and teardown
# If not fixture, you can write separate functions for setup_module, teardown_module
# You need to pass db to all the unit test functions
#If you not pass scope=module, this fixture is called for each and every unit test
@pytest.fixture(scope='module')  
def db:
    print('-------Inside setup-------')
    db = StudentDB()
    db.connect('data.json')
    yield db
    print('-------Inside teardown-------')  # Since this is module level, this is called at the end of module
    db.close()

def test_scott_data(db):  # Passed from above texture
    scott_data = db.get_data('Scott')
    assert scott_data['id'] == 1
    assert scott_data['name'] == 'Scott'
    assert scott_data['result'] == 'Pass'

def test_mark_data(db):  # Passed from above texture
    scott_data = db.get_data('Mark')
    assert scott_data['id'] == 2
    assert scott_data['name'] == 'Mark'
    assert scott_data['result'] == 'Fail'



 
 


pytest Tutorial 1 - Beginner

math_func.py

def add(x,y):
   return x+y

def product(x,y)
   return x*y

test_math_func.py

from math_func import add, subtract
import pytest
import sys

# @pytest.mark.skip(reason="Do not run number add test")
# @pytest.mark.skipif(sys.version_info < (3, 3), reason="Do not run number add test") 
@pytest.mark.number
def test_add():
   assert add(3,4) == 7
   print(f'Inside test_add: {assert add(3,4)}')

@pytest.mark.parameterize('arg1, arg2, result',
[
(7, 3, 10),
('Hello', ' World', 'Hello World')
(5.5, 4.5, 10)
]
)
def test_add_parameterize(arg1, arg2, result):
   assert add(arg1, arg2) == result

@pytest.mark.number
def test_product():
   assert add(3,4) == 12
 
@pytest.mark.strings
def test_add_strings():
   assert add(3,4) == 7
   result add('Hello', ' World')
   assert result == 'Hello World'
   assert 'Hello' in result
   assert type(result) is str 

@pytest.mark.strings
def test_product_strings():
   assert product('Hello', 3) == 'HelloHelloHello'

How to run
pytest test_match_func.py
pytest test_match_func.py -v

pytest test_match_func.py::test_add

(-k Expression)
pytest -v -k "add"  # runs tests with "add" string, run both test_add & test_add_strings
pytest -v -k "add or string" # runs all 3
pytest -v -k "add and string"  # runs test_add_strings alone

(-m, --markers)
pytest -v -m number # run those marked as number
pytest -v -m strings  # run those marked as strings


(-x, --exitfirst)
pytest -v -x  # If any first failure, it totally exits and does not execute following tests

pytest -v -x --tb=no  # It won't show error stack trace

pytest -v --maxfail=2

pytest -v -s  # -s option will output any print lines

pytest -v -q  # quite mode, will not print how many test passed

pytest Tutorial 2 -Fixtures (check the other blog)




Jan 10, 2020

Pandas Dataframes

# Info - lists all of our columns, also gives data types
df.info()

# Set options
pd.set_option('display.max_columns', 85)
pd.set_option('display.max_rows', 85)

# head
df.head(10)

# tail
df.tail(10)

# List all columns
df.columns

# Dataframe shape
print(df1.shape)

# Series - is a list / a column in a data frame
# A data frame is a container for multiple Series (columns)
people = {
              'first' : ['John', 'Mary', 'Linda'],
              'last' : ['Doe', 'Lee', 'Doe'],
              'email' : ['johndoe@gmail.com', 'marylee@gmail.com', 'lindadoe@gmail.com']
 }
df = pd.DataFrame(people)
type(df['email'])  # gives pandas.core.series.Series
df['email']  # gives list of emails
df.email  # gives same as above

pd.DataFrame.from_records (list of tuples)
list = [('John',30,'Bangalore'), ('Doe',25,'Chennai')] df = pd.DataFrame.from_records(list, columns=['Name', 'Age', 'City']) print(df.head(10))

df['email'] Vs df.email 
  • df['email'] is better to use over df.email
  • shape is an attribute of data frame, suppose you have a column name as shape in your DF
  • df['shape'] will give you result of shape column list 
  • df.shape will not work properly as you expect

# iloc Vs loc (Integer Location Vs Location)
# iloc (Search by position)
    df.iloc[0] # return a Series object for 0th index, access row with iloc
    df.iloc[ [0, 1] ] # returns first two rows of data, returns a Data Frame
    df.iloc[ [0, 1],  2] # returns email (2nd column) of first two rows
# loc  
(Search by label) (row_index, column_indexer)
    df.loc[0] # Same as iloc, returns Series object
    df.loc[ [ 0, 1] ] # Same as iloc, returns data frame object
    df.loc[ [ 0, 1 ], 'email' ]  # Instead of index, you can use column name
    df.loc[ [ 0, 1 ], ['email', 'last_name'] ] # Filter by multiple column names for first two rows
    df.loc[ 0, 'Hobby']  # Value of Hobby column for first row
    df.loc[ 0:5, 'Hobby:Employment']  # Values of Hobby to Employment columns for first six rows, slicing is inclusive   # see df.columns to get all the columns
    
df.loc[ df['email'] == 'abc@gmail.com',  : ]  # Rows of all with specific email (all columns)

# Get row by index
       Name  Age PinCode
0    Alex   10     500
1     Bob   12     600
2  Clarke   13     589

df.loc[2] # Gets object of Clarke by index
df1 = df.set_index('Name')  # Set Name as index, inplace=True is also there
print(df1)

             Age PinCode
Name
Alex     10     500
Bob      12     600
Clarke   13     589

df1.loc['Clarke']  # You can get the row by passing Name, since Name is the index


# Get unique values of Column (Yes/No)
df["gender"].value_counts()
Male 100
Female 200

# Unique
ll = ['John', 'Doe', 'Tom', 'Doe']
df1 = pd.Series(ll)
df2 = pd.unique(df1)
print(type(df2)) #<class 'numpy.ndarray'>
print(df2)         #['John' 'Doe' 'Tom']

# Filter
df1_link_keys = df1[df1.link_key != '']
df1_no_link_keys = df1[df1.link_key == '']

# Filter multiple/specific columns
df1 = df[['first', 'last', 'email']]  # Gives DF in return

# Filter isin
df1_subset = df1[df1.index.isin(100, 200)]

# Replace something with another
df1 = df1.replace('NULL', '')
df1 = df1.fillna('')

# Drop index
df1 = df1.drop(matched_index_list)
df1 = df1.drop(100)

# Column to list
df1_names_list = df1['name'].tolist() # column values to list
df1_index_list = df1.index.values.tolist() # index values to list

# Drop duplicates
df1.drop_duplicates(keep='last', inplace=True)  # Keep the last occurence

# Drop duplicates based on specific columns
df1.drop_duplicates(subset=['id', 'name', 'city', 'state'], keep='last', inplace=True)
df1.drop_duplicates(subset=['id', 'name', 'city', 'state'], keep='first', inplace=True)

df1 = df1.drop_duplicates(subset=['id', 'name', 'city', 'state'], keep='last')  # inplace is not true
df1 = df1.drop_duplicates(subset=['id', 'name', 'city', 'state'], keep='first') # inplace is not true

# Drop duplicates with state is empty 
# if only one record with state as empty, keep that
# If two same rows with one state is there & other state is empty, filter one with empty
s_maxes = df1.groupby(['id', 'name', 'city']).state.transform(max)
df1 = df1.loc[df1.state == s_maxes]

# Dataframe To Table
table_dtype = {
                'name': VARCHAR(),
                'city': VARCHAR(),
                'state': VARCHAR(),
                'pincode': INTEGER()
              }
df1.to_sql(con=self.db_conn, name=table_name, dtype=table_dtype,
           if_exists='replace', index=False)

# Dataframe To JSON
df.to_json('data_frame.json', orient='table')

# From Table to Dataframe
raw_data_sql = f""" select id, name, city, state
from event_raw_data
                """
df1 = pd.read_sql(raw_data_sql, con=self.db_conn, index_col="id")

# Loop Dataframe
for index, row in df1.iterrows():
print(index, row.name, row.city, row.state)

# How to subtract rows of one pandas data frame from another?
# You want to achieve df1 - df2
df1 = df1[~df1.index.isin(df2.index)]

# Read CSV
df1 = pd.read_csv('data/test.csv')
df1.shape  # (10, 5)
















SQLAlchemy commands

SQLAlchemy
##########
from sqlalchemy import func
from sqlalchemy.orm import Session
from sqlalchemy.ext.automap import automap_base
from sqlalchemy import create_engine

self.db_engine, self.db_conn = create_db_conn()

self.Base = automap_base()
self.Base.prepare(self.db_engine, reflect=True)
self.db_session = Session(self.db_engine)

self.table1_obj = self.Base.classes.table1
self.table2_obj = self.Base.classes.table2

DATABASE_URI = 'postgresql://postgres:password@localhost:5432/test'

def create_db_conn():
    db_engine = None
    db_conn = None
    try:
        sql_alchemy_engine = create_engine(f'{DATABASE_URI}')

    return db_engine, db_conn



COUNT
#####
rows = vobj.db_session.query(self.table1_obj).count()
print(rows)
rows = vobj.db_session.query(self.table2_obj).count()
print(rows)

activities = self.db_session.query(self.table1_obj).order_by(
            self.table1_obj.id).all()

UPDATE
######
ea = self.db_session.query(self.table2_obj).get(self.activity_id)
            ea.status = status
            self.db_session.commit()

GET
####
current_activity = self.db_session.query(self.table1_obj).filter_by(
    activity_id=self.venue_base_activity_id,
    source_id=row['source_id'],
    venue_id=row['vid']).first()
if current_activity:
    link_key = current_activity.link_key
    market_place_df.loc[index, 'link_key'] = link_key

GET Specific Columns
####################
result = db_session.query(table1_obj.source_id, table1_obj.vid, table1_obj.name,
                              table1_obj.city, table1_obj.state)\
            .filter(table1_obj.source_id.in_((1, 2)))\
            .group_by(table1_obj.source_id, table1_obj.vid, table1_obj.name,
                      table1_obj.city, table1_obj.state)\
            .order_by(table1_obj.source_id).all()

for row in result:
    try:
        source_id = row[0]
        name = clean_string(row[2])
        city = clean_string(row[3])
        state = clean_string(row[4])

GET Count
#########
ws_count = self.db_session.query(func.count(self.table1_obj.id))\
                            .filter_by(source_id=market_place2_source_id).scalar()

group_by
#######
HygroRecord.query.group_by(HygroRecord.sensor_uuid)
        .having(func.max(HygroRecord.timestamp)).all())

insert
######
self.db_session.add(
            self.table1(
                id=row_id,
                name=name
            )
        )
self.db_session.commit()

Insert - bulk insert
#####################
ll = []
ll.append(self.table2(
        id=self.activity_id,
        name=name,
        city=city,
        state=state
    )
)
self.db_session.bulk_save_objects(ll)
self.db_session.commit()


flush
########

    f = vobj.table1(
            id1=9,
            id2=18
        )
    vobj.db_session.add(f)
    vobj.db_session.flush() #without commit if you want to get insert id
    print(f.id)
    vobj.db_session.commit()



Dec 19, 2019

mysql joins group by

Find all duplicate records with (name, state, city) same

select v.venue_id, v.name, v.city, v.state from raw_data v 
join
(select  COUNT(concat(name,state,city)),name,state,city from raw_data
where source_id = 2 group by name,state,city
having COUNT(concat(name,state,city)) > 1) a
on 
v.name = a.name and v.state = a.state and v.city = a.city and v.source_id = 2
order by v.name,v.state,v.city

Dec 16, 2019

Pycharm Save Actions plugin

Pycharm Save Actions plugin

PyCharm Google Doc Strings

PyCharm -> Tools -> Python Integrated Tools -> Doc Strings -> Doc String Format -> Google

Nov 18, 2019

Nohup is not writing log to output file

nohup python long_running_task.py &

Using '-u' with 'nohup' worked for me. Everything will be saved in "nohup.out " file

nohup python -u long_running_task.py &

Nov 16, 2019

Python record linkage


Python fuzzywuzzy

#Ref: https://www.datacamp.com/community/tutorials/fuzzy-string-python

#pip install fuzzywuzzy
#pip install python-Levenshtein

from fuzzywuzzy import fuzz
from fuzzywuzzy import process

print('-------------string matching')
Str1 = "Apple Inc."
Str2 = "apple Inc"
Ratio = fuzz.ratio(Str1.lower(),Str2.lower())
print(Ratio)            #95

print('-------------substring matching')
Str1 = "Los Angeles Lakers"
Str2 = "Lakers"
Ratio = fuzz.ratio(Str1.lower(),Str2.lower())
Partial_Ratio = fuzz.partial_ratio(Str1.lower(),Str2.lower())
print(Ratio)            #50
print(Partial_Ratio)    #100

print('-------------string different order match - same length')
#They tokenize the strings and preprocess them by turning them to lower case and getting rid of punctuation
Str1 = "united states v. nixon"
Str2 = "Nixon v. United States"
Ratio = fuzz.ratio(Str1.lower(),Str2.lower())
Partial_Ratio = fuzz.partial_ratio(Str1.lower(),Str2.lower())
Token_Sort_Ratio = fuzz.token_sort_ratio(Str1,Str2)
print(Ratio)            #59
print(Partial_Ratio)    #74
print(Token_Sort_Ratio) #100

print('-------------string different order match - different length')
Str1 = "The supreme court case of Nixon vs The United States"
Str2 = "Nixon v. United States"
Ratio = fuzz.ratio(Str1.lower(),Str2.lower())
Partial_Ratio = fuzz.partial_ratio(Str1.lower(),Str2.lower())
Token_Sort_Ratio = fuzz.token_sort_ratio(Str1,Str2)
Token_Set_Ratio = fuzz.token_set_ratio(Str1,Str2)
print(Ratio)            #57
print(Partial_Ratio)    #77
print(Token_Sort_Ratio) #58 
print(Token_Set_Ratio)  #95

print('-------------search string in a list of strings with score/ratio')
str2Match = "apple inc"
strOptions = ["Apple Inc.","apple park","apple incorporated","iphone"]
Ratios = process.extract(str2Match,strOptions)
print(Ratios)
#[('Apple Inc.', 100), ('apple incorporated', 90), ('apple park', 67), ('iphone', 40)]
# You can also select the string with the highest matching percentage
highest = process.extractOne(str2Match,strOptions)
print(highest)
#('Apple Inc.', 100)


Nov 14, 2019

ElasticSearch


Python Black


Newman tool Postman


Newman
  • Newman is a command-line collection runner for Postman
  • It allows you to effortlessly run and test a Postman collection directly from the command-line.

Nov 11, 2019

Python AsyncIO

Ref: https://realpython.com/async-io-python/
  • Threading Vs Multi-Processing
    • Threading is better for I/O based tasks
    • Multi-Processing is better for CPU based tasks
    • What’s important to know about threading is that it’s better for IO-bound tasks.
  • Concurrency Vs Parallelism
    • Concurrency is when two tasks can start, run, and complete in overlapping time periods. e.g., Threading, AsyncIO
    • Parallelism is when tasks literally run at the same time, eg. multi-processing. 
  • While a CPU-bound task is characterised by the computer’s cores continually working hard from start to finish, an IO-bound job is dominated by a lot of waiting on input/output to complete.
  • Preemptive multitasking Vs Cooperative multitasking
    • OS preempts a thread forcing it to give up the use of CPU (E.g., Threading)
    • Cooperative multitasking on the other hand, the running process voluntarily gives up the CPU to other processes E.g., (AsyncIO)
  • Coroutine Vs Method/Function/Subroutine
    • Method or Function returns a value and don't remember the state between invocations
    • A coroutine is a special function that can give up control to its caller without losing its state
  • Coroutine Vs Generator
    • Generator yield back value to invoker
    • Coroutine yields control to another coroutine and can resume execution from point it gave the control
    • A generator can't accept arguments once it is started where as a coroutine can accept arguments once it started
  • AsyncIO is a single-threaded, single-process design: it uses cooperative multitasking
  • AsyncIO gives a feeling of concurrency despite using a single thread in a single process
  • Coroutines (a central feature of async IO) can be scheduled concurrently, but they are not inherently concurrent.
  • Asynchronous routines are able to “pause” while waiting on their ultimate result and let other routines run in the meantime.


import asyncio
import time

async def count_func():
    print("Line One")
    await asyncio.sleep(1) # await non-blocking call
    print("Line Two")


async def main():
    await asyncio.gather(count_func(), count_func(), count_func())


if __name__ == "__main__":
    t1 = time.time()
    asyncio.run(main())
    elapsed = time.time() - t1

    #This is supposed to take more than 3 secs
    print(f"{__file__} executed in {elapsed:0.2f} seconds.")


Output:
#####
Line One
Line One
Line One
Line Two
Line Two
Line Two
main.py executed in 1.10 seconds.



Python Disadvantages

Python Disadvantages
  • Its an interpreted language, not as fast as a compiled language
  • Slower than C & C++. Since Python is a high level language unlike C, C++, its not close to hardware 
  • Not good for Gaming, Mobile dev, Desktop UI applications
  • Not good for memory intensive, due to flexibility of data types, python memory consumption is high
  • Python's database access layer is found to be bit underdeveloped and primitive (JDBC/ODBC)
  • GIL
    • Global interpreter lock: can’t run more than one thread using in one interpreter 
    • Creating, managing and tearing down processes (multi-processing, processes are heavier than threads) is more expensive than doing the same for threads. Furthermore, inter-process communication is relatively slower than inter-thread communication. 
    • Both these drawbacks may not make Python a practical technology choice for super-critical or time-sensitive use-cases.
    • Python community are working to remove the GIL from CPython. One such attempt is known as the Gilectomy.
    • GIL exists only in the original Python implementation that is CPython.
    • Python has multiple interpreter implementations. CPython, Jython, IronPython and PyPy, written in C, Java, C# and Python respectively, are the most popular ones.


Python fstrings

elem = 10
elem_index = 5

def to_lowercase(st):
return st.lower()

#Formatted string literals (f-strings)
#The idea behind f-strings is to make string interpolation simpler.
#f-strings are expressions evaluated at runtime rather than constant values
print(f'Index of element {elem} is {elem_index}')

#call functions from f-strings
print(f'String to lowercase: {to_lowercase("TEST_STRING")}')
print(f'String to lowercase: {"TEST_STRING".lower()}')

#Format - used in previous versions of python
print('Index of element {} is {}'.format(elem, elem_index))
elapsed = 23.5678
print(f"{__file__} executed in {elapsed:0.2f} seconds.")


Output:
Index of element 10 is 5 String to lowercase: test_string String to lowercase: test_string Index of element 10 is 5
main.py executed in 23.57 seconds.


Sep 25, 2019

Python Prime number

import math

def is_prime(n):
    if n<2 == 0:
        return False

    sqrt_n = int(math.floor(math.sqrt(n)))
    for i in range(2, sqrt_n + 1): 
        if n % i == 0:
            return False
    return True

foo = [2, 18, 9, 22, 17, 24, 8, 12, 27]
print("All list :", list(foo))
print("Prime list :", list(filter(is_prime, foo)))

Output:
All list : [2, 18, 9, 22, 17, 24, 8, 12, 27]
Prime list : [2, 17]


Sep 24, 2019

Python concurrent.futures ProcessPoolExecutor

"""
The ProcessPoolExecutor class is an Executor subclass that uses a pool of processes to execute calls asynchronously. 

ProcessPoolExecutor uses the multiprocessing module
"""

from concurrent.futures import ProcessPoolExecutor
import math
import multiprocessing
import os
import sys
import time

PRIMES = [
    112272535095293,
    112582705942171,
    112272535095293,
    115280095190773,
    115797848077099,
    109972689928541]

def is_prime(n):
    if n == 2:

        return True

    if n % 2 == 0:
        return False

    sqrt_n = int(math.floor(math.sqrt(n)))
    for i in range(3, sqrt_n + 1, 2):
        if n % i == 0:
            return False
    return True

def main():
    print('No of CPUs/Processors: {}' . format(multiprocessing.cpu_count()))
    a = time.time()
    #default max_workers is number of processors on the machine
    with ProcessPoolExecutor() as executor:
        for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)):
            print('%d is prime: %s' % (number, prime))
    b = time.time()
    print('Time taken: {:.2f} secs'.format(b-a))

if __name__ == '__main__':
    main()


Output:
No of CPUs/Processors: 4
112272535095293 is prime: True
112582705942171 is prime: True
112272535095293 is prime: True
115280095190773 is prime: True
115797848077099 is prime: True
109972689928541 is prime: False
Time taken: 12.67 secs


Python concurrent.futures ThreadPoolExecutor as_completed

import urllib.request 
from concurrent.futures import ThreadPoolExecutor, as_completed

URLS = ['https://www.google.com', 
               'http://www.cnn.com/',
               'http://europe.wsj.com/', 
               'http://www.bbc.co.uk/', 
               'http://abc.abc.com'   #invalid
             ]

def load_url(url, timeout):
  with urllib.request.urlopen(url, timeout=timeout) as conn:
    txt = conn.read()
    return txt

with ThreadPoolExecutor(max_workers = 5) as executor:
  #Forming Key-Value pairs
  future_to_url = {executor.submit(load_url, url, 50): url for url in URLS}
  print(future_to_url)
  print('----')
  for future in as_completed(future_to_url):
    url = future_to_url[future]
    try:
      data = future.result()
      print('%s length is %d' % (url, len(data)))
    except Exception as e:
      print('Error in URL: %s is %s' % (url, e))


Output:
{<Future at 0x7f40d262d2d0 state=running>: 'https://www.google.com', <Future at 0x7f40cadc4ad0 state=running>: 'http://www.cnn.com/', <Future at 0x7f40cadcd710 state=running>: 'http://europe.wsj.com/', <Future at 0x7f40cadcd410 state=running>: 'http://www.bbc.co.uk/', <Future at 0x7f40cade0a10 state=running>: 'http://abc.abc.com'}
----
Error in URL: http://abc.abc.com is <urlopen error [Errno -2] Name or servicenot known>
https://www.google.com length is 12571
http://www.cnn.com/ length is 1134562
http://europe.wsj.com/ length is 1006417
http://www.bbc.co.uk/ length is 311008

Python sort by val

myd = { "Peter": 40, "John": 2, "Bob": 1, "Danny": 3, } #sort by val s = sorted(myd.items(), key= lambda x:x[1]) print(s) Output: [('Bob', 1), ('John', 2), ('Danny', 3), ('Peter', 40)]

Python Sorted 2 Vs 3 versions

employees = {1000: {'name': 'Sahasra','country': 'India', 'age': 25}, \
   1001: {'name': 'Peter','country': 'US', 'age': 21}, \
   1002: {'name': 'John','country': 'US', 'age': 36}, \
   1003: {'name': 'Sarayu','country': 'India', 'age': 30},\
   1004: {'name': 'Akio','country': 'Japan', 'age': 60}, \
   1005: {'name': 'Anand','country': 'India', 'age': 50}, \
   1006: {'name': 'Vidya','country': 'India', 'age': 32}, \
   1007: {'name': 'Salma','country': 'Bangladesh', 'age': 23},}

# Works in Python 2.7 only
ss = sorted(employees.items(), key=lambda(x, y): y['age'])
print(ss)

# Works in Python 2.7 and 3.7
# Using parentheses to unpack the arguments in a lambda is not allowed in ss ss = sorted(employees.items(), key=lambda x: x[1]['age'])
print(ss)


Output:

[(1001, {'country': 'US', 'age': 21, 'name': 'Peter'}), (1007, {'country': 'Bangladesh', 'age': 23, 'name': 'Salma'}), (1000, {'country': 'India', 'age': 25, 'name': 'Sahasra'}), (1003, {'country': 'India', 'age': 30, 'name': 'Sarayu'}), (1006, {'country': 'India', 'age': 32, 'name': 'Vidya'}), (1002, {'country': 'US', 'age': 36, 'name': 'John'}), (1005, {'country': 'India', 'age': 50, 'name': 'Anand'}), (1004, {'country': 'Japan', 'age': 60, 'name': 'Akio'})]

[(1001, {'country': 'US', 'age': 21, 'name': 'Peter'}), (1007, {'country': 'Bangladesh', 'age': 23, 'name': 'Salma'}), (1000, {'country': 'India', 'age': 25, 'name': 'Sahasra'}), (1003, {'country': 'India', 'age': 30, 'name': 'Sarayu'}), (1006, {'country': 'India', 'age': 32, 'name': 'Vidya'}), (1002, {'country': 'US', 'age': 36, 'name': 'John'}), (1005, {'country': 'India', 'age': 50, 'name': 'Anand'}), (1004, {'country': 'Japan', 'age': 60, 'name': 'Akio'})]

Sep 19, 2019

Python ThreadPoolExecutor submit

from concurrent.futures import ThreadPoolExecutor import threading def task(n): print("Processing {} - {}".format(n, threading.current_thread())) def main(): print("Starting ThreadPoolExecutor") with ThreadPoolExecutor(max_workers=3) as executor: future = executor.submit(task, (2)) future = executor.submit(task, (3)) future = executor.submit(task, (4)) print("All tasks complete") if __name__ == '__main__': main()

Output:
Starting ThreadPoolExecutor Processing 2 - <Thread(ThreadPoolExecutor-0_0, started daemon 140052642395904)> Processing 3 - <Thread(ThreadPoolExecutor-0_1, started daemon 140052634003200)> Processing 4 - <Thread(ThreadPoolExecutor-0_2, started daemon 140052625610496)> All tasks complete


Python ThreadPoolExecutor, map

import urllib.request 
from concurrent.futures import ThreadPoolExecutor
import threading

urls = [
  'http://www.python.org', 
  'http://www.python.org/about/',
  'http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html',
  'http://www.python.org/doc/',
  'http://www.python.org/download/',
  'http://www.python.org/getit/',
  'http://www.python.org/community/',
  'https://wiki.python.org/moin/',
]

def fun(url):
  print(url, threading.current_thread())
  r = urllib.request.urlopen(url)
  return r

# make the Pool of workers
pool = ThreadPoolExecutor(4) 

results = pool.map(fun, urls)
real_results = list(results)
print('----')
print(real_results)


Output:
http://www.python.org <Thread(ThreadPoolExecutor-0_0, started daemon 139989036611328)>
http://www.python.org/about/ <Thread(ThreadPoolExecutor-0_1, started daemon 139988956083968)>
http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html <Thread(ThreadPoolExecutor-0_2, started daemon 139988947691264)>
http://www.python.org/doc/ <Thread(ThreadPoolExecutor-0_3, started daemon 139988939298560)>
http://www.python.org/download/ <Thread(ThreadPoolExecutor-0_1, started daemon 139988956083968)>
http://www.python.org/getit/ <Thread(ThreadPoolExecutor-0_3, started daemon 139988939298560)>
http://www.python.org/community/ <Thread(ThreadPoolExecutor-0_0, started daemon 139989036611328)>
https://wiki.python.org/moin/ <Thread(ThreadPoolExecutor-0_3, started daemon 139988939298560)>
----
[<http.client.HTTPResponse object at 0x7f51be3d7910>, <http.client.HTTPResponse object at 0x7f51be3c5f90>, <http.client.HTTPResponse object at 0x7f51be3d73d0>, <http.client.HTTPResponse object at 0x7f51be3d77d0>, <http.client.HTTPResponse object at 0x7f51be3b3b90>, <http.client.HTTPResponse object at 0x7f51be3c5610>, <http.client.HTTPResponse object at 0x7f51be3e1c90>, <http.client.HTTPResponse object at 0x7f51be3d7250>]

Python threads using Queue

#Ref:
#https://stackoverflow.com/questions/47900922/split-list-into-n-lists-and-assign-each-list-to-a-worker-in-multithreading
#https://pymotw.com/2/Queue/

#The Queue module provides a FIFO implementation suitable for multi-threaded programming. 
#It can be used to pass messages or other data between producer and consumer threads safely. 
#Locking is handled for the caller, so it is simple to have as many threads as you want working with the same Queue instance. 
#A Queue’s size (number of elements) may be restricted to throttle memory usage or processing.

#### 3 types of queues
# Basic FIFO Queue
# LIFO Queue
# Priority Queue

from queue import Queue, LifoQueue
from threading import Thread, current_thread
from time import sleep
first_names = ['Steve','Jane','Sara','Mary','Jack','tara','bobby']

q = Queue() #FIFO
lq = LifoQueue() #LifoQueue

num_threads = 3

def do_stuff(q):
    while True:
        print(q.get(), current_thread())
        sleep(1)
        q.task_done()

if __name__ == '__main__':
    print('------ FIFO - Basic ------')

    for x in first_names:
        q.put(x)
    
    for i in range(num_threads):
        worker = Thread(target=do_stuff, args=(q,))
        worker.start()

    q.join()
    
    print('------ LIFO - reverse order -----')

    for x in first_names:
        lq.put(x)
    
    for i in range(num_threads):
        worker = Thread(target=do_stuff, args=(lq,))
        worker.start()

    lq.join()



Output:

------ FIFO - Basic ------
Steve <Thread(Thread-1, started 140202362271488)>
Jane <Thread(Thread-2, started 140202353878784)>
Sara <Thread(Thread-3, started 140202345486080)>
Mary <Thread(Thread-1, started 140202362271488)>
Jack <Thread(Thread-2, started 140202353878784)>
tara <Thread(Thread-3, started 140202345486080)>
bobby <Thread(Thread-1, started 140202362271488)>
------ LIFO - reverse order -----
bobby <Thread(Thread-4, started 140202337093376)>
tara <Thread(Thread-5, started 140202328700672)>
Jack <Thread(Thread-6, started 140202320307968)>
Mary <Thread(Thread-4, started 140202337093376)>
Sara <Thread(Thread-5, started 140202328700672)>
Jane <Thread(Thread-6, started 140202320307968)>
Steve <Thread(Thread-4, started 140202337093376)>


Python multiple threads - how to join

from threading import Thread, active_count, current_thread
import time

def fun(val):
  for _ in range(5):
    print(val, current_thread())
    time.sleep(3)

threads = []
for i in range(1, 11):
   t = Thread(target=fun, args=(i*i,))
   threads.append(t)
   t.start()
   print("Current Threads count: %i." % active_count())

#Join threads
for t in threads:
    t.join()

print('bye')


Output:
######
1 <Thread(Thread-1, started 140645849839360)>
Current Threads count: 2.
4 <Thread(Thread-2, started 140645841446656)>
Current Threads count: 3.
9 <Thread(Thread-3, started 140645833053952)>
Current Threads count: 4.
16 <Thread(Thread-4, started 140645616318208)>
Current Threads count: 5.
25 <Thread(Thread-5, started 140645607925504)>
Current Threads count: 6.
36 <Thread(Thread-6, started 140645599532800)>
Current Threads count: 7.
49 <Thread(Thread-7, started 140645591140096)>
Current Threads count: 8.
64 <Thread(Thread-8, started 140645582747392)>
Current Threads count: 9.
81 <Thread(Thread-9, started 140645574354688)>
Current Threads count: 10.
100 <Thread(Thread-10, started 140645565961984)>
Current Threads count: 11.
4 <Thread(Thread-2, started 140645841446656)>
9 <Thread(Thread-3, started 140645833053952)>
16 <Thread(Thread-4, started 140645616318208)>
1 <Thread(Thread-1, started 140645849839360)>
100 <Thread(Thread-10, started 140645565961984)>
25 <Thread(Thread-5, started 140645607925504)>
36 <Thread(Thread-6, started 140645599532800)>
64 <Thread(Thread-8, started 140645582747392)>
49 <Thread(Thread-7, started 140645591140096)>
81 <Thread(Thread-9, started 140645574354688)>
4 <Thread(Thread-2, started 140645841446656)>
9 <Thread(Thread-3, started 140645833053952)>
16 <Thread(Thread-4, started 140645616318208)>
1 <Thread(Thread-1, started 140645849839360)>
100 <Thread(Thread-10, started 140645565961984)>
25 <Thread(Thread-5, started 140645607925504)>
36 <Thread(Thread-6, started 140645599532800)>
64 <Thread(Thread-8, started 140645582747392)>
81 <Thread(Thread-9, started 140645574354688)>
49 <Thread(Thread-7, started 140645591140096)>
4 <Thread(Thread-2, started 140645841446656)>
9 <Thread(Thread-3, started 140645833053952)>
16 <Thread(Thread-4, started 140645616318208)>
100 <Thread(Thread-10, started 140645565961984)>
1 <Thread(Thread-1, started 140645849839360)>
25 <Thread(Thread-5, started 140645607925504)>
36 <Thread(Thread-6, started 140645599532800)>
64 <Thread(Thread-8, started 140645582747392)>
81 <Thread(Thread-9, started 140645574354688)>
49 <Thread(Thread-7, started 140645591140096)>
4 <Thread(Thread-2, started 140645841446656)>
16 <Thread(Thread-4, started 140645616318208)>
9 <Thread(Thread-3, started 140645833053952)>
1 <Thread(Thread-1, started 140645849839360)>
100 <Thread(Thread-10, started 140645565961984)>
64 <Thread(Thread-8, started 140645582747392)>
25 <Thread(Thread-5, started 140645607925504)>
36 <Thread(Thread-6, started 140645599532800)>
81 <Thread(Thread-9, started 140645574354688)>
49 <Thread(Thread-7, started 140645591140096)>
bye

Python glob vs glob recursive - loop directory

import glob

p = glob.glob('*.py')
print(p)
print(len(p)) #17

#single star - all files in current dir
p = glob.glob('*', recursive=True)
print(p)
print(len(p)) #20

#double star - all folders and files recursively in current dir
p = glob.glob('**', recursive=True)
print(p)
print(len(p)) #22


"""
Output:
['timeit_test.py', 'args_kwargs.py', 'fibonacci.py', 'shallow_vs_deep_copy.py', 'inheritance_example.py', 'python_closure.py', 'super_test.py', 'date_example.py', 'contextlib_example.py', 're_compile_vs_match.py', 'iterator_example.py', 'str_repr_eval.py', 'generator_example.py', 'init_vs_call.py', 'main.py', 'filter_map_reduce.py', '_test_runner.py']
17

['timeit_test.py', 'args_kwargs.py', 'fibonacci.py', 'shallow_vs_deep_copy.py', 'inheritance_example.py', 'python_closure.py', 'super_test.py', 'utils', 'date_example.py', 'contextlib_example.py', 'test1.txt', 're_compile_vs_match.py', 'test.txt', 'iterator_example.py', 'str_repr_eval.py', 'generator_example.py','init_vs_call.py', 'main.py', 'filter_map_reduce.py', '_test_runner.py']
20

['timeit_test.py', 'args_kwargs.py', 'fibonacci.py', 'shallow_vs_deep_copy.py', 'inheritance_example.py', 'python_closure.py', 'super_test.py', 'utils', 'utils/__init__.py', 'utils/utils.py', 'utils/utils1', 'date_example.py', 'contextlib_example.py','test1.txt', 're_compile_vs_match.py', 'test.txt', 'iterator_example.py', 'str_repr_eval.py', 'generator_example.py', 'init_vs_call.py', 'main.py', 'filter_map_reduce.py', '_test_runner.py']
22
"""

python reverse vs reversed

"""
reverse() modifies the list itself, whereas
reversed() returns an iterator ready to traverse the list in reversed order.
"""

#string reverse (best way for string reverse using slicing)
s = 'string'
print(s[::-1]) #gnirts
print(s) #string

#string reversed
rs = reversed(s)
print(''.join(rs)) #gnirts
print(s) #string

#reverse list
l = [1,2,3]
l.reverse()
print(l) #[3,2,1]

#reversed list
ll = reversed(l)
print(ll) #<list_reverseiterator object at 0x7fa572312790>
print(list(ll)) #[1,2,3]