How to Contribute
I would be very happy about any kind of contributions that help to improve and extend the functionality of mlxtend.
Quick Contributor Checklist
This is a quick checklist about the different steps of a typical contribution to mlxtend (and other open source projects). Consider copying this list to a local text file (or the issue tracker) and checking off items as you go.
1) Making and testing code changes:
- [ ] Open a new "issue" on GitHub to discuss the new feature / bug fix
- [ ] Fork the mlxtend repository from GitHub (if not already done earlier)
- [ ] Create and check out a new topic branch (please don't make modifications in the master branch)
- [ ] Implement the new feature or apply the bug-fix
- [ ] Add appropriate unit test functions in
mlxtend/*/tests
-
[ ] Run
PYTHONPATH='.' pytest ./mlxtend -sv
and make sure that all unit tests pass -
[ ] Make sure the newly implemented feature has good test coverage:
python -m pip install coverage
# test all:
# coverage run --source=mlxtend --branch -m pytest .
coverage run --source=mlxtend --branch -m pytest mlxtend/<insert_path>
coverage html
-
[ ] Modify documentation in the appropriate location under
mlxtend/docs/sources/
-
[ ] Add a note about the modification/contribution to the
./docs/sources/changelog.md
file
2) Checking code style:
When you check in a PR, mlxtend will run code style checks via flak8 and black. To make the contributor experience easier, we recommend you check the code style locally before pushing it to the repository. This way it is less likely that the automated checkers will complain and prompt you to make fixes.
There are two ways you can do this:
Option A: Running the tools manually
- [ ] Check for style issues by running
flake8 ./mlxtend
(you may want to runpytest
again after you made modifications to the code) - [ ] We recommend using black to format the code automatically according to recommended style changes. After installing
black
, you can do this via
black [source_file_or_directory]
- [ ] Run
isort
which will sort the imports alphabetically. We recommend the following command:
isort -p mlxtend --line-length 88 --multi-line 3 --profile black mypythonfile.py
Option B: Using pre-commit hooks (recommended)
The pre-commit hooks for mlxtend will check your code via flake8
, black
, and isort
automatically before you make a git commit
. You can read more about pre-commit hooks here.
- [ ] Install the pre-commit package via
pip install pre-commit
. - [ ] In the
mlxtend
folder, runpre-commit install
(you only have to do it once).
3) Submitting your code
- [ ] Push the topic branch to the server and create a pull request.
- [ ] Check the automated tests passed.
- [ ] The automatic PEP8/black integrations may prompt you to modify the code stylistically. It would be nice if you could apply the suggested changes.
Tips for Contributors
Getting Started - Creating a New Issue and Forking the Repository
- If you don't have a GitHub account, yet, please create one to contribute to this project.
- Please submit a ticket for your issue to discuss the fix or new feature before too much time and effort is spent for the implementation.
- Fork the
mlxtend
repository from the GitHub web interface.
- Clone the
mlxtend
repository to your local machine by executinggit clone https://github.com/<your_username>/mlxtend.git
Syncing an Existing Fork
If you already forked mlxtend earlier, you can bring you "Fork" up to date with the master branch as follows:
1. Configuring a remote that points to the upstream repository on GitHub
List the current configured remote repository of your fork by executing
$ git remote -v
If you see something like
origin https://github.com/<your username>/mlxtend.git (fetch)
origin https://github.com/<your username>/mlxtend.git (push)
you need to specify a new remote upstream repository via
$ git remote add upstream https://github.com/rasbt/mlxtend.git
Now, verify the new upstream repository you've specified for your fork by executing
$ git remote -v
You should see following output if everything is configured correctly:
origin https://github.com/<your username>/mlxtend.git (fetch)
origin https://github.com/<your username>/mlxtend.git (push)
upstream https://github.com/rasbt/mlxtend.git (fetch)
upstream https://github.com/rasbt/mlxtend.git (push)
2. Syncing your Fork
First, fetch the updates of the original project's master branch by executing:
$ git fetch upstream
You should see the following output
remote: Counting objects: xx, done.
remote: Compressing objects: 100% (xx/xx), done.
remote: Total xx (delta xx), reused xx (delta x)
Unpacking objects: 100% (xx/xx), done.
From https://github.com/rasbt/mlxtend
* [new branch] master -> upstream/master
This means that the commits to the rasbt/mlxtend
master branch are now
stored in the local branch upstream/master
.
If you are not already on your local project's master branch, execute
$ git checkout master
Finally, merge the changes in upstream/master to your local master branch by executing
$ git merge upstream/master
which will give you an output that looks similar to
Updating xxx...xxx
Fast-forward
SOME FILE1 | 12 +++++++
SOME FILE2 | 10 +++++++
2 files changed, 22 insertions(+),
*The Main Workflow - Making Changes in a New Topic Branch
Listed below are the 9 typical steps of a contribution.
1. Discussing the Feature or Modification
Before you start coding, please discuss the new feature, bugfix, or other modification to the project on the project's issue tracker. Before you open a "new issue," please do a quick search to see if a similar issue has been submitted already.
2. Creating a new feature branch
Please avoid working directly on the master branch but create a new feature branch:
$ git branch <new_feature>
Switch to the new feature branch by executing
$ git checkout <new_feature>
3. Developing the new feature / bug fix
Now it's time to modify existing code or to contribute new code to the project.
4. Testing your code
Add the respective unit tests and check if they pass:
$ PYTHONPATH='.' pytest ./mlxtend ---with-coverage
5. Documenting changes
Please add an entry to the mlxtend/docs/sources/changelog.md
file.
If it is a new feature, it would also be nice if you could update the documentation in appropriate location in mlxtend/sources
.
6. Committing changes
When you are ready to commit the changes, please provide a meaningful commit
message:
$ git add <modifies_files> # or `git add .`
$ git commit -m '<meaningful commit message>'
7. Optional: squashing commits
If you made multiple smaller commits, it would be nice if you could group them into a larger, summarizing commit. First, list your recent commit via
Note
Due to the improved GitHub UI, this is no longer necessary/encouraged.
$ git log
which will list the commits from newest to oldest in the following format by default:
commit 046e3af8a9127df8eac879454f029937c8a31c41
Author: rasbt <mail@sebastianraschka.com>
Date: Tue Nov 24 03:46:37 2015 -0500
fixed setup.py
commit c3c00f6ba0e8f48bbe1c9081b8ae3817e57ecc5c
Author: rasbt <mail@sebastianraschka.com>
Date: Tue Nov 24 03:04:39 2015 -0500
documented feature x
commit d87934fe8726c46f0b166d6290a3bf38915d6e75
Author: rasbt <mail@sebastianraschka.com>
Date: Tue Nov 24 02:44:45 2015 -0500
added support for feature x
Assuming that it would make sense to group these 3 commits into one, we can execute
$ git rebase -i HEAD~3
which will bring our default git editor with the following contents:
pick d87934f added support for feature x
pick c3c00f6 documented feature x
pick 046e3af fixed setup.py
Since c3c00f6
and 046e3af
are related to the original commit of feature x
, let's keep the d87934f
and squash the 2 following commits into this initial one by changes the lines to
pick d87934f added support for feature x
squash c3c00f6 documented feature x
squash 046e3af fixed setup.py
Now, save the changes in your editor. Now, quitting the editor will apply the rebase
changes, and the editor will open a second time, prompting you to enter a new commit message. In this case, we could enter support for feature x
to summarize the contributions.
8. Uploading changes
Push your changes to a topic branch to the git server by executing:
$ git push origin <feature_branch>
9. Submitting a pull request
Go to your GitHub repository online, select the new feature branch, and submit a new pull request:
Notes for Developers
Building the documentation
The documentation is built via MkDocs; to ensure that the documentation is rendered correctly, you can view the documentation locally by executing mkdocs serve
from the mlxtend/docs
directory.
For example,
~/github/mlxtend/docs$ mkdocs serve
1. Building the API documentation
To build the API documentation, navigate to mlxtend/docs
and execute the make_api.py
file from this directory via
~/github/mlxtend/docs$ python make_api.py
This should place the API documentation into the correct directories into the two directories:
mlxtend/docs/sources/api_modules
mlxtend/docs/sources/api_subpackes
2. Editing the User Guide
The documents containing code examples for the "User Guide" are generated from IPython Notebook files. In order to convert a IPython notebook file to markdown after editing, please follow the following steps:
- Modify or edit the existing notebook.
- Execute all cells in the current notebook and make sure that no errors occur.
- Convert the notebook to markdown using the
ipynb2markdown.py
converter
~/github/mlxtend/docs$ python ipynb2markdown.py --ipynb ./sources/user_guide/subpackage/notebookname.ipynb
Note
If you are adding a new document, please also include it in the pages section in the mlxtend/docs/mkdocs.yml
file.
3. Building static HTML files of the documentation
First, please check the documenation via localhost (https://127.0.0.1:8000/):
~/github/mlxtend/docs$ mkdocs serve
Next, build the static HTML files of the mlxtend documentation via
~/github/mlxtend/docs$ mkdocs build --clean
To deploy the documentation, execute
~/github/mlxtend/docs$ mkdocs gh-deploy --clean
4. Generate a PDF of the documentation
To generate a PDF version of the documentation, simply cd
into the mlxtend/docs
directory and execute:
python md2pdf.py
Uploading a new version to PyPI
1. Creating a new testing environment
Assuming we are using conda
, create a new python environment via
$ conda create -n 'mlxtend-testing' python=3 numpy scipy pandas
Next, activate the environment by executing
$ source activate mlxtend-testing
2. Installing the package from local files
Test the installation by executing the following from within the mlxtend main directory:
$ pip install . -e
the --record files.txt
flag will create a files.txt
file listing the locations where these files will be installed.
Try to import the package to see if it works, for example, by executing
$ python -c 'import mlxtend; print(mlxtend.__file__)'
If everything seems to be fine, remove the installation via
$ cat files.txt | xargs rm -rf ; rm files.txt
Next, test if pip
is able to install the packages. First, navigate to a different directory, and from there, install the package:
$ pip uninstall
$ pip install mlxtend
and uninstall it again
$ pip uninstall mlxtend
3. Deploying the package
Consider deploying the package to the PyPI test server first. The setup instructions can be found here.
First, install Twine if you don't have it already installed. E.g., use the following to install all recommended packages:
$ python -m pip install twine build
Second, create the distribution. This by default creates an sdist and wheel
in the ./dist
directory.
$ python -m build
Install the wheel and sdist to make sure they work. The distributions file names will change with each version.
python -m pip install ./dist/mlxtend-0.23.0.dev0.tar.gz --force-reinstall
python -m pip install ./dist/mlxtend-0.23.0.dev0-py3-none-any.whl --force-reinstall
python -m pip uninstall mlxtend
Third, upload the packages to the test server:
$ twine upload --repository-url https://upload.pypi.org/legacy dist/
Then, install it and see if it works:
$ pip install -i https://testpypi.python.org/pypi mlxtend
Next, uninstall it again as follows:
$ pip uninstall mlxtend
Fourth, after this dry-run succeeded, repeat this process using the "real" PyPI:
$ python -m twine upload dist/*
4. Removing the virtual environment
Finally, to cleanup our local drive, remove the virtual testing environment via
$ conda remove --name 'mlxtend-testing' --all
Note:
if you get an error like
HTTPError: 403 Forbidden from https://upload.pypi.org/legacy/
make sure you have an up to date version of twine installed (helped me to uninstall in conda and install via pip.)
5. Updating the conda-forge recipe
Once a new version of mlxtend has been uploaded to PyPI, update the conda-forge build recipe at https://github.com/conda-forge/mlxtend-feedstock by changing the version number in the recipe/meta.yaml
file appropriately.