Skip to content

docs: table and add stars #474

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

Merged
merged 20 commits into from
Dec 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ repos:
- id: check-merge-conflict
- id: check-yaml
- id: end-of-file-fixer
exclude: cibuildwheel/resources/pinned_docker_images.cfg
exclude: (cibuildwheel/resources/pinned_docker_images.cfg)|(.svg$)
- id: mixed-line-ending
- id: trailing-whitespace

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.782
hooks:
- id: mypy
files: cibuildwheel/|test/
files: ^(cibuildwheel/|test/|bin/projects.py)
pass_filenames: false
153 changes: 129 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,35 +125,136 @@ Options
Working examples
----------------

<!--working-examples-start-->

Here are some repos that use cibuildwheel.

- [Matplotlib](https://github.com/matplotlib/matplotlib) - The venerable Matplotlib, a Python library with C++ portions, built for Linux, Mac, and Windows on Github Actions.
- [pyinstrument_cext](https://github.com/joerick/pyinstrument_cext) - A simple C extension, without external dependencies, built on Travis CI/Appveyor.
- [websockets](https://github.com/aaugustin/websockets)
- [Parselmouth](https://github.com/YannickJadoul/Parselmouth) - A Python interface to the Praat software package, using pybind11, C++17 and CMake, with the core Praat static library built only once and shared between wheels; all platforms built on Github Actions.
- [python-admesh](https://github.com/admesh/python-admesh)
- [pybase64](https://github.com/mayeut/pybase64)
- [KDEpy](https://github.com/tommyod/KDEpy)
- [AutoPy](https://github.com/autopilot-rs/autopy)
- [apriltags2-ethz](https://github.com/safijari/apriltags2_ethz)
- [TgCrypto](https://github.com/pyrogram/tgcrypto)
- [twisted-iocpsupport](https://github.com/twisted/twisted-iocpsupport) - A submodule of Twisted that hooks into native C APIs using Cython. Built on Github CI for Windows.
- [gmic-py](https://github.com/dtschump/gmic-py)
- [creme](https://github.com/creme-ml/creme)
- [PyAV](https://github.com/PyAV-Org/PyAV)
- [aiortc](https://github.com/aiortc/aiortc)
- [aioquic](https://github.com/aiortc/aioquic)
- [pikepdf](https://github.com/pikepdf/pikepdf)
- [fathon](https://github.com/stfbnc/fathon)
- [etebase-py](https://github.com/etesync/etebase-py) - Python bindings to a Rust library using `setuptools-rust`, and `sccache` for improved speed, built on Travis CI.
- [xmlstarlet](https://github.com/dimitern/xmlstarlet) - Python 3.6+ CFFI bindings with true MSVC build and GitHub Actions.
- [bx-python](https://github.com/bxlab/bx-python) - A library that includes Cython extensions, built on Travis CI for Mac and Linux.
- [coverage.py](https://github.com/nedbat/coveragepy) - The coverage tool for Python.

> Add your repo here! Send a PR.
<!-- START bin/projects.py -->

<!-- this section is generated by bin/projects.py. Don't edit it directly, instead, edit docs/data/projects.yml -->

| Name | CI | OS | Notes |
|-----------------------------------|----|----|:------|
| [scikit-learn][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The machine learning library. A complex but clean config using many of cibuildwheel's features to build a large project with Cython and C++ extensions. |
| [Matplotlib][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The venerable Matplotlib, a Python library with C++ portions |
| [twisted-iocpsupport][] | ![github icon][] | ![windows icon][] | A submodule of Twisted that hooks into native C APIs using Cython. |
| [scikit-image][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Image processing library. Uses cibuildwheel to build and test a project that uses Cython with platform-native code. |
| [websockets][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | Library for building WebSocket servers and clients. Mostly written in Python, with a small C 'speedups' extension module. |
| [pyzmq][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python bindings for zeromq, the networking library. Uses Cython and CFFI. |
| [aiortc][] | ![github icon][] | ![apple icon][] ![linux icon][] | WebRTC and ORTC implementation for Python using asyncio. |
| [h5py][] | ![azurepipelines icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | HDF5 for Python -- The h5py package is a Pythonic interface to the HDF5 binary data format. |
| [coverage.py][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The coverage tool for Python |
| [River][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | 🌊 Online machine learning in Python |
| [PyAV][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Pythonic bindings for FFmpeg's libraries. |
| [google neuroglancer][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | WebGL-based viewer for volumetric data |
| [aioquic][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | QUIC and HTTP/3 implementation in Python |
| [AutoPy][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes a Windows Travis build. |
| [pikepdf][] | ![azurepipelines icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python library for reading and writing PDF, powered by qpdf |
| [Parselmouth][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python interface to the Praat software package, using pybind11, C++17 and CMake, with the core Praat static library built only once and shared between wheels. |
| [python-rapidjson][] | ![travisci icon][] ![gitlab icon][] ![appveyor icon][] | ![windows icon][] ![linux icon][] | Python wrapper around rapidjson |
| [KDEpy][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Kernel Density Estimation in Python |
| [pybind11 python_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Example pybind11 module built with a Python-based build system |
| [pybind11 cmake_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Example pybind11 module built with a CMake-based build system |
| [iminuit][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Jupyter-friendly Python interface for C++ MINUIT2 |
| [jq.py][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | Python bindings for jq |
| [bx-python][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | A library that includes Cython extensions. |
| [boost-histogram][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Supports full range of wheels, including PyPy and alternate archs. |
| [pybase64][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Fast Base64 encoding/decoding in Python |
| [TgCrypto][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes a Windows Travis build. |
| [etebase-py][] | ![travisci icon][] | ![linux icon][] | Python bindings to a Rust library using `setuptools-rust`, and `sccache` for improved speed. |
| [pyjet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The interface between FastJet and NumPy |
| [numpythia][] | ![github icon][] | ![apple icon][] ![linux icon][] | The interface between PYTHIA and NumPy |
| [fathon][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | python package for DFA (Detrended Fluctuation Analysis) and related algorithms |
| [pyinstrument_cext][] | ![travisci icon][] ![appveyor icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A simple C extension, without external dependencies |
| [xmlstarlet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python 3.6+ CFFI bindings with true MSVC build. |
| [pybind11 scikit_build_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | An example combining scikit-build and pybind11 |

[scikit-learn]: https://github.com/scikit-learn/scikit-learn
[Matplotlib]: https://github.com/matplotlib/matplotlib
[twisted-iocpsupport]: https://github.com/twisted/twisted-iocpsupport
[scikit-image]: https://github.com/scikit-image/scikit-image
[websockets]: https://github.com/aaugustin/websockets
[pyzmq]: https://github.com/zeromq/pyzmq
[aiortc]: https://github.com/aiortc/aiortc
[h5py]: https://github.com/h5py/h5py
[coverage.py]: https://github.com/nedbat/coveragepy
[River]: https://github.com/online-ml/river
[PyAV]: https://github.com/PyAV-Org/PyAV
[google neuroglancer]: https://github.com/google/neuroglancer
[aioquic]: https://github.com/aiortc/aioquic
[AutoPy]: https://github.com/autopilot-rs/autopy
[pikepdf]: https://github.com/pikepdf/pikepdf
[Parselmouth]: https://github.com/YannickJadoul/Parselmouth
[python-rapidjson]: https://github.com/python-rapidjson/python-rapidjson
[KDEpy]: https://github.com/tommyod/KDEpy
[pybind11 python_example]: https://github.com/pybind/python_example
[pybind11 cmake_example]: https://github.com/pybind/cmake_example
[iminuit]: https://github.com/scikit-hep/iminuit
[jq.py]: https://github.com/mwilliamson/jq.py
[bx-python]: https://github.com/bxlab/bx-python
[boost-histogram]: https://github.com/scikit-hep/boost-histogram
[pybase64]: https://github.com/mayeut/pybase64
[TgCrypto]: https://github.com/pyrogram/tgcrypto
[etebase-py]: https://github.com/etesync/etebase-py
[pyjet]: https://github.com/scikit-hep/pyjet
[numpythia]: https://github.com/scikit-hep/numpythia
[fathon]: https://github.com/stfbnc/fathon
[pyinstrument_cext]: https://github.com/joerick/pyinstrument_cext
[xmlstarlet]: https://github.com/dimitern/xmlstarlet
[pybind11 scikit_build_example]: https://github.com/pybind/scikit_build_example

[appveyor icon]: docs/data/readme_icons/appveyor.svg
[github icon]: docs/data/readme_icons/github.svg
[azurepipelines icon]: docs/data/readme_icons/azurepipelines.svg
[circleci icon]: docs/data/readme_icons/circleci.svg
[gitlab icon]: docs/data/readme_icons/gitlab.svg
[travisci icon]: docs/data/readme_icons/travisci.svg
[windows icon]: docs/data/readme_icons/windows.svg
[apple icon]: docs/data/readme_icons/apple.svg
[linux icon]: docs/data/readme_icons/linux.svg

<!-- scikit-learn: 43359, last pushed 0 days ago -->
<!-- Matplotlib: 12734, last pushed 0 days ago -->
<!-- twisted-iocpsupport: 4107, last pushed 0 days ago -->
<!-- scikit-image: 4085, last pushed 0 days ago -->
<!-- websockets: 3065, last pushed 0 days ago -->
<!-- pyzmq: 2655, last pushed 9 days ago -->
<!-- aiortc: 2058, last pushed 10 days ago -->
<!-- h5py: 1451, last pushed 1 days ago -->
<!-- coverage.py: 1429, last pushed 3 days ago -->
<!-- River: 1174, last pushed 0 days ago -->
<!-- PyAV: 1107, last pushed 2 days ago -->
<!-- google neuroglancer: 545, last pushed 2 days ago -->
<!-- aioquic: 543, last pushed 38 days ago -->
<!-- AutoPy: 503, last pushed 94 days ago -->
<!-- pikepdf: 477, last pushed 3 days ago -->
<!-- Parselmouth: 429, last pushed 15 days ago -->
<!-- python-rapidjson: 406, last pushed 2 days ago -->
<!-- KDEpy: 224, last pushed 12 days ago -->
<!-- pybind11 python_example: 219, last pushed 32 days ago -->
<!-- pybind11 cmake_example: 217, last pushed 16 days ago -->
<!-- iminuit: 164, last pushed 3 days ago -->
<!-- jq.py: 137, last pushed 62 days ago -->
<!-- bx-python: 95, last pushed 75 days ago -->
<!-- boost-histogram: 60, last pushed 0 days ago -->
<!-- pybase64: 52, last pushed 2 days ago -->
<!-- TgCrypto: 48, last pushed 24 days ago -->
<!-- etebase-py: 39, last pushed 0 days ago -->
<!-- pyjet: 27, last pushed 17 days ago -->
<!-- numpythia: 23, last pushed 16 days ago -->
<!-- fathon: 17, last pushed 49 days ago -->
<!-- pyinstrument_cext: 9, last pushed 17 days ago -->
<!-- xmlstarlet: 7, last pushed 5 days ago -->
<!-- pybind11 scikit_build_example: 1, last pushed 30 days ago -->

<!-- END bin/projects.py -->

> Add your repo here! Send a PR, adding your information to `docs/data/projects.yml`.
>
> <sup>I'd like to include notes here to indicate why an example might be interesting to cibuildwheel users - the styles/technologies/techniques used in each. Please include that in future additions!</sup>

<!--working-examples-end-->

Legal note
----------

Expand All @@ -166,6 +267,8 @@ This is similar to static linking, so it might have some licence implications. C
Changelog
=========

<!--changelog-start-->

### 1.7.1

_3 December 2020_
Expand Down Expand Up @@ -573,6 +676,8 @@ _31 March 2017_

- 🌟 First public release!

<!--changelog-end-->

Contributing
============

Expand Down
198 changes: 198 additions & 0 deletions bin/projects.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
#!/usr/bin/env python3

"""
Convert a yaml project list into a nice table.
Suggested usage:
./bin/projects.py docs/data/projects.yml --online --auth $GITHUB_API_TOKEN --readme README.md
git diff
"""

import builtins
import functools
from datetime import datetime
from io import StringIO
from typing import Dict, Any, List, Optional, TextIO

import click
import yaml
from github import Github
import urllib.request
import xml.dom.minidom
from pathlib import Path


ICONS = (
"appveyor",
"github",
"azurepipelines",
"circleci",
"gitlab",
"travisci",
"windows",
"apple",
"linux",
)


class Project:
NAME: int = 0

def __init__(self, config: Dict[str, Any], github: Optional[Github] = None):
try:
self.name: str = config["name"]
self.gh: str = config["gh"]
except KeyError:
print("Invalid config, needs at least gh and name!", config)
raise

self.stars_repo: str = config.get("stars", self.gh)
self.notes: str = config.get("notes", "")
self.ci: List[str] = config.get("ci", [])
self.os: List[str] = config.get("os", [])

self.online = github is not None
if github is not None:
repo = github.get_repo(self.stars_repo)
self.num_stars = repo.stargazers_count
self.pushed_at = repo.pushed_at
if not self.notes:
notes = repo.description
if repo.description:
self.notes = notes
else:
self.num_stars = 0
self.pushed_at = datetime.utcnow()

name_len = len(self.name) + 4
self.__class__.NAME = max(self.__class__.NAME, name_len)

def __lt__(self, other: "Project") -> bool:
if self.online:
return self.num_stars < other.num_stars
else:
return self.name < other.name

@classmethod
def header(cls) -> str:
return (
f"| {'Name':{cls.NAME}} | CI | OS | Notes |\n"
f"|{'':-^{cls.NAME+2 }}|----|----|:------|"
)

@property
def namelink(self) -> str:
return f"[{self.name}][]"

@property
def starslink(self) -> str:
return f"![{self.name} stars][]"

@property
def url(self) -> str:
return f"https://github.com/{self.gh}"

@property
def ci_icons(self) -> str:
return " ".join(f"![{icon} icon][]" for icon in self.ci)

@property
def os_icons(self) -> str:
return " ".join(f"![{icon} icon][]" for icon in self.os)

def table_row(self) -> str:
notes = self.notes.replace('\n', ' ')
return f"| {self.namelink: <{self.NAME}} | {self.ci_icons} | {self.os_icons} | {notes} |"

def links(self) -> str:
return f"[{self.name}]: {self.url}"

def info(self) -> str:
days = (datetime.utcnow() - self.pushed_at).days
return f"<!-- {self.name}: {self.num_stars}, last pushed {days} days ago -->"


def fetch_icon(icon_name: str) -> None:
url = f'https://cdn.jsdelivr.net/npm/simple-icons@v4/icons/{icon_name}.svg'
with urllib.request.urlopen(url) as f:
original_svg_data = f.read()

document = xml.dom.minidom.parseString(original_svg_data)
svgElement = document.documentElement
assert svgElement.nodeName == 'svg'
svgElement.setAttribute('width', '16px')
svgElement.setAttribute('fill', '#606060')

icon_path = path_for_icon(icon_name)
icon_path.parent.mkdir(parents=True, exist_ok=True)

with open(path_for_icon(icon_name), 'w') as f:
f.write(svgElement.toxml())


def path_for_icon(icon_name: str) -> Path:
return Path('.') / 'docs' / 'data' / 'readme_icons' / f'{icon_name}.svg'


def str_projects(
config: List[Dict[str, Any]], *, online: bool = True, auth: Optional[str] = None
) -> str:
io = StringIO()
print = functools.partial(builtins.print, file=io)

if online:
for icon in ICONS:
fetch_icon(icon)

github = Github(auth) if online else None

projects = sorted((Project(item, github) for item in config), reverse=online)

print(Project.header())
for project in projects:
print(project.table_row())

print()
for project in projects:
print(project.links())

print()
for icon in ICONS:
print(f"[{icon} icon]: {path_for_icon(icon).as_posix()}")

print()
for project in projects:
print(project.info())

return io.getvalue()


@click.command()
@click.argument("input", type=click.File("r"))
@click.option("--online/--no-online", default=True, help="Get info from GitHub")
@click.option("--auth", help="GitHub authentication token")
@click.option("--readme", type=click.File("r+"), help="Modify a readme file if given")
def projects(
input: TextIO, online: bool, auth: Optional[str], readme: Optional[TextIO]
) -> None:
config = yaml.safe_load(input)
output = str_projects(config, online=online, auth=auth)

if readme is None:
print(output)
else:
text = readme.read()
start_str = "<!-- START bin/projects.py -->\n"
start = text.find(start_str)
end = text.find("<!-- END bin/projects.py -->\n")
generated_note = f'<!-- this section is generated by bin/projects.py. Don\'t edit it directly, instead, edit {input.name} -->'
new_text = f"{text[:start + len(start_str)]}\n{generated_note}\n\n{output}\n{text[end:]}"

readme.seek(0)
readme.write(new_text)
readme.truncate()


if __name__ == "__main__":
projects()
Loading