-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from Quansight-Labs/initial
Initial work
- Loading branch information
Showing
8 changed files
with
310 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
on: [push] | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- name: Set up Python ${{ matrix.python-version }} | ||
uses: actions/setup-python@v1 | ||
with: | ||
python-version: 3.8 | ||
- name: Install dependencies | ||
run: | | ||
python -m pip install --upgrade pip flit | ||
flit install --symlink | ||
- name: Lint with mypy | ||
run: | | ||
mypy beni | ||
- name: Test on self | ||
run: | | ||
beni pyproject.toml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.vscode | ||
.mypy_cache | ||
**/__pycache__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) 2020 Saul Shanabrook | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in | ||
all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
# `beni` | ||
|
||
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) | ||
|
||
> [Eunectes beniensis](https://en.wikipedia.org/wiki/Eunectes_beniensis) is a non-venomous boa species known only from the northeastern parts of Bolivia. | ||
> The four-metre long Eunectes beniensis was initially believed to be the result of **hybridization** between green and yellow anacondas, but was later determined to be a distinct species. The taxonomic status is not clear, due to lack of information and the appearance similarity to Eunectes notaeus. It is closely related to Eunectes notaeus and Eunectes deschauenseei. | ||
It's a light anaconda! So a mashup of [`flit`](https://github.com/takluyver/flit) and [`conda`](https://docs.conda.io/en/latest/). | ||
|
||
## What? | ||
|
||
This is a specific tool to fascilitate one workflow of using flit and conda together. The assumptions are: | ||
|
||
1. You have a repository with at least one Python package | ||
2. You use `flit` and `pyproject.toml` to describe your dependencies | ||
3. You want to use Conda to manage local development but you wanna release your package on PyPi. | ||
4. You want to generate an `environment.yml` for local development that will install as many of your Pypi dependencies through Conda as possible. | ||
|
||
Without this tool you have to manually keep your `environment.yml` up to date with all your `pyproject.toml` files, which is error prone and annoying! | ||
|
||
## Unsolved issues | ||
|
||
1. What if the conda forge name is different than the pypi name? We should keep a list of these mappings. | ||
2. How do we use the `pyproject.toml` to automatically generate a conda forge recipe? | ||
3. In the future could conda just read from the `pyproject.toml` file in some way to create an environment out of it? | ||
|
||
## Usage | ||
|
||
1. `pip install beni` | ||
2. Run `beni <path to pyproject.toml> [<another path to pyproject.tmo>] > binder/environment.yml` to generate an environment file. It adds all your requirements that are conda forge packages to this environment and names it after the first `pyproject.toml` module. | ||
each of your requirements to see if there is an equivalent conda forge package | ||
3. Add `conda env create -f bind/environment.yml && conda activate <module name> && flit install --symlink` to your README as the dev setup. | ||
|
||
## Example | ||
|
||
```bash | ||
$ beni -h | ||
usage: beni [-h] pyproject.toml or flit.ini [pyproject.toml or flit.ini ...] | ||
|
||
Generate a environment.yml. | ||
|
||
positional arguments: | ||
pyproject.toml or flit.ini | ||
a flit config file | ||
|
||
optional arguments: | ||
-h, --help show this help message and exit | ||
$ cat pyproject.toml | ||
[tool.flit.metadata] | ||
requires = [ | ||
"typing_extensions", | ||
"typing_inspect", | ||
"python-igraph=0.8.0" | ||
] | ||
requires-python = ">=3.7" | ||
[tool.flit.metadata.requires-extra] | ||
test = [ | ||
"pytest", | ||
"pytest-cov", | ||
"pytest-mypy", | ||
"pytest-randomly", | ||
"pytest-xdist", | ||
"pytest-testmon", | ||
"pytest-pudb", | ||
"mypy" | ||
] | ||
doc = [ | ||
"sphinx", | ||
"sphinx-autodoc-typehints", | ||
"sphinx_rtd_theme", | ||
'recommonmark', | ||
"nbsphinx", | ||
"ipykernel", | ||
"IPython", | ||
"sphinx-autobuild" | ||
] | ||
dev = [ | ||
"jupyterlab>=1.0.0", | ||
"nbconvert", | ||
"pudb" | ||
] | ||
$ beni pyproject.toml | ||
name: metadsl | ||
channels: | ||
- conda-forge | ||
dependencies: | ||
- python>=3.7 | ||
- pip | ||
- pip: | ||
- flit | ||
- typing_extensions | ||
- typing_inspect | ||
- python-igraph=0.8.0 | ||
- pytest | ||
- pytest-cov | ||
- pytest-mypy | ||
- pytest-randomly | ||
- pytest-xdist | ||
- pytest-testmon | ||
- pytest-pudb | ||
- mypy | ||
- jupyterlab>=1.0.0 | ||
- nbconvert | ||
- pudb | ||
``` | ||
|
||
## Development | ||
|
||
```bash | ||
conda env create -f environment.yml | ||
conda activate beni | ||
flit install --symlink | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
""" | ||
Generate environment.yml from pyproject.toml | ||
""" | ||
|
||
|
||
from __future__ import annotations | ||
|
||
import argparse | ||
import http.client | ||
import typing | ||
import tqdm | ||
import flit_core.inifile | ||
import typeguard | ||
import packaging.requirements | ||
import yaml | ||
|
||
__version__ = "0.1.0" | ||
|
||
parser = argparse.ArgumentParser(description="Generate a environment.yml.") | ||
parser.add_argument( | ||
"paths", | ||
metavar="pyproject.toml or flit.ini", | ||
type=str, | ||
nargs="+", | ||
help="a flit config file", | ||
) | ||
|
||
|
||
def is_conda_forge_package(name: str) -> bool: | ||
""" | ||
Checks if something is a conda forge package by hitting conda page. | ||
If 200 then package, if 302 then not. | ||
""" | ||
# Have to use http.client instead of urllib b/c no way to disable redirects | ||
# on urrlib and it's wasteful to follow (AFAIK) | ||
|
||
# Need user agent or else got unauthorized | ||
conn = http.client.HTTPSConnection("anaconda.org") | ||
conn.request("GET", f"/conda-forge/{name}/", headers={"User-Agent": "beni"}) | ||
r = conn.getresponse() | ||
conn.close() | ||
return r.status == 200 | ||
|
||
|
||
class Environment(typing.TypedDict): | ||
name: str | ||
channels: typing.List[str] | ||
dependencies: typing.List[typing.Union[str, typing.Dict[str, typing.List[str]]]] | ||
|
||
|
||
@typeguard.typechecked | ||
def generate_environment( | ||
name: str, | ||
python_version: typing.Optional[str], | ||
requirements: typing.List[packaging.requirements.Requirement], | ||
) -> Environment: | ||
dependencies = {"pip"} | ||
|
||
if python_version: | ||
dependencies.add(f"python{python_version}") | ||
else: | ||
dependencies.add("python") | ||
|
||
for r in tqdm.tqdm(requirements, desc="Checking packages"): | ||
if not is_conda_forge_package(r.name): | ||
continue | ||
dependencies.add(f"{r.name}{r.specifier}") | ||
|
||
return { | ||
"name": name, | ||
"channels": ["conda-forge"], | ||
"dependencies": [{"pip": ["flit"]}, *dependencies], | ||
} | ||
|
||
|
||
def main() -> None: | ||
args = parser.parse_args() | ||
python_version: typing.Optional[str] = None | ||
requires: typing.List[str] = [] | ||
own_modules: typing.List[str] = [] | ||
for path in tqdm.tqdm(args.paths, desc="Parsing configs"): | ||
c = flit_core.inifile.read_flit_config(path) | ||
own_modules.append(c.module) | ||
metadata = c.metadata | ||
if "requires_python" in metadata: | ||
python_version = metadata["requires_python"] | ||
if "requires_dist" in metadata: | ||
requires.extend(metadata["requires_dist"]) | ||
|
||
env = generate_environment( | ||
own_modules[0], | ||
python_version, | ||
[ | ||
packaging.requirements.Requirement(r) | ||
for r in requires | ||
if r not in own_modules | ||
], | ||
) | ||
print(yaml.dump(env)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
channels: | ||
- conda-forge | ||
dependencies: | ||
- pip: | ||
- flit | ||
- pyyaml | ||
- pip | ||
- ipython | ||
- toml | ||
- packaging | ||
- python>=3.8 | ||
- mypy | ||
- black | ||
- typeguard | ||
- tqdm | ||
name: beni | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
[mypy] | ||
python_version = 3.8 | ||
ignore_missing_imports = True | ||
warn_redundant_casts = True | ||
check_untyped_defs = True | ||
strict_equality = True | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
[build-system] | ||
requires = ["flit_core >=2,<3"] | ||
build-backend = "flit_core.buildapi" | ||
|
||
[tool.flit.metadata] | ||
module = "beni" | ||
author = "Saul Shanabrook" | ||
author-email = "s.shanabrook@gmail.com" | ||
home-page = "https://github.com/quansight-labs/beni" | ||
classifiers = ["License :: OSI Approved :: MIT License"] | ||
requires = [ | ||
"toml", | ||
"pyyaml", | ||
"typeguard", | ||
"packaging", | ||
"tqdm" | ||
] | ||
requires-python = ">=3.8" | ||
|
||
[tool.flit.metadata.requires-extra] | ||
dev = [ | ||
"black", | ||
"ipython", | ||
"mypy" | ||
] | ||
[tool.flit.scripts] | ||
beni = "beni:main" |