Sunday 31 May 2015

Python 3 - New File Creator Module

So I have decided to create a module for file saving for my Python 3 project and though I would share it.
My problem is that I wanted more control over how I handled file saving rather than let a user open a file dialog window like tkFileDialog and put things in places I didn't want them to go.
I also didn't want them to use a wrong source file. In my program I have a JSON file pre-set for input if they save a blank JSON file or some other file extension, the program with break.
Finally, I had an image file that went with my JSON file. The user would select the file from anywhere, which is fine, and then I thought it would make life easier for me to save it with the same file name.

Enter the new_file module. Its main tool is the new_file object. It allows you to quickly choose:

  • a file source
  • a file name for your new file
  • the location you want to put the file in
  • the file type
It also cleans the name of the file just in case you have a user putting in the name and they are a little crazy about white space and symbols that will stuff up your files.
Lastly it checks if the file already exists and appends a file with a number so you don't copy over over a file.
The new_file module also has another object, the extra_file. You can choose to apply this object after using the main new_file object. It allows you to quickly save a file using the same name.
So now instead of 50+ lines of code you only need one or two.

You can get the file on Github here.

Below is a copy of the documentation I have written to give you some more detail.

# new_file_creator
Python 3 module for creating new files where you need a little more control over file location and file copy template

:mod:`new_file` -- New File Creator
===================================

.. module:: New File
   :synopsis: Sometimes you want a little more control over your source file and where you want to save it rather than use something like tkFileDialog where the user has the choice over the location.
The new_file module allows you to direct to the location of the template file, choose the file name and select the directory it is in. It also allows you to quickly save child fills with the  same file name.
.. moduleauthor:: Scott Donald

FEATURES
      new_file object
         Use this file to save a file in a directory.
       
         new_file(file_to_copy, new_file_name, new_file_path, file_type)
       

  •          *file_to_copy - The template file you want to copy. e.g. 'tmp.txt' if it is in the same file path or 'c:/Users/Batman/Documents/tmp/txt'
  •          *new_file_name -The name you want to give your new file. e.g. 'Harry Botter'
  •          *new_file_path -The directory you want your file in. If you are putting your file in the same location as your program, leave it blank (e.g. ''). If it is in a child directory just add the file location (e.g. 'JSON/' or 'Images/'). If your folder location lies outside your program you will need to use the full path (e.g. 'c:/Users/Batman/Documents/tmp/txt') 
  •          *file_type - The file extension of your file (e.g. 'jpg', 'txt','json','wav').

       
      extra_file object
         Use this file to save a file using the same name that was created in the new_file object.
       
         extra_file((file_to_copy, directory, file_type))
       

  •          *file_to_copy - The template file you want to copy. e.g. 'tmp.txt' if it is in the same file path or 
  •                         'c:/Users/Batman/Documents/tmp.txt'
  •          *directory - The directory you want your file in. If you are putting your file in the same location as your program, leave it blank (e.g. ''). If it is in a child directory jsut add the file location (e.g. 'JSON/' or 'Images/'). If your folder location lies outside your program you will need to use the full path (e.g. 'c:/Users/Batman/Documents/tmp.txt')
  •          *file_type - The file extension of your file (e.g. 'jpg', 'txt','json','wav').
  •          NOTE - This file uses the directory name from the new_file object.

       
      getting your file once it is loaded
         You can call your newly created file by:
         new_file.new_file.created_file 
         #For your main file.
       
         new_file.extra_file.created_extra
         #For your child files.
   
 
EXAMPLE 1- Single File Save
       
import new_file
chicken = new_file.new_file('blank.json','Jeeves #Smelly B^%#um34','JSON/', 'json')
       
         PROCESS

  •          *CLEAN THE FILE NAME - if the user creates the file and goes to town on symbols and spaces this will clean it up.
  •             *Get's rid of whitespace and joins it with and underscore
  •             *matches any alphanumeric character and the underscore only and joins it back into one string. 
  •             *Cut filename length to 150 characters if it is over. In our example 'Jeeves #Smelly B^%#um34' will be transformed to 'Jeeves_Smelly_Bum34'
  •          *CHECKS THE IF FILE EXISTS - checks if file already exists in new directory. 
  •             *Searches for file. 
  •             *If it exists it creates a copy of the file. For example 'Jeeves_Smelly_Bum34' will become 'Jeeves_Smelly_Bum34(1)'
  •             *If a copy exists it will loop through until the numbers run out and creates the next file number.For example if 'Jeeves_Smelly_Bum34(1)' 'Jeeves_Smelly_Bum34(2)' 'Jeeves_Smelly_Bum34(3)' files exists in your directory then your file will be saved as 'Jeeves_Smelly_Bum34(1)'
  •             *Concatenates the directory(if present), new file name and file extension
  •             *Creates the file
  •             *Saves a copy of the file name for your use if needed. 


EXAMPLE 2 - File and Child Files You Want Saved With the Same File Name
       
import_new_file
chicken = new_file.new_file('blank.json','Jeeves #Smelly B^%#um34','JSON/', 'json')
duck = new_file.extra_file('none.png','Image/','png')
turkey = new_file.extra_file('Images/gobblegobble.jpg','','jpg')
emu = new_file.extra_file(''c:/Users/Batman/Documents/tmp.txt'','text/','txt')
       
         PROCESS

  •          *RUNS THROUGH STEPS IN FIRST EXAMPLE - as you can the 'chicken' instance runs through the new_file object. This is essentially the parent file. 
  •          * For 'duck','turkey' and 'emu' instances use the extra_file object and do the same thing as      each other.
  •          *GRABS NEW FILE NAME - Gets a copy of the new file name from the new_file object
  •          *IF IN DIRECTORY - Checks if file created in the new_file class is in a directory and removes 
  •          the directory if needed.
  •          *NEW DIRECTORY AND FILE - Concatenates the directory(if present), new file name and file extension

       
POSSIBLE USES
         REGISTER USER
         You could use the new_file module to save username data in a database file, save their avatar with the same name.
       
         GAME SAVE
         You need some control over the location of where the file needs to be saved here. You can use the users nickname as the name of the file and name any child files like avatar details file, game save location file, inventory file etc all with the same name.
       
P.S. I'm a noop hobbiest programmer. I created this module to help me with my first program. If you have any suggestions
for improvement I would appreciate any guidance. ~Scott

Hey you made it!


Friday 29 May 2015

Python - Finding an Item Between Two Characters In a String Using: partition and rpartition

I'm making a file saver at the moment and I need a little control over the location of the saved files so I can't use Python's handy tkFileDialog to save the file. This means I have to create my own file saver.

Problem

One of the problems my file saver might face is: what happens if a user chooses a file name that already exists. I'll have to rename the file.
So for example if the user creates a filename: batman.jpg. And a batman.jpg file already exists in the folder. Then I don't want to overwrite it. I want to give it the value: batman(1).jpg. Okay that is pretty easy to fix. Run a file search
But what if the user os.path.isfile search then and an if statement asking if the file exists. if it does:

All sorted.
But what if our user is the Hordor of Batman fans and wants to save every file as batman.jpg. We then I need a to run a for loop to search through the folder for batman(1)jpg, batman(2).jpg ... batman(x).jpg and then save it as the next number.

But how do I isolate the number?

Solution

Enter Pythons partition and rpartition. I need to get between the two brackets. I can use partition  split the string at the first bracket keeping everything after the occurrence. Then I can use rpartition to split the string at the last bracket keeping everything before the occurrence. Take a look at the example below:

Saturday 23 May 2015

Python 3 - Opening files Using the "with" Statement

I just learnt how to save a few lines when opening files in Python 3 using the with statement.

From what I understand, the statement uses try and then opens the file, processes it and closes it. How efficient is that?



To learn more about the with statement:
http://effbot.org/zone/python-with-statement.htm

Friday 22 May 2015

Python 3 - Install Modules and Packages Using PIP- Plus Troubleshooting

This is much of a quick reference for me than anything else.

PIP is the installer for modules and packages for Python. You can use it to install modules like mathplotlib and pygame. 
If you want a quick resource for python extension packages for your version of Python and your system then then:

Unofficial Windows Binaries for Python Extension Packages

is your one-stop-shop. 

To Download

Just:
  •  ctrl-f and type the item you want. 
  • Click the link. 
  • Select the version that matches your version of Python and 32 or 64 bit system.
  • Wait for it to down load. 
To Install
Once it has downloaded:
  • Go into your cmd for Windows (bash, iOS, terminal for Linux). In windows. Search for cmd, right click and run as administrator.
  • Once in, type: pip install package
    • For example:

  • Hi enter and it should install. 
  • To test if it works go into your Python terminal and type: import package
    • For example:

  • If there is no error then you have downloaded it successfully. If you get an error it may not have down loaded:


Troubleshooting in the CMD line

There are two issues I have come across that have caused me not to download the image in the command line:

'pip' is not recognized as an internal or external command,
operable program or batch file.

This is usually because you have two versions of pip installed on your computer (and more than likely you have installed Python 2.7 before Python 3.4)

To fix this problem you will need to type the whole path to your version of python you want to install your package on. In my case, I would type something like:

D:/Python34/Scripts/pip install package

Where the package is the name of the package, like mathplotlib. Your path may be in C:/ drive or in a different directory too. 

The second error will run the setup but will come up with:

warning: no files found matching 'distribute_setup.py'

And a big list of syntax errors.

For me, this is either as a result of a spelling mistake on by behalf or PIP could not find the file to install. To fix this I just accessed the directory and file where it was downloaded. 

For example:

pip install C:/Users/Scott/Downloads/package.v2iiBlahBlahBlah.whl

This seems to fix the problem. 



Wednesday 20 May 2015

Python 3 - Use In For In Range Loop To Do Differently Occurring Tasks

Problem

I wanted a fast way to run through an operation in a loop and then to do another operation, say every fifth time in Python 3.
You can run a loop in a certain range quite easily:

count = 1
for i in range (0,20):
print(count)
count += 1
This would reveal a list of numbers from 1 - 20 one under the other.
I knew that this was what I wanted to do but how could I print print ("ping") every fifth number (eg after,0,5,10,15,20)
My first direction was to use the step option in range which you can add to the end of your arguments:

count = 1
for i in range (0,20,5):
print(count)
count += 1
This would display:
1
2
3
4

The operation will loop through 20 times but every fifth time (step) the operation will print a number.
Not what I had in mind but useful.

Solution

The solution turned out to be fairly simple:

What I did was use two loops. One nested in the other. The first one printed the "ping". The nested loop counted through the numbers.
If I wanted the "ping" printed after every 5th time in a range of 20 it would occur 4 times (20/5 = 4). So I set the "ping" for loop for the to start at 0 and end at 4.
In the nested for loop I run the loop to 5 adding 1 to the count.
Now when the "ping" loop is run the first time it prints "ping" and counts from 1-5. The second time the "ping" loop runs it prints "ping" again and counts from 6-10.
This will continue until after the "ping" loop runs it's last loop at 4.

Applications

This might be useful for adding a note or a warning after a certain amount of data iterates through.
In a simple shooting game you might want to shoot a number of times before a rocket is launched if the fire key is still depressed. 

Monday 18 May 2015

Python 3 - Open File Dialog Window In Tkinter With filedialog

I wanted to make a file loader for a chatbot program I am working on in Python 3 using Tkinter. I thought  that it would be a tricky task until I stumbled up the filedialoge module and the askopenfilename function.

Tkinter uses the filedialoge access the askopenfilename to open a window that matches the format of your operating system. Mine is currently Windows 8, so it looks like this.


How good does that look. To use the askopenfilename function you need to import it:
from tkinter.filedialog import askopenfilename
Because you will probably want to run the file from a command in a menu bar of from a button click it's probably a good idea to wrap it in a function:
def OpenFile():
    name = askopenfilename(initialdir="C:/Users/Batman/tkinter/",
                           filetypes =(("Text File", "*.txt"),("All Files","*.*")),
                           title = "Choose a file."
                           )
The askopenfilename function can have a number of options or no options and you can leave it blank. The ones I have used in this example I think are the most useful:

initialdir 

 set the the initial file location that the function will open it.

filetypes


This allows you set the type of files you want the user open. The end result appears in the bottom drop down menu.
First you set the file in a tuple ("Text File", "*.txt"). The first input is the title you want to name the file type(e.g. "Text File") and the second string is the file name ("*.txt"). If you have a custom file type, like ("*.noob"), then you can use that too.
What I discovered is that it requires a minimum of two file types for this option to work. So if you get an error this might be it.

title

This is the title you want to add to the top bar. 


In the below example you can execute the file in the Menu in File-Open. I thought I'd give you a realistic application of the askopenfilename.
As you can see from the first print the file does not open the document, rather it gets the file location and from there you can open and use the file. In the above example I have opened the file as a variable and then read it because I had a text file. You could as easily put the variable in a label or text widget in tkinter.

Useful Links:
http://effbot.org/tkinterbook/tkinter-file-dialogs.htm
http://tkinter.unpythonic.net/wiki/tkFileDialog

Saturday 16 May 2015

Changing The Colour Of Selected Text In Tkinter Text Wiget In Python

I am working on a simple chatbot program using Tkinter in Python 3 and have finished all the back end.
I'm now working on making the front end look pretty.

The Problem
One of the things I wanted to do was change the colour of the chatbot's title in the text widget to make it easier to read. I thought it would be pretty easy.
My guess was that I could modify the colour from the .insert method. A little like this:

text.insert(END,'Bottity Bottity Bot Bot: '+ BotInput + '\n',foreground='red')
Fail!!!
Life isn't that easy.

The Solution
It turns out that it is quite a task to add a colour to words in a text widget in Tkinter. The best hack I could find was to modify a search and highlight function I found in Python in a Nutshell by Alex Martelli.


I had to make some changes which basically removed the search function and replaced it with a key word of the name of my chatbot, in this case: Bottity Bottity Bot Bot

Here are the results in a simple example:

As you can see, the find() function searches for my chatbot name and then changes it's foreground color in the text.tag_config('found', foreground='red') section. in tag_config you can also modify the font styles and the background.

P.S. I really like the lastidx = '%s+%dc' % (idx, len(s)) variable. This was such a clever bit of code that I spent an hour down the rabbit hole on String Formatting Operations.

Returning A Value From A Function To Be Used Outside The Function in Python 3

Functions are really useful for doing stuff for you in a program. But the hardest thing for me to work out was how to use what ever they did in the rest of my program.

Problem
Let's say I wanted to make a function to convert my string to lowercase. My program would look a little like this:

# Returns a string in lowercase
def Make_Lowercase(cmt):
cmt = cmt.lower()
comment = "My name is SCOTT."
print ("Commment without lowercase formatting:")
print (comment)
print("")
 
#Replace the old variable with the lowercase one created in the function
print ("Comment run through function to make it lowercase:")
print (cmt)
 Here I am trying to get the new comment, cmt, but when I run the program it yells at me with:
Traceback (most recent call last):
  File "C:/Users/Im/Batman/Python3/ReturnFunction.py", line 13, in <module>
    print(cmt)
NameError: name 'cmt' is not defined
Boo! I can't access the local variable inside the Make_Lowercase function.

Solution
To fix this, we need to return the variable inside the function and place the result back into the original (or a new variable. Up to you.) variable.

Here is an example:

Now we can use the results from the function outside of the function and in the rest of the program. Yay!


Removing Unwanted Whitespace in a String in Python 3

I have written a simple chatbot program in Python 3 where the user enters a comment and the bot responds. After offering it to family to play with I discovered that they would often put whitespace in front of the sentence or after. For example:

'  How are you?     '  or  'How are you? '
Problem:
The problem is that when I send this to the file to search for the match response. It comes up without a match because the string is saved as:
 'How are you?'
As you can see this has no spaces before or after. The single quotation marks. So when I run the search with it comes up with nothing and I don't really want to add unessessary lists with spaces just in case the program receives sloppy input.

Solution:
It turns our that the solution is quite simple. Python provides two simple tools to remove extra white space before and after the sentence or even duplicate spaces between words in a string.

In the first function, remove_whitespace_either_side, we use the variable.strip() method. This method essentially strips the white space from either side of the sentence in the string.

But what happens if your program user is a bit of a typing numpty and manages to put extra white spaces between the works? For example:
' I am     a typing                   numpty!'
As you can see, the first function cannot deal with this.

This is where the second function, remove_any_duplicated_white_space , is so useful. This function uses two methods forming " ".join(variable.spit()). Here, we split all the words into individual strings and then join them back together into one string with a single space between each.

You can see the result of each in the code above.

Looking at the quality of input I have been getting for my chatbot I think I will be using the second function.

Friday 15 May 2015

Python 3 - Tkinter Scrolling with Inserted Text

I am using tkinter's ScrolledText to create a text box that I insert text in each line.

The problem
The problem was that when I inserted new text, the text box would not automatically scroll down to reveal the new text.

The solution
The solution turned out to be the yview method.

In the example below, I added while loop of 100 numbers(lines) to demonstrate that noew the text box is now focussed to the bottom of the text.