Skip to content

Burst run's documentation between user guide and dev guide, merge FAQ's run questions in the user guide #6658

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

22 changes: 22 additions & 0 deletions doc/development_guide/api/epylint.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
=======
epylint
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole section of API should probably go into User guide? It's more usage related than development related right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me everything that is not doable by using the pylint executable with options is development. (Beside creating a file to call epylint's API is development ?).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But Development is about developing pylint right? Since pylint is a developer's tool everything related to it will be "development", but I feel like this is more part of "using pylint" than "developing or contributing to pylint". We never use these APIs in our own development and you don't really need them when writing a checker.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, it's still unclear what is what. How about this:

  • User guides : using pylint's result from the command line
  • Developer guides: using pylint's API programmatically, understanding pylint plugin system, extension, checkers, etc.
  • Contributor guides : developing for pylint itself launching tests, process, etc. (also maintaining pylint : we have a release.md document that is not included in the doc yet).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that! Although I would perhaps put Developers and Contributing under a more general header of "Development" like black does. That would also allow showing some of the sub-headers of Usage in the sidebar.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're almost ready to do the big table of content revamp then πŸ˜„ .

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm planning on adding readme and release.md first.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll let you choose, but I'd prefer a PR that sets up the TOC first. It's quite hard to review content + redirects + new pages at the same time.
If we create one PR with all pages/sections we want to have and make sure redirects work we can then do the content afterwards. I would even be okay with adding some blank pages for now considering that you're working on this quite hard at the moment.

=======

To silently run epylint on a ``module_name.py`` module, and get its standard output and error:

.. sourcecode:: python

from pylint import epylint as lint

(pylint_stdout, pylint_stderr) = lint.py_run('module_name.py', return_std=True)

It is also possible to include additional Pylint options in the first argument to ``py_run``:

.. sourcecode:: python

from pylint import epylint as lint

(pylint_stdout, pylint_stderr) = lint.py_run('module_name.py --disable C0114', return_std=True)

The options ``--msg-template="{path}:{line}: {category} ({msg_id}, {symbol}, {obj}) {msg}"`` and
``--reports=n`` are set implicitly inside the ``epylint`` module.
23 changes: 23 additions & 0 deletions doc/development_guide/api/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
###
API
###

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably write something here. https://pylint--6658.org.readthedocs.build/en/6658/development_guide/api/index.html feels a bit empty.

You can call ``Pylint``, ``epylint``, ``symilar`` and ``pyreverse`` from another
Python program thanks to their APIs:

.. sourcecode:: python

from pylint import run_pylint, run_epylint, run_pyreverse, run_symilar

run_pylint("--disable=C", "myfile.py")
run_epylint(...)
run_pyreverse(...)
run_symilar(...)


.. toctree::
:maxdepth: 1
:hidden:

pylint
epylint
67 changes: 67 additions & 0 deletions doc/development_guide/api/pylint.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
=======
Pylint
=======

As you would launch the command line
------------------------------------

You can use the ``run_pylint`` function, which is the same function
called by the command line (using ``sys.argv``). You can supply
arguments yourself:

.. sourcecode:: python

from pylint import run_pylint

run_pylint(argv=["--disable=line-too-long", "myfile.py"])


Recover the result in a stream
------------------------------

You can also use ``pylint.lint.Run`` directly if you want to do something that
can't be done using only pylint's command line options. Here's the basic example:

.. sourcecode:: python

from pylint.lint import Run

Run(argv=["--disable=line-too-long", "myfile.py"])

With ``Run`` it is possible to invoke pylint programmatically with a
reporter initialized with a custom stream:

.. sourcecode:: python

from io import StringIO

from pylint.lint import Run
from pylint.reporters.text import TextReporter

pylint_output = StringIO() # Custom open stream
reporter = TextReporter(pylint_output)
Run(["test_file.py"], reporter=reporter, do_exit=False)
print(pylint_output.getvalue()) # Retrieve and print the text report

The reporter can accept any stream object as as parameter. In this example,
the stream outputs to a file:

.. sourcecode:: python

from pylint.lint import Run
from pylint.reporters.text import TextReporter

with open("report.out", "w") as f:
reporter = TextReporter(f)
Run(["test_file.py"], reporter=reporter, do_exit=False)

This would be useful to capture pylint output in an open stream which
can be passed onto another program.

If your program expects that the files being linted might be edited
between runs, you will need to clear pylint's inference cache:

.. sourcecode:: python

from pylint.lint import pylinter
pylinter.MANAGER.clear_cache()
1 change: 1 addition & 0 deletions doc/development_guide/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ Development

contribute
testing
api/index
profiling
54 changes: 2 additions & 52 deletions doc/faq.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,35 +24,7 @@ Pylint uses git. To get the latest version of Pylint from the repository, simply
3. Running Pylint
=================

3.1 Can I give pylint a file as an argument instead of a module?
----------------------------------------------------------------

Pylint expects the name of a package or module as its argument. As a
convenience, you can give it a file name if it's possible to guess a module name from
the file's path using the python path. Some examples:

"pylint mymodule.py" should always work since the current working
directory is automatically added on top of the python path

"pylint directory/mymodule.py" will work if "directory" is a python
package (i.e. has an __init__.py file), an implicit namespace package
or if "directory" is in the python path.

"pylint /whatever/directory/mymodule.py" will work if either:

- "/whatever/directory" is in the python path

- your cwd is "/whatever/directory"

- "directory" is a python package and "/whatever" is in the python
path

- "directory" is an implicit namespace package and is in the python path.

- "directory" is a python package and your cwd is "/whatever" and so
on...

3.2 Where is the persistent data stored to compare between successive runs?
3.1 Where is the persistent data stored to compare between successive runs?
---------------------------------------------------------------------------

Analysis data are stored as a pickle file in a directory which is
Expand All @@ -71,7 +43,7 @@ localized using the following rules:
* ".pylint.d" directory in the current directory


3.3 How do I find the option name corresponding to a specific command line option?
3.2 How do I find the option name corresponding to a specific command line option?
----------------------------------------------------------------------------------

You can generate a sample configuration file with ``--generate-toml-config``.
Expand All @@ -82,28 +54,6 @@ For example::

pylint --disable=bare-except,invalid-name --class-rgx='[A-Z][a-z]+' --generate-toml-config

3.5 I need to run pylint over all modules and packages in my project directory.
-------------------------------------------------------------------------------

By default the ``pylint`` command only accepts a list of python modules and packages. Using a
directory which is not a package results in an error::

pylint mydir
************* Module mydir
mydir/__init__.py:1:0: F0010: error while code parsing: Unable to load file mydir/__init__.py:
[Errno 2] No such file or directory: 'mydir/__init__.py' (parse-error)

To execute pylint over all modules and packages under the directory, the ``--recursive=y`` option must
be provided. This option makes ``pylint`` attempt to discover all modules (files ending with ``.py`` extension)
and all packages (all directories containing a ``__init__.py`` file).
Those modules and packages are then analyzed::

pylint --recursive=y mydir

When ``--recursive=y`` option is used, modules and packages are also accepted as parameters::

pylint --recursive=y mydir mymodule mypackage

4. Message Control
==================

Expand Down
132 changes: 26 additions & 106 deletions doc/user_guide/run.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,126 +2,46 @@
Running Pylint
================

From the command line
---------------------
On module packages or directories
---------------------------------

Pylint is meant to be called from the command line. The usage is ::

pylint [options] modules_or_packages

You should give Pylint the name of a python package or module, or some number
of packages or modules. Pylint
``will not import`` this package or module, though uses Python internals
to locate them and as such is subject to the same rules and configuration.
You should pay attention to your ``PYTHONPATH``, since it is a common error
to analyze an installed version of a module instead of the
development version.

It is also possible to analyze Python files, with a few
restrictions. The thing to keep in mind is that Pylint will try to
convert the file name to a module name, and only be able to process
the file if it succeeds. ::

pylint mymodule.py

should always work since the current working
directory is automatically added on top of the python path ::

pylint directory/mymodule.py

will work if ``directory`` is a python package (i.e. has an __init__.py
file or it is an implicit namespace package) or if "directory" is in the
python path.

By default, pylint will exit with an error when one of the arguments is a directory which is not
a python package. In order to run pylint over all modules and packages within the provided
subtree of a directory, the ``--recursive=y`` option must be provided.

For more details on this see the :ref:`faq`.

From another python program
---------------------------

It is also possible to call Pylint from another Python program,
thanks to the ``Run()`` function in the ``pylint.lint`` module
(assuming Pylint options are stored in a list of strings ``pylint_options``) as:

.. sourcecode:: python

import pylint.lint
pylint_opts = ['--disable=line-too-long', 'myfile.py']
pylint.lint.Run(pylint_opts)

Another option would be to use the ``run_pylint`` function, which is the same function
called by the command line. You can either patch ``sys.argv`` or supply arguments yourself:

.. sourcecode:: python

import pylint

sys.argv = ["pylint", "your_file"]
pylint.run_pylint()
# Or:
pylint.run_pylint(argv=["your_file"])
By default the ``pylint`` command only accepts a list of python modules and packages. Using a
directory which is not a package results in an error::

To silently run Pylint on a ``module_name.py`` module,
and get its standard output and error:
pylint mydir
************* Module mydir
mydir/__init__.py:1:0: F0010: error while code parsing: Unable to load file mydir/__init__.py:
[Errno 2] No such file or directory: 'mydir/__init__.py' (parse-error)

.. sourcecode:: python
When ``--recursive=y`` option is used, modules and packages are also accepted as parameters::

from pylint import epylint as lint
pylint --recursive=y mydir mymodule mypackage

(pylint_stdout, pylint_stderr) = lint.py_run('module_name.py', return_std=True)
This option makes ``pylint`` attempt to discover all modules (files ending with ``.py`` extension)
and all packages (all directories containing a ``__init__.py`` file).

It is also possible to include additional Pylint options in the first argument to ``py_run``:

.. sourcecode:: python

from pylint import epylint as lint

(pylint_stdout, pylint_stderr) = lint.py_run('module_name.py --disable C0114', return_std=True)

The options ``--msg-template="{path}:{line}: {category} ({msg_id}, {symbol}, {obj}) {msg}"`` and
``--reports=n`` are set implicitly inside the ``epylint`` module.

Finally, it is possible to invoke pylint programmatically with a
reporter initialized with a custom stream:

.. sourcecode:: python

from io import StringIO

from pylint.lint import Run
from pylint.reporters.text import TextReporter

pylint_output = StringIO() # Custom open stream
reporter = TextReporter(pylint_output)
Run(["test_file.py"], reporter=reporter, do_exit=False)
print(pylint_output.getvalue()) # Retrieve and print the text report

The reporter can accept any stream object as as parameter. In this example,
the stream outputs to a file:

.. sourcecode:: python

from pylint.lint import Run
from pylint.reporters.text import TextReporter

with open("report.out", "w") as f:
reporter = TextReporter(f)
Run(["test_file.py"], reporter=reporter, do_exit=False)

This would be useful to capture pylint output in an open stream which
can be passed onto another program.
Pylint **will not import** this package or module, though uses Python internals
to locate them and as such is subject to the same rules and configuration.
You should pay attention to your ``PYTHONPATH``, since it is a common error
to analyze an installed version of a module instead of the development version.

If your program expects that the files being linted might be edited
between runs, you will need to clear pylint's inference cache:
On files
--------

.. sourcecode:: python
It is also possible to analyze Python files, with a few restrictions. As a convenience,
you can give it a file name if it's possible to guess a module name from the file's
path using the python path. Some examples:

from pylint.lint import pylinter
pylinter.MANAGER.clear_cache()
``pylint mymodule.py`` should always work since the current working
directory is automatically added on top of the python path

``pylint directory/mymodule.py`` will work if: ``directory`` is a python
package (i.e. has an ``__init__.py`` file), an implicit namespace package
or if ``directory`` is in the python path.

Command line options
--------------------
Expand Down