Contributing to Python-Markdown

The following is a set of guidelines for contributing to Python-Markdown and its extensions, which are hosted in the Python-Markdown Organization on GitHub. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.

Code of Conduct

This project and everyone participating in it is governed by the Python-Markdown Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to markdown@freewisdom.org.

Project Organization

The core Python-Markdown code base and any built-in extensions are hosted in the Python-Markdown/markdown project on GitHub. Other extensions maintained by the Python-Markdown project may be hosted as separate repositories in the Python-Markdown Organization on GitHub and must follow best practices for third-party extensions.

The Python-Markdown/markdown project is organized as follows:

  • Branch master should generally be stable and release-ready at all times.
  • Version branches should be used for bug-fixes back-ported to the most recent PATCH release.
  • No other branches should be created. Any other branches which exist are preserved for historical reasons only.

Issues

Feature requests, bug reports, usage questions, and other issues can all be raised on the GitHub issue tracker.

When describing issues try to phrase your ticket in terms of the behavior you think needs to change rather than the code you think needs to change.

Make sure you're running the latest version of Python-Markdown before reporting an issue.

Search the issue list first for related items. Be sure to check closed issues and pull requests. GitHub's search only checks open issues by default.

You may want to check the syntax rules and/or Babelmark to confirm that your expectations align with the rules and/or other implementations of Markdown.

If reporting a syntax bug, you must provide the minimal input which exhibits the behavior, the actual output and the output you expected. All three items must be provided as textual code blocks (screen-shots are not helpful). It may also be helpful to point to the syntax rules which specifically address the area of concern.

Feature requests will often be closed with a recommendation that they be implemented as third party extensions outside of the core Python-Markdown library. Keeping new feature requests implemented as third party extensions allows us to keep the maintenance overhead of Python-Markdown to a minimum, so that the focus can be on continued stability, bug fixes, and documentation.

Closing an issue does not necessarily mean the end of a discussion. If you believe your issue has been closed incorrectly, explain why and we'll consider if it needs to be reopened.

Pull Requests

A pull request often represents the start of a discussion, and does not necessarily need to be the final, finished submission. In fact, if you discover an issue and intend to provide a fix for it, there is no need to open an issue first. You can report the issue and provide the fix together in a pull request.

All pull requests should be made from your personal fork of the library hosted in your personal GitHub account. Do not create branches on the Python-Markdown/markdown project for pull requests. All pull requests should be implemented in a new branch with a unique name. Remember that if you have an outstanding pull request, pushing new commits to the related branch of your GitHub repository will also automatically update the pull request. It may help to review GitHub's documentation on Creating a pull request from a fork.

If you are providing a fix for a previously reported issue, you must reference the issue in your commit message. Be sure to prefix the reference with one of GitHub's action words which will automatically close the issue when the pull request is merged. For example, fixes #42 and closes #42 would be acceptable, whereas ref #42 would not. Of course, if merging a pull request should not cause an issue to be closed, then the action word should not be included when referencing that issue.

Before being accepted, each pull request must include the applicable code, new tests of all new features, updated tests for any changed features, documentation updates, and an appropriate update to the release notes. All changes must follow the applicable style guides. Failure to meet any one of the requirements is likely to delay any serious consideration of your pull request and may even cause it to be closed. Of course, if you are in the early stages of development, you may include a note in the pull request acknowledging that it is incomplete along with a request for feedback.

Pull requests will generally not be accepted if any tests are failing. Therefore, it is recommended that you run the tests before submitting your pull request. After making a pull request, check the Travis build status in the GitHub interface to ensure that all tests are running as expected. If any checks fail, you may push additional commits to your branch. GitHub will add those commits to the pull request and rerun the checks.

Style Guides

In an effort to maintain consistency, Python-Markdown adheres to the following style guides in its code and documentation. A pull request may be rejected if it fails to match the relevant style guides.

Code Style Guide

Except as noted below, all pull requests should follow Python's standard PEP8 Style Guide and are run through Flake8 to ensure that the style guide is followed.

Legacy code which does not follow the guidelines should only be updated if and when other changes (bug fix, feature addition, etc.) are being made to that section of code. While new features should be given names that follow modern Python naming conventions, existing names should be preserved to avoid backward incompatible changes.

Line length is limited to a maximum of 119 characters.

When a line of code does not fit within the line length limit, continuation lines should align elements wrapped inside parentheses, brackets and braces using a hanging indent. When using a hanging indent there should be no arguments on the first line and further indentation should be used to clearly distinguish itself as a continuation line. The closing parenthesis, bracket or brace should be on a line by itself and should line up under the first character of the line that starts the multi-line construct.

my_list = [
    1, 2, 3,
    4, 5, 6,
]
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
)

When the conditional part of an if-statement is long enough to require that it be written across multiple lines, extra indentation should be included on the conditional continuation line.

if (this_is_one_thing
        and that_is_another_thing):
    do_something()

Documentation Style Guide

Documentation should be in American English. The tone of the documentation should be simple, plain, objective and well-balanced where possible.

Keep paragraphs reasonably short.

With the exception of code blocks, limit line length to 79 characters. You may want to use your editor's tools to automatically hard wrap lines of text.

Don't use abbreviations such as 'e.g.' but instead use the long form, such as 'For example'.

The documentation is built from the Markdown source files in the docs directory by the MkDocs static site generator. In addition to the basic Markdown syntax, the following extensions are supported: extra, admonition, smarty, codehilite, and toc.

There are a few conventions you should follow when working on the documentation.

Headers

Headers should use the hash style. For example:

## Some important topic

The underline style should not be used. Don't do this:

Some important topic
====================

Links

Links should always use the reference style, with the referenced hyperlinks kept at the end of the document.

Here is a link to [some other thing][other-thing].

More text...

[other-thing]: http://example.com/other/thing

This style helps keep the documentation source consistent and readable.

If you are linking to another document within Python-Markdown's documentation, you should use a relative link, and link to the .md suffix. If applicable, it is preferred that the link includes a hash fragment pointing to the specific section of the page. For example:

[authentication]: reference.md#Markdown

Linking in this style ensures that the links work when browsing the documentation on GitHub. If your Markdown editor makes links clickable, they will work there as well. When the documentation is built, these links will be converted into regular links which point to the built HTML pages.

Notes and Warnings

If you want to draw attention to a note or warning, use the syntax defined in Python-Markdown's Admonition Extension:

!!! note

    This is the content of the note.

Commit Message Style Guide

Use the present tense ("Add feature" not "Added feature").

Use the imperative mood ("Move item to..." not "Moves item to...").

Limit the first line to 72 characters or less.

Reference issues and pull requests liberally after the first line. Include a summary of the changes/additions made without replicating the content of the documentation or release notes. This is where an explanation of the choices made should be found. References to issues and pull requests should only provide the context in which a choice was made. However, the commit should be able to stand on its own.

Development Environment

To start developing on Python-Markdown is it best to create a fork of the project on GitHub. After cloning your fork to your local system, you will want to configure a remote that points to the upstream repository so that you can sync changes made in the original repository with your fork.

It is recommended that all development be done from within a Python virtual environment, which isolates any experimental code from the general system. To create a virtual environment, use the following command from the root of the local working copy of your GitHub fork:

virtualenv venv

That creates a virtual environment which is contained in the venv directory within your local working copy. Note that the repository is configured so that git will ignore any files within a directory named venv or ENV for this very reason.

On Posix systems (Linux, BSD, MacOS, etc.), use the following command to activate the environment:

source venv/bin/activate

On Windows, use this command instead:

venv/Scripts/activate

See the User Guide for more information on using virtual environments.

To be able to run the Markdown library directly while working on it, install the working copy into the environment in Development Mode after activating the virtual environment for the first time:

pip install --editable .

Now any saved changes will immediately be available within the virtual environment.

You can run the command line script with the following command:

python -m markdown

And you can directly run the tests with:

python -m unittest discover tests

!!! note

Some tests require the [PyTidyLib] library, which depends on the [HTML Tidy]
library. If you do not have PyTidyLib installed, the tests which depend upon
it will be skipped. Given the difficulty in installing the HTML Tidy library
on many systems, you may choose to leave both libraries uninstalled and
depend on the Travis server to run those tests when you submit a pull
request.

The above setup will only run tests against the code in one version of Python. However, Python-Markdown supports multiple versions of Python. Therefore, a tox configuration is included in the repository, which includes test environments for all supported Python versions, a Flake8 test environment, and a spellchecker for the documentation. While it is generally fine to leave those tests for the Travis server to run when a pull request is submitted, for more advanced changes, you may want to run those tests locally. To do so, simply install tox:

pip install tox

Then, to run all configured test environments, simply call the command tox with no arguments. See help (tox -h) for more options.

!!! note

The tox environments expect that some dependencies are already installed on
your system. For example, by default, any Python version specific
environment will fail if that version of Python is not installed.
Additionally, the tox environments assume that the [HTML Tidy] library is
installed and may fail when attempting to install [PyTidyLib] if it is not.
Finally, the `spellchecker` environment requires [aspell] and the
`aspell-en` dictionary to be installed. Unfortunately, installing those
dependencies may differ significantly from system to system and is outside
the scope of this guide.

Versions

Python-Markdown follows Semantic Versioning and uses the MAJOR.MINOR.PATCH[.dev#|a#|b#|rc#] format for identifying releases. The status of the master branch should always be identified in the __version_info__ tuple defined in markdown/__init__.py. The contents of that tuple will automatically be converted into a normalized version which conforms to PEP 440. An invalid __version_info__ tuple will raise an error, preventing the library from running and the package from building.

Version Status

A MAJOR version is in development status when the MINOR version is 0, the PATCH version is 0, and the version includes a dev segment.

A MINOR version is in development status when the MINOR version is not 0, the PATCH version is 0, and the version includes a dev segment.

At all other times, the code is considered stable and release-ready.

MAJOR and MINOR releases may or may not get pre-releases (alpha, beta, release candidate, etc.) at the discretion of the project maintainers.

Version Workflow

Bug fixes may be merged from a pull request to the master branch at any time so long as all tests pass, including one or more new tests which would have failed prior to the change.

New features and backward incompatible changes may only be merged to the master branch when the MAJOR and/or MINOR version is in development status pursuant to Semantic Versioning.

A separate commit to the master branch should be made to bump up the MAJOR and/or MINOR version and set development status. Only then will any pull requests implementing new features or backward incompatible changes be accepted.

If a bug fix is deemed to be important and the master branch is in development status, a back-port of the fix should be committed to a version branch. If the appropriate version branch does not exist, then it should be created and a pull request back-porting the fix made against that branch. The version branch should be named with the most recently released MINOR version. For example, if the master branch is at 3.1.dev0 and the most recent MINOR release was 3.0.4, then the version branch would be named 3.0 and any releases from that branch would increment the PATCH version only (3.0.5, 3.0.6...).

Release Process

When a new release is being prepared, the release manager should follow the following steps:

  1. Verify that all outstanding issues and pull requests related to the release have been resolved.

  2. Confirm that the release notes and change log have been updated and indicate the date of the new release.

  3. Update the version defined in markdown/__init__.py.

  4. Build a local copy of the documentation, browse through the pages and confirm that no obvious issues exist with the documentation.

  5. Create a pull request with a commit message in the following format:

    Bump version to X.X.X
    
  6. After all checks (Travis, etc.) have passed, merge the pull request.

  7. Create a git tag with the new version as the tag name and push to the Python-Markdown/markdown repository.

  8. Deploy the release to PyPI with the command make deploy.

  9. Deploy an update to the documentation using MkDocs. The following example assumes that local clones of the Python-Markdown/markdown and Python-Markdown/Python-Markdown.github.io repositories are in sibling directories named markdown and Python-Markdown.github.io respectively.

    cd Python-Markdown.github.io
    mkdocs gh-deploy --config-file ../markdown/mkdocs.yml --remote-branch master
    

Issue and Pull Request Labels

Below are the labels used to track and manages issues and pull requests. The labels are loosely grouped by their purpose, but it is not necessary for every issue to have a label from every group, and an issue may have more than one label from the same group.

Type of Issue or Pull Request

Label name Description
bug Bug report.
feature Feature request.
support Support request.
process Discussions regarding policies and development process.

Category of Issue or Pull Request

Label name Description
core Related to the core parser code.
extension Related to one or more of the included extensions.
docs Related to the project documentation.

Status of Issue

Label name Description
more-info-needed More information needs to be provided.
needs-confirmation The alleged behavior needs to be confirmed.
needs-decision A decision needs to be made regarding request.
confirmed Confirmed bug report or approved feature request.
someday-maybe Approved low priority request.
duplicate The issue has been previously reported.
wontfix The issue will not be fixed for the stated reasons.
invalid Invalid report (user error, upstream issue, etc).
3rd-party Should be implemented as a third party extension.

Status of Pull Request

Label name Description
work-in-progress A partial solution. More changes will be coming.
needs-review Needs to be reviewed and/or approved.
requires-changes Awaiting updates after a review.
approved The pull request is ready to be merged.
rejected The pull request is rejected for the stated reasons.