5 Replies - 652 Views - Last Post: 21 March 2013 - 10:12 AM Rate Topic: -----

#1 Midwest Product  Icon User is offline

  • D.I.C Head

Reputation: 2
  • View blog
  • Posts: 74
  • Joined: 05-February 10

Counting lines of each method in a python file

Posted 19 March 2013 - 01:56 PM

Say I have this file:

class ClassA():
    def __init__(self):
        pass
    def methodA(self, parameter1 = "")
        pass
class ClassB(ClassA):
    def methodB(self):
        pass



I want to:
1. Count the components (there are two in this file: ClassA and ClassB)
2. Count the number of methods in each component
3. Count the number of lines in each component

This would result in this output:
ClassA:
Methods=2
Lines=5
ClassB:
Methods=1
Lines=3

Does anyone have any recommendations on how to go about doing this? Can I determine what each line is by counting the whitespace at the beginning of each line? Components should all be left justified (no whitespace), methods would have 4 spaces, and lines would have +4?

Is This A Good Question/Topic? 0
  • +

Replies To: Counting lines of each method in a python file

#2 jon.kiparsky  Icon User is online

  • Pancakes!
  • member icon


Reputation: 7875
  • View blog
  • Posts: 13,364
  • Joined: 19-March 11

Re: Counting lines of each method in a python file

Posted 19 March 2013 - 02:13 PM

Python is awkward about whitespace. I believe the best procedure would be to not assume what sort of indentation is used, but to derive that information from the code. So after a class declaration, look at the next line: it should be indented by one level. Use that as your "one level indentation", rather than any preset assumptions, or your code will be pretty fragile.
(you might run into someone who uses tabs, and then where would you be? up a tree, that's where!)
Was This Post Helpful? 1
  • +
  • -

#3 andrewsw  Icon User is offline

  • It's just been revoked!
  • member icon

Reputation: 3614
  • View blog
  • Posts: 12,437
  • Joined: 12-December 12

Re: Counting lines of each method in a python file

Posted 19 March 2013 - 03:38 PM

If the code you are exploring will only contain classes, defs and perhaps comments (perhaps this is an assignment?) then I would considering removing all whitespace on the right (rstrip()) and just reading the first word of each line.
Was This Post Helpful? 3
  • +
  • -

#4 Nekroze  Icon User is offline

  • D.I.C Head

Reputation: 14
  • View blog
  • Posts: 170
  • Joined: 08-May 11

Re: Counting lines of each method in a python file

Posted 20 March 2013 - 10:45 PM

Maybe have a look at partpy: https://pypi.python.org/pypi/partpy

It is made for parsing or lexing languages like python and works with either spaces or tabs and has some nice features that should help with this kind of problem.

For example it can retrieve a specific line or set of lines as partpy.SourceLine objects and you can then use the count_indentation method to get the amount of indentation on each line and also the get_first_char method of a SourceLine to detect if it has anything interesting on that line or if its just blank. It can also skip to the next non white space character and line or detect the indentations of the previous significant line (ignoring the empty ones).

Might be a tad overkill but it should be easy enough to do with partpy.
Was This Post Helpful? 0
  • +
  • -

#5 Nekroze  Icon User is offline

  • D.I.C Head

Reputation: 14
  • View blog
  • Posts: 170
  • Joined: 08-May 11

Re: Counting lines of each method in a python file

Posted 20 March 2013 - 11:22 PM

Messy and quick example but using partpy you could do this:

from __future__ import print_function
from partpy import SourceString

source = SourceString("""# Example
class ClassA():
    def __init__(self):
        pass
    def methodA(self, parameter1 = "")
        pass
class ClassB(ClassA):
    def methodB(self):
        pass
""")

results = []
info = {}
currentclass = None

# Work with each SourceLine from the SourceString
for line in source.get_all_lines():
    # Count this lines indents as 4 spaces, 1 enables tab recognition
    indents = line.count_indents(4, 1)

    # Check for a class definition then add it to the list
    if indents == 0 and line.get_first_char() == 'c':

        currentclass = line.string  # Store the entire class def as name
        results.append(currentclass)  # Add to the list of classes
        # Empty class info, 0 methods and lines
        info[currentclass] = {"methods": 0, "lines": 0}

    elif indents == 1:
        # Part of a class definition (will match top level function blocks)
        if line.get_first_char() == 'd':
            info[currentclass]["methods"] += 1  # Has indent and starts with d
    elif indents > 1:  # Count only non blank lines
        info[currentclass]["lines"] += 1  # Add to lines regardless


for result in results:
    print("{0}  Methods:{1}\n  Lines:{2}\n".format(result,
                                                   info[result]["methods"],
                                                   info[result]["lines"]))



Partpy is heavily tested for compatibility with multiple versions of and types of python and also for speed. It can even be compiled as Cython or RPython. Good thing is it can be a simple or as complex as you want, in this case there is no need to sublcass anything. All we do here is look through each line and make a best guess of what it is (ie: if it has no indentation and starts with the letter 'c' its probably a class. This can be made as complex and accurate as you want but this is an example) then store the results as we go. At the moment it will trip up on top level functions and it only counts non blank lines but changing this should be pretty easy.

Hope this is the kind of thing you are looking for mate, GL!
Was This Post Helpful? 0
  • +
  • -

#6 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon

Reputation: 5882
  • View blog
  • Posts: 12,760
  • Joined: 16-October 07

Re: Counting lines of each method in a python file

Posted 21 March 2013 - 10:12 AM

My first thought was just use Python meta data:
>>> import metaTest
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "metaTest.py", line 4
    def methodA(self, parameter1 = "")
                                     ^
SyntaxError: invalid syntax
>>> import metaTest
>>> dir(metaTest)
['ClassA', 'ClassB', '__builtins__', '__doc__', '__file__', '__name__', '__package__']
>>> dir(metaTest.ClassA)
['__doc__', '__init__', '__module__', 'methodA']
>>> metaTest
<module 'metaTest' from 'metaTest.py'>
>>> metaTest.__file__
'metaTest.py'
>>> 




However, we're talking lines here. What follows is my wondering toward a solution:
>>> with open('metaTest.py') as fh: txt = ''.join(fh.readlines())
... 
>>> txt
'class ClassA():\n    def __init__(self):\n        pass\n    def methodA(self, parameter1 = ""):\n        pass\nclass ClassB(ClassA):\n    def methodB(self):\n        pass\n\n'
>>> ('\n'+txt).split('\nclass')
['', ' ClassA():\n    def __init__(self):\n        pass\n    def methodA(self, parameter1 = ""):\n        pass', ' ClassB(ClassA):\n    def methodB(self):\n        pass\n\n']
>>> classes = [ c for c in ('\n'+txt).split('\nclass') if len(c.strip())>0 ]
>>> classes
[' ClassA():\n    def __init__(self):\n        pass\n    def methodA(self, parameter1 = ""):\n        pass', ' ClassB(ClassA):\n    def methodB(self):\n        pass\n\n']
>>> c1 = classes[0]
>>> c1
' ClassA():\n    def __init__(self):\n        pass\n    def methodA(self, parameter1 = ""):\n        pass'
>>> [ i for i in c1 if i.strip().startswith('def') ]
[]
>>> [ i for i in c1.split('\n') if i.strip().startswith('def') ]
['    def __init__(self):', '    def methodA(self, parameter1 = ""):']
>>> for c in classes:
...     lines = c.split('\n')
...     print lines[0]
...     print " Methods:", sum(1 for i in lines if i.strip().startswith('def'))
...     print " Lines:", len(lines)
... 
 ClassA():
 Methods: 2
 Lines: 5
 ClassB(ClassA):
 Methods: 1
 Lines: 5
>>> 



Because the case in question doesn't rely on indents exactly, this will basically work. If you have anything more complex, it's probably toast.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1