A CLI tool to search for Python code in a path using jQuery-like selectors.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Caio Ariede b719ed8c1c Added --ignore-dir and --no-recurse options 3 years ago
pyq Added --ignore-dir and --no-recurse options 3 years ago
sizzle Allows to easily extend selectors 3 years ago
testfiles Added --ignore-dir and --no-recurse options 3 years ago
.gitignore Initial commit 3 years ago
CHANGELOG.md Added --ignore-dir and --no-recurse options 3 years ago
LICENSE Initial commit 3 years ago
README.md Added --ignore-dir and --no-recurse options 3 years ago
setup.py Added --ignore-dir and --no-recurse options 3 years ago
test_cmd.py Added --ignore-dir and --no-recurse options 3 years ago
test_pyq.py Fixes a bug when matching 'assign[name=foo]' 3 years ago
test_sizzle.py Adds support for :has() pseudo-selector 3 years ago

README.md

pyq

A command-line tool to search for Python code using jQuery-like selectors

PyPI version

Installation

pip install pyqtool

Notice: As the tool is still under heavy development, you may see that some features are not yet available in the version distributed over PyPI. If you want to have a fresh taste, you can get it directly from source:

pip install https://github.com/caioariede/pyq/archive/master.zip -U

Please report any possible issues, we expect the master branch to be stable.

Usage

Usage: pyq3 [OPTIONS] SELECTOR [PATH]...

Options:
-l / --files       Only print filenames containing matches.
--ignore-dir TEXT  Ignore directory
-n / --no-recurse  No descending into subdirectories
--help             Show this message and exit.

The executable name will vary depending on the Python version: pyq2 pyq3

Available selectors

Type selectors
Name Attributes Additional notes
class class name
def def name
import import name
import name as name
from from import name
It’s also possible to match the full import using
the special attribute full
assign name [, name …] = value
call name(arg, arg, …, kwarg=, kwarg=, …)
attr foo.name.name
ID/Name selector
Syntax Applied to
#name class, def, assign, call, attr

Attribute selectors

Syntax Description
[name=value] Attribute name is equal to value
[name!=value] Attribute name is not equal to value
[name*=value] Attribute name contains value
[name^=value] Attribute name starts with value
[name$=value] Attribute name endswith value

Pseudo selectors

Syntax Applies to Description
:extends(selector) class Selects classes that its bases matches selector
:has(selector) all Selects everything that its body match selector
:not(selector) all Selects everything that do not match selector

Combinators

Syntax Description
parent > child Select direct child from parent
parent descendant Selects all descendant from parent

Examples

Search for classes that extends the IntegerField class:

❯ pyq3 'class:extends(#IntegerField)' django/forms
django/forms/fields.py:278 class FloatField(IntegerField):
django/forms/fields.py:315 class DecimalField(IntegerField):

Search for classes with the name FloatField:

❯ pyq3 'class[name=FloatField]' django/forms
django/forms/fields.py:278 class FloatField(IntegerField):

Search for methods under the FloatField class:

❯ pyq3 'class[name=FloatField] > def' django/forms
django/forms/fields.py:283     def to_python(self, value):
django/forms/fields.py:299     def validate(self, value):
django/forms/fields.py:308     def widget_attrs(self, widget):

Search for methods whose name starts with to under the FloatField class:

❯ pyq3 'class[name=FloatField] > def[name^=to]' django/forms
django/forms/fields.py:283     def to_python(self, value):

Search for import statements importing Counter:

❯ pyq3 'import[from=collections][name=Counter]' django/
django/apps/registry.py:5 from collections import Counter, OrderedDict, defaultdict
django/template/utils.py:3 from collections import Counter, OrderedDict
django/test/testcases.py:14 from collections import Counter
...

Search for classes without methods:

❯ pyq3 'class:not(:has(> def))' django/core
django/core/exceptions.py:8 class FieldDoesNotExist(Exception):
django/core/exceptions.py:13 class DjangoRuntimeWarning(RuntimeWarning):
django/core/exceptions.py:17 class AppRegistryNotReady(Exception):
...