#hide
# default_exp conda
Pure python packages created from nbdev settings.ini
#export
from fastcore.script import *
from fastcore.all import *
from fastrelease.core import find_config
import yaml,subprocess
from copy import deepcopy
try: from packaging.version import parse
except ImportError: from pip._vendor.packaging.version import parse
_PYPI_URL = 'https://pypi.org/pypi/'
#export
def pypi_json(s):
"Dictionary decoded JSON for PYPI path `s`"
return urljson(f'{_PYPI_URL}{s}/json')
#export
def latest_pypi(name):
"Latest version of `name` on pypi"
return max(parse(r) for r,o in pypi_json(name)['releases'].items()
if not parse(r).is_prerelease and not o[0]['yanked'])
#export
def _pip_conda_meta(name, path):
ver = str(latest_pypi('sentencepiece'))
pypi = pypi_json(f'{name}/{ver}')
info = pypi['info']
rel = [o for o in pypi['urls'] if o['packagetype']=='sdist'][0]
reqs = ['pip', 'python', 'packaging']
# Work around conda build bug - 'package' and 'source' must be first
d1 = {
'package': {'name': name, 'version': ver},
'source': {'url':rel['url'], 'sha256':rel['digests']['sha256']}
}
d2 = {
'build': {'number': '0', 'noarch': 'python',
'script': '{{ PYTHON }} -m pip install . -vv'},
'test': {'imports': [name]},
'requirements': {'host':reqs, 'run':reqs},
'about': {'license': info['license'], 'home': info['project_url'], 'summary': info['summary']}
}
return d1,d2
#export
def _write_yaml(path, name, d1, d2):
path = Path(path)
p = path/name
p.mkdir(exist_ok=True, parents=True)
yaml.SafeDumper.ignore_aliases = lambda *args : True
with (p/'meta.yaml').open('w') as f:
yaml.safe_dump(d1, f)
yaml.safe_dump(d2, f)
#export
def write_pip_conda_meta(name, path='conda'):
"Writes a `meta.yaml` file for `name` to the `conda` directory of the current directory"
_write_yaml(path, name, *_pip_conda_meta(name))
#export
def _get_conda_meta():
cfg,cfg_path = find_config()
name,ver = cfg.get('lib_name'),cfg.get('version')
url = cfg.get('doc_host') or cfg.get('git_url')
reqs = ['pip', 'python', 'packaging']
if cfg.get('requirements'): reqs += cfg.get('requirements').split()
if cfg.get('conda_requirements'): reqs += cfg.get('conda_requirements').split()
pypi = pypi_json(f'{name}/{ver}')
rel = [o for o in pypi['urls'] if o['packagetype']=='sdist'][0]
# Work around conda build bug - 'package' and 'source' must be first
d1 = {
'package': {'name': name, 'version': ver},
'source': {'url':rel['url'], 'sha256':rel['digests']['sha256']}
}
d2 = {
'build': {'number': '0', 'noarch': 'python',
'script': '{{ PYTHON }} -m pip install . -vv'},
'requirements': {'host':reqs, 'run':reqs},
'test': {'imports': [cfg.get('lib_path')]},
'about': {
'license': 'Apache Software',
'license_family': 'APACHE',
'home': url, 'doc_url': url, 'dev_url': url,
'summary': cfg.get('description')
},
'extra': {'recipe-maintainers': [cfg.get('user')]}
}
return name,d1,d2
#export
def write_conda_meta(path='conda'):
"Writes a `meta.yaml` file to the `conda` directory of the current directory"
_write_yaml(path, *_get_conda_meta())
This function is used in the fastrelease_conda_package
CLI command.
NB: you need to first of all upload your package to PyPi, before creating the conda package.
#export
@call_parse
def fastrelease_conda_package(path:Param("Path where package will be created", str)='conda',
do_build:Param("Run `conda build` step", bool_arg)=True,
build_args:Param("Additional args (as str) to send to `conda build`", str)='',
do_upload:Param("Run `anaconda upload` step", bool_arg)=True,
upload_user:Param("Optional user to upload package to")=None):
"Create a `meta.yaml` file ready to be built into a package, and optionally build and upload it"
write_conda_meta(path)
cfg,cfg_path = find_config()
out = f"Done. Next steps:\n```\`cd {path}\n"""
name,lib_path = cfg.get('lib_name'),cfg.get('lib_path')
out_upl = f"anaconda upload build/noarch/{lib_path}-{cfg.get('version')}-py_0.tar.bz2"
if not do_build:
print(f"{out}conda build .\n{out_upl}\n```")
return
os.chdir(path)
res = run(f"conda build --output-folder build {build_args} {name}")
if 'anaconda upload' not in res:
print(f"{res}\n\Build failed.")
return
upload_str = re.findall('(anaconda upload .*)', res)[0]
if upload_user: upload_str = upload_str.replace('anaconda upload ', f'anaconda upload -u {upload_user} ')
res = run(upload_str)
To build and upload a conda package, cd to the root of your repo, and then:
fastrelease_conda_package
Or to do things more manually:
fastrelease_conda_package --do_build false
cd conda
conda build {name}
anaconda upload $CONDA_PREFIX/conda-bld/noarch/{name}-{ver}-*.tar.bz2
Add --debug
to the conda build command
to debug any problems that occur. Note that the build step takes a few minutes. Add -u {org_name}
to the anaconda upload
command if you wish to upload to an organization, or pass upload_user
to fastrelease_conda_package
.
NB: you need to first of all upload your package to PyPi, before creating the conda package.
#hide
from nbdev.export import notebook2script
notebook2script()
Converted 00_core.ipynb. Converted 01_conda.ipynb. Converted index.ipynb.