# Generating a password to save to a .txt file

Here is my basic password generator which saves your password to a .txt file which you can choose the name of etc.

import random
import string
import os.path
#random numbers section
num1 = random.randrange(100,999)
number_section =  num1
#random letters section
string.letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()' let1 = random.choice(string.letters) let2 = random.choice(string.letters) let3 = random.choice(string.letters) let4 = random.choice(string.letters) let5 = random.choice(string.letters) let6 = random.choice(string.letters) let7 = random.choice(string.letters) let8 = random.choice(string.letters) letters_section = let1 + let2 + let3 + let4 + let5 + let6 + let7 + let8 #letters and numbers combination password = str(number_section) + letters_section #input section password_for = raw_input('This password is for: ') your_pass = 'Your password for' + ' ' + password_for + ' ' + 'is:' + ' ' + password print your_pass #save section save_path = 'C:\Users\Charles\Desktop\Passes' name_of_file = raw_input("What is the name of the file: ") completeName = os.path.join(save_path, name_of_file+".txt") file1 = open(completeName, "w") toFile = your_pass file1.write(toFile) file1.close()  This will make a .txt file with a line such as: Your password for IBM bluemix is: 451juoxQYky How can I make it 'stronger'? Are there any major holes in it? How can I make it more compact? This is just a personal project I'm doing to improve my python knowledge. • No reason all passwords shouldn't be random 32 char strings now. (use a password manager!) – bjb568 Aug 22 '15 at 16:16 • The best thing you could do to make it stronger is not save your passwords to file in plain text. – 101 Aug 22 '15 at 21:58 • @bjb568 no matter how many chars you use, this password generator is only capable on creating as many password as the seed is big (not sure about python, but java is only 48 bits). and anyway random is not a module that should be used for security purposes. In this case, knowing the approximate date of creation of the password goes a long way in finding it. – njzk2 Aug 23 '15 at 0:30 • Yes, and a general rule with security: don't write your only code, use somebody else's that's already been battle-tested. – bjb568 Aug 23 '15 at 0:49 ## 5 Answers By making it more Pythonic for one: string.letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()'
let1 = random.choice(string.letters)
let2 = random.choice(string.letters)
let3 = random.choice(string.letters)
let4 = random.choice(string.letters)
let5 = random.choice(string.letters)
let6 = random.choice(string.letters)
let7 = random.choice(string.letters)
let8 = random.choice(string.letters)
letters_section = let1 + let2 + let3 + let4 + let5 + let6 + let7 + let8


should be:

''.join(random.choice(string.letters) for _ in range(length))


Now instead of a hard coded length you can ask the user for a length or easily change it by changing one variable instead of adding or deleting lines.

file1 = open(completeName, "w")
toFile = your_pass
file1.write(toFile)
file1.close()


You want:

with open(completeName, "w") as file1:
file1.write(your_pass)  # no need to assign a new variable


The with context manager will automatically handle closing the file for you.

This seems to be a pattern in your code but its wholly unnecessary:

num1 = random.randrange(100,999)
number_section =  num1


Just use num1 or save the output of randrange() to number_section directly there is no need for an intermediate variable.

So in the end you can simplify to:

import random
import string
import os.path

num1 = random.randrange(100,999)
string.letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()' letters_section = ''.join(random.choice(string.letters) for _ in range(8)) # change 8 to a variable if you want to ask the user for a length or have it passed as an argument password = str(number_section) + letters_section password_for = raw_input('This password is for: ') your_pass = 'Your password for {} is: {}'.format(password_for, password) print(your_pass) save_path = 'C:\Users\Charles\Desktop\Passes' name_of_file = raw_input("What is the name of the file: ") completeName = os.path.join(save_path, name_of_file+".txt") with open(completeName, "w") as file1: file1.write(your_pass)  Or even more simply: def gen_password(length): choices = string.digits + string.punctuation + string.ascii_letters return ''.join(random.choice(choices) for _ in range(length)) >>> gen_password(13) '7P~R6dSy<T)+Z' >>> gen_password(20) "Q{qHs6ahwj^EaT_'t,.7" >>> gen_password(11) 'XDi49z+;^?='  • Good answer, very elegant. Makes me consider learning python. – rpax Aug 23 '15 at 11:14 • @rpax Python good practice will often lean towards easier to read/maintain/understand code rather than clever or fancy. Well written Python reads almost as easily as English sometimes. – kylie.a Aug 24 '15 at 2:17 • don't use default random for passwords. Use random.SystemRandom() or secrets.choice() – jfs Feb 21 '17 at 18:32 ## Regarding the code (not making it stronger!): You can get random letters let1, let2, etc... much easier, simply: let1, let2, let3, let4, let5, let6, let7, let8 = random.sample(string.letters, 8)  See more about random.sample here. Note this will get different letters, so there won't be any repeats. In fact, you could shorten it much more: letters_section = "".join(random.sample(string.letters, 8))  Over here, you are defining, immediately, the letters_section variable by joining, straight away, the separate letters! Depending on which Python version you are running, you should write to your file differently: In Python 2.5 and higher, use with: with open(completeName, "w") as file1: toFile = your_pass file1.write(toFile)  This will close the file itself, without you haiving to do so. In Python 2.*, when adding to the file, you should put the actual writing in a try statement in case something goes wrong writing to the file: file1 = open(completeName, "w") try: toFile = your_pass file1.write(toFile) finally: #close it no matter if it works or not file1.close()  When forming sentences, for the space after each word, simply add the ' ' within the previous (or next) print. So change your_pass = 'Your password for' + ' ' + password_for + ' ' + 'is:' + ' ' + password  to your_pass = 'Your password for ' + password_for + ' is: ' + password  You've got: num1 = random.randrange(100,999) number_section = num1  Why? Just have one variable: number_section = random.randrange(100,999)  With these in mind, your code is now: import random import string import os.path #random numbers section number_section = random.randrange(100,999) #random letters section string.letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()'
letters_section = "".join(random.sample(string.letters, 8))
#letters and numbers combination
#input section
print your_pass
#save section
save_path = 'C:\Users\Charles\Desktop\Passes'
name_of_file = raw_input("What is the name of the file: ")
completeName = os.path.join(save_path, name_of_file+".txt")
with open(completeName, "w") as file1:
toFile = your_pass
file1.write(toFile)

• random.sample is not the right function to use; it’ll get distinct characters. – Ry- Aug 23 '15 at 8:14
• 8 is a magic number. – Mast Aug 23 '15 at 19:37
• Don’t modify string.letters. It doesn’t belong to your module. Make your own constant instead.

• Use random.SystemRandom to generate secure random values; weak randomness is not usually appropriate for a password.

• Avoid shuffling variables around for no reason. For example, you should assign your random number to one variable only and use it throughout.

• Be aware that randrange has an exclusive upper bound. Unless you want numbers from 100 to 998, you should pass 1000.

• Make use of functions. You can put password generation into a function.

• Use string formatting to avoid str() and long concatenations.

import random
import os.path

generator = random.SystemRandom()

number = generator.randrange(100, 1000)
letters = ''.join(generator.choice(PASSWORD_CHARACTERS) for _ in range(8))

return '%d%s' % (number, letters)

# Prompt

save_path = r'C:\Users\Charles\Desktop\Passes'
name_of_file = raw_input('What is the name of the file: ')
complete_name = os.path.join(save_path, name_of_file + '.txt')

with open(complete_name, "w") as f:


So there are a few things you can do:

1. Add a check to ensure that there are no runs of the same character families, i.e, no more than three upper case letters in a row.
3. This one will get some flak, increase the length of the actual password. This is up for debate because it is entropy, not the length of the password that makes it more secure.

With this class (below) obtains basic functionality.
Add some code to ask user (raw_input) and voilà.

import string
import random

class PassGen(object):
""""""

SAVE_PATH = r"c:\Users\{}\Desktop\Passes"
CHARS = ''.join([string.digits, string.letters, string.punctuation])

"""Return a random password in each execution."""


For the second basic question (stronger), give more length to password_length param