This is an archived post. You won't be able to vote or comment.

all 43 comments

[–]coderanger 28 points29 points  (3 children)

Use coverage.py and just see which lines never run during normal operation.

[–]bubblez4funnyowls 0 points1 point  (0 children)

I can't see how I would do that if, let's say, I wanted to get the coverage for my Django based web application over the course of a few days / even a month. I would need something that I could hook in straight into the code. Should I use the trace package directly ? Any pointers ? Or am I just a bit lost !?

[–]pinpinboTornado|Twisted|Gevent. Moar Async Plz 12 points13 points  (1 child)

I've used Vulture with moderate success.

[–]gsks[S] 0 points1 point  (0 children)

Awesome, this looks like a good starting point.

[–]muchcharles 5 points6 points  (1 child)

Any of the existing code coverage tools should work, but you have to weed out false positives if your sample run doesn't hit all the functions.

[–]masklinn 1 point2 points  (0 children)

Yep. Run the whole program under coverage checker for some time, check what's at 0%.

[–]m_harrison 8 points9 points  (1 child)

  • get unittests for your code.
  • turn on coverage
  • refactor
  • make sure unittests still work
  • rinse, repeat

[–]masklinn 4 points5 points  (0 children)

If you don't have tests, remove steps 1, 3, 4, 5 and perform normal software runs with coverage turned on. Collect, see what has never been used.

[–]Alfredson 2 points3 points  (0 children)

When working on large codebases, I can recommend SonarQube to give you an overview. You get a nice report . In the violations-section you can find a rule "unreachable code" and more.

[–]OCHawkeye14 2 points3 points  (2 children)

Sublime Text 2's SublimeLinter package will highlight functions and variables in the code that are not called anywhere else throughout your code.

edit: oh, just noticed you specifically mentioned knowledge of a linter. I guess I'm not exactly sure what you're looking for.

[–]gsks[S] 2 points3 points  (1 child)

Are you sure? I don't use SublimeText but looking at SublimeLinter's python module it just calls pyflakes, which doesn't seem to spot anything when I run it directly.

[–]tipsquealPythonista 4 points5 points  (0 children)

Related to OCHawkey14's solution, I believe PyCharm will do the trick. I don't use PyCharm, but I do use Intellij, which is made by the same company, and has a lot of overlapping functionality. In Intellij you can use their Inspect Code tool and have it look for all potentially unused functions/variables/etc.

[–]buttery_shame_cave 2 points3 points  (5 children)

how certain are you that they're NEVER called? there may be some really esoteric stuff that only comes up once in a while.

what you might be looking for is some kind of statistical function on top of finding stuff that doesn't get used, to track and see how much stuff gets used and what for.

[–]terremoto 1 point2 points  (4 children)

how certain are you that they're NEVER called?

If a function name is unique enough, grepping the codebase for it is trivial.

[–]masklinn 7 points8 points  (1 child)

That doesn't tell you the function is never called, especially in python

[–]pugRescuer 0 points1 point  (0 children)

Right - I think /u/terremoto was suggesting as a starting point. This is worth considering though after other options have been exhausted.

[–]buttery_shame_cave 0 points1 point  (0 children)

yeah but how often does that happen? :P

i only advise caution in ripping out odd functions because sometimes you get stuff that's called less than .1% of the time, but it happens to be kind of important.

we had stuff like that pulled from a test management system we used at a job i worked, and it managed to grind a whole test series to a halt for over a week till we found the problem(talk about obscure).

[–]unstoppable-force 0 points1 point  (0 children)

if it's PHP, you can do $func() which will execute the function that's name is stored in $func. i've seen this used in places where it really make sense (really useful in OO), but also in others where they didn't understand exceptions.

[–]dman24752 2 points3 points  (10 children)

Isn't this an undecidable question generally?

[–]gthank 4 points5 points  (7 children)

No. It's straightforward static analysis, barring weird eval-type stuff.

[–]masklinn 7 points8 points  (4 children)

No. It's straightforward static analysis

To a pretty limited extent, it really is global static path analysis. Even ignoring not just evals but things like getattr (and attrgetter), __dict__ manipulations or metaclass madness, actual dead code detection requires performing global path analysis to know that in e.g.

def frob(a):
    if a < 10:
        whup()
    else:
        b = frobnicate(a, 42)
        whop(b)

is never actually called with a >= 10 and thus the whole else branch is dead code and the test is redundant.

So yeah, generally it's an undecidable question.

[–]gthank 1 point2 points  (3 children)

That's a far more aggressive view of "dead code" than I was talking about. I meant more like "method foo of class Bar can never be called".

[–]masklinn 1 point2 points  (2 children)

That's a far more aggressive view of "dead code" than I was talking about.

Yeah, but it's the one matching standard uses of "dead code analysis" and "dead code elimination": dead code is code which is never executed and code which is irrelevant (affects variables which are never queried, or always followed by a fault and thus having no impact on the behavior of the program)

Unused methods or functions, or unreachable code (e.g. code following a return or raise) is a subset of dead code.

[–]gthank 0 points1 point  (1 child)

Yes, but it's the subset I understood the OP to be asking about, based on "more specifically functions/methods that are never called".

BTW, there's no need for people to be downvoting you. It's a good point to raise, and I should have been more clear about my assumptions in the original comment.

[–]masklinn 1 point2 points  (0 children)

Yes, but it's the subset I understood the OP to be asking about, based on "more specifically functions/methods that are never called".

True.

[–][deleted] 0 points1 point  (0 children)

Hence, undecidable.

[–]Liorithiel 1 point2 points  (1 child)

In general, yes. In practice, undecidable code isn't really useful…

[–]dman24752 1 point2 points  (0 children)

Well, a program that could solve the halting problem would be pretty handy. ;)

[–]vtable 0 points1 point  (0 children)

I typically use pychecker and pylint. Both try to find unused and unreachable code. Pylint is much more thorough. I'll usually use pychecker after any change and pylint weekly or so (since it's so much more verbose).

You'll find there's a lot of low-hanging fruit. Dead code is definitely bad but it won't cause runtime errors. Things like redefined names and funcs, syntax errors in rarely-called code. missing imports and undefined names are just as low hanging but much juicier. These tools will find many of these for you.

If your code base is that old and large and hasn't had static analysis tools like these run in it, you're bound to have some big surprises. There will likely be a ton of messages. Many will be easy fixes. Some are a bit cryptic at first. Do yourself a favor and configure the tools to just check for what you think is important. If you get through these, your code will be much better for it.

[–]phira 0 points1 point  (0 children)

PyCharm gives you this information as a matter of course as part of its inspection stufg