pynd - search Python code

For a while I have wanted a smarter grep1. A grep that understands Python syntax and idioms.

Over the last week or two I had a go at writing this and called it pynd (python find). As a very young project it is likely to change and evolve but I would love some feedback. Is this something you think you would use? What features would you like to see? Please send me your feedback.

I have spent lots of time grepping huge Python projects, pynd is starting to make that easier for me.

What can it do?

pynd is best demonstrated with some simple examples from the docs, ran against another project of mine.

Find and list all public functions

$ pynd --def --public
./retrace.py
181:def retry(*dargs, **dkwargs):
105:    def delay(self, attempt_number):
117:    def delay(self, attempt_number):
128:    def attempt(self, attempt):
140:    def attempt(self, attempt_number):
150:    def validate(self, result):
159:    def validate(self, result):
171:    def delay(self, attempt_number):
174:    def attempt(self, attempt_number):
177:    def validate(self, result):

or, with the --private flag.

$ pynd --private --def
./retrace.py
49:    def _update_wrapper(wrapper, wrapped,
67:    def _wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS,
233:    def _setup_limit(self, limit):
248:    def _setup_interval(self, interval):
263:    def _setup_validator(self, validator):
276:    def _nice_name(self, thing):

Look for each time a class instance was created

$ pynd --class Interval --call
./retrace.py
100:class Interval(_BaseAction):
251:            self._interval = Interval()

Search only within docstrings

$ pynd --doc "decorator" --ignore-case
./retrace.py
181:def retry(*dargs, **dkwargs):
The retry decorator. Can be passed all the arguments that are accepted by
Retry.__init__.
210:class Retry(object):
The Retry decorator class.

This class handles the retry process, calling wither limiters or interval
objects which control the retry flow.

Everything else

Check out pynd --help

$ pynd --help
usage: pynd [-h] [--version] [--ignore-dir [IGNORE_DIR [IGNORE_DIR ...]]]
            [--ignore-case] [--files-with-matches] [--show-stats]
            [--public | --private] [--verbose | --debug] [-d] [-c] [-f] [-i]
            [-C] [-a]
            [PATTERN] [FILES OR DIRECTORIES [FILES OR DIRECTORIES ...]]

Search for PATTERN in each Python file in filesystem from the current
directory down. If any files or directories are specified then only those are
checked.

positional arguments:
  PATTERN               The pattern to match against. This must be a valid
                        Python regular expression.
  FILES OR DIRECTORIES  A file or directory to limit the search scope. This
                        can be provided multiple times.

optional arguments:
  -h, --help            show this help message and exit
  --version             show program's version number and exit
  --ignore-dir [IGNORE_DIR [IGNORE_DIR ...]]
                        A pattern to exclude directories. This must be a valid
                        Python regular expression. It can be provided multiple
                        times.
  --ignore-case         Make all the regular expression matching case
                        insesitive.
  --files-with-matches  Don't output all the results, just the paths to files
                        that contain a result.
  --show-stats          At the end, show some stats.
  --public              Only show results considered to be public in Python.
                        They don't start with an underscore.
  --private             Only show results considered to be private in Python.
                        They start with an underscore.
  --verbose             Explain what is happening.
  --debug               Output excessively to make debugging easier
  -d, --doc             Match class and function docstrings.
  -c, --class           Match class names.
  -f, --def             Match function names.
  -i, --import          Match imported package names.
  -C, --call            Match call statements.
  -a, --attr            Match attributes on objects

What next?

That was just a super quick tour of some of the features. Now I just need to settle in and use the project for a while and hopefully find a few others to do the same. Then we can see what to do next.

Get involved.

See the contributing docs and the roadmap or just join in on Github.


  1. I actually use ack, but grep is a better catch-all term. 


Thanks for reading. You should follow me on Twitter.

Do you have any feedback or comments? The best place for discussion is on Reddit or Hacker News. Otherwise, email me.