Commit f5563b82 authored by Paul McCarthy's avatar Paul McCarthy 🚵
Browse files

Merge branch 'enh/settings_set_use' into 'master'

Enh/settings set use

See merge request fsl/fslpy!66
parents a37e0499 f7427452
Pipeline #2623 canceled with stages
#!/usr/bin/env bash
set -e
name=$1
version=$2
# add any extra channels that are needed
for channel in $FSL_CONDA_CHANNELS; do
conda config --append channels $channel
done
# make sure to update fundamental
# packages from the default channel
conda update --yes -c defaults -n base conda
conda install --yes -c defaults -n base setuptools conda-build
# insert project name/version into meta.yaml
echo "{% set name = '$name' %}" > vars.txt
echo "{% set version = '$version' %}" >> vars.txt
cat vars.txt .conda/meta.yaml > tempfile
mv tempfile .conda/meta.yaml
rm vars.txt
mkdir -p dist/conda-bld
conda build --output-folder=dist/conda-bld .conda
# Make sure package is installable
for pyver in 2.7 3.4 3.5 3.6; do
conda create -y --name "test$pyver" python=$pyver
source activate test$pyver
conda install -y -c file://`pwd`/dist/conda-bld $name
source deactivate
done
#!/usr/bin/env bash
set -e
rsync -rv dist/conda-bld/ --exclude 'repodata*' --exclude "*json" "condadeploy:"
ssh condaindex
python:
- 3.6
\ No newline at end of file
{% set data = load_setup_py_data() %}
package:
name: fslpy
version: {{ data['version']}}
build:
noarch: python
script: python setup.py install --single-version-externally-managed --record=record.txt
source:
path: ../
requirements:
build:
- python {{ python }}
- setuptools
{% for package in data.get('setup_requires', {}) %}
- {{ package.lower() }}
{% endfor %}
run:
- python
{% for package in data.get('install_requires', {}) %}
- {{ package.lower() }}
{% endfor %}
run_constrained:
{% for name, pkgs in data.get('extras_require', dict()).items() %}
{% for package in pkgs %}
- {{ package.lower() }}
{% endfor %}
{% endfor %}
{% if 'test_suite' in data %}
test:
requires:
{% for package in data.get('setup_requires', {}) %}
- {{ package.lower() }}
{% endfor %}
source_files:
- {{ data['test_suite'] }}
commands:
- python -m pytest {{ data['test_suite'] }} -m "not (fsltest or wxtest or dicomtest or meshtest or igziptest or noroottest or longtest)"
{% endif %}
about:
license_file: LICENSE
if [ -e ${FSLDIR}/etc/fslconf/requestFSLpythonLink.sh ]; then
$FSLDIR/etc/fslconf/requestFSLpythonLink.sh atlasquery atlasq imcp immv imglob extract_noise
fi
if [ -e ${FSLDIR}/etc/fslconf/requestFSLpythonUnlink.sh ]; then
$FSLDIR/etc/fslconf/requestFSLpythonUnlink.sh atlasquery atlasq imcp immv imglob
fi
......@@ -11,7 +11,7 @@
#
# 3. doc: Building API documentation
#
# 4. build: Building source, wheel and conda distributions
# 4. build: Building source and wheel distributions
#
# 5. deploy: Uploading the build outputs to pypi/hosting servers, and the
# documentation to a hosting server.
......@@ -64,12 +64,6 @@ stages:
# - SSH_PRIVATE_KEY_DOC_DEPLOY - private key for rsyncing documentation
# to remote host (DOC_HOST)
#
# - SSH_PRIVATE_KEY_CONDA_DEPLOY - private key for rsyncing conda builds
# to remote host (CONDA_HOST)
#
# - SSH_PRIVATE_KEY_CONDA_INDEX - private key for updating conda channel
# (on CONDA_HOST)
#
# - SSH_SERVER_HOSTKEYS - List of trusted SSH hosts
#
# - DOC_HOST: - Username@host to upload documentation to
......@@ -78,12 +72,6 @@ stages:
# - FSL_HOST: - Username@host to download FSL data from
# (e.g. "paulmc@jalapeno.fmrib.ox.ac.uk")
#
# - CONDA_HOST: - Username@host to upload conda build to
# (e.g. "paulmc@jalapeno.fmrib.ox.ac.uk")
#
# - CONDA_CHANNELS - List of additional conda channels to
# use for conda build.
#
# - TWINE_USERNAME: - Username to use when uploading to pypi
#
# - TWINE_PASSWORD: - Password to use when uploading to pypi
......@@ -244,25 +232,6 @@ build-pypi-dist:
- dist/*
build-conda-dist:
<<: *only_releases
<<: *patch_version
stage: build
image: continuumio/miniconda3
tags:
- docker
script:
- bash ./.ci/build_conda_dist.sh fslpy "$CI_COMMIT_REF_NAME"
artifacts:
expire_in: 1 day
paths:
- dist/conda-bld
##############
# Deploy stage
##############
......@@ -300,21 +269,3 @@ deploy-pypi:
script:
- bash ./.ci/deploy_pypi.sh
deploy-conda:
<<: *only_releases
<<: *setup_ssh
stage: deploy
when: manual
image: python:3.5
tags:
- docker
dependencies:
- build-conda-dist
script:
- bash ./.ci/deploy_conda.sh
Paul McCarthy <pauldmccarthy@gmail.com>
Michiel Cottaar <michiel.cottaar@ndcn.ox.ac.uk>
Matthew Webster <matthew.webster@ndcn.ox.ac.uk>
Sean Fitzgibbon <sean.fitzgibbon@ndcn.ox.ac.uk>
\ No newline at end of file
Sean Fitzgibbon <sean.fitzgibbon@ndcn.ox.ac.uk>
Martin Craig <martin.craig@eng.ox.ac.uk>
\ No newline at end of file
......@@ -2,6 +2,26 @@ This document contains the ``fslpy`` release history in reverse chronological
order.
1.11.0 (Thursday September 13th 2018)
-------------------------------------
Added
^^^^^
* A couple of new convenience functions to the :mod:`.settings` module.
Changed
^^^^^^^
* Development (test and documentation dependencies) are no longer listed
in ``setup.py`` - they now need to be installed manually.
* Removed conda build infrastructure.
1.10.3 (Sunday September 9th 2018)
----------------------------------
......
......@@ -11,6 +11,9 @@ fslpy
.. image:: https://img.shields.io/pypi/v/fslpy.svg
:target: https://pypi.python.org/pypi/fslpy/
.. image:: https://anaconda.org/conda-forge/fslpy/badges/version.svg
:target: https://anaconda.org/conda-forge/fslpy
The ``fslpy`` project is a `FSL <http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/>`_
programming library written in Python. It is used by `FSLeyes
......@@ -26,6 +29,11 @@ Install ``fslpy`` and its core dependencies via pip::
pip install fslpy
``fslpy`` is also available on `conda-forge <https://conda-forge.org/>`_::
conda install -c conda-forge fslpy
Dependencies
------------
......@@ -36,16 +44,16 @@ All of the core dependencies of ``fslpy`` are listed in the `requirements.txt
Some extra dependencies are listed in `requirements.txt
<requirements-extra.txt>`_ which provide addditional functionality:
- ``wxPython``: The `fsl.utils.idle <fsl/utils/idle.py>`_ module has
functionality to schedule functions on the ``wx`` idle loop.
- ``wxPython``: The `fsl.utils.idle <fsl/utils/idle.py>`_ module has
functionality to schedule functions on the ``wx`` idle loop.
- ``indexed_gzip``: The `fsl.data.image.Image <fsl/data/image.py>`_ class
can use ``indexed_gzip`` to keep large compressed images on disk instead
of decompressing and loading them into memory..
- ``indexed_gzip``: The `fsl.data.image.Image <fsl/data/image.py>`_ class
can use ``indexed_gzip`` to keep large compressed images on disk instead
of decompressing and loading them into memory..
- ``trimesh``/``rtree``: The `fsl.data.mesh.TriangleMesh <fsl/data/mesh.py>`_
class has some methods which use ``trimesh`` to perform geometric queries
on the mesh.
- ``trimesh``/``rtree``: The `fsl.data.mesh.TriangleMesh <fsl/data/mesh.py>`_
class has some methods which use ``trimesh`` to perform geometric queries
on the mesh.
If you are using Linux, need to install wxPython first, as binaries are not
......@@ -64,33 +72,43 @@ the rest of the extra dependencies::
pip install fslpy[extras]
Dependencies for testing and documentation are listed in the
`requirements-dev.txt <requirements-dev.txt>`_ file.
Documentation
-------------
``fslpy`` is documented using `sphinx <http://http://sphinx-doc.org/>`_. You
can build the API documentation by running::
pip install -r requirements-dev.txt
python setup.py doc
The HTML documentation will be generated and saved in the ``doc/html/``
directory.
If you are interested in contributing to ``fslpy``, check out the
`contributing guide <doc/contributing.rst>`_.
Tests
-----
Run the test suite via::
pip install -r requirements-dev.txt
python setup.py test
A test report will be generated at ``report.html``, and a code coverage report
will be generated in ``htmlcov/``.
Contributing
------------
If you are interested in contributing to ``fslpy``, check out the
`contributing guide <doc/contributing.rst>`_.
Credits
-------
......
......@@ -25,6 +25,16 @@ the following functions can be called at the module-level:
Settings.clear
Some functions are also available to replace the module-level :class:`Settings`
instance:
.. autosummary::
:nosignatures:
set
use
These functions will have no effect before :func:`initialise` is called.
Two types of configuration data are available:
......@@ -67,15 +77,9 @@ storing configuration files.
"""
def initialise(*args, **kwargs):
"""Initialise the ``settings`` module. This function creates a
:class:`Settings` instance, and enables the module-level
functions. All settings are passed through to :meth:`Settings.__init__`.
"""
mod = sys.modules[__name__]
settings = Settings(*args, **kwargs)
def set(settings):
"""Set the module-level :class:`Settings` instance. """
mod = sys.modules[__name__]
mod.settings = settings
mod.read = settings.read
mod.write = settings.write
......@@ -89,6 +93,31 @@ def initialise(*args, **kwargs):
mod.clear = settings.clear
def initialise(*args, **kwargs):
"""Initialise the ``settings`` module. This function creates a
:class:`Settings` instance, and enables the module-level
functions. All settings are passed through to :meth:`Settings.__init__`.
"""
set(Settings(*args, **kwargs))
@contextlib.contextmanager
def use(settings):
"""Temporarily replace the module-level :class:`Settings` object
with the given one.
"""
mod = sys.modules[__name__]
old = getattr(mod, 'settings', None)
try:
set(settings)
yield
finally:
if old is not None:
set(old)
# These are all overwritten by
# the initialise function.
def read(name, default=None):
......@@ -391,7 +420,7 @@ class Settings(object):
try:
with open(configFile, 'wb') as f:
pickle.dump(config, f, protocol=2)
except (IOError, pickle.PicklingError, EOFError):
except (FileNotFoundError, IOError, pickle.PicklingError, EOFError):
log.warning('Unable to save {} configuration file '
'{}'.format(self.__configID, configFile),
exc_info=True)
......@@ -23,10 +23,6 @@ basedir = op.dirname(__file__)
with open(op.join(basedir, 'requirements.txt'), 'rt') as f:
install_requires = [l.strip() for l in f.readlines()]
# Development/test dependencies are listed in requirements-dev.txt
with open(op.join(basedir, 'requirements-dev.txt'), 'rt') as f:
dev_requires = [l.strip() for l in f.readlines()]
# Optional dependencies are listed in requirements-extra.txt
with open(op.join(basedir, 'requirements-extra.txt'), 'rt') as f:
extra_requires = {'extras' : [l.strip() for l in f.readlines()]}
......@@ -116,7 +112,6 @@ setup(
install_requires=install_requires,
extras_require=extra_requires,
setup_requires=dev_requires,
test_suite='tests',
......
......@@ -23,6 +23,7 @@ import pytest
import tests
import fsl.utils.settings as settings
import fsl.utils.tempdir as tempdir
def test_initialise():
......@@ -431,3 +432,88 @@ def test_writeConfigFile():
with open(op.join(testdir, 'config.pkl'), 'rb') as f:
readback = pickle.load(f)
assert testdata == readback
def test_set():
with tempdir.tempdir(changeto=False) as td1,\
tempdir.tempdir(changeto=False) as td2:
s1 = settings.Settings(cfgdir=td1, writeOnExit=False)
s2 = settings.Settings(cfgdir=td2, writeOnExit=False)
settings.set(s1)
with settings.writeFile('file1') as f:
f.write('hi!')
assert os.listdir(td1) == ['file1']
assert os.listdir(td2) == []
settings.set(s2)
with settings.writeFile('file2') as f:
f.write('hi!')
assert os.listdir(td1) == ['file1']
assert os.listdir(td2) == ['file2']
settings.set(s1)
with settings.writeFile('file3') as f:
f.write('hi!')
assert sorted(os.listdir(td1)) == ['file1', 'file3']
assert os.listdir(td2) == ['file2']
settings.set(s2)
with settings.writeFile('file4') as f:
f.write('hi!')
assert sorted(os.listdir(td1)) == ['file1', 'file3']
assert sorted(os.listdir(td2)) == ['file2', 'file4']
def test_use():
with tempdir.tempdir(changeto=False) as td1,\
tempdir.tempdir(changeto=False) as td2:
s1 = settings.Settings(cfgdir=td1, writeOnExit=False)
s2 = settings.Settings(cfgdir=td2, writeOnExit=False)
with settings.use(s1):
with settings.writeFile('file1') as f:
f.write('hi!')
assert os.listdir(td1) == ['file1']
assert os.listdir(td2) == []
with settings.use(s2):
with settings.writeFile('file2') as f:
f.write('hi!')
settings.set(s1)
with settings.writeFile('file3') as f:
f.write('hi!')
with settings.use(s2):
with settings.writeFile('file4') as f:
f.write('hi!')
assert sorted(os.listdir(td1)) == ['file1', 'file3']
assert sorted(os.listdir(td2)) == ['file2', 'file4']
# should go back to s1
with settings.writeFile('file5') as f:
f.write('hi!')
assert sorted(os.listdir(td1)) == ['file1', 'file3', 'file5']
assert sorted(os.listdir(td2)) == ['file2', 'file4']
try:
with settings.use(s2):
raise Exception('hur')
except Exception:
pass
# should go back to s1
with settings.writeFile('file6') as f:
f.write('hi!')
assert sorted(os.listdir(td1)) == ['file1', 'file3', 'file5', 'file6']
assert sorted(os.listdir(td2)) == ['file2', 'file4']
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment