mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-04 00:14:41 +01:00
438 lines
16 KiB
ReStructuredText
438 lines
16 KiB
ReStructuredText
.. _devguide:
|
|
|
|
=================
|
|
Developer's Guide
|
|
=================
|
|
.. image:: docs/_static/knight-vs-snail.jpg
|
|
:width: 80 %
|
|
:alt: knight-vs-snail
|
|
:align: center
|
|
|
|
Welcome to the xonsh developer's guide! This is a place for developers to
|
|
place information that does not belong in the user's guide or the library
|
|
reference but is useful or necessary for the next people that come along to
|
|
develop xonsh.
|
|
|
|
.. note:: All code changes must go through the pull request review procedure.
|
|
|
|
|
|
Making Your First Change
|
|
========================
|
|
|
|
First, install xonsh from source and open a xonsh shell in your favorite
|
|
terminal application. See installation instructions for details, but it
|
|
is recommended to do an 'editable' install via `pip'
|
|
|
|
$ pip install -e .
|
|
|
|
Next, make a trivial change (e.g. ``print("hello!")`` in ``main.py``).
|
|
|
|
Finally, run the following commands. You should see the effects of your change
|
|
(e.g. ``hello!``)::
|
|
|
|
$ $XONSH_DEBUG=1
|
|
$ xonsh
|
|
|
|
The xonsh build process collapses all Python source files into a single
|
|
``__amalgam__.py`` file. When xonsh is started with a falsy value for
|
|
`$XONSH_DEBUG <envvars.html>`_, it imports Python modules straight from
|
|
``__amalgam__.py``, which decreases startup times by eliminating the cost of
|
|
runtime imports. But setting ``$ $XONSH_DEBUG=1`` will suppress amalgamated
|
|
imports. Reloading the xonsh shell (``$ xonsh``) won't simply import the stale
|
|
``__amalgam__.py`` file that doesn't contain your new change, but will instead
|
|
import the unamalgamated source code which does contain your change. You can now
|
|
load every subsequent change by reloading xonsh, and if your code changes don't
|
|
seem to have any effect, make sure you check ``$XONSH_DEBUG`` first!
|
|
|
|
|
|
Changelog
|
|
=========
|
|
Pull requests will often have CHANGELOG entries associated with. However,
|
|
to avoid excessive merge conflicts, please follow the following procedure:
|
|
|
|
1. Go into the ``news/`` directory,
|
|
2. Copy the ``TEMPLATE.rst`` file to another file in the ``news/`` directory.
|
|
We suggest using the branchname::
|
|
|
|
$ cp TEMPLATE.rst branch.rst
|
|
|
|
3. Add your entries as a bullet pointed lists in your ``branch.rst`` file in
|
|
the appropriate category. It is OK to leave the ``None`` entries for later
|
|
use.
|
|
4. Commit your ``branch.rst``.
|
|
|
|
Feel free to update this file whenever you want! Please don't use someone
|
|
else's file name. All of the files in this ``news/`` directory will be merged
|
|
automatically at release time. The ``None`` entries will be automatically
|
|
filtered out too!
|
|
|
|
|
|
Style Guide
|
|
===========
|
|
xonsh is a pure Python project, and so we use PEP8 (with some additions) to
|
|
ensure consistency throughout the code base.
|
|
|
|
----------------------------------
|
|
Rules to Write By
|
|
----------------------------------
|
|
It is important to refer to things and concepts by their most specific name.
|
|
When writing xonsh code or documentation please use technical terms
|
|
appropriately. The following rules help provide needed clarity.
|
|
|
|
**********
|
|
Interfaces
|
|
**********
|
|
* User-facing APIs should be as generic and robust as possible.
|
|
* Tests belong in the top-level ``tests`` directory.
|
|
* Documentation belongs in the top-level ``docs`` directory.
|
|
|
|
************
|
|
Expectations
|
|
************
|
|
* Code must have associated tests and adequate documentation.
|
|
* User-interaction code (such as the Shell class) is hard to test.
|
|
Mechanism to test such constructs should be developed over time.
|
|
* Have *extreme* empathy for your users.
|
|
* Be selfish. Since you will be writing tests you will be your first user.
|
|
|
|
-------------------
|
|
Python Style Guide
|
|
-------------------
|
|
xonsh uses `PEP8`_ for all Python code. The following rules apply where `PEP8`_
|
|
is open to interpretation.
|
|
|
|
* Use absolute imports (``import xonsh.tools``) rather than explicit
|
|
relative imports (``import .tools``). Implicit relative imports
|
|
(``import tools``) are never allowed.
|
|
* Use ``"double quotes"`` for string literals, and
|
|
``"""triple double quotes"""`` for docstrings.
|
|
* We use sphinx with the numpydoc extension to autogenerate API documentation. Follow
|
|
the `numpydoc`_ standard for docstrings.
|
|
* Simple functions should have simple docstrings.
|
|
* Lines should be at most 80 characters long. The 72 and 79 character
|
|
recommendations from PEP8 are not required here.
|
|
* All Python code should be compliant with Python 3.5+.
|
|
* Tests should be written with `pytest <https://docs.pytest.org/>`_ using a procedural style. Do not use
|
|
unittest directly or write tests in an object-oriented style.
|
|
* Test generators make more dots and the dots must flow!
|
|
|
|
You can easily check for style issues, including some outright bugs such
|
|
as misspelled variable names, using `flake8 <https://flake8.pycqa.org/>`_. If you're using Anaconda you'll
|
|
need to run "conda install flake8" once. You can easily run flake8 on
|
|
the edited files in your uncommitted git change::
|
|
|
|
$ git status -s | awk '/\.py$$/ { print $2 }' | xargs flake8
|
|
|
|
If you want to lint the entire code base run::
|
|
|
|
$ flake8
|
|
|
|
We also use `black <https://github.com/psf/black>`_ for formatting the code base (which includes running in
|
|
our tests)::
|
|
|
|
$ black --check xonsh/ xontrib/
|
|
|
|
To add this as a git pre-commit hook::
|
|
|
|
$ pre-commit install
|
|
|
|
**********
|
|
Imports
|
|
**********
|
|
Xonsh source code may be amalgamated into a single file (``__amalgam__.py``)
|
|
to speed up imports. The way the code amalgamater works is that other modules
|
|
that are in the same package (and amalgamated) should be imported with::
|
|
|
|
from pkg.x import a, c, d
|
|
|
|
This is because the amalgamater puts all such modules in the same globals(),
|
|
which is effectively what the from-imports do. For example, ``xonsh.ast`` and
|
|
``xonsh.execer`` are both in the same package (``xonsh``). Thus they should use
|
|
the above from from-import syntax.
|
|
|
|
Alternatively, for modules outside of the current package (or modules that are
|
|
not amalgamated) the import statement should be either ``import pkg.x`` or
|
|
``import pkg.x as name``. This is because these are the only cases where the
|
|
amalgamater is able to automatically insert lazy imports in way that is guaranteed
|
|
to be safe. This is due to the ambiguity that ``from pkg.x import name`` may
|
|
import a variable that cannot be lazily constructed or may import a module.
|
|
So the simple rules to follow are that:
|
|
|
|
1. Import objects from modules in the same package directly in using from-import,
|
|
2. Import objects from modules outside of the package via a direct import
|
|
or import-as statement.
|
|
|
|
How to Test
|
|
================
|
|
|
|
----------------------------------
|
|
Docker
|
|
----------------------------------
|
|
|
|
If you want to run your "work in progress version" without installing
|
|
and in a fresh environment you can use Docker. If Docker is installed
|
|
you just have to run this::
|
|
|
|
$ python xonsh-in-docker.py
|
|
|
|
This will build and run the current state of the repository in an isolated
|
|
container (it may take a while the first time you run it). There are two
|
|
additional arguments you can pass this script.
|
|
|
|
* The version of python
|
|
* the version of ``prompt_toolkit``
|
|
|
|
Example::
|
|
|
|
$ python docker.py 3.4 0.57
|
|
|
|
Ensure your cwd is the root directory of the project (i.e., the one containing the
|
|
.git directory).
|
|
|
|
----------------------------------
|
|
Dependencies
|
|
----------------------------------
|
|
|
|
Prep your environment for running the tests::
|
|
|
|
$ pip install -r requirements/tests.txt
|
|
|
|
|
|
----------------------------------
|
|
Running the Tests - Basic
|
|
----------------------------------
|
|
|
|
Run all the tests using pytest::
|
|
|
|
$ pytest -q
|
|
|
|
Use "-q" to keep pytest from outputting a bunch of info for every test.
|
|
|
|
----------------------------------
|
|
Running the Tests - Advanced
|
|
----------------------------------
|
|
|
|
To perform all unit tests::
|
|
|
|
$ pytest
|
|
|
|
If you want to run specific tests you can specify the test names to
|
|
execute. For example to run test_aliases::
|
|
|
|
$ pytest test_aliases.py
|
|
|
|
Note that you can pass multiple test names in the above examples::
|
|
|
|
$ pytest test_aliases.py test_environ.py
|
|
|
|
----------------------------------
|
|
Writing the Tests - Advanced
|
|
----------------------------------
|
|
|
|
(refer to pytest documentation)
|
|
|
|
With the Pytest framework you can use bare `assert` statements on
|
|
anything you're trying to test, note that the name of the test function
|
|
has to be prefixed with `test_`::
|
|
|
|
def test_whatever():
|
|
assert is_true_or_false
|
|
|
|
The conftest.py in tests directory defines fixtures for mocking various
|
|
parts of xonsh for more test isolation. For a list of the various fixtures::
|
|
|
|
$ pytest --fixtures
|
|
|
|
when writing tests it's best to use pytest features i.e. parametrization::
|
|
|
|
@pytest.mark.parametrize('env', [test_env1, test_env2])
|
|
def test_one(env, xession):
|
|
# update the environment variables instead of setting the attribute
|
|
# which could result in leaks to other tests.
|
|
# each run will have the same set of default env variables set.
|
|
xession.env.update(env)
|
|
...
|
|
|
|
this will run the test two times each time with the respective `test_env`.
|
|
This can be done with a for loop too but the test will run
|
|
only once for the different test cases and you get less isolation.
|
|
|
|
With that in mind, each test should have the least `assert` statements,
|
|
preferably one.
|
|
|
|
At the moment, xonsh doesn't support any pytest plugins.
|
|
|
|
Happy Testing!
|
|
|
|
|
|
How to Document
|
|
====================
|
|
Documentation takes many forms. This will guide you through the steps of
|
|
successful documentation.
|
|
|
|
----------
|
|
Docstrings
|
|
----------
|
|
No matter what language you are writing in, you should always have
|
|
documentation strings along with you code. This is so important that it is
|
|
part of the style guide. When writing in Python, your docstrings should be
|
|
in reStructured Text using the `numpydoc`_ format.
|
|
|
|
------------------------
|
|
Auto-Documentation Hooks
|
|
------------------------
|
|
The docstrings that you have written will automatically be connected to the
|
|
website, once the appropriate hooks have been setup. At this stage, all
|
|
documentation lives within xonsh's top-level ``docs`` directory.
|
|
We uses the sphinx tool to manage and generate the documentation, which
|
|
you can learn about from `the sphinx website <http://sphinx-doc.org/>`_.
|
|
If you want to generate the documentation, first xonsh itself must be installed
|
|
and then you may run the following command from the ``docs`` dir:
|
|
|
|
.. code-block:: console
|
|
|
|
~/xonsh/docs $ make html
|
|
|
|
For each new
|
|
module, you will have to supply the appropriate hooks. This should be done the
|
|
first time that the module appears in a pull request. From here, call the
|
|
new module ``mymod``. The following explains how to add hooks.
|
|
|
|
------------------------
|
|
Python Hooks
|
|
------------------------
|
|
Python API documentation is generated for the entries in ``docs/api.rst``.
|
|
`sphinx-autosummary<https://www.sphinx-doc.org/en/master/usage/extensions/autosummary.html>`_
|
|
is used to generate documentation for the modules.
|
|
Mention your module ``mymod`` under appropriate header.
|
|
This will discover all of the docstrings in ``mymod`` and create the
|
|
appropriate webpage.
|
|
|
|
|
|
Building the Website
|
|
===========================
|
|
|
|
Building the website/documentation requires the following dependencies:
|
|
|
|
#. `Sphinx <http://sphinx-doc.org/>`_
|
|
#. `Cloud Sphinx Theme <https://cloud-sptheme.readthedocs.io/>`_
|
|
#. `numpydoc <https://numpydoc.readthedocs.io/>`__
|
|
|
|
Note that xonsh itself needs to be installed too.
|
|
|
|
|
|
-----------------------------------
|
|
Procedure for modifying the website
|
|
-----------------------------------
|
|
The xonsh website source files are located in the ``docs`` directory.
|
|
A developer first makes necessary changes, then rebuilds the website locally
|
|
by executing the command::
|
|
|
|
$ make html
|
|
|
|
This will generate html files for the website in the ``_build/html/`` folder.
|
|
The developer may view the local changes by opening these files with their
|
|
favorite browser, e.g.::
|
|
|
|
$ google-chrome _build/html/index.html
|
|
|
|
Once the developer is satisfied with the changes, the changes should be
|
|
committed and pull-requested per usual. Once the pull request is accepted, the
|
|
developer can push their local changes directly to the website by::
|
|
|
|
$ make push-root
|
|
|
|
Branches and Releases
|
|
=============================
|
|
Mainline xonsh development occurs on the ``main`` branch. Other branches
|
|
may be used for feature development (topical branches) or to represent
|
|
past and upcoming releases.
|
|
|
|
All releases should have a release candidate ('-rc1') that comes out 2 - 5 days
|
|
prior to the scheduled release. During this time, no changes should occur to
|
|
a special release branch ('vX.X.X-release').
|
|
|
|
The release branch is there so that development can continue on the
|
|
develop branch while the release candidates (rc) are out and under review.
|
|
This is because otherwise any new developments would have to wait until
|
|
post-release to be merged into develop to prevent them from accidentally
|
|
getting released early.
|
|
|
|
As such, the 'vX.X.X-release' branch should only exist while there are
|
|
release candidates out. They are akin to a temporary second level of staging,
|
|
and so everything that is in this branch should also be part of main.
|
|
|
|
Every time a new release candidate comes out the vX.X.X-release should be
|
|
tagged with the name 'X.X.X-rcX'. There should be a 2 - 5 day period of time
|
|
in between release candidates. When the full and final release happens, the
|
|
'vX.X.X-release' branch is merged into main and then deleted.
|
|
|
|
If you have a new fix that needs to be in the next release candidate, you
|
|
should make a topical branch and then pull request it into the release branch.
|
|
After this has been accepted, the topical branch should be merged with
|
|
main as well.
|
|
|
|
The release branch must be quiet and untouched for 2 - 5 days prior to the
|
|
full release.
|
|
|
|
The release candidate procedure here only applies to major and minor releases.
|
|
Micro releases may be pushed and released directly without having a release
|
|
candidate.
|
|
|
|
--------------------
|
|
Maintenance Tasks
|
|
--------------------
|
|
You can cleanup your local repository of transient files such as \*.pyc files
|
|
created by unit testing by running::
|
|
|
|
$ rm -f xonsh/parser_table.py xonsh/completion_parser_table.py
|
|
$ rm -f xonsh/*.pyc tests/*.pyc
|
|
$ rm -fr build
|
|
|
|
-----------------------
|
|
Performing the Release
|
|
-----------------------
|
|
This is done through the `rever <https://github.com/regro/rever>`_. To get a list of the
|
|
valid options use::
|
|
|
|
$ pip install re-ver
|
|
|
|
You can perform a full release::
|
|
|
|
$ rever check
|
|
$ rever <version-number>
|
|
|
|
|
|
-----------------------
|
|
Cross-platform testing
|
|
-----------------------
|
|
Most of the time, an actual VM machine is needed to test the nuances of cross platform testing.
|
|
But alas here are some other ways to test things
|
|
|
|
1. Windows
|
|
|
|
|
|
- `wine <https://www.winehq.org/>`_ can be used to emulate the development environment. It provides cmd.exe with its default installation.
|
|
|
|
2. OS X
|
|
|
|
- `darlinghq <https://www.darlinghq.org/>`_ can be used to emulate the development environment for Linux users.
|
|
Windows users can use Linux inside a virtual machine or WSL to run the same.
|
|
- `OSX KVM <https://github.com/kholia/OSX-KVM>` can be used for virtualization.
|
|
|
|
3. Linux
|
|
|
|
- It far easier to test things for Linux. `docker <https://www.docker.com/>`_ is available on all three platforms.
|
|
|
|
One can leverage the Github Actions to provide a reverse shell to test things out.
|
|
Solutions like `actions-tmate <https://mxschmitt.github.io/action-tmate/>`_ are available,
|
|
but they should not in any way violate the Github Action policies.
|
|
|
|
|
|
Document History
|
|
===================
|
|
Portions of this page have been forked from the PyNE documentation,
|
|
Copyright 2011-2015, the PyNE Development Team. All rights reserved.
|
|
|
|
.. _PEP8: https://www.python.org/dev/peps/pep-0008/
|
|
.. _numpydoc: https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard
|