Gribouillis 1,391 Programming Explorer Team Colleague

If you want to load the files separately, you only need ny.loadtxt("filename") . But you shouldn't worry too much about performance, because 20 lines is not many lines, unless it's called 1000000 times.

Gribouillis 1,391 Programming Explorer Team Colleague

The following works for me

import numpy as ny
data = list(ny.loadtxt(filename) for filename in ("data1.txt", "data2.txt"))
result = ny.array(zip(*data))
print result
print result.shape

If there is a numpy way to do the zip(*data), it would probably be faster. You can also time itertools.izip() for comparison.

Gribouillis 1,391 Programming Explorer Team Colleague

BeautifulSoup requires the sgmllib module, which has been removed in Python 3.

Have a look at this however https://bitbucket.org/outcomm/bs4 . I read about bs4 in the BeautifulSoup google group, which may be worth exploring as well http://groups.google.com/group/beautifulsoup . This is what the README says

>>> from bs4 import BeautifulSoup

== It works with Python 3 ==

Beautiful Soup 3.1.0 worked with Python 3, but the parser it used was
so bad that it barely worked at all. Beautiful Soup 4 works with
Python 3, and since its parser is pluggable, you don't sacrifice
quality.
Gribouillis 1,391 Programming Explorer Team Colleague

you install setup tools with installer http://packages.python.org/an_example_pypi_project/setuptools.html

I'm not sure there is an installer for python 3.

Gribouillis 1,391 Programming Explorer Team Colleague

easy install is itself a module how I'm going to install it into python 3.2

I don't usually work in windows, but it seems to me that you should first install the 'distribute' package using one of the installation methods described here http://pypi.python.org/pypi/distribute#installation-instructions . Perhaps you must replace 'python' on the command line with 'python3', or the complete path to your python 3 executable. Then read distribute's documentation http://packages.python.org/distribute/ , especially the sections about easy_install and multiple versions of python. Again, after you install distribute, there will probably be an easy_install.exe in the 'scripts' folder of your python 3 installation. It may be sufficient to use this executable to easily install python 3 modules. If all this doesn't work, you can probably also use for most modules the traditional sequence - download source - run 'python setup.py install' in the module's source folder (replacing python with the path to your python 3 executable).

Gribouillis 1,391 Programming Explorer Team Colleague

I think easy_install supports multiple versions of python.

Gribouillis 1,391 Programming Explorer Team Colleague

Oh man I can't believe it!!!! It's working!!!! I sweat blood over it!
One last thing if you can: why I'm getting this output in the file:


rather than, you know just a column without list and string symbols like:
54.22953
54.17732
54.13724

and so on...

Instead of write("%s" % block), use writelines(block), it should print a column.

>>> import sys
>>> sys.stdout.writelines([' 54.22953\n', ' 54.17732\n', ' 54.13724\n', ' 54.10664\n', ' 54.08554\n'])
 54.22953
 54.17732
 54.13724
 54.10664
 54.08554
>>>
Gribouillis 1,391 Programming Explorer Team Colleague

As I said, your algorithm is wrong. There is no reason to call blocks_generator() for each output file. It only needs to be called once. Try this first

def tgrid_files ():
    """Creates the t.grid files"""
    times = open ('test', 'r') # what is this ?
    header = header_tgrid_files()
    file_names = open ('receiver_names', 'r')
    blocks = blocks_generator('test')
    for (element, block) in zip(file_names, blocks):
        names = element.split()[0] # the plural is misleading. I guess it's only one name
        print names, block

It should print each output file name with the block that goes in this file. If this works, you only need to open the file and write the header and the block (use output_files.writelines(block))

Gribouillis 1,391 Programming Explorer Team Colleague
with open ("%s" % names, 'w') as output_files: # this can't work
# a call to open() can't open more than one file.

Your problem is that you don't think about your code's logic. WRITE PSEUDO CODE to describe the sequence of operations that your program should do. You want to write one block per file ? I see 2 algorithms

for each block:
    open a file # how do we pick the file's name ?
    write the block in the file

and

open 3 files
for each pair (file, block):
    write the block in the file

both can be implemented. I'd choose the first.

Gribouillis 1,391 Programming Explorer Team Colleague

File objects have no append() method. To add lines to a file, you must open it in append mode (mode 'a') and use the write() method. If you want to create a new file, it's the same code with mode 'w'.

f = open('filename', 'r')
new = open('other_filename', 'a')
for data in f: # f is iterable: no need for readlines()
    if '#' not in data:
        new.write('notExist\n')
    elif ('SRM' in data) or ('%' in data): # elif because a line may contain % and not #
        new.write(data) # data already contains \n
f.close()
new.close()
Gribouillis 1,391 Programming Explorer Team Colleague

Actually, at the end of the itertools module documentation, there is a list of recipes containing the following grouper() function which could be used

from itertools import izip_longest

def grouper(n, iterable, fillvalue=None):
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

for b in grouper(4, open("blocks.txt")):
    print b

""" my output -->
('56.71739\n', '56.67950\n', '56.65762\n', '56.63320\n')
('56.61648\n', '56.60323\n', '56.63215\n', '56.74365\n')
('56.98378\n', '57.34681\n', '57.78903\n', '58.27959\n')
"""

In python 3, izip_longest() becomes zip_longest(). I recommend saving the whole list of recipes in a module itertoolsrecipes.py. New python 3 recipes can also be added to the list.

Gribouillis 1,391 Programming Explorer Team Colleague

Then use

def prova():
    return blocks(open("test"))

If you write 'return' in a for loop, the loop exits at first iteration.

Edit: also why did you write this infile = fileobj.readlines()[5::] . You're breaking the code by using readlines() which loads the whole file. Use infile = islice(fileobj, 5, None)

Gribouillis 1,391 Programming Explorer Team Colleague

It works but again the same problem with 'return', exactly as I said above. It returns only one block instead of three as 'print' correctly does.... Why?????

I don't see any problem. blocks() returns an iterable which yields the blocks one after the other. Please post your problematic code

Gribouillis 1,391 Programming Explorer Team Colleague

Here is a pure "itertool style" solution

from itertools import islice, repeat, takewhile

def blocks(fileobj, size=4):
    blank = " " * 10
    lines = (line for line in fileobj if not line.startswith(blank))
    return takewhile(len, (list(islice(lines, 0, size)) for x in repeat(None)))

with open("blocks.txt") as ifh:
    for b in blocks(ifh):
        print b

""" my output -->
['56.71739\n', '56.67950\n', '56.65762\n', '56.63320\n']
['56.61648\n', '56.60323\n', '56.63215\n', '56.74365\n']
['56.98378\n', '57.34681\n', '57.78903\n', '58.27959\n']
"""

Notice that the file is not loaded in memory.

Gribouillis 1,391 Programming Explorer Team Colleague

I found the way to do it programmatically

import tkinter
import pydoc

with open("tkinterhelp.txt", "w") as ofh:
    ofh.write(pydoc.render_doc(tkinter))

Notice that the tkinter help is 1 MB long.

Gribouillis 1,391 Programming Explorer Team Colleague

Instead of the 'break' statements in the invalid cases, you could use 'return None'. This would allow you to write code like

password = passw()
if password is not None: # password was ok
    user = usname()
    if user is not None: # user was ok
        print "success"

However, programs usually ask simultaneously the user name and the password, and don't say which of the user name or the password failed in case of failure. That would mean more changes to your program.

Gribouillis 1,391 Programming Explorer Team Colleague

Also you will get better answers if you post your code instead of pseudo code. This issue was already mentioned a few days ago, and it's not a difficult one.

Gribouillis 1,391 Programming Explorer Team Colleague

I did try that, but it also deletes the V count down the side

I see V in the first column.

Gribouillis 1,391 Programming Explorer Team Colleague

I see the problem but I can't figure out how to fix it, I been at it forever

Well, here is my solution. It's not perfect: the next step is to print the numbers in fixed width fields using format(), but I won't help you on this. See http://www.daniweb.com/software-development/python/code/232375

def iround(x):
    return int(x + (0.5 if x > 0 else -0.5))

def windchill(V,T):
    wc = 35.74 + .6215*T-35.75*(V**.16)+.4275*(V**.16)
    return wc # <------------- return a float here because it's a physical quantity

def main():
    print("                         Temperature \n")
    print("Speed \n")
    print("---- -20 70 10 0 10 20 30 40 50 60 ")

    for V in range(0,55,5):
        print(V, end="")
        for T in range(-20,70,10):
            wc = windchill(V,T)
            print(iround(wc), end=" ") # <-------------- V removed !
        print()

main()
Gribouillis 1,391 Programming Explorer Team Colleague

python is adding a 0 to each of my numbers for some reason, it is rounding like I want I believe, but when I run it, all the numbers get a 0 added to them- I don't know why

It is not adding a 0: it's printing wc and the next V, which is 0 in the first line (and 5, 10, 15, .. in subsequent lines). Did you run the code I just posted to understand its output ?

Gribouillis 1,391 Programming Explorer Team Colleague

I would hopefully like to get it to 34. I just don't understand why python made the number jump to 10 times the number as seen in the last post. It won't just compute a 34- its always 34.876 or 340 for some reason

If you want 34, you don't need iround(), which gives 35 (the nearest integer). The problem is the V in your print(). I added a "@" separator to show your error

from __future__ import print_function

def iround(x):
    return int(x + (0.5 if x > 0 else -0.5))

def windchill(V,T):
    wc = 35.74 + .6215*T-35.75*(V**.16)+.4275*(V**.16)
    we = int(wc) # <---- this if you want 34, iround if you prefer 35
    return we

def main():
    print("                         Temperature \n")
    print("Speed \n")
    print("---- -20 70 10 0 10 20 30 40 50 60 ")

    for V in range(0,55,5):
        print(V)
        for T in range(-20,70,10):
            wc = windchill(V,T)
            print(V, "@", wc, end=" ") # <-----See ?

main()

Also it would be more logical that windchill() returns a floating number and that you round the number only in the call to print(). For example you can print iround(wc).

Gribouillis 1,391 Programming Explorer Team Colleague

What is your expected result ? Your function windchill() first computes a floating number named wc, then you convert it to a we and return. Suppose that wc is 34.8768678, what do you want to output ?

Gribouillis 1,391 Programming Explorer Team Colleague

just tried it, i keep getting:

Temperature

Speed

---- -20 70 10 0 10 20 30 40 50 60
0
0 23.30 29.50 35.70 42.00 48.20 54.40 60.60 66.80 73.05
5 -22.45 -16.25 -10.05 -3.75 2.55 8.75 14.95 21.15 27.310
10 -27.810 -21.510 -15.310 -9.110 -2.910 3.310 9.510 15.810 22.015
15 -31.215 -24.915 -18.715 -12.515 -6.315 -0.115 6.115 12.315 18.620
20 -33.720 -27.520 -21.320 -15.120 -8.920 -2.720 3.620 9.820 16.025
25 -35.825 -29.625 -23.425 -17.225 -10.925 -4.725 1.525 7.725 13.930
30 -37.630 -31.330 -25.130 -18.930 -12.730 -6.530 -0.330 6.030 12.235
35 -39.135 -32.935 -26.635 -20.435 -14.235 -8.035 -1.835 4.435 10.640
40 -40.440 -34.240 -28.040 -21.840 -15.640 -9.340 -3.140 3.140 9.345
45 -41.645 -35.445 -29.245 -23.045 -16.845 -10.645 -4.345 1.945 8.150
50 -42.750 -36.550 -30.350 -24.150 -17.950 -11.750 -5.550 0.850 7.0


if i could get them to round to the same number I think it would line up as well

You must also remove your {0:1.1f} formatting:

def iround(x):
    return int(x + (0.5 if x > 0 else -0.5))

def windchill(V,T):
    wc = 35.74 + .6215*T-35.75*(V**.16)+.4275*(V**.16)
    we = iround(wc) # <---- used iround
    return we

def main():
    print("                         Temperature \n")
    print("Speed \n")
    print("---- -20 70 10 0 10 20 30 40 50 60 ")

    for V in range(0,55,5):
        print(V)
        for T in range(-20,70,10):
            wc = windchill(V,T)
            print(V, wc, end="") # <---  removed formatting

main()
Gribouillis 1,391 Programming Explorer Team Colleague

Ah ah! recurrent question. I once started a thread with same issue. The best solution I know is

def iround(x):
    return int(x + (0.5 if x > 0 else -0.5))
Gribouillis 1,391 Programming Explorer Team Colleague

Here is the link given by google http://www.cplusplus.com/forum/articles/12974/

Gribouillis 1,391 Programming Explorer Team Colleague

This leads to another problem. Pydoc does not work in windows CMD.
When i ran this command on cmd, the command was not recognized . Do i need to add the path of the file pydoc in Environment? By the way , thanks for the reply.This is my only clue till now.

I don't know exactly, i'm in linux. Here is the content of my executable /usr/bin/pydoc

#!/usr/bin/python2.6

import pydoc
if __name__ == '__main__':
    pydoc.cli()

You could perhaps write this in a file 'mypydoc.py' and then use

python mypydoc.py tkinter > tkinterhelp.txt
Gribouillis 1,391 Programming Explorer Team Colleague

The easiest way is to open a cmd shell and type

pydoc tkinter > tkinterhelp.txt

or

pydoc -w tkinter

which creates a file tkinter.html
The best way, however is to type

pydoc -p 9999

and then direct your web browser to http://localhost:9999 . From here you can browse the help of all your python modules.

Gribouillis 1,391 Programming Explorer Team Colleague

I made the corrections I believe but the code still returns 0 even though there are 19 periods in the document. Help?

def percount(myFile):

    periods = 0

    for char in myFile.read():

        if char == '.':
            periods +=1

        return periods

myFile = open("inn.txt", "r")

p = percount(myFile)
print p

Carefully compare your code with vegaseat's code and the light will come...

@vegaseat: nice to see you again Mr moderator !

Gribouillis 1,391 Programming Explorer Team Colleague

As you wrote your class, i is a static variable (a class member and not an instance member). You can update it with App.i += 1

vegaseat commented: nice and helpful +15
Gribouillis 1,391 Programming Explorer Team Colleague

This perhaps print(sum(str1.count(c) for c in ".!")) or sum(c in ".!" for c in str1)

Gribouillis 1,391 Programming Explorer Team Colleague

You called fin.read() twice. It doesn't work because the file position is at the end of the file for the second read, so the empty string is read.

Gribouillis 1,391 Programming Explorer Team Colleague

I read the tutorial. But I still don't know exactly what arguments my functions have, I know what they should return. For example if fcn1 returns nr and name and its name I want to use in fcn2. How do I accomplish that?

if fnc1 returns 2 values and you only want to use one of them in the call to fcn2, there are different ways to do that

def fnc1():
    # some code here
    return nr, name

def fnc2(somestring):
    # some code

# first way
foo, bar = fnc1()
fnc2(bar)

# second way
fnc2(fnc1()[1])

# third way
result = fnc1()
fnc2(result[1])
Gribouillis 1,391 Programming Explorer Team Colleague

I think I'm confusing myself in how to name everything in the functions and then be able to use the results in the 'main' program. I have done this so far in pseudocode.

f = open("filename", "r") 
for lines in f.readlines():
get name
	get nr
	f1 = fcn1(name,nr)
	f2 = fcn2(f1) 
	f3 = fcn3(f2)

def fcn1(a_name,a_nr): 
	f = open("filename", "r")
	for lines in f.readlines():
		if ('a_name=' in lines) and ('a_nr' in lines):
			search for it 
			return name, nr

def fcn2(f1): 
	f2 = open("filename", "r")
	for lines in f2.readlines():
                if a_nr in lines:
                        return lines

def fcn3(f2):
        if f2 exists: 
            f3=open(f2, 'r')   #consists of many txt files with m rows and n cols
            for data in f3.readlines():
                  if f2[1] in data:
                     return that column from data

I don't know how to name everything correct and then calling from the functions in the main program on top of the code I just wrote. Alos now I'm opening f two times.

Perhaps you could read this tutorial page http://learnpythonthehardway.org/book/ex18.html and the subsequent pages first to understand how functions work.

Gribouillis 1,391 Programming Explorer Team Colleague

Without a 'break' or 'return' statement, a 'while True' loop is always infinite (unless one of its lines raises an exception, which is not the case here).
Also there is a hidden error, try to understand this:

>>> "1000" < 9999
False
Gribouillis 1,391 Programming Explorer Team Colleague
IOError: [Errno 2] No such file or directory:

This error means that the filename does not exist in the file system. This can be tested using os.path.isfile()

import os
filename = raw_input("enter a path to a file: ")
if not os.path.isfile(filename):
    print "There is no file %s." % repr(filename)
else:
    print "The file %s exists." % repr(filename)
Gribouillis 1,391 Programming Explorer Team Colleague

Thanks. But how does the result argument work? If I e.g. wanted to do something like this applied on my code (see code below). Where f2 does some stuff based in result in f1 and f3 does some stuff based on res2:

def f1():
    do something
    return res1
def f2(result1):
    do something 
    return res2
def f3(result2):
    do something 
    return res3

Also I was wondering how do you read in the data in to the file when using fcns? Do you use the open function? (like this: open('filename', 'r') and the same for the outfile but with 'w' instead of 'r'). Do I use it inside def or outside? I'm unsure about the syntax.

The key questions are: what are the arguments and what does the functions return. In your code above you would compose the functions in an expression like result = f3(f2(f1())) . This works for example if f1() returns a string and f2() takes a string as argument and returns a string, and f3() takes a string as argument. There is no general rule as to where you open the files, inside or outside functions.
If you want f1 to take no argument and return a string, you could open an infile inside f1's body and create a StringIO for outfile and return the string obtained with the StringIO's getvalue() method for example.
The code I posted above should be very easy to use for you because you only need to write the code that you already …

Gribouillis 1,391 Programming Explorer Team Colleague

You could define 3 functions which take 2 arguments, a file opened for reading and a file opened for writing. Then you could use StringIO objects instead of temporary files on the disk. StringIO are memory files. They can be used like opened files (for reading or writing or appending). Here is an example with 3 file transform functions and a main function which calls the 3 transform functions one after the other to chain their action, using StringIOs as intermediary files

try:
    from cStringIO import StringIO # python 2
except ImportError:
    from io import StringIO # python 3

def funcA(infile, outfile):
    for line in infile:
        outfile.write(line.upper())

def funcB(infile, outfile):
    for line in infile:
        outfile.write(line[:-1][::-1]+"\n")
        
def funcC(infile, outfile):
    for line in infile:
        outfile.write(line.replace('E', 'e'))

def main():
    with open("inputfile.txt", "r") as fh1:
        fh2 = StringIO()
        funcA(fh1, fh2)
    fh3 = StringIO()
    fh2.seek(0) # go to the beginning of file 2 because we're now going to read it.
    funcB(fh2, fh3)
    fh3.seek(0)
    with open("outputfile.txt", "w") as fh4:
        funcC(fh3, fh4)
        
if __name__ == "__main__":
    main()

Another good solution would be to use generator functions, but since you're new to python, you must learn ordinary functions before generators.

Notice that you can see the content of a StringIO by calling fh2.getvalue() for example, which returns a string that you could print or write in a file.

Gribouillis 1,391 Programming Explorer Team Colleague

I seems to me that you add a datetime.timedelta of one hour to a datetime.datetime to get a new datetime.datetime.

Gribouillis 1,391 Programming Explorer Team Colleague

How about

sorted(set(open('f1')))

Or even better

with open('f2', 'w') as f2:
    with open('f1') as f1:
        f2.writelines(sorted(set(f1)))
Gribouillis 1,391 Programming Explorer Team Colleague

Thanks for the reply,

I imagined that I could just get the development package for python, but I wouldn't really know how to tell vim when it is installing to look at my folder for the development package instead of the one in /usr. That is where the real problem lies.

Also, I know vim has pythoninterp, but would this also allow me to point to an iPython development package and be operational?

I don't know about ipython, but google gives a link to this thread with configure options that could help you http://stackoverflow.com/questions/3373914/compiling-vim-with-python-support

Gribouillis 1,391 Programming Explorer Team Colleague

The python development files may be missing in your system. Usually in linux, there is a 'python' package and a 'python devel' package (on my mandriva it's 'lib64python2.6-devel'). The devel package contains header files and libraries typically used by C programs which interact with python. So, try to find the development package that goes with your OS.

Gribouillis 1,391 Programming Explorer Team Colleague

Don't open the files for writing, it will erase the files content !!! In fact you don't need to open the files at all. I suggest that you first create a dictionary newname --> oldname, this allows to detect the potential name collisions before renaming anything. Here is a possible script

import os
import re
startdigits = re.compile(r"^\d+")

def create_map():
    result = dict()
    for filename in os.listdir("."):
        if not os.path.isfile(filename): # skip subdirectories
            continue
        newfilename = startdigits.sub("", filename)
        if newfilename in result or (newfilename != filename
                                    and os.path.isfile(newfilename)):
            raise Exception("Name collision detected for '%s'" % filename)
        if newfilename != filename:
            result[newfilename] = filename
            
if __name__ == "__main__":
    filemap = create_map()
    for new, old in filemap.items():
        os.rename(old, new)
Gribouillis 1,391 Programming Explorer Team Colleague

also I've tried the same with

def search(self,val,event):
   pop_up(val)

to make sure it wasn't just an issue of it being clicked on and having an extra event, as happens when binding '<Return>' to something.

I suggest search(self, val=None) .

Gribouillis 1,391 Programming Explorer Team Colleague

In versions of python >= 2.3, there is a function random.sample() which does exactly what you need.

>>> L = range(100)
>>> import random
>>> random.sample(L, 3)
[32, 93, 51]

So, I think it would be a good solution to reuse the source code to write your own sample() function. Here is the module random from python 2.6.

Gribouillis 1,391 Programming Explorer Team Colleague

The -0.0 exists in the ieee 754 representation, it's zero with the sign bit set

>>> from binascii import hexlify
>>> import struct
>>> def ieee754(x):
...  p = struct.pack("d", x)
...  s = bin(int(b"1" + hexlify(p), 16))[3:]
...  return " ".join(reversed([s[i:i+8] for i in xrange(0, len(s), 8)]))
... 
>>> ieee754(0.0)
'00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000'
>>> ieee754(-0.0)
'10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000'
Gribouillis 1,391 Programming Explorer Team Colleague

The method sort() sorts the list in place and returns None

>>> list1 = ['Herring','used','to','be','abundant','in','the','AtlAntic','Ocean','then','herring','got','overfished']
>>> list1.sort(key=lambda s : s.count('a'))
>>> print list1
['Herring', 'used', 'to', 'be', 'in', 'the', 'AtlAntic', 'then', 'herring', 'got', 'overfished', 'Ocean', 'abundant']

The function sorted() creates a new sorted list and does not modify the initial list

>>> list1 = ['Herring','used','to','be','abundant','in','the','AtlAntic','Ocean','then','herring','got','overfished']
>>> print sorted(list1, key=lambda s : s.count('a'))
['Herring', 'used', 'to', 'be', 'in', 'the', 'AtlAntic', 'then', 'herring', 'got', 'overfished', 'Ocean', 'abundant']
>>> print list1
['Herring', 'used', 'to', 'be', 'abundant', 'in', 'the', 'AtlAntic', 'Ocean', 'then', 'herring', 'got', 'overfished']
Gribouillis 1,391 Programming Explorer Team Colleague

The normal solution is to use a 'with' statement

from contextlib import contextmanager

@contextmanager
def threadmgr_running(*args, **kwd):
    threadmgr = ThreadManager(*args, **kwd)
    threadmgr.start() # or whatever
    try:
        yield threadmgr
    finally:
        threadmgr.waiting = False

# in code

with threadmgr_running(...) as threadmgr:
    etc # the threadmgr terminates automatically after this block
JoshuaBurleson commented: for the props you deserve but didn't get +3
Gribouillis 1,391 Programming Explorer Team Colleague

The trouble is, it shouldn't become None at all..

Here is the whole code:

from tkinter import *

class Application(Frame):
    def __init__(self, master):
        super(Application, self).__init__(master)
        self.grid()
        self.create_widgets()
        
    def create_widgets(self):
        self.inst_lbl = Label(self, text = "Enter the password for the secret of longevity").grid(row = 0, column = 0, columnspan = 2, sticky = W)
        self.pw_lbl = Label(self, text = "Password: ").grid(row = 1, column = 0, sticky = W)
        self.pw_ent = Entry(self).grid(row = 1, column = 1, sticky = W)
        self.submit_bttn = Button(self, text = "Submit", command = self.reveal).grid(row = 2, column = 0, sticky = W)
        self.secret_txt = Text(self, width = 35, height = 5, wrap = WORD).grid(row = 3, column = 0, columnspan = 2, sticky = W)
        
        
    def reveal(self):
        contents = self.pw_ent.get()
        if contents == "secret":
            message = "Here's the secret to living to 100: live to 99 and then be VERY careful."
        else:
            message = "That wasn't the right password, I can let you know the secret."
        
        self.secret_txt.delete(0.0, END)
        self.secret_txt.insert(0.0, message)
        

root = Tk()
root.title("Secret of Longevity")
root.geometry("300x150")
app = Application(root)
root.mainloop()

As mentioned, I just changed 'WORD' to 'CHAR', and that's when the error began, and it didn't help to change it back.

As I said before, grid() returns None and for each of your subwidgets, you must use 2 lines, one to create the widget and the second line to call grid(). See my first post and compare carefully to your code.

Gribouillis 1,391 Programming Explorer Team Colleague

The two lines didn't work either.

Now I sound dumb, but how do I find out what the return value is?.

Your error message means that self.secret_txt is None, so what you can do is find out when this member becomes None. This can be done with a few prints in your program.

Gribouillis 1,391 Programming Explorer Team Colleague

I just finished a program, it worked perfectly, then I changed a bit of it, and now it won't work at all, even if I change it back.

self.secret_txt = Text(self, width = 35, height = 5, wrap = WORD).grid(row = 3, column = 0, columnspan = 2, sticky = W)

That it the code which is faulty.
I tried to change wrap = WORD to wrap = CHAR (just to see the change), and got this error: AttributeError: 'NoneType' object has no attribute 'delete'
'delete' comes from here:

self.secret_txt.delete(0.0, END)

Now I always get the error, even when using wrap = WORD, and also in new programs.

Help please!

What is the return value of the grid() method ? Try to write on two lines

self.secret_txt = Text(self, width = 35, height = 5, wrap = WORD)
self.secret_txt.grid(row = 3, column = 0, columnspan = 2, sticky = W)