|
| 1 | +--- |
| 2 | +authors: |
| 3 | + - marcelotrevisani |
| 4 | +tags: [conda] |
| 5 | +--- |
| 6 | + |
| 7 | +# By the power of Grayskull... I have the Conda recipe! |
| 8 | + |
| 9 | +_The main goal of the Skeleto_~~n~~_r is to conquer Grayskull._ |
| 10 | + |
| 11 | +## Introduction |
| 12 | + |
| 13 | +All jokes aside, the new project |
| 14 | +[grayskull](https://github.com/marcelotrevisani/grayskull) was created |
| 15 | +with the **intention** of generating better Conda recipes that would |
| 16 | +allow to package properly projects available in different channels such |
| 17 | +as PyPI, CRAN, Conan, GitHub register, GitHub repositories and so on. On |
| 18 | +top of that, Grayskull is also being developed to help |
| 19 | +[conda-forge](https://conda-forge.org/) to update recipes. |
| 20 | + |
| 21 | +<!--truncate--> |
| 22 | + |
| 23 | +## Current status |
| 24 | + |
| 25 | +Currently, Grayskull (version `0.2.1`) is able to generate recipes just |
| 26 | +looking for packages on [PyPI](https://pypi.org/), and it is available |
| 27 | +on [PyPI](https://pypi.org/project/grayskull/) and |
| 28 | +[conda-forge](https://github.com/conda-forge/grayskull-feedstock). The |
| 29 | +GitHub repository for this package is: |
| 30 | +<https://github.com/marcelotrevisani/grayskull>. |
| 31 | + |
| 32 | +Before Grayskull, we just had `conda-build skeleton` to generate recipes |
| 33 | +for Python packages on PyPI. In all other aspects, the difference of |
| 34 | +quality of the generated recipes, and also the time spent to generate |
| 35 | +them have a big discrepancy when compared to `conda-build skeleton` and |
| 36 | +`grayskull`. Grayskull generates recipes taking in consideration the |
| 37 | +platform, Python version available, selectors, compilers (Fortran, C and |
| 38 | +C++), packages constrains, license type, license file, and so forth. It |
| 39 | +uses metadata available from multiple sources to try to create the best |
| 40 | +recipe possible. |
| 41 | + |
| 42 | +## Installation |
| 43 | + |
| 44 | +You can install `grayskull` using `pip` or `conda`. `Grayskull` does not |
| 45 | +rely on `conda` to run and can generate recipes with minimum |
| 46 | +dependencies. |
| 47 | + |
| 48 | +### With conda |
| 49 | + |
| 50 | +Grayskull is available on the conda-forge channel. |
| 51 | + |
| 52 | +```bash |
| 53 | +conda install -c conda-forge grayskull |
| 54 | +``` |
| 55 | + |
| 56 | +### With pip |
| 57 | + |
| 58 | +```bash |
| 59 | +pip install grayskull |
| 60 | +``` |
| 61 | + |
| 62 | +## Grayskull vs conda-build skeleton |
| 63 | + |
| 64 | +There are some differences of recipes generated by `grayskull` and |
| 65 | +`conda skeleton`. Taking as example the `pytest` recipe, which has |
| 66 | +selectors for platforms, Python version constrains, and has several |
| 67 | +package constrains as well. |
| 68 | + |
| 69 | +### Grayskull (0.2.1) - took 4 seconds to generate the recipe |
| 70 | + |
| 71 | +```yaml |
| 72 | +{% set name = "pytest" %} |
| 73 | +{% set version = "5.3.5" %} |
| 74 | + |
| 75 | +package: |
| 76 | + name: {{ name|lower }} |
| 77 | + version: {{ version }} |
| 78 | + |
| 79 | +source: |
| 80 | + url: https://pypi.io/packages/source/{{ name[0] }}/{{ name }}/{{ name }}-{{ version }}.tar.gz |
| 81 | + sha256: 0d5fe9189a148acc3c3eb2ac8e1ac0742cb7618c084f3d228baaec0c254b318d |
| 82 | + |
| 83 | +build: |
| 84 | + number: 0 |
| 85 | + skip: true # [py2k] |
| 86 | + entry_points: |
| 87 | + - pytest=pytest:main |
| 88 | + - py.test=pytest:main |
| 89 | + script: {{ PYTHON }} -m pip install . -vv |
| 90 | + |
| 91 | +requirements: |
| 92 | + host: |
| 93 | + - pip |
| 94 | + - python |
| 95 | + - setuptools >=40.0 |
| 96 | + - setuptools_scm |
| 97 | + run: |
| 98 | + - atomicwrites >=1.0 # [win] |
| 99 | + - attrs >=17.4.0 |
| 100 | + - colorama # [win] |
| 101 | + - importlib-metadata >=0.12 # [py<38] |
| 102 | + - more-itertools >=4.0.0 |
| 103 | + - packaging |
| 104 | + - pathlib2 >=2.2.0 # [py<36] |
| 105 | + - pluggy <1.0,>=0.12 |
| 106 | + - py >=1.5.0 |
| 107 | + - python |
| 108 | + - wcwidth |
| 109 | + |
| 110 | +test: |
| 111 | + imports: |
| 112 | + - pytest |
| 113 | + commands: |
| 114 | + - pip check |
| 115 | + - pytest --help |
| 116 | + - py.test --help |
| 117 | + requires: |
| 118 | + - pip |
| 119 | + |
| 120 | +about: |
| 121 | + home: https://pypi.org/project/pytest/ |
| 122 | + summary: 'pytest: simple powerful testing with Python' |
| 123 | + dev_url: https://github.com/pytest-dev/pytest |
| 124 | + license: MIT |
| 125 | + license_file: LICENSE |
| 126 | + |
| 127 | +extra: |
| 128 | + recipe-maintainers: |
| 129 | + - marcelotrevisani |
| 130 | +``` |
| 131 | +
|
| 132 | +### Skeleton (3.18.11) - took 31 seconds to generate the recipe |
| 133 | +
|
| 134 | +```yaml |
| 135 | +{% set name = "pytest" %} |
| 136 | +{% set version = "5.3.5" %} |
| 137 | + |
| 138 | +package: |
| 139 | + name: "{{ name|lower }}" |
| 140 | + version: "{{ version }}" |
| 141 | + |
| 142 | +source: |
| 143 | + url: "https://pypi.io/packages/source/{{ name[0] }}/{{ name }}/{{ name }}-{{ version }}.tar.gz" |
| 144 | + sha256: 0d5fe9189a148acc3c3eb2ac8e1ac0742cb7618c084f3d228baaec0c254b318d |
| 145 | + |
| 146 | +build: |
| 147 | + number: 0 |
| 148 | + script: "{{ PYTHON }} -m pip install . -vv" |
| 149 | + |
| 150 | +requirements: |
| 151 | + host: |
| 152 | + - atomicwrites >=1.0 |
| 153 | + - attrs >=17.4.0 |
| 154 | + - colorama;sys_platform =="win32" |
| 155 | + - importlib-metadata >=0.12 |
| 156 | + - more-itertools >=4.0.0 |
| 157 | + - packaging |
| 158 | + - pathlib2 >=2.2.0 |
| 159 | + - pip |
| 160 | + - pluggy >=0.12,<1.0 |
| 161 | + - py >=1.5.0 |
| 162 | + - python |
| 163 | + - wcwidth |
| 164 | + run: |
| 165 | + - atomicwrites >=1.0 |
| 166 | + - attrs >=17.4.0 |
| 167 | + - colorama;sys_platform =="win32" |
| 168 | + - importlib-metadata >=0.12 |
| 169 | + - more-itertools >=4.0.0 |
| 170 | + - packaging |
| 171 | + - pathlib2 >=2.2.0 |
| 172 | + - pluggy >=0.12,<1.0 |
| 173 | + - py >=1.5.0 |
| 174 | + - python |
| 175 | + - wcwidth |
| 176 | + |
| 177 | +about: |
| 178 | + home: The package home page |
| 179 | + license: MIT |
| 180 | + license_family: MIT |
| 181 | + license_file: |
| 182 | + summary: "pytest: simple powerful testing with Python" |
| 183 | + doc_url: |
| 184 | + dev_url: |
| 185 | + |
| 186 | +extra: |
| 187 | + recipe-maintainers: |
| 188 | + - your-github-id-here |
| 189 | +``` |
| 190 | +
|
| 191 | +### Original recipe on `conda-forge` for `pytest 5.3.5` |
| 192 | + |
| 193 | +```yaml |
| 194 | +{% set version = "5.3.5" %} |
| 195 | +
|
| 196 | +package: |
| 197 | + name: pytest |
| 198 | + version: {{ version }} |
| 199 | +
|
| 200 | +source: |
| 201 | + url: https://pypi.io/packages/source/p/pytest/pytest-{{ version }}.tar.gz |
| 202 | + sha256: 0d5fe9189a148acc3c3eb2ac8e1ac0742cb7618c084f3d228baaec0c254b318d |
| 203 | +
|
| 204 | +build: |
| 205 | + skip: True # [py27] |
| 206 | + number: 1 |
| 207 | + script: "{{ PYTHON }} setup.py install --single-version-externally-managed --record record.txt" |
| 208 | + entry_points: |
| 209 | + - py.test = py.test:main |
| 210 | + - pytest = py.test:main |
| 211 | +
|
| 212 | +requirements: |
| 213 | + host: |
| 214 | + - pip |
| 215 | + - python |
| 216 | + - setuptools >=40.0 |
| 217 | + - setuptools_scm |
| 218 | + run: |
| 219 | + - atomicwrites >=1.0 # [win] |
| 220 | + - attrs >=17.4.0 |
| 221 | + - colorama # [win] |
| 222 | + - importlib_metadata >=0.12 # [py<38] |
| 223 | + - more-itertools >=4.0 |
| 224 | + - packaging |
| 225 | + - pathlib2 >=2.2.0 # [py<36] |
| 226 | + - pluggy >=0.12,<1.0 |
| 227 | + - py >=1.5.0 |
| 228 | + - python |
| 229 | + - setuptools >=40.0 |
| 230 | + - wcwidth |
| 231 | + run_constrained: |
| 232 | + # pytest-faulthandler 2 is a dummy package. |
| 233 | + # if an older version of fault-handler is installed, it will conflict with pytest >=5. |
| 234 | + - pytest-faulthandler >=2 |
| 235 | +
|
| 236 | +test: |
| 237 | + commands: |
| 238 | + - pytest -h |
| 239 | + imports: |
| 240 | + - pytest |
| 241 | +
|
| 242 | +about: |
| 243 | + home: https://docs.pytest.org/en/latest/ |
| 244 | + license: MIT |
| 245 | + license_file: LICENSE |
| 246 | + summary: 'Simple and powerful testing with Python.' |
| 247 | + description: | |
| 248 | + The pytest framework makes it easy to write small tests, yet scales to |
| 249 | + support complex functional testing for applications and libraries. |
| 250 | + doc_url: https://docs.pytest.org/en/latest/ |
| 251 | + dev_url: https://github.com/pytest-dev/pytest/ |
| 252 | +
|
| 253 | +extra: |
| 254 | + recipe-maintainers: |
| 255 | + - flub |
| 256 | + - goanpeca |
| 257 | + - nicoddemus |
| 258 | + - ocefpaf |
| 259 | + - mingwandroid |
| 260 | +``` |
| 261 | + |
| 262 | +### Major differences |
| 263 | + |
| 264 | +| Attribute | Grayskull (0.2.1) | Skeleton (3.18.11) | |
| 265 | +| --------- | ----------------- | ------------------ | |
| 266 | + **Command** | ✅ grayskull pypi pytest | ✅ conda skeleton pypi pytest | |
| 267 | + **Time** | ✅ 4 seconds | ❌ 31 seconds | |
| 268 | + **License** | ✅ Added the license file and license type correctly | ❗️ Added just the license type | |
| 269 | + **Host Requirements** | ✅ Added correctly all the host requirements | ❌ it didn't add the correctly the host dependencies. It added unnecessary dependencies and it is missing quite a few of them necessary to build the package | |
| 270 | + **Run Requirements** | ✅ Missing just setuptools from the host requirements (but this dependency is not defined on pytest package) | ❌ incorrect dependencies added to the project | |
| 271 | + **Selectors** | ✅ Skipping correctly Python 2 and added selectors for windows and python versions | ❌ it didn't add any information regarding selectors. Actually conda-build added wrong information which will result in a broken recipe. For example 'sys_platform == win32' was added which is a wrong format for conda recipes | |
| 272 | + **Entry points** | ✅ Added all entry points correctly | ❌ No entry points | |
| 273 | + **Does it build?** | ✅ YES | ❌ NO | |
| 274 | + |
| 275 | +In the case of `noarch: python`, Grayskull is smart enough to detect |
| 276 | +when the recipe supports it, which is not done by Skeleton. It is |
| 277 | +important to highlight that Skeleton does not detect compilers as well. |
| 278 | +Nevertheless, Grayskull always try to detect it. |
| 279 | + |
| 280 | +## Usage Grayskull (0.2.1) |
| 281 | + |
| 282 | +Project options: |
| 283 | + |
| 284 | +```bash |
| 285 | +$ grayskull --help |
| 286 | +usage: grayskull [-h] [--version] {pypi} ... |
| 287 | +
|
| 288 | +Grayskull - Conda recipe generator |
| 289 | +
|
| 290 | +positional arguments: |
| 291 | +{pypi} Options to generate PyPI recipes |
| 292 | +pypi Generate recipes based on PyPI |
| 293 | +
|
| 294 | +optional arguments: |
| 295 | +-h, --help show this help message and exit |
| 296 | +--version, -v Print Grayskull version and exit |
| 297 | +``` |
| 298 | + |
| 299 | +```bash |
| 300 | +$ grayskull pypi --help |
| 301 | +usage: grayskull pypi [-h] [--maintainers MAINTAINERS [MAINTAINERS...]] |
| 302 | +[--output OUTPUT] |
| 303 | +pypi_packages [pypi_packages ...] |
| 304 | +
|
| 305 | +positional arguments: |
| 306 | +pypi_packages Specify the PyPI package name. |
| 307 | +
|
| 308 | +optional arguments: |
| 309 | +-h, --help show this help message and exit |
| 310 | +--maintainers MAINTAINERS [MAINTAINERS ...], -m MAINTAINERS [MAINTAINERS...] List of maintainers which will be added to the recipe. |
| 311 | +--output OUTPUT, -o OUTPUT Path to where the recipe will be created |
| 312 | +``` |
| 313 | + |
| 314 | +To generate the recipe you can just call `grayskull` and pass the |
| 315 | +channel (as for now we are just supporting PyPI, it should be pypi) and |
| 316 | +the package name. You should also specify an output folder using the |
| 317 | +option `--output` or `-o` and it will create the package folder, and the |
| 318 | +recipe in there. It is important to note that the user can specify a |
| 319 | +list of maintainers which will be added to the recipe using the option |
| 320 | +`--maintainers`. |
| 321 | + |
| 322 | +Example for pytest: |
| 323 | + |
| 324 | + |
| 325 | + |
| 326 | +If you need to specify the package version you can do it just puting the |
| 327 | +equal sign after the package name and the version just right after that. |
| 328 | +Example: |
| 329 | + |
| 330 | +```bash |
| 331 | +grayskull pypi requests=2.21.0 |
| 332 | +``` |
| 333 | + |
| 334 | +or |
| 335 | + |
| 336 | +```bash |
| 337 | +grayskull pypi requests==2.21.0 |
| 338 | +``` |
| 339 | + |
| 340 | + |
| 341 | + |
| 342 | +If you want to generate multiple recipes just pass a list of packages, |
| 343 | +such as: |
| 344 | + |
| 345 | +```bash |
| 346 | +grayskul pypi pytest requests=2.21.0 colorama |
| 347 | +``` |
| 348 | + |
| 349 | +## Future plans |
| 350 | + |
| 351 | +> - For the next major version (1.0.0) it is planned to add the |
| 352 | +> functionality to be able to load the recipe and update just parts |
| 353 | +> of it; |
| 354 | +> - Generate Conda recipes using CRAN (R) channel (2.0.0); |
| 355 | +> - Generate Conda recipes using Conan (C++) channel (3.0.0); |
| 356 | + |
| 357 | +## Issues |
| 358 | + |
| 359 | +Any problem, question, suggestions please feel free to open an issue on |
| 360 | +the repository: <https://github.com/marcelotrevisani/grayskull/issues>. |
| 361 | + |
| 362 | +Contributions are very welcome! :) |
| 363 | + |
| 364 | +------------------------------------------------------------------------ |
| 365 | + |
| 366 | +This work was possible thanks to the [NumFOCUS](https://numfocus.org/) |
| 367 | +Small Development Grant program. |
0 commit comments