views:

265

answers:

2

I'm trying to use the str.find() and it keeps raising an error, what am I doing wrong?

import codecs

    def countLOC(inFile):
        """ Receives a file and then returns the amount
            of actual lines of code by not counting commented
            or blank lines """

        LOC = 0  
        for line in inFile:
            if line.isspace():
                continue
            comment = line.find('#')
            if comment > 0:
                for letter in range(comment):
                    if not letter.whitespace:
                        LOC += 1
                        break            
        return LOC

    if __name__ == "__main__":
        while True:
            file_loc = input("Enter the file name: ").strip()
            try:
                source = codecs.open(file_loc)
            except:
                print ("**Invalid filename**")
            else:
                break 
        LOC_count = countLOC(source)

        print ("\nThere were {0} lines of code in {1}".format(LOC_count,source.name))

Error

  File "C:\Users\Justen-san\Documents\Eclipse Workspace\countLOC\src\root\nested\linesOfCode.py", line 12, in countLOC
        comment = line.find('#')
    TypeError: expected an object with the buffer interface
+1  A: 

Are you actually passing an open file to the function? Maybe try printing type(file) and type(line), as there's something fishy here -- with an open file as the argument, I just can't reproduce your problem! (There are other bugs in your code but none that would cause that exception). Oh btw, as best practice, DON'T use names of builtins, such as file, for your own purposes -- that causes incredible amounts of confusion!

Alex Martelli
Alright, I added full source to my post and changed the parameter name from 'file' to 'inFile' and after trying the type() command,type(inFile) = <class 'io.BufferedReader'>type(line) = <class 'bytes'>Am I passing the file incorrectly to the function?
Justen
+1  A: 

Use the built-in function open() instead of codecs.open().

You're running afoul of the difference between non-Unicode (Python 3 bytes, Python 2 str) and Unicode (Python 3 str, Python 2 unicode) string types. Python 3 won't convert automatically between non-Unicode and Unicode like Python 2 will. Using codecs.open() without an encoding parameter returns an object which yields bytes when you read from it.

Also, your countLOC function won't work:

for letter in range(comment):
    if not letter.whitespace:
        LOC += 1
        break

That for loop will iterate over the numbers from zero to one less than the position of '#' in the string (letter = 0, 1, 2...); whitespace isn't a method of integers, and even if it were, you're not calling it.

Also, you're never incrementing LOC if the line doesn't contain #.

A "fixed" but otherwise faithful (and inefficient) version of your countLOC:

def countLOC(inFile):
    LOC = 0  
    for line in inFile:
        if line.isspace():
            continue
        comment = line.find('#')
        if comment > 0:
            for letter in line[:comment]:
                if not letter.isspace():
                    LOC += 1
                    break
        else:
            LOC += 1
    return LOC

How I might write the function:

def count_LOC(in_file):
    loc = 0  
    for line in in_file:
        line = line.lstrip()
        if len(line) > 0 and not line.startswith('#'):
            loc += 1
    return loc
Miles
I figured out my error with the letter.whitespace, forgot to make letter the index of the string. And I know I didn't add to the LOC counter if a '#' wasn't found, I just didn't get that far because of the previous error. Thanks for the code though, I'm having a hard time writing "pythonically" coming from c++. Question on lstrip() -- why use that instead of just strip()?
Justen
lstrip and strip should give the same results; lstrip should do (slightly) less work so I went with that one.
Miles
ah okay. Well thanks again for the code, wasn't aware of the str.startswith method, should come in handy. Another question concerning python 3.0, how come line.lstrip is a valid command, but I have to type line = line.lstrip for it to actually work as intended?
Justen
Strings are immutable (the value of a particular string object can't be changed). String methods don't modify the string—they return a new one with the changes applied.
Miles