Python Projects for Beginners to Advanced [With Source Code]

 

Python Projects for Beginners to Advanced [With Source Code]


Python Projects

Python is an extremely popular programming language. Almost, 8.2M developers all over the globe use Python for their projects which is more than Java now. So, in order to gain expertise in the Python language, it is recommended to start by creating some projects.
In this article, we are going to cover Python Project Ideas for beginners and experts with valid source code.

Python Project Ideas for Beginners

Well, if you’ve just started out learning Python or are in a stage where you really want to get your hands dirty, then follow this section. We have discussed a few Python projects with source codes here for you to delve deep and get expertise:

1. Email Slicer

One of the easiest projects to start with is getting an email ID as input and slicing it into username and domain name. 

Source Code:

email = input("Enter Your Email: ").strip()
username = email[:email.index('@')]
domain = email[email.index('@') + 1:]

Input: dev.carol@gmail.com
        Username: dev.carol
Domain: gmail.com

2. Number to Words

This Python project can make you spell out the numbers as you may define. This Python code will help you support more than a million inputs along with the non-positive integers like zero, negative integers, or floating numbers. 

Source Code:

import num2words as n2w
from tkinter import *

def num_to_words():
    given_num = float(num.get())
    num_in_word = n2w.num2words(given_num)
    display.config(text=str(num_in_word).capitalize())

root = Tk()
root.title("Numbers tdo Words")
root.geometry("650x400")

num = StringVar()

# Adding title
title = Label(root, text="Number to Words converter",
               fg="Blue", font=("Arial", 20, 'bold')).place(x=220, y=10)

# Options
formats_lable = Label(root, text="Formats supported :  ",
               fg="green", font=("Arial", 10, 'bold')).place(x=100, y=70)
pos_format_lable = Label(root, text="1. Positives :  ",
               fg="green", font=("Arial", 10, 'bold')).place(x=200, y=90)
neg_format_lable = Label(root, text="2. Negatives ",
               fg="green", font=("Arial", 10, 'bold')).place(x=200, y=110)
float_format_lable = Label(root, text="3. Zeros  ",
               fg="green", font=("Arial", 10, 'bold')).place(x=200, y=130)
zero_format_lable = Label(root, text="4. Floating points/decimals/fractions  ",
               fg="green", font=("Arial", 10, 'bold')).place(x=200, y=150)

num_entry_lable = Label(root, text="Enter a number :",
               fg="Blue", font=("Arial", 15, 'bold')).place(x=50, y=200)
num_entry = Entry(root,textvariable=num,width=30).place(x=220, y=200)

btn = Button(master=root, text="calculate",fg="green",

font=("Arial", 10, 'bold')
             ,command=num_to_words).place(x=280,y=230)


display = Label(root, text="",fg="black", font=("Arial", 10, 'bold'))
display.place(x=10, y=300)


photo = PhotoImage(file = "Num2Words/number.png")
root.iconphoto(False, photo)

root.mainloop()

3. Google Image downloader

Need a bunch of images for your new project? Then just run this program and download any number of images for a  topic. Only ensure that you do not violate copyright issues and give due credit to the owner, if needed. 

Source Code

from setuptools import setup, find_packages
from codecs import open
from os import path

__version__ = '2.8.0'

here = path.abspath(path.dirname(__file__))

# Get the long description from the README file
with open('README.rst', encoding='utf-8') as f:
    long_description = f.read()

# get the dependencies and installs
with open(path.join(here, 'requirements.txt'), encoding='utf-8') as f:
    all_reqs = f.read().split('\n')

install_requires = [x.strip() for x in all_reqs if 'git+' not in x]
dependency_links = [x.strip().replace('git+', '') for x in all_reqs if x.startswith('git+')]

setup(
    name='google_images_download',
    version=__version__,
    description="Python Script to download hundreds of images from 'Google Images'. It is a ready-to-run code! ",
    long_description=long_description,
    url='https://github.com/hardikvasa/google-images-download',
    download_url='https://github.com/hardikvasa/google-images-download/tarball/' + __version__,
    license='MIT',
    classifiers=[
        'Development Status :: 4 - Beta',
        'Intended Audience :: Developers',
        'License :: OSI Approved :: MIT License',
        'Programming Language :: Python :: 2.7',
        'Programming Language :: Python :: 3.3',
        'Programming Language :: Python :: 3.4',
        'Programming Language :: Python :: 3.5',
        'Programming Language :: Python :: 3.6',
    ],
    keywords='google images download save filter color image-search image-dataset image-scrapper image-gallery terminal command-line',
    packages=find_packages(exclude=['docs', 'tests*']),
    include_package_data=True,
    author='Hardik Vasa',
    install_requires=install_requires,
    dependency_links=dependency_links,
    author_email='hnvasa@gmail.com',
    entry_points={
        'console_scripts': [
            'googleimagesdownload = google_images_download.google_images_download:main'
        ]},

)

4. Contact List

As old school as it may sound, creating a contact list, adding contacts along with phone numbers or emails, and editing them, is still prevalent. To create one, you can use the SQLAlchemy library which uses SQLite to store contacts. 

Source Code:

from Tkinter import *
from tkMessageBox import *
import sqlite3
import ttk
def insert():	
        n=name.get()
        
        p=phone.get()
        m=mail.get()
        if(n!="" and p!="" and  m!="" ):
                con = sqlite3.connect('data.db')
                c = con.cursor()
 
                c.execute('CREATE TABLE IF NOT EXISTS contact (name TEXT, phone TEXT, mail TEXT)')
    
                r=c.execute("INSERT INTO contact(name, phone, mail) VALUES(?,?,?)",(n,p,m))
        
                con.commit()
                if(r):
                         g=showinfo('Insert', 'Successfully inserted')
                        
                         						 
else:
showerror("Error ", "Something went worng check once")

con.close()
        else:
             showerror("Invaild Data ", "Some fields are empty check once!!!")

            
def dele():
    n=name.get()
    if(n!=""):
        con = sqlite3.connect('data.db')
        c = con.cursor()
 
 
        r=c.execute("DELETE FROM contact WHERE name=?",(n,))
        
        con.commit()
        if(r):
             showinfo('Deleted', 'Successfully Deleted')
             n=""
        else:
            showerror("Invaild Data ", "Some error occured check once!!!")

    con.close()
    else:
        showwarning('NO', 'Check filed once!!!!')
        
    
def delete():
    top = Toplevel()
    top.title("DELETE DATA")
    l=Label(top,text="Enter the name to delete")
    l.grid(row=0,columnspan=4)
    e=Entry(top,width=30,textvar=name)
    e.grid(row=2,columnspan=2)
    b=Button(top,text="Delete",command=dele)
    b.grid(row=4,columnspan=4)

    top.mainloop()
def add():
    top = Toplevel()
    top.title("ADD DATA")
    
    lbl_text = Label(top)
    lbl_text.grid(row=0, columnspan=3)
    l=Label(top,text="NAME :-")
    l.grid(row=1)
    l2=Label(top,text="MOBILE :-")
    l2.grid(row=2)
    l3=Label(top,text="E-MAIL :-")
    l3.grid(row=3)
    e=Entry(top,width=30,textvar=name)
    e.grid(row=1,column=1)
    
    e1=Entry(top,width=30,textvar=phone)
    e1.grid(row=2,column=1)

    e2=Entry(top,width=30,textvar=mail)
    e2.grid(row=3,column=1)
    b=Button(top,text="Submit",command=insert)
    b.grid(row=4,columnspan=2)
    
    top.mainloop()
def update():
    showinfo('sorry','These feature not avaiible')

root=Tk()
root.title("Contact Application with Sqlite")
root.geometry("700x500")
name=StringVar()
phone=StringVar()
mail=StringVar()
top=""
f=Frame(root,height=50)

f.pack(fill=X,side=TOP)
l=Label(f,text="Contact Application",bg="white",fg="red")
l.pack(fill=X)
f2=Frame(root,height=100,bg="black")
f2.pack(fill=X,side=TOP)
b1=Button(f2, text="DELETE",command=delete).grid(row=1, column=3, sticky=N,padx=80)
b2=Button(f2, text="+ADD",command=add).grid(row=1, column=4, sticky=N,padx=50)
b3=Button(f2, text="UPDATE",command=update).grid(row=1, column=5, sticky=N,padx=100)
f3=Frame(root,height=200,bg="blue")
f3.pack(fill=X)

tree =ttk.Treeview(f3)


tree["columns"]=("one","two","three")
tree.column("#0", width=210, minwidth=270, stretch=NO)
tree.column("one", width=210, minwidth=200, stretch=NO)
tree.column("two", width=250, minwidth=230,stretch=NO)

tree.heading("#0",text="Name",anchor=W)
tree.heading("one", text="Mobile Number",anchor=W)
tree.heading("two", text="Mail Id",anchor=W)
con = sqlite3.connect('data.db')
c = con.cursor()
c.execute('CREATE TABLE IF NOT EXISTS contact (name TEXT, phone TEXT, mail TEXT)')
r=c.execute("SELECT * FROM contact")
for row in r:
        tree.insert('', 'end',text=row[0],
                         values=(row[1],row[2]))
con.close()

tree.pack(side=TOP,fill=X)
root.resizable(0,0)
root.mainloop()

5. Monty Hall Simulation Problem

Monty Hall Simulation Problem Python Project

Monty hall problem comes from a famous movie where three doors are used to help you win a car. How? Each door hides something behind it–a car and two goats. Any door can have the car while the remaining two have goats. The probability to find a car is ⅓. Now, if you select Door 1 and the host opens Door 3 to find a goat, your chances just become ⅔. This program will help you solve this problem. 

Source Code:

import random
from tkinter import StringVar, Label, Tk, Entry

window = Tk()
window.geometry("400x100")
window.title("Monty hall simulation")
window.resizable(0, 0)

same_choice = StringVar()
switched_choice = StringVar()
same_choice.set(0)
switched_choice.set(0)
no_sample = Entry()
Label(text="Same choice").place(x=80, y=8)
Label(text="Switched choice").place(x=80, y=40)
Label(textvariable=same_choice, font=(15)).place(x=180, y=8)
Label(textvariable=switched_choice, font=(15)).place(x=180, y=40)
no_sample.place(x=100, y=70)


def simulate(event):
    same_choice_result = 0
    switched_choice_result = 0
    samples = int(no_sample.get())
    doors = ["gold", "goat", "bed"]
    for _ in range(samples):
        simulated_doors = doors.copy()
        random.shuffle(simulated_doors)
        first_choice = random.choice(simulated_doors)
        simulated_doors.remove(first_choice)
        opened_door = (
            simulated_doors[0] if simulated_doors[0] != "gold" else simulated_doors[1]
        )
        simulated_doors.remove(opened_door)
        switched_second_choice = simulated_doors[0]
        if first_choice == "gold":
            same_choice_result += 1
            same_choice.set(same_choice_result)
        elif switched_second_choice == "gold":
            switched_choice_result += 1
            switched_choice.set(switched_choice_result)
        else:
            print("That's will never happed")


no_sample.bind("<Return>", simulate)
window.mainloop()

6. Image to Sound

You can create sound from image files now. Imagine displaying an image from the forest with the actual forest sound in the background–Just adds to the drama. For this to run, have an image file and sound file (in .mp3 format) ready. 

Install these libraries before running the program:

-> pip install pytesseract
-> pip install gTTS -> pip install pytesseract -> pip install gTTS

Source Code:

from PIL import Image
from gtts import gTTS
from pytesseract import image_to_string


def image_to_sound(path_to_image):
    """
    Function for converting an  image to sound
    """
    try:
        loaded_image = Image.open(path_to_image)
        decoded_text = image_to_string(loaded_image)
        cleaned_text = " ".join(decoded_text.split("\n"))
        print(cleaned_text)
        sound = gTTS(cleaned_text, lang="en")
        sound.save("sound.mp3")
        return True
    except Exception as bug:
        print("The bug thrown while executing the code\n", bug)
        return


if __name__ == "__main__":
    image_to_sound("image.jpg")
    input()

7. Snake Game

Snake Game Python Project

With older Nokia phones, we had an old-age addiction with the snake game. But of course, we don’t have it anymore. What if you could write one for yourself using Python?

Source Code:

"""Snake, classic arcade game.

Excercises

1. How do you make the snake faster or slower?
2. How can you make the snake go around the edges?
3. How would you move the food?
4. Change the snake to respond to arrow keys.

"""

from turtle import *
from random import randrange
from freegames import square, vector

food = vector(0, 0)
snake = [vector(10, 0)]
aim = vector(0, -10)

def change(x, y):
    "Change snake direction."
    aim.x = x
    aim.y = y

def inside(head):
    "Return True if head inside boundaries."
    return -200 < head.x < 190 and -200 < head.y < 190

def move():
    "Move snake forward one segment."
    head = snake[-1].copy()
    head.move(aim)

    if not inside(head) or head in snake:
        square(head.x, head.y, 9, 'red')
        update()
        return

    snake.append(head)

    if head == food:
        print('Snake:', len(snake))
        food.x = randrange(-15, 15) * 10
        food.y = randrange(-15, 15) * 10
    else:
        snake.pop(0)
 clear()

    for body in snake:
        square(body.x, body.y, 9, 'black')

    square(food.x, food.y, 9, 'green')
    update()
    ontimer(move, 100)

setup(420, 420, 370, 0)
hideturtle()
tracer(False)
listen()
onkey(lambda: change(10, 0), 'Right')
onkey(lambda: change(-10, 0), 'Left')
onkey(lambda: change(0, 10), 'Up')
onkey(lambda: change(0, -10), 'Down')
move()
done()

8. GIF Creator

As famous as the gif market has become over these years now, demand for quality gif is going up. To expand your horizon, if you find a video that might make a good GIF, then just convert that video into a gif using this Python Project.

Source Code:

from moviepy.editor import *

from moviepy.editor import *
clip = (VideoFileClip("Gif-Creator/video.webm").subclip((2.25),(6.25))
        .resize(0.3))
clip.write_gif("output.gif")

9. Website blocker

Website blocker python project

Aren’t we all tired of random pop-ups during site surfing? So, we can create website blockers for restraining pushy ads by creating this Python project.
Remember, when you code this, you can add the sites you need to block by editing sites_to_block, change the host, or edit the time when you need to block the sites.

Source Code:

import time
from datetime import datetime as dt

sites_to_block = [
    "www.facebook.com",
    "facebook.com",
    "www.youtube.com",
    "youtube.com",
    "www.gmail.com",
    "gmail.com",
]

Linux_host = "/etc/hosts"
Window_host = r"C:\Windows\System32\drivers\etc\hosts"
default_hoster = Linux_host
redirect = "127.0.0.1"


def block_websites(start_hour, end_hour):
    while True:
        if (
            dt(dt.now().year, dt.now().month, dt.now().day, start_hour)
            < dt.now()
            < dt(dt.now().year, dt.now().month, dt.now().day, end_hour)
        ):
            print("Do the work ....")
            with open(default_hoster, "r+") as hostfile:
                hosts = hostfile.read()
                for site in sites_to_block:
                    if site not in hosts:
                        hostfile.write(redirect + " " + site + "\n")
        else:
            with open(default_hoster, "r+") as hostfile:
                hosts = hostfile.readlines()
                hostfile.seek(0)
                for host in hosts:
                    if not any(site in host for site in sites_to_block):
                        hostfile.write(host)
                hostfile.truncate()
            print("Good Time")
        time.sleep(3)


if __name__ == "__main__":
    block_websites(9, 21)

10. Binary Search Algorithm

As the binary term explains, the system will take any input starting from 0 to any range that you specify and display a range of numbers with a difference of two.

def binary_search(a_list, item):
   """Performs iterative binary search to find the position of an integer in a given, sorted, list.
   a_list -- sorted list of integers
   item -- integer you are searching for the position of
   """
   first = 0
   last = len(a_list) - 1
   while first <= last:
       i = (first + last) / 2
       if a_list[i] == item:
           return ' found at position '.format(item=item, i=i)
       elif a_list[i] > item:
           last = i - 1
       elif a_list[i] < item:
           first = i + 1
       else:
           return ' not found in the list'.format(item=item)
// recursive implementation of binary search in Python
def binary_search_recursive(a_list, item):
   """Performs recursive binary search of an integer in a given, sorted, list.
   a_list -- sorted list of integers
   item -- integer you are searching for the position of
   """
   first = 0
   last = len(a_list) - 1
   if len(a_list) == 0:
       return ' was not found in the list'.format(item=item)
   else:
       i = (first + last) // 2
       if item == a_list[i]:
           return ' found'.format(item=item)
       else:
           if a_list[i] < item:
               return binary_search_recursive(a_list[i+1:], item)
           else:
                return binary_search_recursive(a_list[:i], item)

Python Project Ideas for Intermediate

If you have a little expertise with Python projects, you can directly start building these projects. These projects are for intermediate users who have some knowledge and wish to create more.

1. Image to Story

Want to create amazing stories from images? This project will let you produce a sentence after capturing the image. For this to work, download some pre-trained models and style vectors. Run:

wget http://www.cs.toronto.edu/~rkiros/neural_storyteller.zip

Finally, we need the VGG-19 ConvNet parameters. You can obtain them by running:

wget 
https://s3.amazonaws.com/lasagne/recipes/pretrained/imagenet/vgg19.pkl

Open config.py and specify the locations of all of the models and style vectors that you downloaded.
For running on CPU, you will need to download the VGG-19 prototxt and model by:

wget 
http://www.robots.ox.ac.uk/~vgg/software/very_deep/caffe/VGG_ILSVRC_19_layers.caffemodel
wget 
https://gist.githubusercontent.com/ksimonyan/3785162f95cd2d5fee77/raw/bb2b4fe0a9bb0669211cf3d0bc949dfdda173e9e/VGG_ILSVRC_19_layers_deploy.prototxt

Now, to generate a story, open Ipython and run:

import generate
z = generate.load_all()
generate.story(z, './images/ex1.jpg')

2. Number Guessing

A fun project to guess the number after getting a few hints from the computer. So, the system will generate a number from 0 to 200 and ask the user to guess it after a clue. Every time a user gives a wrong answer, another hint pops up to make it easier for them.

Source Code:

import random #bring in the random number
import time
number=random.randint(1, 200) #pick the number between 1 and 200

def intro():
    print("May I ask you for your name?")
    name=input() #asks for the name
    print(name + ", we are going to play a game. I am thinking of a number between 1 and 200")
    time.sleep(.5)
    print("Go ahead. Guess!")

def pick():
    guessesTaken = 0
    while guessesTaken < 6: #if the number of guesses is less than 6
        time.sleep(.25)
        enter=input("Guess: ") #inserts the place to enter guess
        try: #check if a number was entered
            guess = int(enter) #stores the guess as an integer instead of a string    

            if guess<=200 and guess>=1: #if they are in range
                guessesTaken=guessesTaken+1 #adds one guess each time the player is wrong
                if guessesTaken<6:
                    if guess<number:
                        print("The guess of the number that you have entered is too low")
                    if guess>number:
                        print("The guess of the number that you have entered is too high")
                    if guess != number:
                        time.sleep(.5)
                        print("Try Again!")
                if guess==number:
                    break #if the guess is right, then we are going to jump out of the while block
            if guess>200 or guess<1: #if they aren't in the range
                print("Silly Goose! That number isn't in the range!")
                time.sleep(.25)
                print("Please enter a number between 1 and 200")

        except: #if a number wasn't entered
            print("I don't think that "+enter+" is a number. Sorry")
            
    if guess == number:
        guessesTaken = str(guessesTaken)
        print('Good job, ' + name + '! You guessed my number in ' + guessesTaken + ' guesses!')

    if guess != number:
        print('Nope. The number I was thinking of was ' + str(number))

playagain="yes"
while playagain=="yes" or playagain=="y" or playagain=="Yes":
    intro()
    pick()
    print("Do you want to play again?")
    playagain=input()

3. Voice Assistant

Voice Assistant Python Project

Looking at the market majorly, we realise voice assistants are all up to take over our tasks. Siri, Alexa, and OkGoogle are already leading the market. How about you have a personal assistant of your own> Create your own voice assistant using this Python program.

Source Code:

import pyttsx3
import speech_recognition as sr
import wikipedia
import webbrowser
import os

# init pyttsx
engine = pyttsx3.init("sapi5")
voices = engine.getProperty("voices")

engine.setProperty('voice', voices[1].id)  # 1 for female and 0 for male voice


def speak(audio):
    engine.say(audio)
    engine.runAndWait()


def take_command():
    r = sr.Recognizer()
    with sr.Microphone() as source:
        print("Listening...")
        r.pause_threshold = 1
        audio = r.listen(source)
    try:
        print("Recognizing...")
        query = r.recognize_google(audio, language='en-in')
        print("User said:" + query + "\n")
    except Exception as e:
        print(e)
        speak("I didnt understand")
        return "None"
    return query


if __name__ == '__main__':

    speak("Amigo assistance activated ")
    speak("How can i help you")
    while True:
        query = take_command().lower()
        if 'wikipedia' in query:
speak("Searching Wikipedia ...")

            query = query.replace("wikipedia", '')
            results = wikipedia.summary(query, sentences=2)
            speak("According to wikipedia")
            speak(results)
        elif 'are you' in query:
            speak("I am amigo developed by Jaspreet Singh")
        elif 'open youtube' in query:
            speak("opening youtube")
            webbrowser.open("youtube.com")
        elif 'open google' in query:
            speak("opening google")
            webbrowser.open("google.com")
        elif 'open github' in query:
            speak("opening github")
            webbrowser.open("github.com")
        elif 'open stackoverflow' in query:
            speak("opening stackoverflow")
            webbrowser.open("stackoverflow.com")
        elif 'open spotify' in query:
            speak("opening spotify")
            webbrowser.open("spotify.com")
        elif 'open whatsapp' in query:
            speak("opening whatsapp")
            loc = "C:\\Users\\jaspr\\AppData\\Local\\WhatsApp\\WhatsApp.exe"
            os.startfile(loc)
        elif 'play music' in query:
            speak("opening music")
            webbrowser.open("spotify.com")
        elif 'play music' in query:
            speak("opening music")
            webbrowser.open("spotify.com")
        elif 'local disk d' in query:
            speak("opening local disk D")
            webbrowser.open("D://")
        elif 'local disk c' in query:
            speak("opening local disk C")
            webbrowser.open("C://")
        elif 'local disk e' in query:
            speak("opening local disk E")
            webbrowser.open("E://")
        elif 'sleep' in query:
            exit(0)

4. Password Generator

The most difficult part of managing multiple accounts is generating a different strong password for each. A strong password is a mix of alphabets, numbers, and alphanumeric characters. Therefore, the best use of Python could be building a project where you could generate random passwords for any of your accounts.

Source CodeSource Code

import random

def generatePassword(pwlength):

    alphabet = "abcdefghijklmnopqrstuvwxyz"

    passwords = [] 

    for i in pwlength:
        
        password = "" 
        for j in range(i):
            next_letter_index = random.randrange(len(alphabet))
            password = password + alphabet[next_letter_index]
        
        password = replaceWithNumber(password)
        password = replaceWithUppercaseLetter(password)
        
        passwords.append(password) 
    
    return passwords


def replaceWithNumber(pword):
    for i in range(random.randrange(1,3)):
        replace_index = random.randrange(len(pword)//2)
        pword = pword[0:replace_index] + str(random.randrange(10)) + pword[replace_index+1:]
        return pword


def replaceWithUppercaseLetter(pword):
    for i in range(random.randrange(1,3)):
        replace_index = random.randrange(len(pword)//2,len(pword))
        pword = pword[0:replace_index] + pword[replace_index].upper() + pword[replace_index+1:]
        return pword

def main():
    
    numPasswords = int(input("How many passwords do you want to generate? "))
    
    print("Generating " +str(numPasswords)+" passwords")
    
    passwordLengths = []

    print("Minimum length of password should be 3")

    for i in range(numPasswords):
        length = int(input("Enter the length of Password #" + str(i+1) + " "))
        if length<3:
            length = 3
        passwordLengths.append(length)
    
    
    Password = generatePassword(passwordLengths)

    for i in range(numPasswords):
        print ("Password #"+str(i+1)+" = " + Password[i])



main()

5. Reddit Bot

Reddit Bot Python Project

We all have used Reddit for one purpose or the other. The famous question-answer app can now also have a bot linked to it. The bot will automate comments on the posts based on specified criteria.

For this to work:

  • Pick a subreddit to scan
  • Designate a specific comment to search for
  • Set your bot’s reply
  • Create a config.py file with your Reddit account details and Reddit.py file with the bot requirements
  • Pre-requisites: Python, Praw, and A reddit account

Config.py

username = "RedditUsername"
password = "password"
client_id = "idGoesHere"
client_secret = "secretGoesHere"

Reddit.py

import praw
import config
import time
import os

def bot_login():
    print "Logging in..."
    r = praw.Reddit(username = config.username,
                password = config.password,
                client_id = config.client_id,
                client_secret = config.client_secret,
                user_agent = "The Reddit Commenter v1.0")
    print "Logged in!"

    return r

def run_bot(r, comments_replied_to):
    print "Searching last 1,000 comments"

    for comment in r.subreddit('test').comments(limit=1000):
        if "sample user comment" in comment.body and comment.id not in comments_replied_to and comment.author != r.user.me():
            print "String with \"sample user comment\" found in comment " + comment.id
            comment.reply("Hey, I like your comment!")
            print "Replied to comment " + comment.id

            comments_replied_to.append(comment.id)

            with open ("comments_replied_to.txt", "a") as f:
                f.write(comment.id + "\n")

    print "Search Completed."

    print comments_replied_to

    print "Sleeping for 10 seconds..."
    #Sleep for 10 seconds...		
    time.sleep(10)

def get_saved_comments():

if not os.path.isfile("comments_replied_to.txt"):
        comments_replied_to = []
    else:
        with open("comments_replied_to.txt", "r") as f:
            comments_replied_to = f.read()
            comments_replied_to = comments_replied_to.split("\n")
            comments_replied_to = filter(None, comments_replied_to)

    return comments_replied_to

r = bot_login()
comments_replied_to = get_saved_comments()
print comments_replied_to

while True:
    run_bot(r, comments_replied_to)

6. Black Jack

Creating the most famous card game of the casinos in Python would be a wonderful project. This game is played with a deck of 52 cards where the strategies play at best. Shuffle the cards, announce the buy-in amount, and decide the ranking of the cards. For ex. If Ace is given number 1 or 11. The player who gets the value of cards to 21 wins the game.

Source Code

#!/Users/Utsav/downloads/udemy python

# For using the same code in either Python 2 or 3
# from __future__ import print_function

# Importing libraries -- used for shuffling cards
import random

# Boolean type to know whether play is in hand
playing = False

# Amount for buy-in
chip_pool = 100
# raw_input('Enter the amount for buy-in: ')
print 'Your buy-in amount is: ',chip_pool

bet = 1

restart_phrase = "Press d to deal the cards again, or press q to quit."

# Hearts, Diamonds, Clubs, Spades
suits = ('H','D','S','C')

# Possible Card Ranks
ranking = ('A','2','3','4','5','6','7','8','9','10','J','Q','K')

# Point Val Dict (Dual existence of Ace is defined later)
card_val = {'A':1, '2':2, '3':3, '4':4, '5':5, '6':6, '7':7, '8':8, '9':9, '10':10, 'J':10, 'Q':10, 'K':10}

# Creating Card Class

class Card:

    def __init__(self, suit, rank):
        self.suit = suit
        self.rank = rank

    def __str__(self):
        return self.suit + self.rank

    def grab_suit(self):
        return self.suit

    def grab_rank(rank):
        return self.rank

    def draw(self):
        print (self.suit + self.rank)

# Creating Hand Class
# Gives dual existence to Ace

class Hand:

    def __init__(self):
        self.cards = []
        self.value = 0

        # Aces can be 1 0r 11 as defined below
        self.ace = False
def __str__(self):
        '''Return a string of current hand composition'''
        hand_comp = ""

        # List Comprehension
        for card in self.cards:
            card_name = card.__str__()
            hand_comp += " " + card_name

        return 'The hand has %s' %hand_comp

    def card_add(self,card):
        '''Add another card to the hand'''
        self.cards.append(card)

        # Checking for Aces
        if card.rank == 'A':
            self.ace = True
        self.value += card_val[card.rank]

    def calc_val(self):
        '''Calculating value of hand, making aces = 1 if they don't bust the hand'''

        if (self.ace == True and self.value < 12):
            return self.value + 10
        else:
            return self.value

    def draw(self, hidden):
        if hidden == True and playing == True:
            # Don't show first hidden card
            starting_card = 1
        else:
            starting_card = 0
        for x in range(starting_card, len(self.cards)):
            self.cards[x].draw()

# Creating Class Deck

class Deck:

    def __init__(self):
        '''Creating a deck in order'''
        self.deck = []
for suit in suits:
            for rank in ranking:
                self.deck.append(Card(suit,rank))

    def shuffle(self):
        '''Shuffles the deck, using python's built-in random library'''
        random.shuffle(self.deck)

    def deal(self):
        '''Grabbing the first item in the deck'''
        single_card = self.deck.pop()
        return single_card

    def __str__(self):
        deck_comp = " "
        for card in self.cards:
            deck_comp += " " + deck_comp.__str__()

        return "The deck has " + deck_comp

# End of Classes

# First Bet

def make_bet():
    '''Ask the player for the bet amount and '''

    global bet
    bet = 0

    print 'What amount of chips would you like to bet? (Please enter whole integer) '

    # While loop to keep asking for the bet
    while bet == 0:
        # Using bet_comp as a checker
        bet_comp = raw_input()
        bet_comp = int(bet_comp)

        # Check to make sure the bet is within the remaining amount of chips left
        if bet_comp >= 1 and bet_comp <= chip_pool:
            bet = bet_comp
        else:
            print "Invalid bet, you only have " + 
str(chip_pool) + " remaining"

def deal_cards():
    '''This function deals out cards and sets up round'''

    # Set up all global variables
    global result, playing, deck, player_hand, dealer_hand, chip_pool, bet

    # Creating a deck
    deck = Deck()

    # Shuffle it
    deck.shuffle()

    # Set up the bet
    make_bet()

    # Set up both player and dealer hands
    player_hand = Hand()
    dealer_hand = Hand()

    # Deal out initial cards
    player_hand.card_add(deck.deal())
    player_hand.card_add(deck.deal())

    result = "Hit or Stand? Press h for hit or s for stand: "

    if playing == True:
        print 'Fold, Sorry'
        chip_pool -= bet

    # Set up to know currently playing hand
    playing = True
    game_step()


# Hit Function

def hit():
    '''Implementing the hit button'''

    global playing, chip_pool, deck, player_hand, dealer_hand, result, bet

    # If hand is in play add card

if playing:
        if player_hand.calc_val() <= 21:
            player_hand.card_add(deck.deal())

        print "Player hand is %s" %player_hand

        if player_hand.calc_val() > 21:
            result = 'Busted!' + restart_phrase

            chip_pool -= bet
            playing = False

    else:
        result = "Sorry, can't hit"	+ restart_phrase

    game_step()

# Stand Function

def stand():
    global playing, chip_pool, deck, player_hand, dealer_hand, result, bet

    '''This function plays the dealers hand, since stand was chosen'''

    if playing == False:
        if player_hand.calc_val() > 0:
            result = "Sorry, you can't stand!"

    # Going through all other possible options
    else:

        # Sfot 17 Rule
        while dealer_hand.calc_val() < 17:
            dealer_hand.card_add(deck.deal())

        # Dealer Busts
        if dealer_hand.calc_val() > 21:
            result = 'Dealer busts! You win! ' + restart_phrase

            chip_pool += bet
            playing = False

        # Player has better hand than dealer
elif dealer_hand.calc_val() < player_hand.calc_val():
            result = 'You beat the dealer, you win! ' + restart_phrase
            chip_pool += bet
            playing = False

        # Push
        elif dealer_hand.calc_val == player_hand.calc_val():
            result = 'Tied up, push!' + restart_phrase
            playing = False

        # Dealer beats player
        else:
            result = 'Dealer Wins! ' + restart_phrase
            chip_pool -= bet
            playing = False

    game_step()

# Function to print results and ask user for next step

def game_step():
    '''Function to print game step/status on output'''

    # Display Player Hand
    print ""
    print ('Player Hand is: '),player_hand.draw(hidden = False)

    print ''
    print 'Player hand total is: ' +str(player_hand.calc_val())

    # Display Dealer Hand
    print ''
    print('Dealer Hand is: '), dealer_hand.draw(hidden = True)

    # If game round is over
    if playing == False:
        print " --- for a total of " + str(dealer_hand.calc_val())
        print "Chip Total: " +str(chip_pool)

    # Otherwise, don't know the second card yet
    else:
        print " with another card hidden upside down"

    # Print result of hit or stand
print ''
    print result

    player_input()


# Function to exit the game

def game_exit():
    print 'Thanks for playing!'
    exit()

# Function to read user input

def player_input():
    '''Read user input, lower case it jsuts to be safe'''

    plin = raw_input().lower()

    if plin == 'h':
        hit()
    elif plin == 's':
        stand()
    elif plin == 'd':
        deal_cards()
    elif plin == 'q':
        game_exit()
    else:
        print "Invalid Input. Enter h, s, d, or q: "
        player_input()

# Intro to game

def intro():
    statement = '''Welcome to BlackJack! Get as close to 21 as you can without getting over! 
Dealer hits until she reaches 17. Aces count as 1 or 11. Card output goes a letter followed by a number of face notation. '''

    print statement
    print ''

# Playing the Game

'''The following code will initiate the game! 
(Note: Need to Run a 11 Cells)'''

# Create a Deck
deck = Deck()

# Shuffle it
deck.shuffle()

# Create player and dealer hands
print ''
player_hand = Hand()
print ''
deal_hand = Hand()

# Print the intro
intro()

# Deal out the cards and start the game!
deal_cards()

7. Recursive Triangle

This program creates a triangle using stars, recursively.

def triangle(n):
    return recursive_triangle(n, n)

def recursive_triangle(x, n):
    # First we must verify that both input values are integers.
    if type(x) != int or type(n) != int:
        return 'error'
    # If x is bigger than n, we will still only print the full triangle, so we can set them equal.
    if x > n:
        x = n
    # If either value is zero, the output should be an empty string because there are no lines or triangle to print.
    if x == 0 or n == 0:
        return ''
    # Let's set some variable names to help us out.
    star_print = n
    line_number = x
    # I'll create an empty string that we can concatenate values to.
    line_print = ''

# The difference value will determine how many shapes are needed to fill the line before the stars are printed.
    difference = star_print - line_number
    # If difference is not zero, we will print that value of spaces before the stars. The star print will be the
    # remainder, also known as line number.
    if difference != 0:
        line_print += ' '*difference
        line_print += '*'*line_number
    # If difference is zero, then we can just fill the line with stars.
    else:
        line_print += '*'*star_print
    # If the line number is greater than one, we can return our string and use the recursive call to run the function
    # again with the line number as one value less.
    if line_number > 1:
        return line_print+'\n'+str(recursive_triangle(line_number-1, star_print))
    # If the line number is exactly one, then we don't need to use the recursive call.
    elif line_number == 1:
        return line_print

8. Queue

Implements queue data structure. A queue is an entity that maintains the data in a linear format and processes it in FIFO order.

class Node:

    def __init__(self, value):
        self.value = value  
        self.next = None 
    
    def __str__(self):
        return "Node({})".format(self.value) 

    __repr__ = __str__
                        
                          
class Queue:

    def __init__(self): 
        self.head=None
        self.tail=None

    def __str__(self):
temp=self.head
        out=[]
        while temp:
            out.append(str(temp.value))
            temp=temp.next
        out=' '.join(out)
        return ('Head:{}\nTail:{}\nQueue:{}'.format(self.head,self.tail,out))

    __repr__=__str__

    def isEmpty(self):
        # This is where my code begins. I will check to see if self.head is none: if it is, the queue must be empty.
        if self.head is None:
            return True
        else:
            # Otherwise, the queue is not empty and we return False.
            return False

    def __len__(self):
        # I'll create a temp value starting at self.head, the "front" of the queue. I'll also set a count variable to 0.
        temp = self.head
        count = 0
        # We'll traverse the list until the temp value is none, meaning we've reached the end of the queue. For each
        # item, we increase our count value by 1.
        while temp is not None:
            count += 1
            temp = temp.next
        # Then we return our count variable.
        return count

    def enqueue(self, value):
        # If the queue is not empty, we need to examine the tail of the queue.
        if self.head is not None:
            # We'll create an instance of class Node at our value and call it new_node.
            new_node = Node(value)
            # I'll set a temp value to the existing tail of the queue.
            temp = self.tail
            # I'll let the value after the temp variable equal our 
new node.
            temp.next = new_node
            # Then, I'll reassign self.tail as the new_node.
            self.tail = new_node
        else:
            # If the queue is empty, we still instantiate class Node at our value.
            new_node = Node(value)
            # Because the queue is empty, self.head and self.tail will both equal new_node until new items are enqueued.
            self.head = new_node
            self.tail = new_node

    def dequeue(self):
        # First, we must check if the queue is empty.
        if self.head is not None:
            # Then, we need to check if the queue has only one value.
            if self.head == self.tail:
                # I'll set a variable at self.head, chosen arbitrarily over self.tail since there is only one item.
                item = self.head
                # I'll save the value of my item for returning later.
                return_value = item.value
                # I'm setting both self.head and self.tail to "item.next," which is simply None. When we have dequeued
                # the item variable, these values should both be none.
                self.head = item.next
                self.tail = item.next
                # Then I delete my single item.
                del item
                # We return the value that we saved earlier.
                return return_value
            else:
                # If the queue has at least two values, we only examine self.head. I'll call it an item variable.
                item = self.head
                # I'll save the value of my item for returning later.
                return_value = item.value
                # I'll set the new self.head to the next item in the queue after my item.
                self.head = item.next
                # Then I delete my item.
                del item
                # We return the value that we saved earlier.
                return return_value
        else:
            # If the queue is empty, we cannot dequeue anything.
            return 'Queue is empty'

Python Project Ideas for Advanced Users

These Python projects are for all those developers who wish to explode the market with high-end applications for use.

1. Content Aggregator

Surfing through various websites to collate the best material for content is a tedious task. With this Python Project, searching and collating all the resources and materials in one place, becomes a lot easier.

Source Code:

import urllib, os, requests, datetime, subprocess
// reddit imports
import praw, pprint
// pip install feedparser
import feedparser
// stockexchange
from nsetools import Nse
// Place your CLIENT_ID & CLIENT_SECRET below
reddit = praw.Reddit(client_id='XXXXXXX',
                    client_secret='XXXXXXXXXXX',
                    grant_type_access='client_credentials',
                    user_agent='script/1.0')
// class Reddit:
//    def TopNews(self):
//          Add your favorite NEWS subreddits in the argument as many as you'd like.
//         for submission in reddit.subreddit('News+WorldNews+UpliftingNews+').top(limit=10):
//             top_news = reddit.domain(submission).top('month')
//             print(top_news)
"""
Each class contains functions which further calls
APIs from the neccesary packages and the rest is
self explanatory I suppose
"""
class News:
   def Indian_News(self):
       newsfeed = feedparser.parse(
           "http://feeds.feedburner.com/ndtvnews-india-news"
       )
print("Today's News: ")
       for i in range(0, 20):
           entry = newsfeed.entries[i]
           print(entry.title)
           print(entry.summary)
           print("------News Link--------")
           print(entry.link)
           print("###########################################")
       print('-------------------------------------------------------------------------------------------------------')
class Medium:
   // https://github.com/thepracticaldev/dev.to/issues/28#issuecomment-325544385
   def medium_programming(self):
       feed = feedparser.parse(
           "https://medium.com/feed/tag/programming"
       )
       print("Programming Today: ")
       for i in range(10):
           entry = feed.entries[i]
           print(entry.title)
           print("URL: " + entry.link)
           print("###########################################")
       print('-------------------------------------------------------------------------------------------------------')
   def medium_python(self):
       feed_python = feedparser.parse(
           "https://medium.com/feed/tag/python"
       )
       print("Python Today: ")
       for i in range(10):
           entry = feed_python.entries[i]
           print(entry.title)
           print("URL: " + entry.link)
           print("###########################################")
       print('-------------------------------------------------------------------------------------------------------')
   def medium_developer(self):
       feed_developer = feedparser.parse(
           "https://medium.com/feed/tag/developer"
       )
       print("Developer News Today: ")
       for i in range(5):
           entry = feed_developer.entries[i]
           print(entry.title)
           print("URL: " + entry.link)
           print("###########################################")

print('-------------------------------------------------------------------------------------------------------')
class StockExchange:
   def nse_stock(self):
       nse = Nse()
       print("TOP GAINERS OF YESTERDAY")
       pprint.pprint(nse.get_top_gainers())
       print("###########################################")
       print("TOP LOSERS OF YESTERDAY")
       pprint.pprint(nse.get_top_losers())
       print("###########################################")
       print('-------------------------------------------------------------------------------------------------------')
// objects inititalization
// reddit_object = Reddit()
News_object = News()
Medium_object = Medium()
StockExchange_object = StockExchange()
if __name__ == "__main__":
   // Functions call of each class
   // reddit_object.TopNews()
   News_object.Indian_News()
   Medium_object.medium_python()
   Medium_object.medium_programming()
   Medium_object.medium_developer()
   StockExchange_object.nse_stock()

2. Building Chatbot

Chatbot Python Project

Every site that we open nowadays has a chatbot integrated to extract information from the user/visitor in real-time. This way the problem for manually looking out for customers is solved. Now, you can even create chatbots that talk to the user and grab information. This AI provides numerous features like learn, memory, conditional switch, topic-based conversation handling, etc.

Source Code:

Install from Pypi

pip install chatbotAI

Init.py

import re
import random
import requests
import json
from os import path
from .substitution import Substitution
from .spellcheck import SpellChecker
from . import version
from . import mapper
from .constants import FIRST_QUESTIONS, TERMINATES, LANGUAGE_SUPPORT  # noqa: F401

try:
    from urllib import quote
except ImportError:
    from urllib.parse import quote

try:
    input_reader = raw_input
except NameError:
    input_reader = input


__version__ = version.__version__


DEFAULT_ATTRIBUTE = {"match": None, "pmatch": None, "_quote": False, "substitute": True}
RE_TAG_PARENTHESIS = re.compile(r'{%?|%?}|\[|\]')
RE_OPERATORS = re.compile(r'([\<\>!=]=|[\<\>]|&|\|)')
RE_NAMED_GROUP = re.compile(r'%([a-zA-Z_][a-zA-Z_0-9]*)([^a-zA-Z_0-9]|$)')
RE_NAMED_GROUP_SILENT = re.compile(r'%!([a-zA-Z_][a-zA-Z_0-9]*)([^a-zA-Z_0-9]|$)')
RE_NUMBERED_GROUP = re.compile(r'%[0-9]+')
RE_NUMBERED_GROUP_SILENT = re.compile(r'%![0-9]+')


class MultiFunctionCall:

    def __init__(self, func=None):
        self.__func__ = {} if func is None else func

    @staticmethod
    def default_func(session, string):
        return string

    def call(self, session, string):
        s = string.split(":")
        if len(s) <= 1:
            return string
        name = s[0].strip()
        s = ":".join(s[1:])
func = self.default_func
        try:
            func = self.__func__[name]
        except KeyError:
            s = string
        new_string = re.sub(r'([\[\]{}%:])', r"\\\1", s)
        return re.sub(r'\\([\[\]{}%:])', r"\1", func(session, new_string))


_function_call = MultiFunctionCall()


def register_call(function_name=None):
    def wrap(function):
        if type(function).__name__ != 'function':
            raise TypeError("function expected found %s" % type(function).__name__)
        function_mapper = _function_call.__func__
        if name in function_mapper:
            raise ValueError("function with same name is already registered")
        function_mapper[name] = function
        return function

    if function_name is None:
        return register_call
    if type(function_name).__name__ in ('unicode', 'str'):
        name = function_name
        return wrap
    if type(function_name).__name__ != 'function':
        raise TypeError("String is expected for function name found {}".format(
            type(function_name).__name__))
    name = function_name.__name__
    return wrap(function_name)


class DummyMatch:

    def __init__(self, string):
        self.string = string

    def group(self, index):
        if index == 0:
            return self.string
raise IndexError("no such group")

    @staticmethod
    def groupdict(*arg, **kwargs):
        return {}


class Topic:

    def __init__(self, topics):
        self.topic = {"general": ''}
        self.topics = topics

    def __setitem__(self, key, value):
        value = value.strip()
        if value and value[0] == ".":
            index = 1
            current_topic = self.topic[key].split(".")
            while value[index] == ".":
                index += 1
                current_topic.pop()
            current_topic.append(value[index:])
            value = ".".join(current_topic)
        self.topic[key] = value

    def __getitem__(self, key):
        topic = self.topic[key]
        if topic in self.topics():
            return topic
        return ''


class Chat(object):
    def __init__(self, pairs=(), reflections=None, call=_function_call,
                 api=None, normalizer=None, default_template=None, language="en", local_path=None):
        """
        Initialize the chatbot.  Pairs is a list of patterns and responses.  Each
        pattern is a regular expression matching the user's statement or question,
        e.g. r'I like (.*)'.  For each such pattern a list of possible responses
        is given, e.g. ['Why do you like %1', 'Did you ever dislike %1'].  Material
which is matched by parenthesized sections of the patterns (e.g. .*) is mapped to
        the numbered positions in the responses, e.g. %1.

        :type pairs: list of tuple
        :param pairs: The patterns and responses
        :type reflections: dict
        :param reflections: A mapping between first and second person expressions
        :type call: MultiFunctionCall
        :param call: A mapping between user defined function and template function call name
        :rtype: None
        """
        self.__init__handler()
        if local_path is None:
            self.local_path = path.join(path.dirname(path.abspath(__file__)), "local")
        else:
            self.local_path = local_path
        self.spell_checker = SpellChecker(self.local_path, language)
        self.substitution = Substitution(self.local_path, language)
        self._re_tags = re.compile(r'^[\s\t]*(if|endif|elif|else|chat|low|up|cap|call|topic)[\s\t]+')
        self._re_block_tags = re.compile(
            r'{%[\s\t]*((end)?(block|learn|response|client|prev|group))[\s\t]*([^%]*|%(?=[^}]))%}')
        if default_template is None:
            default_template = path.join(self.local_path, language, "default.template")
        default_pairs = self.__process_template_file(default_template)
        if type(pairs).__name__ in ('unicode', 'str'):
            pairs = self.__process_template_file(pairs)
        self._pairs = {'': {"pairs": [], "defaults": []}}
        if not isinstance(pairs, dict):
            pairs = {'': {"pairs": pairs, "defaults": []}}
        elif '' not in pairs:
            raise KeyError("Default topic missing")
        normalizer = dict(normalizer) if normalizer else self.substitution.normal
        self._normalizer = {}
 for key in normalizer:
            self._normalizer[key.lower()] = normalizer[key]
        self._normalizer_regex = self._compile_reflections(normalizer)
        self.__process_learn(default_pairs)
        self.__process_learn(pairs)
        self._reflections = reflections if reflections else self.substitution.reflections
        self._regex = self._compile_reflections(self._reflections)
        self._memory = mapper.SessionHandler(dict, general={})
        self._conversation = mapper.SessionHandler(mapper.Conversation, general=[])
        self._attr = mapper.SessionHandler(dict, general=DEFAULT_ATTRIBUTE.copy())
        self.call = call
        self._topic = Topic(self._pairs.keys)
        self._api = self.__process_api(api)

    @staticmethod
    def __process_api(api):
        if api is None:
            return {}
        if isinstance(api, dict):
            return api
        if not isinstance(api, str):
            raise TypeError("Expected file path or dict for api found %s" % type(api).__name__)
        with open(api) as file:
            try:
                return json.load(file)
            except json.decoder.JSONDecodeError as e:
                raise SyntaxError("Invalid value for api: %s" % e)

    def __init__handler(self):
        """
        initialize handlers and operator functionality
        """
        self.__action_handlers = {
            "chat": self.__chat_handler,
            "low": self.__low_handler,
            "up": self.__up_handler,
            "cap": self.__cap_handler,
            "call": self.__call_handler,
            "topic": self.__topic_handler,
            "map": self.__map_handler,
            "eval": self.__eval_handler,
 }
        self.__conditional_operator = {
                "!=": lambda a, b: a != b,
                ">=": lambda a, b: a >= b,
                "<=": lambda a, b: a <= b,
                "==": lambda a, b: a == b,
                "<": lambda a, b: a < b,
                ">": lambda a, b: a > b
            }
        self.__logical_operator = {
                '&': lambda a, b: a and b,
                '|': lambda a, b: a or b,
                '^': lambda a, b: a ^ b
            }

    def __normalize(self, text):
        """
        Substitute words in the string, according to the specified Normal,
        e.g. "I'm" -> "I am"

        :type text: str
        :param text: The string to be normalized
        :rtype: str
        """
        return self._normalizer_regex.sub(lambda mo: self._normalizer[mo.string[mo.start():mo.end()].lower()], text)

    @staticmethod
    def __error_message(expected, text, pos, index):
        content = text[max(0, pos[index - 1][0]): pos[index][1] + 5].strip()
        return "Expected '%s' tag found '%s' in line `%s`" % (expected, pos[index][2], content)

    def __response_tags(self, text, pos, index):
        next_index = index+1
        if pos[next_index][2] != "endresponse":
            raise SyntaxError(self.__error_message("endresponse", text, pos, index))
        return text[pos[index][1]:pos[next_index][0]].strip(" \t\n")

    def __block_tags(self, text, pos, length, index):
        within_block = {"learn": {}, "response": [], "client": [], "prev": []}
while pos[index][2] != "endblock":
            if pos[index][2] == "learn":
                within_block["learn"] = {}
                index = self.__group_tags(text, pos, within_block["learn"],
                                          (lambda i: pos[i][2] != "endlearn"), length, index+1)
                index -= 1
            elif pos[index][2] == "response":
                within_block["response"].append(self.__response_tags(text, pos, index))
                index += 1
            elif pos[index][2] == "client":
                index += 1
                if pos[index][2] != "endclient":
                    raise SyntaxError(self.__error_message("endclient", text, pos, index))
                within_block["client"].append(text[pos[index-1][1]:pos[index][0]].strip(" \t\n"))
            elif pos[index][2] == "prev":
                index += 1
                if pos[index][2] != "endprev":
                    raise SyntaxError(self.__error_message("endprev", text, pos, index))
                within_block["prev"].append(text[pos[index-1][1]:pos[index][0]].strip(" \t\n"))
            else:
                content = text[max(0, pos[index-1][0]): pos[index][1]+5].strip()
                raise NameError("Invalid Tag '%s':  Error in `%s` " % (pos[index][2], content))
            index += 1
        return index+1, (within_block["client"],
                         within_block["prev"] if within_block["prev"] else None,
                         within_block["response"],
                         within_block["learn"])

    def __group_tags(self, text, pos, groups, condition, length, index=0, name=""):
        pairs = []
        defaults = []
        while condition(index):
 if pos[index][2] == "block":
                p, within = self.__block_tags(text, pos, length, index+1)
                pairs.append(within)
                index = p
            elif pos[index][2] == "response":
                defaults.append(self.__response_tags(text, pos, index))
                index += 2
            elif pos[index][2] == "group":
                child_name = (name+"."+pos[index][3].strip()) if name else pos[index][3].strip()
                index = self.__group_tags(text, pos, groups,
                                          (lambda i: pos[i][2] != "endgroup"), length, index+1, name=child_name)
            else:
                raise SyntaxError(self.__error_message('group, block, or response', text, pos, index))
        if name in groups:
            groups[name]["pairs"].extend(pairs)
            groups[name]["defaults"].extend(defaults)
        else:
            groups[name] = {"pairs": pairs, "defaults": defaults}
        return index+1

    def __process_template_file(self, file_name):
        with open(file_name, encoding='utf-8') as template:
            text = template.read()
        pos = [(m.start(0), m.end(0), text[m.start(1):m.end(1)], text[m.start(4):m.end(4)])
               for m in self._re_block_tags.finditer(text)]
        length = len(pos)
        groups = {}
        self.__group_tags(text, pos, groups, (lambda i: i < length), length)
        return groups

    def __build_pattern(self, patterns):
        if patterns is None:
            return
        if type(patterns).__name__ in ('unicode', 'str'):
            patterns = [patterns]
        regexps = []
        for pattern in patterns:
            try:
                
regexps.append(re.compile(self.__normalize(pattern), re.IGNORECASE))
            except Exception as e:
                e.args = (str(e) + " in pattern "+pattern, )
                raise e
        return regexps

    def __process_learn(self, pairs):
        for topic in pairs:
            if topic not in self._pairs:
                self._pairs[topic] = {"pairs": [], "defaults": []}
            self._pairs[topic]["defaults"].extend([(i, self._condition(i))
                                                   for i in pairs[topic].get("defaults", [])])
            for pair in pairs[topic]["pairs"][::-1]:
                learn, previous = {}, None
                length = len(pair)
                if length > 3:
                    client, previous, responses, learn = pair[:4]
                elif length == 3:
                    if isinstance(pair[1], (tuple, list)):
                        client, responses, learn = pair
                    else:
                        client, previous, responses = pair
                elif length == 2 and isinstance(pair[1], (tuple, list)):
                    client, responses = pair
                else:
                    raise ValueError("Response not specified")
                if not isinstance(learn, dict):
                    raise TypeError("Invalid Type for learn expected dict got '%s'" % type(learn).__name__)
                if not client:
                    raise ValueError("Each block should contain at least 1 client regex")
                self._pairs[topic]["pairs"].insert(0, (self.__build_pattern(client),
                                                       self.__build_pattern(previous),
                                                       tuple((i, self._condition(i)) for i in responses),
                                                       learn))

    def start_new_session(self, session_id, topic=''):
        self._memory[session_id] = {}
self._conversation[session_id] = []
        self._attr[session_id] = DEFAULT_ATTRIBUTE.copy()
        self._topic[session_id] = topic

    @staticmethod
    def remove_items(items, to_remove):
        for i in to_remove:
            try:
                items.remove(i)
            except ValueError:
                pass

    def _restructure(self, group, index=None):
        if index is None:
            to_remove = {}
            groups = list(group)
            for i in group:
                to_remove[i] = set()
                for j in group[i]:
                    to_remove[i].update(set(group[i]).intersection(group[j]))
            for i in group:
                for j in to_remove[i]:
                    group[i].remove(j)
                    try:
                        groups.remove(j)
                    except ValueError:
                        pass
            index = list(group)
            to_remove = [j for i in list(groups) for j in group[i]]
            self.remove_items(groups, to_remove)
        else:
            groups = list(index)
        while index:
            i = index.pop()
            if isinstance(group[i], list):
                group[i] = self._restructure(dict(group), group[i])
                self.remove_items(index, group[i])
        return {i: group[i] for i in groups}

    def _sub_action(self, group, start_end_pair, action):
        return {i: {
                    "action": action[i],
                    "start": start_end_pair[i][0],
"end": start_end_pair[i][1],
                    "child": self._sub_action(group[i], start_end_pair, action)
                  } for i in group}

    def _get_within(self, group, index):

        def init_group(p):
            group[index[p]]["within"] = []
            ordered_group.append(group[index[p]])
            return p+1

        def append_group(position, p):
            position, within = self._get_within(group, index[position:])
            group[index[p-1]]["within"] += within
            return position

        i = 0
        ordered_group = []
        while i < len(index):
            if group[index[i]]["action"] == "if":
                i = init_group(i)
                start_if = True
                while start_if:
                    if i >= len(index):
                        raise SyntaxError("If not closed in Conditional statement")
                    if group[index[i]]["action"] == "elif":
                        i = init_group(i)
                    elif group[index[i]]["action"] == "else":
                        pos = i = init_group(i)
                        start_if = False
                        while group[index[pos]]["action"] != "endif":
                            pos = append_group(pos, i)+i
                        i = init_group(pos)
                    elif group[index[i]]["action"] == "endif":
                        i = init_group(i)
                        start_if = False
                    else:
                        pos = append_group(i, i)
                        for j in range(i, pos):
                            del group[index[j]]
                        i += pos
            elif group[index[i]]["action"] in 
self.__action_handlers.keys():
                ordered_group.append(group[index[i]])
                i += 1
            else:
                return i, ordered_group
        return i, ordered_group

    def _set_within(self, group):
        for i in group:
            group[i]["child"] = self._set_within(group[i]["child"]) if group[i]["child"] else []
        index = list(group)
        index.sort(key=lambda x: group[x]["start"])
        pos, ordered_group = self._get_within(group, index)
        if pos < len(index):
            raise SyntaxError("invalid statement")
        return ordered_group

    def _inherit(self, start_end_pair, action):
        group = {}
        for i, primary in enumerate(start_end_pair):
            group[i] = []
            for j, secondary in enumerate(start_end_pair):
                if primary[0] < secondary[0] and primary[1] > secondary[1]:
                    group[i].append(j)
        group = self._restructure(group)
        group = self._sub_action(group, start_end_pair, action)
        return self._set_within(group)

    def __action(self, response, pos, index):
        end_tag = pos.pop(index)
        begin_tag = pos.pop(index-1)
        b_n = begin_tag[1]-begin_tag[0]
        e_n = end_tag[1]-end_tag[0]
        start_char = response[begin_tag[0]]
        end_char = response[end_tag[1]-1]
        if b_n != e_n or not ((start_char == "{" and end_char == "}") or (start_char == "[" and end_char == "]")):
            raise SyntaxError("invalid syntax '%s'" % response)
        if b_n == 2:
            statement = self._re_tags.findall(response[begin_tag[1]: end_tag[0]])
            if not statement:
                raise SyntaxError("invalid statement '%s'" % response[begin_tag[1]:end_tag[0]])
 action = statement[0]
        elif start_char == "{":
            action = "map"
        else:
            action = "eval"
        return begin_tag[1], end_tag[0], action

    def _condition(self, response):
        pos = ((m.start(0), m.end(0)) for m in RE_TAG_PARENTHESIS.finditer(response))
        pos = [(start, end) for start, end in pos if (not start) or response[start-1] != "\\"]
        start_end_pair = []
        actions = []
        while pos:
            index = 0
            for _, ele in pos[1:]:
                index += 1
                if response[ele-1] in "}]":
                    break
            if not (index and response[pos[index-1][0]] in "{["):
                raise SyntaxError("invalid syntax in \"%s\"" % response)
            start, end, action = self.__action(response, pos, index)
            start_end_pair.append((start, end))
            actions.append(action)
        return self._inherit(start_end_pair, actions)

    @staticmethod
    def _compile_reflections(normal):
        sorted_reflection = sorted(normal.keys(), key=len, reverse=True)
        return re.compile(r"\b({0})\b".format("|".join(map(re.escape, sorted_reflection))), re.IGNORECASE)

    def _substitute(self, session, text):
        """
        Substitute words in the string, according to the specified reflections,
        e.g. "I'm" -> "you are"

        :type session: Session
        :param session: Session object
        :type text: str
:param text: The string to be mapped
        :rtype: str
        """
        if not session.attr.get("substitute", True):
            return text
        return self._regex.sub(lambda mo: self._reflections[mo.string[mo.start():mo.end()]], text.lower())

    def _check_if(self, session, con):
        pos = [(m.start(0), m.end(0), m.group(0)) for m in RE_OPERATORS.finditer(con)]
        if not pos:
            return con.strip()
        res = prev_res = True
        symbol = "&"
        first = con[0:pos[0][0]].strip()
        for j, ele in enumerate(pos):
            s, e, o = ele
            try:
                second = con[e:pos[j+1][0]].strip()
            except IndexError:
                second = con[e:].strip()
            try:
                a, b = float(first), float(second)
            except (TypeError, ValueError):
                a, b = first, second
            if o in self.__conditional_operator:
                res = self.__conditional_operator[o](a, b) and res
            elif symbol in self.__logical_operator:
                prev_res, res = self.__logical_operator[symbol](prev_res, res), True
                symbol = o
            else:
                raise SyntaxError("Invalid conditional operator '%s'" % symbol)
            first = second
        return self.__logical_operator[symbol](prev_res, res)

    def __if_handler(self, session, i, condition, response):
        start = self.__get_start_pos(condition[i]["start"], response, "if")
        end = condition[i]["end"]
        check = True
        matched_index = None
        _quote = session.attr["_quote"]
        session.attr["_quote"] = False
substitute = session.attr.get("substitute", True)
        session.attr["substitute"] = False
        while check:
            con = self._check_and_evaluate_condition(session, response, condition[i]["child"],
                                                     start, end)
            i += 1
            if self._check_if(session, con):
                matched_index = i-1
                while condition[i]["action"] != "endif":
                    i += 1
                check = False
            elif condition[i]["action"] == "else":
                matched_index = i
                while condition[i]["action"] != "endif":
                    i += 1
                check = False
            elif condition[i]["action"] == "elif":
                start = self.__get_start_pos(condition[i]["start"], response, "elif")
                end = condition[i]["end"]
            elif condition[i]["action"] == "endif":
                check = False
        session.attr["_quote"] = _quote
        session.attr["substitute"] = substitute
        return ((self._check_and_evaluate_condition(session, response,
                                                    condition[matched_index]["within"],
                                                    condition[matched_index]["end"]+2,
                                                    condition[matched_index+1]["start"]-2
                                                    ) if matched_index is not None else ""), i)

    def __handler(self, session, condition, response, action):
        return self._check_and_evaluate_condition(
            session, response, condition["child"], self.__get_start_pos(condition["start"], response, action),
            condition["end"])

    def __chat_handler(self, session, condition, response):
        substitute = session.attr.get("substitute", True)
        session.attr["substitute"] = False
        response = self._respond(session, self.__handler(session, 
condition, response, "chat"))
        session.attr["substitute"] = substitute
        return response

    def __low_handler(self, session, condition, response):
        return self.__handler(session, condition, response, "low").lower()

    def __up_handler(self, session, condition, response):
        return self.__handler(session, condition, response, "up").upper()

    def __cap_handler(self, session, condition, response):
        return self.__handler(session, condition, response, "cap").capitalize()

    def __call_handler(self, session, condition, response):
        substitute = session.attr.get("substitute", True)
        session.attr["substitute"] = False
        response = self.call.call(session, self.__handler(session, condition, response, "call"))
        session.attr["substitute"] = substitute
        return response

    def __topic_handler(self, session, condition, response):
        session.topic = self.__handler(session, condition, response, "topic").strip()
        return ""

    @staticmethod
    def __get_start_pos(start, response, exp):
        return start+re.compile(r"([\s\t]*"+exp+r"[\s\t]+)").search(response[start:]).end(1)

    def __map_handler(self, session, condition, response):
        start = condition["start"]
        end = condition["end"]
        think = False
        if response[start] == "!":
            think = True
            start += 1
        content = self._check_and_evaluate_condition(session, response, condition["child"], start,
        end).strip().split(":")

        name = content[0]
        this_index = 0
        for this_index in range(1, len(content)):
            if name[-1] == "\\":
                name += ":"+content[this_index]
            else:
                this_index -= 1
                break
        this_index += 1
        name = name.strip().lower()
        if this_index < (len(content)):
            value = content[this_index]
            for this_index in range(this_index+1, len(content)):
                if value[-1] == "\\":
                    value += ":"+content[this_index]
                else:
                    break
            session.memory[name] = self._substitute(session, value.strip())
        if think:
            return ""
        return session.memory.get(name, "")

    def __eval_handler(self, session, condition, response):
        start = condition["start"]
        end = condition["end"]
        think = False
        if response[start] == "!":
            think = True
            start += 1
        _quote = session.attr["_quote"]
        session.attr["_quote"] = True
        content = self._check_and_evaluate_condition(session, response, condition["child"], start,
                                                     end).strip()
        session.attr["_quote"] = _quote
        values = content.split(",")
        names = values[0].split(":")
        api_name = names[0]
        method_name = ":".join(names[1:])
        data = {}
        key = None
        for i in values[1:]:
            pair = i.split(":")
            if len(pair) >= 2:
                key = pair[0]
 data[key] = ":".join(pair[1:])
            elif key is not None:
                data[key] += ","+pair[0]
            else:
                raise SyntaxError("invalid syntax '%s'" % response[start:end])
        result = self.__api_handler(api_name, method_name, data)
        return "" if think else result

    def __api_request(self, url, method, **karg):
        try:
            return requests.__dict__[method.lower().strip()](url, **karg)
        except requests.exceptions.MissingSchema:
            return self.__api_request("http://"+url, method, **karg)
        except requests.exceptions.ConnectionError:
            raise RuntimeError("Couldn't connect to server (unreachable). Check your network")
        except KeyError:
            raise RuntimeError("Invalid method name '%s' in api.json" % method)

    def __api_handler(self, api_name, method_name, data={}):
        if api_name not in self._api or method_name not in self._api[api_name]:
            raise RuntimeError("Invalid method name '%s' for api '%s' ", (method_name, api_name))
        api_params = dict(self._api[api_name][method_name])
        if "auth" in self._api[api_name]:
            try:
                api_params["cookies"] = self.__api_request(**self._api[api_name]["auth"]).cookies
            except TypeError:
                raise ValueError("In api.json 'auth' of '%s' is wrongly configured." % api_name)
        param = "params" if self._api[api_name][method_name]["method"].upper().strip() == "GET" else "data"
        try:
            api_params[param].update(data)
        except KeyError:
            api_params[param] = data
        api_type = "normal"
        if "type" in api_params:
            api_type = api_params["type"]
del api_params["type"]
        api_data_getter = []
        if "value_getter" in api_params:
            api_data_getter = api_params["value_getter"]
            del api_params["value_getter"]
        response = self.__api_request(**api_params)
        response_text = response.json() if api_type.upper().strip() == "JSON" else response.content
        for key in api_data_getter:
            response_text = response_text[key]
        return response_text

    def _quote(self, session, string):
        if session.attr["_quote"]:
            try:
                return quote(string)
            except TypeError:
                return quote(string.encode("UTF-8"))
        return string

    def __substitute_from_client_statement(self, session, match, prev_response, silent=False):
        """
        Substitute from Client statement into response
        """
        prev = 0
        if silent:
            start_padding = 2
            re_numbered_group = RE_NUMBERED_GROUP_SILENT
            re_named_group = RE_NAMED_GROUP_SILENT
        else:
            start_padding = 1
            re_numbered_group = RE_NUMBERED_GROUP
            re_named_group = RE_NAMED_GROUP
        final_response = ""
        for m in re_numbered_group.finditer(prev_response):
            start = m.start(0)
            end = m.end(0)
            num = int(prev_response[start+start_padding:end])
            final_response += prev_response[prev:start]
            try:
                final_response += self._quote(session, self._substitute(session, match.group(num)))
            except IndexError:
                pass
            prev = end
named_group = match.groupdict()
        prev_response = final_response + prev_response[prev:]
        final_response = ""
        prev = 0

        for m in re_named_group.finditer(prev_response):
            start = m.start(1)
            end = m.end(1)
            final_response += prev_response[prev:start-start_padding]
            value = named_group.get(prev_response[start:end], "").strip()
            if value:
                final_response += self._quote(session, self._substitute(session, value))
            prev = end
        return final_response + prev_response[prev:]

    def _check_and_evaluate_condition(self, session, response, condition=[], start_index=0, end_index=None):
        end_index = end_index if end_index is not None else len(response)
        if not condition:
            final_response = self.__substitute_from_client_statement(
                session, session.attr["match"], response[start_index:end_index])
            parent_match = session.attr["pmatch"]
            if parent_match is None:
                return final_response
            return self.__substitute_from_client_statement(session, parent_match, final_response,
                                                           silent=True)
        i = 0
        final_response = ""
        _quote = session.attr.get("_quote", True)
        while i < len(condition):
            pos = condition[i]["start"]-(1 if condition[i]["action"] in ("map", "eval") else 2)
            final_response += self._check_and_evaluate_condition(session, response[start_index:pos])
            try:
                session.attr["_quote"] = False
temp_response = self.__action_handlers[condition[i]["action"]](session, condition[i], response)
                session.attr["_quote"] = _quote
                final_response += self._quote(session, temp_response)
            except KeyError:
                session.attr["_quote"] = _quote
                if condition[i]["action"] == "if":
                    response_txt, i = self.__if_handler(session, i, condition, response)
                    final_response += response_txt
            start_index = condition[i]["end"]+(1 if condition[i]["action"] in ("map", "eval") else 2)
            i += 1
        final_response += self._check_and_evaluate_condition(session, response[start_index:end_index])
        return final_response

    def _wildcards(self, session, response, match, parent_match):
        session.attr["match"] = match
        session.attr["pmatch"] = parent_match
        response, condition = response
        return re.sub(r'\\([\[\]{}%:])', r"\1", self._check_and_evaluate_condition(session, response, condition))

    def __chose_and_process(self, session, choices, match, parent_match):
        resp = random.choice(choices)    # pick a random response
        resp = self._wildcards(session, resp, match, parent_match)  # process wildcards
        # fix munged punctuation at the end
        if resp[-2:] == '?.':
            resp = resp[:-2] + '.'
        if resp[-2:] == '??':
            resp = resp[:-2] + '?'
        return resp

    def __intend_selection(self, text, previous_text, current_topic):
        for (patterns, parents, response, learn) in self._pairs[current_topic]["pairs"]:  # check each pattern
            for pattern in patterns:
                match = pattern.match(text)
                if match:
  break
            else:
                continue
            if parents is None:
                return match, None, response, learn
            for parent in parents:
                parent_match = parent.match(previous_text)
                if parent_match:  # did the pattern match?
                    return match, parent_match, response, learn

    def __response_on_topic(self, session, text, previous_text, text_correction, current_topic):
        match = self.__intend_selection(text, previous_text, current_topic) or \
              self.__intend_selection(text_correction, previous_text, current_topic)
        if match:
            match, parent_match, response, learn = match
            if learn:
                self.__process_learn({
                    self._wildcards(session, (topic, self._condition(topic)), match, parent_match):
                    {
                        'pairs': [self.__substitute_in_learn(session, pair, match, parent_match)
                                  for pair in learn[topic]['pairs']],
                        'defaults': [self._wildcards(session, (default, self._condition(default)), match, parent_match)
                                     for default in learn[topic]['defaults']]}
                    for topic in learn
                })
            return self.__chose_and_process(session, response, match, parent_match)
        if self._pairs[current_topic]["defaults"]:
            return self.__chose_and_process(session, self._pairs[current_topic]["defaults"], DummyMatch(text), None)
        raise ValueError("No match found")

    def _respond(self, session, text):
        text = self.__normalize(text)
        try:
            previous_text = self.__normalize(session.conversation.get_bot_message(-1))
        except IndexError:

            previous_text = ""
        text_correction = self.spell_checker.correction(text)
        current_topic = session.topic
        current_topic_order = current_topic.split(".")
        while current_topic_order:
            try:
                return self.__response_on_topic(session, text, previous_text, text_correction, current_topic)
            except ValueError:
                pass
            current_topic_order.pop()
            current_topic = ".".join(current_topic_order)
        try:
            return self.__response_on_topic(session, text, previous_text, text_correction, current_topic)
        except ValueError:
            return "Sorry I couldn't find anything relevant"

    def __substitute_in_learn(self, session, pair, match, parent_match):
        return tuple((self.__substitute_in_learn(session, i, match, parent_match)
                      if isinstance(i, (tuple, list)) else
                      (i if isinstance(i, dict) else (
                          self._wildcards(session, (i, self._condition(i)), match,
                                          parent_match) if i else i))) for i in pair)

    @staticmethod
    def __get_topic_recursion(topics):
        result = {}
        for topic in topics:
            topic_depth = result
            for sub_topic in topic.split("."):
                topic_depth = topic_depth.setdefault(sub_topic, {})
        try:
            del result['']
            result = {'': result}
        except KeyError:
            pass
        return result

    def save_template(self, filename):
        with open(filename, "w") as template:
for topic_name, sub_topic in self.__get_topic_recursion(self._pairs).items():
                self.__generate_and_write_template(template, self._pairs, topic_name, sub_topic)

    def __generate_and_write_template(self, template, pairs, topic, sub_topics, base_path=None, padding=""):
        full_path = (base_path+"."+topic) if base_path else topic
        if topic:
            template.write(padding + "{% group "+topic+" %}\n")
            new_padding = padding + "\t"
        else:
            new_padding = padding
        for topic_name, sub_topic in sub_topics.items():
            self.__generate_and_write_template(template, pairs, topic_name, sub_topic, full_path,
                                               padding=new_padding+"\t")
        for (patterns, parents, response, learn) in pairs[full_path]["pairs"]:
            template.write(new_padding + "{% block %}\n")
            if parents is None:
                parents = []
            for parent in parents:
                template.write(new_padding + "\t{% prev %}"+parent.pattern+"{% endprev %}\n")
            for pattern in patterns:
                template.write(new_padding + "\t{% client %}"+pattern.pattern+"{% endclient %}\n")
            for res in response:
                template.write(new_padding + "\t{% response %}"+res[0]+"{% response %}\n")
            if learn:
                template.write(new_padding + "\t{% learn %}\n")
                for topic_name, sub_topic in self.__get_topic_recursion(learn).items():
                    self.__generate_and_write_template(template, learn, topic_name, sub_topic,
                                                       padding=new_padding+"\t")
                template.write(new_padding + "\t{% endlearn %}\n")
            template.write(new_padding + "{% endblock %}\n")
        for res in pairs[topic]["defaults"]:
            template.write(new_padding + "{% response %}"+res[0]+"{% response %}\n")
        if topic:
 template.write(padding + "{% endgroup %}\n")

    def _say(self, session, message):
        session.conversation.append_user_message(message)
        response = self._respond(session, message.rstrip("!."))
        session.conversation.append_bot_message(response)
        return response

    def respond(self, message, session_id="general"):
        """
        Generate a response to the user input.

        :type message: str
        :param message: The string to be mapped
        :type session_id: str
        :param session_id: Current User session when used for multi user scenario
        :rtype: str
        """
        return self._respond(mapper.Session(self, session_id), message)

    def say(self, message, session_id="general"):
        """
        say is a messagehandler takes a client message and returns response
        :type message: str
        :param message: Client message
        :type session_id: str
        :param session_id: Current User session when used for multi user scenario
        :rtype: str
        """
        return self._say(mapper.Session(self, session_id), message)

    # Hold a conversation with a chat bot
    def converse(self, first_question=None, terminate="quit", session_id="general"):
        """
        Conversation initiator

        :type first_question: str
        :param first_question: Start up message
        :type terminate: str
        :param terminate: Conversation termination command
:type session: str
        :param session: Current User session when used for multi user scenario
        :rtype: str
        """
        session = mapper.Session(self, session_id)
        if first_question:
            session.conversation.append_bot_message(first_question)
            print(first_question)
        input_sentence = ""
        while input_sentence != terminate:
            input_sentence = terminate
            try:
                input_sentence = input_reader("> ")
            except EOFError:
                print(input_sentence)
            if input_sentence:
                print(self._say(session, input_sentence))


def demo(first_question=None, language="en", **kwargs):
    if not first_question:
        first_question = FIRST_QUESTIONS.get(language, FIRST_QUESTIONS["en"])
    terminate = TERMINATES.get(language, TERMINATES["en"])
    Chat(language=language, **kwargs).converse(first_question, terminate=terminate)

Constants.py
FIRST_QUESTIONS = {
    "en": "Hi, how are you?",
    "de": "Hallo, wie geht es dir?",
    "pt-br": "Oi como você está?",
    "he": "היי מה קורה?",
}
TERMINATES = {
    "en": "quit",
    "de": "ende",
    "pt-br": "sair",
    "he": "זהו"
}
LANGUAGE_SUPPORT = ["en", "de", "pt-br","he"]

Mappers.py

class Session:

    def __init__(self, chat, session_id):
        self.__chat = chat
        self.session_id = session_id

    @property
    def conversation(self):
        return self.__chat._conversation[self.session_id]

    @conversation.setter
    def conversation(self, value):
        self.__chat._conversation[self.session_id] = value

    @property
    def memory(self):
        return self.__chat._memory[self.session_id]

    @memory.setter
    def memory(self, value):
        self.__chat._memory[self.session_id] = value

    @property
    def attr(self):
        return self.__chat._attr[self.session_id]

    @attr.setter
    def attr(self, value):
        self.__chat._attr[self.session_id] = value

    @property
    def topic(self):
        return self.__chat._topic[self.session_id]

    @topic.setter
    def topic(self, value):
        self.__chat._topic[self.session_id] = value


class Conversation(list):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.__bot_message = []
        self.__user_message = []

    def append_bot_message(self, message):
        self.__bot_message.append(message)
        self.append(message)

    def append_user_message(self, message):
        self.__user_message.append(message)
        self.append(message)

    def get_bot_message(self, index):
        return self.__bot_message[index]

    def get_user_message(self, index):
        return self.__user_message[index]


class SessionHandler:

    def __init__(self, _class, **kwargs):
        self._class = _class
        self.__data = {key: _class(value) for key, value in kwargs.items()}

    def __getitem__(self, key):
        return self.__data[key]

    def __setitem__(self, sender_id, val):
        self.__data[sender_id] = self._class(val)

    def update(self, *args, **kwargs):
        data = dict(*args, **kwargs)
        for key, val in data.items():
            self.__data[key] = self._class(val)

    def __delitem__(self, *args, **kwargs):
        return self.__data.__delitem__(*args, **kwargs)

    def __contains__(self, *args, **kwargs):
        return self.__data.__contains__(*args, **kwargs)

    def __iter__(self):
        return self.__data.__iter__()

    def __len__(self):
        return self.__data.__len__()

def __repr__(self, *args, **kwargs):
        return self.__data.__repr__()

    def __sizeof__(self, *args, **kwargs):
        return self.__data.__sizeof__()

    def __str__(self, *args, **kwargs):
        return self.__data.__str__()

    def clear(self):
        return self.__data.clear()

    def copy(self):
        return SessionHandler(self._class, **self.__data)

    def fromkeys(self, *args):
        return self.__data.fromkeys(*args)

    def get(self, *args):
        return self.__data.get(*args)

    def items(self):
        return self.__data.items()

    def keys(self):
        return self.__data.keys()

    def pop(self, *args):
        return self.__data.pop(*args)

    def popitem(self):
        return self.__data.popitem()

    def setdefault(self, *args, **kwargs):
        return self.__data.setdefault(*args, **kwargs)

    def values(self):
        return self.__data.values()

Setup.py

#!/usr/bin/env python

from setuptools import setup

version = __import__('chatbot.version').__version__
LANGUAGE_SUPPORT = __import__('chatbot.constants').LANGUAGE_SUPPORT
package_data = []

with open("README.md", "r") as fh:
    long_description = fh.read()

for language in LANGUAGE_SUPPORT:
    package_data.extend([
        "local/%s/default.template" % language,
        "local/%s/words.txt" % language,
        "local/%s/substitutions.json" % language
    ])
setup(
    name='chatbotAI',
    version=version,
    author="Ahmad Faizal B H",
    author_email="ahmadfaizalbh726@gmail.com",
    url="https://github.com/ahmadfaizalbh/Chatbot",
    description="A chatbot AI engine is a chatbot builder platform that provids both bot intelligence and"
                " chat handler with minimal codding",
    long_description=long_description,
    long_description_content_type="text/markdown",
    packages=['chatbot', 'chatbot.spellcheck', 'chatbot.substitution'],
    license='MIT',
    keywords='chatbot ai engine and chat builder platform',
    platforms=["Windows", "Linux", "Solaris", "Mac OS-X", "Unix"],
    package_dir={
        'chatbot': 'chatbot',
        'chatbot.spellcheck': 'chatbot/spellcheck',
        'chatbot.substitution': 'chatbot/substitution'
    },
    include_package_data=True,
    package_data={"chatbot":  package_data},
    install_requires=[
          'requests',
      ]
)

3. Face Mask Detection

With the current pandemic times, a face mask is highly appreciated wherever we go. But it also becomes tiresome to manually detect people without a mask. This Python Project lets you detect a mask and prompt any error. This can be applied in malls or any public meeting place. For the source code, you can refer to the Github link.

4. Plagiarism Checker

A nightmare for a writer is whether or not the written work falls into plagiarism barriers. Plagiarism tool scans through your work to find an overlap from an existing source posted online. 

To avoid any overlap for stealing someone’s work, we tend to put our work through plagiarism checkers. But the tools cost a fortune. So, with this Python project, you can create a plagiarism checker to scour through any writing work. This Python project uses a Natural Language Processing tool along with a search API to prepare a full-fledged usable Plagiarism checker. 

Source Code:

Before you begin the code, install the dependencies:

pip install scikit-learn

Also, you need to have a text file in the .txt format for checking plagiarism. When you run the code, it will load the text files and compare the similarities. For example

$-> cd Plagiarism-checker-Python
$ Plagiarism-checker-Python-> python3 app.py
('john.txt', 'juma.txt', 0.5465972177348937)
('fatma.txt', 'john.txt', 0.14806887549598566)
('fatma.txt', 'juma.txt', 0.18643448370323362)

import os
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

student_files = [doc for doc in os.listdir() if doc.endswith('.txt')]
student_notes = [open(_file, encoding='utf-8').read()
                 for _file in student_files]


def vectorize(Text): return TfidfVectorizer().fit_transform(Text).toarray()
def similarity(doc1, doc2): return cosine_similarity([doc1, doc2])


vectors = vectorize(student_notes)
s_vectors = list(zip(student_files, vectors))
plagiarism_results = set()


def check_plagiarism():
    global s_vectors
    for student_a, text_vector_a in s_vectors:
        new_vectors = s_vectors.copy()
        current_index = new_vectors.index((student_a, text_vector_a))
        del new_vectors[current_index]
        for student_b, text_vector_b in new_vectors:
            sim_score = similarity(text_vector_a, text_vector_b)[0][1]
            student_pair = sorted((student_a, student_b))
            score = (student_pair[0], student_pair[1], sim_score)
            plagiarism_results.add(score)
    return plagiarism_results


for data in check_plagiarism():
    print(data)

5. Music Player

Almost everyone loves to listen to music. Imagine, creating a music player of your own that involves scanning through project files to find music files, browse through various tracks, add music from your favorite artists, or control the volume. 

With this Python project, you create a full-fledged music player with an interactive UI to play around with.

Source Code:

import os
import threading
import time
import tkinter.messagebox
from tkinter import *
from tkinter import filedialog

from tkinter import ttk
from ttkthemes import themed_tk as tk

from mutagen.mp3 import MP3
from pygame import mixer

root = tk.ThemedTk()
root.get_themes()                 # Returns a list of all themes that can be set
root.set_theme("radiance")         # Sets an available theme

# Fonts - Arial (corresponds to Helvetica), Courier New (Courier), Comic Sans MS, Fixedsys,
# MS Sans Serif, MS Serif, Symbol, System, Times New Roman (Times), and Verdana
#
# Styles - normal, bold, roman, italic, underline, and overstrike.

statusbar = ttk.Label(root, text="Welcome to Melody", relief=SUNKEN, anchor=W, font='Times 10 italic')
statusbar.pack(side=BOTTOM, fill=X)

# Create the menubar
menubar = Menu(root)
root.config(menu=menubar)

# Create the submenu

subMenu = Menu(menubar, tearoff=0)

playlist = []


# playlist - contains the full path + filename
# playlistbox - contains just the filename
# Fullpath + filename is required to play the music inside play_music load function

def browse_file():
    global filename_path
    filename_path = filedialog.askopenfilename()
    add_to_playlist(filename_path)

    mixer.music.queue(filename_path)


def add_to_playlist(filename):
    filename = os.path.basename(filename)
    index = 0
    playlistbox.insert(index, filename)
    playlist.insert(index, filename_path)
    index += 1


menubar.add_cascade(label="File", menu=subMenu)
subMenu.add_command(label="Open", command=browse_file)
subMenu.add_command(label="Exit", command=root.destroy)


def about_us():
    tkinter.messagebox.showinfo('About Melody', 'This is a music player build using Python Tkinter by @attreyabhatt')


subMenu = Menu(menubar, tearoff=0)
menubar.add_cascade(label="Help", menu=subMenu)
subMenu.add_command(label="About Us", command=about_us)

mixer.init()  # initializing the mixer

root.title("Melody")
root.iconbitmap(r'images/melody.ico')

# Root Window - StatusBar, LeftFrame, RightFrame
# LeftFrame - The listbox (playlist)
# RightFrame - TopFrame,MiddleFrame and the BottomFrame

leftframe = Frame(root)
leftframe.pack(side=LEFT, padx=30, pady=30)

playlistbox = Listbox(leftframe)
playlistbox.pack()

addBtn = ttk.Button(leftframe, text="+ Add", command=browse_file)
addBtn.pack(side=LEFT)


def del_song():
    selected_song = playlistbox.curselection()
    selected_song = int(selected_song[0])
    playlistbox.delete(selected_song)
    playlist.pop(selected_song)


delBtn = ttk.Button(leftframe, text="- Del", command=del_song)
delBtn.pack(side=LEFT)

rightframe = Frame(root)
rightframe.pack(pady=30)

topframe = Frame(rightframe)
topframe.pack()

lengthlabel = ttk.Label(topframe, text='Total Length : --:--')
lengthlabel.pack(pady=5)

currenttimelabel = ttk.Label(topframe, text='Current Time : --:--', relief=GROOVE)
currenttimelabel.pack()


def show_details(play_song):
    file_data = os.path.splitext(play_song)

    if file_data[1] == '.mp3':
        audio = MP3(play_song)
        total_length = audio.info.length
else:
        a = mixer.Sound(play_song)
        total_length = a.get_length()

    # div - total_length/60, mod - total_length % 60
    mins, secs = divmod(total_length, 60)
    mins = round(mins)
    secs = round(secs)
    timeformat = '{:02d}:{:02d}'.format(mins, secs)
    lengthlabel['text'] = "Total Length" + ' - ' + timeformat

    t1 = threading.Thread(target=start_count, args=(total_length,))
    t1.start()


def start_count(t):
    global paused
    # mixer.music.get_busy(): - Returns FALSE when we press the stop button (music stop playing)
    # Continue - Ignores all of the statements below it. We check if music is paused or not.
    current_time = 0
    while current_time <= t and mixer.music.get_busy():
        if paused:
            continue
        else:
            mins, secs = divmod(current_time, 60)
            mins = round(mins)
            secs = round(secs)
            timeformat = '{:02d}:{:02d}'.format(mins, secs)
            currenttimelabel['text'] = "Current Time" + ' - ' + timeformat
            time.sleep(1)
            current_time += 1


def play_music():
    global paused

    if paused:
        mixer.music.unpause()
        statusbar['text'] = "Music Resumed"
        paused = FALSE
    else:
        try:
            stop_music()
            time.sleep(1)
            selected_song = playlistbox.curselection()
            selected_song = int(selected_song[0])
            play_it = playlist[selected_song]
            mixer.music.load(play_it)
mixer.music.play()
            statusbar['text'] = "Playing music" + ' - ' + os.path.basename(play_it)
            show_details(play_it)
        except:
            tkinter.messagebox.showerror('File not found', 'Melody could not find the file. Please check again.')


def stop_music():
    mixer.music.stop()
    statusbar['text'] = "Music Stopped"


paused = FALSE


def pause_music():
    global paused
    paused = TRUE
    mixer.music.pause()
    statusbar['text'] = "Music Paused"


def rewind_music():
    play_music()
    statusbar['text'] = "Music Rewinded"


def set_vol(val):
    volume = float(val) / 100
    mixer.music.set_volume(volume)
    # set_volume of mixer takes value only from 0 to 1. Example - 0, 0.1,0.55,0.54.0.99,1


muted = FALSE


def mute_music():
    global muted
    if muted:  # Unmute the music
        mixer.music.set_volume(0.7)
        volumeBtn.configure(image=volumePhoto)
        scale.set(70)
        muted = FALSE
    else:  # mute the music
        mixer.music.set_volume(0)
        volumeBtn.configure(image=mutePhoto)
        scale.set(0)
        muted = TRUE


middleframe = Frame(rightframe)
middleframe.pack(pady=30, padx=30)

playPhoto = PhotoImage(file='images/play.png')
playBtn = ttk.Button(middleframe, image=playPhoto, command=play_music)
playBtn.grid(row=0, column=0, padx=10)

stopPhoto = PhotoImage(file='images/stop.png')
stopBtn = ttk.Button(middleframe, image=stopPhoto, command=stop_music)
stopBtn.grid(row=0, column=1, padx=10)

pausePhoto = PhotoImage(file='images/pause.png')
pauseBtn = ttk.Button(middleframe, image=pausePhoto, command=pause_music)
pauseBtn.grid(row=0, column=2, padx=10)

# Bottom Frame for volume, rewind, mute etc.

bottomframe = Frame(rightframe)
bottomframe.pack()

rewindPhoto = PhotoImage(file='images/rewind.png')
rewindBtn = ttk.Button(bottomframe, image=rewindPhoto, command=rewind_music)
rewindBtn.grid(row=0, column=0)

mutePhoto = PhotoImage(file='images/mute.png')
volumePhoto = PhotoImage(file='images/volume.png')
volumeBtn = ttk.Button(bottomframe, image=volumePhoto, command=mute_music)
volumeBtn.grid(row=0, column=1)

scale = ttk.Scale(bottomframe, from_=0, to=100, orient=HORIZONTAL, command=set_vol)
scale.set(70)  # implement the default value of scale when music player starts
mixer.music.set_volume(0.7)
scale.grid(row=0, column=2, pady=15, padx=30)


def on_closing():
    stop_music()
    root.destroy()


root.protocol("WM_DELETE_WINDOW", on_closing)
root.mainloop()

Why are Python Projects Important?

The real value of whatever you learn comes with APPLICATION. Application of your learnings and processes. Building Python projects:

  • Build confidence: You realize how comfortable you’ve become with the language. This allows you to try on new features without any hesitation. 
  • Technologies: 
  • Concepts: Your programming concepts become solid and you tend to write more maintainable codes. With this you learn to create better design patterns, integrate OOPS concerts, and avoid repeating yourself in the codes. 
  • Product Lifecycle: By building projects yourself, you involve yourself in the nitty-gritty stuff of the entire lifecycle. You get involved with–Planning, managing, and updating the code. Also keeping the clients’ requests on top. 
  • Broader Scope: By building projects using Python, you not only build daily stuff easily but get access to fields like data science, web development,machine learning, and many more. 
  • Community Building: You build your own community, create open-source projects, and create a name for yourself.

FAQs

1. Is Python suitable for large projects?

Python is suitable for any kind of project, especially long form projects. To handle a large project, you need loose coupling and high cohesion. A large project essentially needs an orthogonal structure to carry out small sub-projects as well. It’s speed is relatively high to handle all the mathematical functions. And Python can indeed be a great language to handle every such demand, efficiently. 

For example, pydev provides auto-completion and debugging support for python with all the other eclipse goodies like svn support.

2. How do you write a project in Python?

For writing a project in Python, 

  • Choose any tool like Pycharm and follow the steps.
  • Using CMD

3. What should my first python project be?

Start from any of the beginner level Python projects that are mentioned above. Once you get a handle on Python with those simple projects like creating–MadLibs Generator, Rock-Paper-Scissors, or Website blocker, you can move to creating other projects.

4. Is Python bad for big projects?

Maybe. Python is used to create large projects but not a large monolithic project because it is dynamically typed. In large monolithic projects, it is difficult to keep a track of all the data types. So, it’s better to design the system as smaller components combined together with better functionality and interface. 

5. What kind of projects can be done in python?

We have discussed a plethora of Python projects above for every level. Consider using any project.

6. How to make projects in python?

Creating a project on Python is highly dependent on your own interests as an individual. Find your interests and see projects overlapping with those interests. Try creating using those libraries and code structure.

7. How to run a python project?

Python code after coding is converted into bytecode, internally. To convert that code into readable format, we need an interpreter called the Python Virtual Machine:

  1. A syntax checker runs on the code.
  2. Code is internally compiled
  3. The bytecode is interpreted using PVM
  4. Finally, the output is generated. 

The steps involved to run a Python Project are:

  1. Open a CMD prompt. Press CMD+R (For windows) and press ENTER.
  2. Navigate to the folder (C:\….) on your local folder and find the .py file.
  3. And type python filename.py




Post a Comment

0 Comments