Examples

  • Find usages of a function called open:

    $ pyastgrep './/Call/func/Name[@id="open"]'
    src/pyastgrep/search.py:88:18:            with open(path) as f:
    
  • Literal numbers:

    $ pyastgrep './/Constant[@type="int" or @type="float"]'
    tests/examples/test_xml/everything.py:5:20:    assigned_int = 123
    tests/examples/test_xml/everything.py:6:22:    assigned_float = 3.14
    
  • Function calls where:

    • the function is named open:

    • the second positional argument is a string literal containing the character b:

    pyastgrep './/Call[./func/Name[@id="open"]][./args/Constant[position()=1][contains(@value, "b")]]'
    
  • Usages of open that are not in a with item expression:

    pyastgrep './/Call[not(ancestor::withitem)]/func/Name[@id="open"]'
    
  • Names longer than 42 characters, wherever they are used.

    pyastgrep './/Name[string-length(@id) > 42]'
    
  • except clauses that raise a different exception class than they catch:

    pyastgrep "//ExceptHandler[body//Raise/exc//Name and not(contains(body//Raise/exc//Name/@id, type/Name/@id))]"
    
  • Functions whose name contain a certain substring:

    pyastgrep './/FunctionDef[contains(@name, "something")]'
    
  • Classes whose name matches a regular expression:

    pyastgrep ".//ClassDef[re:match('M.*', @name)]"
    

    The above uses the Python re.match method. You can also use re:search to use the Python re.search method.

  • Case-insensitive match of names on the left hand side of an assignment containing a certain string. This can be achieved using the lower-case function from XPath2:

    pyastgrep './/Assign/targets//Name[contains(lower-case(@id), "something")]' --xpath2
    

    You can also use regexes, passing the i (case-insensitive flag) as below, as described in the Python Regular Expression Syntax docs

    pyastgrep './/Assign/targets//Name[re:search("(?i)something", @id)]'
    
  • Assignments to the name foo, including type annotated assignments, which use AnnAssign, and tuple unpacking assignments (while avoiding things like foo.bar = ...). Note the use of the | operator to do a union.

    pyastgrep '(.//AnnAssign/target|.//Assign/targets|.//Assign/targets/Tuple/elts)/Name[@id="foo"]'
    
  • Docstrings of functions/methods whose value contains “hello”:

    pyastgrep './/FunctionDef/body/Expr[1]/value/Constant[@type="str"][contains(@value, "hello")]'
    
  • For-loop variables called i or j (including those created by tuple unpacking):

    pyastgrep './/For/target//Name[@id="i" or @id="j"]'
    
  • Method calls: These are actually “calls” on objects that are attributes of other objects. This will match the top-level object:

    pyastgrep './/Call/func/Attribute'
    
  • Individual positional arguments to a method call named encode, where the arguments are literal strings or numbers. Note the use of Call[…] to match “Call nodes that have descendants that match …”, rather than matching those descendant nodes themselves.

    pyastgrep './/Call[./func/Attribute[@attr="encode"]]/args/Constant'
    
  • For a Django code base, find all .filter and .exclude method calls, and all Q object calls, which have a keyword argument where the name contains the string "user", for finding ORM calls like .filter(user__id__in=...) or Q(thing__user=...):

    pyastgrep '(.//Call[./func/Attribute[@attr="filter" or @attr="exclude"]] | .//Call[./func/Name[@id="Q"]]) [./keywords/keyword[contains(@arg, "user")]]'