Skip to content

Commit 4f4dae2

Browse files
authored
Merge pull request #474 from henryiii/docs/stars
docs: table and add stars
2 parents 00a217d + c76ee0b commit 4f4dae2

19 files changed

+595
-27
lines changed

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ repos:
1313
- id: check-merge-conflict
1414
- id: check-yaml
1515
- id: end-of-file-fixer
16-
exclude: cibuildwheel/resources/pinned_docker_images.cfg
16+
exclude: (cibuildwheel/resources/pinned_docker_images.cfg)|(.svg$)
1717
- id: mixed-line-ending
1818
- id: trailing-whitespace
1919

2020
- repo: https://github.com/pre-commit/mirrors-mypy
2121
rev: v0.782
2222
hooks:
2323
- id: mypy
24-
files: cibuildwheel/|test/
24+
files: ^(cibuildwheel/|test/|bin/projects.py)
2525
pass_filenames: false

README.md

Lines changed: 129 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -125,35 +125,136 @@ Options
125125
Working examples
126126
----------------
127127

128+
<!--working-examples-start-->
129+
128130
Here are some repos that use cibuildwheel.
129131

130-
- [Matplotlib](https://github.com/matplotlib/matplotlib) - The venerable Matplotlib, a Python library with C++ portions, built for Linux, Mac, and Windows on Github Actions.
131-
- [pyinstrument_cext](https://github.com/joerick/pyinstrument_cext) - A simple C extension, without external dependencies, built on Travis CI/Appveyor.
132-
- [websockets](https://github.com/aaugustin/websockets)
133-
- [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.
134-
- [python-admesh](https://github.com/admesh/python-admesh)
135-
- [pybase64](https://github.com/mayeut/pybase64)
136-
- [KDEpy](https://github.com/tommyod/KDEpy)
137-
- [AutoPy](https://github.com/autopilot-rs/autopy)
138-
- [apriltags2-ethz](https://github.com/safijari/apriltags2_ethz)
139-
- [TgCrypto](https://github.com/pyrogram/tgcrypto)
140-
- [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.
141-
- [gmic-py](https://github.com/dtschump/gmic-py)
142-
- [creme](https://github.com/creme-ml/creme)
143-
- [PyAV](https://github.com/PyAV-Org/PyAV)
144-
- [aiortc](https://github.com/aiortc/aiortc)
145-
- [aioquic](https://github.com/aiortc/aioquic)
146-
- [pikepdf](https://github.com/pikepdf/pikepdf)
147-
- [fathon](https://github.com/stfbnc/fathon)
148-
- [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.
149-
- [xmlstarlet](https://github.com/dimitern/xmlstarlet) - Python 3.6+ CFFI bindings with true MSVC build and GitHub Actions.
150-
- [bx-python](https://github.com/bxlab/bx-python) - A library that includes Cython extensions, built on Travis CI for Mac and Linux.
151-
- [coverage.py](https://github.com/nedbat/coveragepy) - The coverage tool for Python.
152-
153-
> Add your repo here! Send a PR.
132+
<!-- START bin/projects.py -->
133+
134+
<!-- this section is generated by bin/projects.py. Don't edit it directly, instead, edit docs/data/projects.yml -->
135+
136+
| Name | CI | OS | Notes |
137+
|-----------------------------------|----|----|:------|
138+
| [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. |
139+
| [Matplotlib][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The venerable Matplotlib, a Python library with C++ portions |
140+
| [twisted-iocpsupport][] | ![github icon][] | ![windows icon][] | A submodule of Twisted that hooks into native C APIs using Cython. |
141+
| [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. |
142+
| [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. |
143+
| [pyzmq][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python bindings for zeromq, the networking library. Uses Cython and CFFI. |
144+
| [aiortc][] | ![github icon][] | ![apple icon][] ![linux icon][] | WebRTC and ORTC implementation for Python using asyncio. |
145+
| [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. |
146+
| [coverage.py][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The coverage tool for Python |
147+
| [River][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | 🌊 Online machine learning in Python |
148+
| [PyAV][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Pythonic bindings for FFmpeg's libraries. |
149+
| [google neuroglancer][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | WebGL-based viewer for volumetric data |
150+
| [aioquic][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | QUIC and HTTP/3 implementation in Python |
151+
| [AutoPy][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes a Windows Travis build. |
152+
| [pikepdf][] | ![azurepipelines icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python library for reading and writing PDF, powered by qpdf |
153+
| [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. |
154+
| [python-rapidjson][] | ![travisci icon][] ![gitlab icon][] ![appveyor icon][] | ![windows icon][] ![linux icon][] | Python wrapper around rapidjson |
155+
| [KDEpy][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Kernel Density Estimation in Python |
156+
| [pybind11 python_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Example pybind11 module built with a Python-based build system |
157+
| [pybind11 cmake_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Example pybind11 module built with a CMake-based build system |
158+
| [iminuit][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Jupyter-friendly Python interface for C++ MINUIT2 |
159+
| [jq.py][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | Python bindings for jq |
160+
| [bx-python][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | A library that includes Cython extensions. |
161+
| [boost-histogram][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Supports full range of wheels, including PyPy and alternate archs. |
162+
| [pybase64][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Fast Base64 encoding/decoding in Python |
163+
| [TgCrypto][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes a Windows Travis build. |
164+
| [etebase-py][] | ![travisci icon][] | ![linux icon][] | Python bindings to a Rust library using `setuptools-rust`, and `sccache` for improved speed. |
165+
| [pyjet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The interface between FastJet and NumPy |
166+
| [numpythia][] | ![github icon][] | ![apple icon][] ![linux icon][] | The interface between PYTHIA and NumPy |
167+
| [fathon][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | python package for DFA (Detrended Fluctuation Analysis) and related algorithms |
168+
| [pyinstrument_cext][] | ![travisci icon][] ![appveyor icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A simple C extension, without external dependencies |
169+
| [xmlstarlet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python 3.6+ CFFI bindings with true MSVC build. |
170+
| [pybind11 scikit_build_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | An example combining scikit-build and pybind11 |
171+
172+
[scikit-learn]: https://github.com/scikit-learn/scikit-learn
173+
[Matplotlib]: https://github.com/matplotlib/matplotlib
174+
[twisted-iocpsupport]: https://github.com/twisted/twisted-iocpsupport
175+
[scikit-image]: https://github.com/scikit-image/scikit-image
176+
[websockets]: https://github.com/aaugustin/websockets
177+
[pyzmq]: https://github.com/zeromq/pyzmq
178+
[aiortc]: https://github.com/aiortc/aiortc
179+
[h5py]: https://github.com/h5py/h5py
180+
[coverage.py]: https://github.com/nedbat/coveragepy
181+
[River]: https://github.com/online-ml/river
182+
[PyAV]: https://github.com/PyAV-Org/PyAV
183+
[google neuroglancer]: https://github.com/google/neuroglancer
184+
[aioquic]: https://github.com/aiortc/aioquic
185+
[AutoPy]: https://github.com/autopilot-rs/autopy
186+
[pikepdf]: https://github.com/pikepdf/pikepdf
187+
[Parselmouth]: https://github.com/YannickJadoul/Parselmouth
188+
[python-rapidjson]: https://github.com/python-rapidjson/python-rapidjson
189+
[KDEpy]: https://github.com/tommyod/KDEpy
190+
[pybind11 python_example]: https://github.com/pybind/python_example
191+
[pybind11 cmake_example]: https://github.com/pybind/cmake_example
192+
[iminuit]: https://github.com/scikit-hep/iminuit
193+
[jq.py]: https://github.com/mwilliamson/jq.py
194+
[bx-python]: https://github.com/bxlab/bx-python
195+
[boost-histogram]: https://github.com/scikit-hep/boost-histogram
196+
[pybase64]: https://github.com/mayeut/pybase64
197+
[TgCrypto]: https://github.com/pyrogram/tgcrypto
198+
[etebase-py]: https://github.com/etesync/etebase-py
199+
[pyjet]: https://github.com/scikit-hep/pyjet
200+
[numpythia]: https://github.com/scikit-hep/numpythia
201+
[fathon]: https://github.com/stfbnc/fathon
202+
[pyinstrument_cext]: https://github.com/joerick/pyinstrument_cext
203+
[xmlstarlet]: https://github.com/dimitern/xmlstarlet
204+
[pybind11 scikit_build_example]: https://github.com/pybind/scikit_build_example
205+
206+
[appveyor icon]: docs/data/readme_icons/appveyor.svg
207+
[github icon]: docs/data/readme_icons/github.svg
208+
[azurepipelines icon]: docs/data/readme_icons/azurepipelines.svg
209+
[circleci icon]: docs/data/readme_icons/circleci.svg
210+
[gitlab icon]: docs/data/readme_icons/gitlab.svg
211+
[travisci icon]: docs/data/readme_icons/travisci.svg
212+
[windows icon]: docs/data/readme_icons/windows.svg
213+
[apple icon]: docs/data/readme_icons/apple.svg
214+
[linux icon]: docs/data/readme_icons/linux.svg
215+
216+
<!-- scikit-learn: 43359, last pushed 0 days ago -->
217+
<!-- Matplotlib: 12734, last pushed 0 days ago -->
218+
<!-- twisted-iocpsupport: 4107, last pushed 0 days ago -->
219+
<!-- scikit-image: 4085, last pushed 0 days ago -->
220+
<!-- websockets: 3065, last pushed 0 days ago -->
221+
<!-- pyzmq: 2655, last pushed 9 days ago -->
222+
<!-- aiortc: 2058, last pushed 10 days ago -->
223+
<!-- h5py: 1451, last pushed 1 days ago -->
224+
<!-- coverage.py: 1429, last pushed 3 days ago -->
225+
<!-- River: 1174, last pushed 0 days ago -->
226+
<!-- PyAV: 1107, last pushed 2 days ago -->
227+
<!-- google neuroglancer: 545, last pushed 2 days ago -->
228+
<!-- aioquic: 543, last pushed 38 days ago -->
229+
<!-- AutoPy: 503, last pushed 94 days ago -->
230+
<!-- pikepdf: 477, last pushed 3 days ago -->
231+
<!-- Parselmouth: 429, last pushed 15 days ago -->
232+
<!-- python-rapidjson: 406, last pushed 2 days ago -->
233+
<!-- KDEpy: 224, last pushed 12 days ago -->
234+
<!-- pybind11 python_example: 219, last pushed 32 days ago -->
235+
<!-- pybind11 cmake_example: 217, last pushed 16 days ago -->
236+
<!-- iminuit: 164, last pushed 3 days ago -->
237+
<!-- jq.py: 137, last pushed 62 days ago -->
238+
<!-- bx-python: 95, last pushed 75 days ago -->
239+
<!-- boost-histogram: 60, last pushed 0 days ago -->
240+
<!-- pybase64: 52, last pushed 2 days ago -->
241+
<!-- TgCrypto: 48, last pushed 24 days ago -->
242+
<!-- etebase-py: 39, last pushed 0 days ago -->
243+
<!-- pyjet: 27, last pushed 17 days ago -->
244+
<!-- numpythia: 23, last pushed 16 days ago -->
245+
<!-- fathon: 17, last pushed 49 days ago -->
246+
<!-- pyinstrument_cext: 9, last pushed 17 days ago -->
247+
<!-- xmlstarlet: 7, last pushed 5 days ago -->
248+
<!-- pybind11 scikit_build_example: 1, last pushed 30 days ago -->
249+
250+
<!-- END bin/projects.py -->
251+
252+
> Add your repo here! Send a PR, adding your information to `docs/data/projects.yml`.
154253
>
155254
> <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>
156255

256+
<!--working-examples-end-->
257+
157258
Legal note
158259
----------
159260

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

270+
<!--changelog-start-->
271+
169272
### 1.7.1
170273

171274
_3 December 2020_
@@ -573,6 +676,8 @@ _31 March 2017_
573676

574677
- 🌟 First public release!
575678

679+
<!--changelog-end-->
680+
576681
Contributing
577682
============
578683

bin/projects.py

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
#!/usr/bin/env python3
2+
3+
"""
4+
Convert a yaml project list into a nice table.
5+
6+
Suggested usage:
7+
8+
./bin/projects.py docs/data/projects.yml --online --auth $GITHUB_API_TOKEN --readme README.md
9+
git diff
10+
"""
11+
12+
import builtins
13+
import functools
14+
from datetime import datetime
15+
from io import StringIO
16+
from typing import Dict, Any, List, Optional, TextIO
17+
18+
import click
19+
import yaml
20+
from github import Github
21+
import urllib.request
22+
import xml.dom.minidom
23+
from pathlib import Path
24+
25+
26+
ICONS = (
27+
"appveyor",
28+
"github",
29+
"azurepipelines",
30+
"circleci",
31+
"gitlab",
32+
"travisci",
33+
"windows",
34+
"apple",
35+
"linux",
36+
)
37+
38+
39+
class Project:
40+
NAME: int = 0
41+
42+
def __init__(self, config: Dict[str, Any], github: Optional[Github] = None):
43+
try:
44+
self.name: str = config["name"]
45+
self.gh: str = config["gh"]
46+
except KeyError:
47+
print("Invalid config, needs at least gh and name!", config)
48+
raise
49+
50+
self.stars_repo: str = config.get("stars", self.gh)
51+
self.notes: str = config.get("notes", "")
52+
self.ci: List[str] = config.get("ci", [])
53+
self.os: List[str] = config.get("os", [])
54+
55+
self.online = github is not None
56+
if github is not None:
57+
repo = github.get_repo(self.stars_repo)
58+
self.num_stars = repo.stargazers_count
59+
self.pushed_at = repo.pushed_at
60+
if not self.notes:
61+
notes = repo.description
62+
if repo.description:
63+
self.notes = notes
64+
else:
65+
self.num_stars = 0
66+
self.pushed_at = datetime.utcnow()
67+
68+
name_len = len(self.name) + 4
69+
self.__class__.NAME = max(self.__class__.NAME, name_len)
70+
71+
def __lt__(self, other: "Project") -> bool:
72+
if self.online:
73+
return self.num_stars < other.num_stars
74+
else:
75+
return self.name < other.name
76+
77+
@classmethod
78+
def header(cls) -> str:
79+
return (
80+
f"| {'Name':{cls.NAME}} | CI | OS | Notes |\n"
81+
f"|{'':-^{cls.NAME+2 }}|----|----|:------|"
82+
)
83+
84+
@property
85+
def namelink(self) -> str:
86+
return f"[{self.name}][]"
87+
88+
@property
89+
def starslink(self) -> str:
90+
return f"![{self.name} stars][]"
91+
92+
@property
93+
def url(self) -> str:
94+
return f"https://github.com/{self.gh}"
95+
96+
@property
97+
def ci_icons(self) -> str:
98+
return " ".join(f"![{icon} icon][]" for icon in self.ci)
99+
100+
@property
101+
def os_icons(self) -> str:
102+
return " ".join(f"![{icon} icon][]" for icon in self.os)
103+
104+
def table_row(self) -> str:
105+
notes = self.notes.replace('\n', ' ')
106+
return f"| {self.namelink: <{self.NAME}} | {self.ci_icons} | {self.os_icons} | {notes} |"
107+
108+
def links(self) -> str:
109+
return f"[{self.name}]: {self.url}"
110+
111+
def info(self) -> str:
112+
days = (datetime.utcnow() - self.pushed_at).days
113+
return f"<!-- {self.name}: {self.num_stars}, last pushed {days} days ago -->"
114+
115+
116+
def fetch_icon(icon_name: str) -> None:
117+
url = f'https://cdn.jsdelivr.net/npm/simple-icons@v4/icons/{icon_name}.svg'
118+
with urllib.request.urlopen(url) as f:
119+
original_svg_data = f.read()
120+
121+
document = xml.dom.minidom.parseString(original_svg_data)
122+
svgElement = document.documentElement
123+
assert svgElement.nodeName == 'svg'
124+
svgElement.setAttribute('width', '16px')
125+
svgElement.setAttribute('fill', '#606060')
126+
127+
icon_path = path_for_icon(icon_name)
128+
icon_path.parent.mkdir(parents=True, exist_ok=True)
129+
130+
with open(path_for_icon(icon_name), 'w') as f:
131+
f.write(svgElement.toxml())
132+
133+
134+
def path_for_icon(icon_name: str) -> Path:
135+
return Path('.') / 'docs' / 'data' / 'readme_icons' / f'{icon_name}.svg'
136+
137+
138+
def str_projects(
139+
config: List[Dict[str, Any]], *, online: bool = True, auth: Optional[str] = None
140+
) -> str:
141+
io = StringIO()
142+
print = functools.partial(builtins.print, file=io)
143+
144+
if online:
145+
for icon in ICONS:
146+
fetch_icon(icon)
147+
148+
github = Github(auth) if online else None
149+
150+
projects = sorted((Project(item, github) for item in config), reverse=online)
151+
152+
print(Project.header())
153+
for project in projects:
154+
print(project.table_row())
155+
156+
print()
157+
for project in projects:
158+
print(project.links())
159+
160+
print()
161+
for icon in ICONS:
162+
print(f"[{icon} icon]: {path_for_icon(icon).as_posix()}")
163+
164+
print()
165+
for project in projects:
166+
print(project.info())
167+
168+
return io.getvalue()
169+
170+
171+
@click.command()
172+
@click.argument("input", type=click.File("r"))
173+
@click.option("--online/--no-online", default=True, help="Get info from GitHub")
174+
@click.option("--auth", help="GitHub authentication token")
175+
@click.option("--readme", type=click.File("r+"), help="Modify a readme file if given")
176+
def projects(
177+
input: TextIO, online: bool, auth: Optional[str], readme: Optional[TextIO]
178+
) -> None:
179+
config = yaml.safe_load(input)
180+
output = str_projects(config, online=online, auth=auth)
181+
182+
if readme is None:
183+
print(output)
184+
else:
185+
text = readme.read()
186+
start_str = "<!-- START bin/projects.py -->\n"
187+
start = text.find(start_str)
188+
end = text.find("<!-- END bin/projects.py -->\n")
189+
generated_note = f'<!-- this section is generated by bin/projects.py. Don\'t edit it directly, instead, edit {input.name} -->'
190+
new_text = f"{text[:start + len(start_str)]}\n{generated_note}\n\n{output}\n{text[end:]}"
191+
192+
readme.seek(0)
193+
readme.write(new_text)
194+
readme.truncate()
195+
196+
197+
if __name__ == "__main__":
198+
projects()

0 commit comments

Comments
 (0)