Skip to content
Snippets Groups Projects
Commit a8cc63a0 authored by Paul McCarthy's avatar Paul McCarthy :mountain_bicyclist:
Browse files

Merge branch 'rf/multi_feedsrun' into 'master'

Rf/multi feedsrun

See merge request !16
parents fde555d5 ff24edba
No related branches found
No related tags found
1 merge request!16Rf/multi feedsrun
Pipeline #4535 passed
Showing
with 256 additions and 100 deletions
#!/bin/bash
set -e
pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
pytest
[run]
source = pyfeeds
[report]
omit =
pyfeeds/tests/*
......@@ -5,8 +5,9 @@
#
# The build pipeline comprises the following stages:
#
# 4. build: Building source and wheel distributions
# 5. deploy: Uploading the build outputs to pypi
# 1. test: Running unit tests
# 2. build: Building source and wheel distributions
# 3. deploy: Uploading the build outputs to pypi
#
# The build stage, and the remaining jobs in the deploy stage, are only
# executed on the upstream repository, and only for release tags.
......@@ -19,6 +20,7 @@
stages:
- test
- build
- deploy
......@@ -27,15 +29,15 @@ stages:
# A number of variables must be set for the jobs to work. The following
# variables are implicitly defined in any gitlab CI job:
#
# - CI_PROJECT_PATH - gitlab namespace/project
# - CI_COMMIT_REF_NAME - branch name, provided by gitlab
# - CI_COMMIT_TAG - present if build is running on a tag
# - CI_PROJECT_PATH - gitlab namespace/project
# - CI_COMMIT_REF_NAME - branch name, provided by gitlab
# - CI_COMMIT_TAG - present if build is running on a tag
#
# - TWINE_USERNAME: - Username to use when uploading to pypi
# - TWINE_USERNAME: - Username to use when uploading to pypi
#
# - TWINE_PASSWORD: - Password to use when uploading to pypi
# - TWINE_PASSWORD: - Password to use when uploading to pypi
#
# - TWINE_REPOSITORY_URL: - Pypi repository to upload to
# - TWINE_REPOSITORY_URL: - Pypi repository to upload to
###############################################################################
......@@ -49,6 +51,42 @@ variables:
- tags@fsl/pyfeeds
.except_releases: &except_releases
except:
- tags
############
# Test stage
############
.test: &test_template
# Releases are just tags on a release
# branch, so we don't need to test them.
<<: *except_releases
stage: test
tags:
- docker
script:
- bash ./.ci/unit_tests.sh
test:3.6:
image: python:3.6
<<: *test_template
test:3.7:
image: python:3.7
<<: *test_template
#############
# Build stage
#############
......
......@@ -2,6 +2,34 @@
=====================
0.9.0 (Monday 30th September 2019)
----------------------------------
* Test directories may now contain multiple ``feedsRun`` scripts - test
scripts must have a name of the form ``feedsRun[.suffix]``.
* The output data for nested tests is now organised in the same way as the
tests themselves. For example, the output data for a test called
``tests/subtests/test1/feedsRun`` will now be stored in
``outoput/subtests/test1/``, instead of ``output/subtests_test1/``.
* New ``--forceHashes`` option, to force calculation of test data hashes, even
if the file modification times suggest that the data has not changed.
* Changed command line interface - there are no longer any "global" options
(i.e. ``pyfeeds [global_options] command``). Instead, all options must
come after the ``command``.
* The ``--inputDir`` and ``--benchmarkDir`` arguments to ``run``, ``bundle``,
``genhash`` and ``checkhash`` are now optional.
* If no test directories are specified on the command line, the current
directory is searched for tests.
* Removed the ``--skipInputDir`` and ``--skipBenchmarkDir`` arguments to the
``bundle`` command.
* Changed the short form of the ``--cacheSize`` argument from ``-s`` to
``-cs``.
* Changed the ``compare`` command-line interface - the input and benchmark
directories are now positional. If the ``--outputFile`` argument is not
provided, the results are printed to standard output.
0.8.1 (Tuesday 24th September 2019)
-----------------------------------
......
......@@ -2,7 +2,7 @@
[![PyPi version](https://img.shields.io/pypi/v/fsl-pyfeeds.svg)](https://pypi.python.org/pypi/fsl-pyfeeds/) [![Anaconda version](https://anaconda.org/conda-forge/fsl-pyfeeds/badges/version.svg)](https://anaconda.org/conda-forge/fsl-pyfeeds/)
[![Coverage report](https://git.fmrib.ox.ac.uk/fsl/pyfeeds/badges/master/coverage.svg)](https://git.fmrib.ox.ac.uk/fsl/pyfeeds/commits/master)
## The FSL Evaluation and Example Data Suite (FEEDS), now in Python!
......@@ -46,3 +46,6 @@ Use the following commands to run the tests:
-i exampleInputData \
-b exampleBenchmarkData \
-o exampleOutput examples
| Note that the FEAT example test may not pass for you, as different versions
| of FSL may produce slightly different results.
......@@ -5,6 +5,7 @@
* [Excluding files](#excluding-files)
* [Specifying tolerances](#specifying-tolerances)
* [Self-evaluating tests](#self-evaluating-tests)
* [`pyfeeds` configuration file](#pyfeeds-configuration-file)
---
......@@ -169,4 +170,4 @@ rather than on the command-line. A `pyfeeds` configuration file is an
The [`examplePyfeedsConfig`](./examplePyfeedsConfig) file is an example of a
typical `pyfeeds` configuration file.
\ No newline at end of file
typical `pyfeeds` configuration file.
......@@ -3,19 +3,20 @@
* [Test directories](#test-directories)
* [External/shared data](#externalshared-data)
* [Test bundles](#test-bundles)
* [Tracking changes to tests](#tracking-changes-to-tests-and-data)
* [Tracking changes to tests and data](#tracking-changes-to-tests-and-data)
## Test directories
`pyfeeds` expects to be provided with one or more input directories, in which a
set of tests are contained. These tests can be located anywhere within the
`pyfeeds` expects to be provided with one or more input directories, in which
a set of tests are contained. These tests can be located anywhere within the
input directory, i.e. nested arbitrarily deep within the input directory
tree. However, each test must be contained within its own sub-directory. Each
test sub-directory may contain data, libraries, code, etc, but must contain an
executable file called `feedsRun`. For example, a typical `pyfeeds` test directory
might look like this:
executable file called `feedsRun`, or multiple executable files, each with a
different suffix, e.g. `feedsRun.test1`, `feedsRun.test2`, etc. For example,
a typical `pyfeeds` test directory might look like this:
```
......@@ -30,7 +31,7 @@ $
Each `feedsRun` script is executed with the following parameters (see the page
on [Writing a test] (writing_a_test.md) for an overview of the parameters):
on [Writing a test](writing_a_test.md) for an overview of the parameters):
```
......@@ -125,8 +126,8 @@ The `pyfeeds` `bundle` command is used to extract all detected tests and copy
them, and their external data dependencies, into a new directory - a
*bundle*. This is useful if you want to create a sub-set of *standalone* tests
to be executed in another location. A bundle is standalone because the
`bundle` command creates a copy of all of the shared data that is required by
the tests included in the bundle.
`bundle` command creates a copy of all of the input and benchmark data that is
required by the tests included in the bundle.
When you use the `bundle` command, you must specify a directory in which the
......@@ -135,11 +136,16 @@ all FLIRT-related tests:
```
$ feeds bundle -d exampleSharedData -o myBundle examples/flirt examples/flirt_shared examples/nested/flirt
$ pyfeeds bundle -i exampleInputData \
-b exampleBenchmarkData \
-o myBundle \
examples/flirt \
examples/flirt_shared \
examples/nested/flirt
2015-11-26 15:30:36,608 INFO - Adding flirt to bundle...
2015-11-26 15:30:36,610 INFO - Adding flirt_shared to bundle...
2015-11-26 15:30:36,615 INFO - Adding nested_flirt to bundle...
2015-11-26 15:30:36,615 INFO - Adding nested/flirt to bundle...
$
```
......@@ -155,24 +161,35 @@ following structure:
```
$ ls myBundle
benchmarks/
data/
tests/
$
```
The `myBundle/data/` directory contains the shared data required by all of the
tests that have been included in the bundle. The `myBundle/tests/` directory
contains one sub-directory for every test included in the bundle; the directory
for each test is given a unique name, based upon its original location:
The `myBundle/data/` directory contains the input data required by all of the
tests that have been included in the bundle. The `myBundle/benchmarks/`
directory contains the benchmark data for each test. The `myBundle/tests/`
directory contains one sub-directory for every test included in the bundle;
the directory for each test is given a unique name, based upon its original
location:
```
$ ls myBundle/tests
myBundle/tests/flirt
myBundle/tests/flirt_shared
myBundle/tests/nested_flirt
$ tree myBundle/tests
bundle/tests
├── flirt
│ ├── feedsRun
│ ├── input.nii.gz
│ └── xform.mat
├── flirt_shared
│ ├── feedsInputs
│ └── feedsRun
└── nested
└── flirt
└── feedsRun
$
```
......@@ -182,29 +199,27 @@ So once you have created a bundle (e.g. ``myBundle``), you can run the tests
contained within with a command such as the following:
```
$ feeds run -d myBundle/data -o bundleTestOutput myBundle/tests
$ cd myBundle
$ pyfeeds run -i data -b benchmarks -o bundleTestOutput tests
```
## Tracking changes to tests and data
`pyfeeds` keeps track of changes to tests and to test data, and outputs a warning
when it detects that a test (or its data) has changed since it was last
executed. When `pyfeeds` runs a test, it calculates an MD5 digest upon the
contents of test directory; this digest is used as an identifier for the
test. For all tests with a `feedsInput` file, `pyfeeds` also calculates a MD5
digest upon all of the files and directories listed in `feedsInputs`. The
digests for each tests are stored in a file (called `.feedsHashes`, and
located in the `--dataDir` directory by default; a different location can be
specified via the `--hashFile` argument). This file looks something like the
following:
`pyfeeds` keeps track of changes to tests and to test data, and outputs a
warning when it detects that a test (or its data) has changed since it was
last executed. When `pyfeeds` runs a test, it calculates an MD5 digest upon
the contents of test directory. For all tests with a `feedsInput` file,
`pyfeeds` also calculates a MD5 digest upon all of the files and directories
listed in `feedsInputs`. The digests for each test are stored in a file
(called `.feedsHashes`, and located in the `--inputDir` directory by default;
a different location can be specified via the `--hashFile` argument). This
file looks something like the following:
```
$ cat exampleSharedData/.feedsHashes
$ cat exampleInputData/.feedsHashes
db96c131504ba709dfe9a6c4af5c7a2a c1333ef13d031be5fc29365e34e551a2
d27e3cda6a2dc1c737fd014fddc5813b None
......@@ -221,21 +236,21 @@ $
The digests in the first column are those calculated upon each test directory,
and the digests in the second column are those calculated upon the input data
for each test. A value of `None` in the second column indicates that this
particular test does not depend upon any shared data. When a test is run, its
test and data digest values are calculated and compared against the digests
contained in the `.feedsHashes` file. If the digests do not match, a warning
is output, but the test is still executed.
particular test does not depend upon any external data. When a test is run,
its test and data digest values are calculated and compared against the
digests contained in the `.feedsHashes` file. If the digests do not match, a
warning is output, but the test is still executed.
---
The `pyfeeds` `genhash` command allows you to calculate the digests for a set of
The `pyfeeds genhash` command allows you to calculate the digests for a set of
tests:
```
$ feeds genhash -d exampleSharedData/ examples/
$ pyfeeds genhash -i exampleInputData/ examples/
Test verification hashes
......@@ -246,8 +261,8 @@ csv_data | 323e035aef25b6744c0dc18daec4b36e | None
feat | 06182094c1e82e46e0e6c2050c650ac6 | b3039335d985e68e11a44bb5e997f6db
flirt | d27e3cda6a2dc1c737fd014fddc5813b | None
flirt_shared | 0eaf79d5c4988e9686de808f5634cec6 | 7867f5598930ce992e6e5a0c49f44ea4
nested_flirt | 20b6f482c2cc64af2b800ac0f61a422f | None
nested_ntest1 | 20b6f482c2cc64af2b800ac0f61a422f | None
nested/flirt | 20b6f482c2cc64af2b800ac0f61a422f | None
nested/ntest1 | 20b6f482c2cc64af2b800ac0f61a422f | None
shared_data | db96c131504ba709dfe9a6c4af5c7a2a | c1333ef13d031be5fc29365e34e551a2
$
......@@ -261,12 +276,12 @@ in the same format as that of the `.feedsHashes` file described above.
---
The `pyfeeds` `checkhash` command allows you to verify a set of tests without
The `pyfeeds checkhash` command allows you to verify a set of tests without
running them:
```
$ feeds checkhash -d exampleSharedData/ examples/
$ pyfeeds checkhash -i exampleInputData/ examples/
Test verification results
......@@ -277,8 +292,8 @@ csv_data | Passed (test does not use any shared data)
feat | Passed
flirt | Passed (test does not use any shared data)
flirt_shared | Passed
nested_flirt | Passed (test does not use any shared data)
nested_ntest1 | Passed (test does not use any shared data)
nested/flirt | Passed (test does not use any shared data)
nested/ntest1 | Passed (test does not use any shared data)
shared_data | Passed
$
......
......@@ -14,6 +14,10 @@ test is simply a directory which contains an executable file called `feedsRun`
`pyfeeds` tests.
> A pyfeeds directory may alternately contain multiple `feedsRun` scripts, each
> with a different suffix (e.g. `feedsRun.test1`, `feedsRun.test2`, etc.
To get help on how to use `pyfeeds`, simply type `pyfeeds --help`. `pyfeeds`
has a number of commands which allow you to run and manage the tests that it
finds. To get help on one of these commands, type `pyfeeds <command> --help`.
......@@ -49,8 +53,8 @@ csv_data | /Projects/pyfeeds/examples/csv_data
feat | /Projects/pyfeeds/examples/feat
flirt | /Projects/pyfeeds/examples/flirt
flirt_shared | /Projects/pyfeeds/examples/flirt_shared
nested_flirt | /Projects/pyfeeds/examples/nested/flirt
nested_ntest1 | /Projects/pyfeeds/examples/nested/ntest1
nested/flirt | /Projects/pyfeeds/examples/nested/flirt
nested/ntest1 | /Projects/pyfeeds/examples/nested/ntest1
shared_data | /Projects/pyfeeds/examples/shared_data
$
......@@ -66,12 +70,13 @@ $
The `run` command runs all detected tests. You need to give `pyfeeds` the
following pieces of information:
- `-o`: Where to store the test outputs
- `-i`: The location of shared input data
- `-b`: The location of benchmark data to compare the test outputs against
- `-o`: Where to store the test outputs
If you are running tests which do not use any input data, or do not have any
benchmark data, you can pass in any directory for these options.
benchmark data, you do not need to provide those options.
```
$ pyfeeds run -i exampleInputData -b exampleBenchmarkData -o ./exampleOutput examples/
......@@ -82,8 +87,8 @@ $ pyfeeds run -i exampleInputData -b exampleBenchmarkData -o ./exampleOutput exa
2015-11-25 11:23:43,113 INFO - Running test feat ...
2015-11-25 11:26:46,354 INFO - Running test flirt ...
2015-11-25 11:26:46,706 INFO - Running test flirt_shared ...
2015-11-25 11:26:47,066 INFO - Running test nested_flirt ...
2015-11-25 11:26:47,071 INFO - Running test nested_ntest1 ...
2015-11-25 11:26:47,066 INFO - Running test nested/flirt ...
2015-11-25 11:26:47,071 INFO - Running test nested/ntest1 ...
2015-11-25 11:26:47,077 INFO - Running test shared_data ...
Test | Time (seconds) | Result | Data status
-------------------- | -------------- | ------ | -----------
......@@ -92,8 +97,8 @@ csv_data | 0 | Passed | No data
feat | 186 | Failed | Passed
flirt | 0 | Passed | No data
flirt_shared | 0 | Passed | Passed
nested_flirt | 0 | Passed | No data
nested_ntest1 | 0 | Passed | No data
nested/flirt | 0 | Passed | No data
nested/ntest1 | 0 | Passed | No data
shared_data | 0 | Passed | Passed
2016-04-06 18:33:05,657 INFO - 7 / 8 tests passed in 3.12 minutes
$
......@@ -156,7 +161,7 @@ results to the specified output file:
```
$ pyfeeds compare -b benchmark_output -i test_output -o results.txt
$ pyfeeds compare test_output benchmark_output -o results.txt
$
```
......
......@@ -13,17 +13,17 @@
A `pyfeeds` test is simply an executable file which is called `feedsRun`, and
which is contained within its own sub-directory. We recommend that you include
your `pyfeeds` tests alongside the source code for your project, in your
version control repository of choice (e.g. [git](https://git.fmrib.ox.ac.uk),
[CVS](http://cvs.fmrib.ox.ac.uk/cgi-bin/cvsweb.cgi), etc).
which is contained within its own sub-directory. The `feedsRun` file should be
an executable script, or binary, which runs a test. You can write your
`feedsRun` test in any language you like; you just need to make sure that it
[accepts three parameters](#test-input-parameters), and exits with a return
value of zero to indicate that the test passed, or non-zero to indicate that
the test failed.
The `feedsRun` file should be an executable script, or binary, which runs a
test. You can write your `feedsRun` test in any language you like; you just
need to make sure that it [accepts three parameters](#test-input-parameters),
and exits with a return value of zero to indicate that the test passed, or
non-zero to indicate that the test failed.
Instead of writing a single `feedsRun` script, you may also write multiple
`feedsRun` scripts, giving each of them a unique suffix,
e.g. `feedsRun.test1`, `feedsRun.test2`, etc.
If you need data to test your software, you can store it alongside your test,
......@@ -31,13 +31,24 @@ as long as it is not too large (more than a few MB). Or, your test may make
use of [shared data resources](#externalshared-data).
We recommend that you either:
- Include your `pyfeeds` tests alongside the source code for your project, in
your version control repository of choice
(e.g. [git](https://git.fmrib.ox.ac.uk),
[CVS](http://cvs.fmrib.ox.ac.uk/cgi-bin/cvsweb.cgi), etc).
- Add your tests to the
[pyfeeds-tests](https://git.fmrib.ox.ac.uk/fsl/pyfeeds-tests) repository.
## Writing a test
A `pyfeeds` test must be contained within its own sub-directory. This test
directory may contain data, libraries, code, etc, but above all else must
contain an executable file called `feedsRun`. As an example, let's consider
the `examples/flirt/` test:
contain an executable file called `feedsRun`, or multiple executables called
(e.g.) `feedsRun.a`, `feedsRun.b`, etc. . As an example, let's consider the
`examples/flirt/` test:
```
......@@ -152,12 +163,11 @@ test above, the `feedsRun` script assumes that its `input.nii.gz`,
For self-contained tests such as this (i.e. where all of the required test
data is stored in the test directory), you can completely ignore the data
directory (the third parameter passed to the test script). However, if your
directory (the second parameter passed to the test script). However, if your
test requires access to some large, shared data source, you must specify the
files and directories to which your test needs access. This can be done by
creating a plain text file in the test directory, called `feedsInputs`,
which simply contains a list of the files and directories that your test
needs.
creating a plain text file in the test directory, called `feedsInputs`, which
simply contains a list of the files and directories that your test needs.
The `examples/flirt_shared/` test is a modification of the `examples/flirt/`
......@@ -171,7 +181,7 @@ flirt/xform.mat
```
> The shared data directory will be made available in a known common location
> on our file system (e.g. `/vols/Data/fsldev/dataSets/flirt/`). In your
> on our file system (e.g. `/vols/Data/fsldev/dataSets/`). In your
> `feedsInputs` file, you must specify your data paths relative to this
> location, such as in the example paths above.
......@@ -221,7 +231,7 @@ A `pyfeeds` test is called with three parameters:
While `bash` is great for simple tests, there are some tasks which would
unweildy to write in `bash`. The `flirt_python` example provides a simple
unwieldy to write in `bash`. The `flirt_python` example provides a simple
example of a `pyfeeds` test written in Python:
......@@ -255,8 +265,8 @@ sp.call('flirt -in {} -ref {} -out {} -omat {}'.format(
All of these scripts can be found in [pyfeeds/examples/](examples/), along
with a few more examples. Shared and benchmark data (for those example scripts
which use it) can be respectively found in
[pyfeeds/exampleSharedData](exampleSharedData/) and
[pyfeeds/exampleBenchmarkdData](exampleBenchmarkData/).
[pyfeeds/exampleInputData](exampleInputData/) and
[pyfeeds/exampleBenchmarkData](exampleBenchmarkData/).
---
......@@ -346,7 +356,8 @@ exampleData/input.nii.gz
And the `feedsRun` script is as follows:
```python#!/usr/bin/env python
```python
#!/usr/bin/env python
#
# An example FEEDS test which loads some data from
# a shared data directory, and uses it to test an
......
mean: 0.5172000788656557
\ No newline at end of file
minmax: 0.0008378965646630432 0.9992247459171346
\ No newline at end of file
File added
56fccdd48f34f5fb776cb5bdf545ccde b518c53a55a3c2635d550805c6ffb3fd
53ff69fd2a26ec17aa341588ea1ef95b 0023f29fb56a3ff066569f846f046739
8b2f4d35272135a76e536ebcaaa5274b None
48d9c8c5bfb395399ce1dfb5f5df091e None
f58fb36443f10c40c7243d3c33154810 None
6297b119b9c42bd836c6b4c80bdc4b1b None
08694be2f77ef3b20758aa085b1afc83 b518c53a55a3c2635d550805c6ffb3fd
30585b0a503668a04215a5fb07e67765 None
4f8ca570bce0403e4ccc4f1969987307 bb83ea1c12a3231a79bc539775dcd472
83cdf1b8d1748dad546fc8e3bc1076d2 b518c53a55a3c2635d550805c6ffb3fd
57e2006a9225d1e96f35ca3558bbf525 None
452ee7b0ff61b474c2da96535c0c65ec None
6b9f22778edc6cca12e373ee12aaa2b2 0023f29fb56a3ff066569f846f046739
f58fb36443f10c40c7243d3c33154810 None
fc350fb4808c5bc500b4b4aafb7595a5 f3d8647e7f0bcf0dce1addf17cec3d47
4f8ca570bce0403e4ccc4f1969987307 bb83ea1c12a3231a79bc539775dcd472
30585b0a503668a04215a5fb07e67765 None
d415bfeab38a56e4ac37a68c74d89dae 0023f29fb56a3ff066569f846f046739
48d9c8c5bfb395399ce1dfb5f5df091e None
53ff69fd2a26ec17aa341588ea1ef95b 0023f29fb56a3ff066569f846f046739
e00d52ed3c775ed297d1f007232b96a9 b518c53a55a3c2635d550805c6ffb3fd
8b2f4d35272135a76e536ebcaaa5274b None
452ee7b0ff61b474c2da96535c0c65ec None
83cdf1b8d1748dad546fc8e3bc1076d2 b518c53a55a3c2635d550805c6ffb3fd
56fccdd48f34f5fb776cb5bdf545ccde b518c53a55a3c2635d550805c6ffb3fd
......@@ -4,7 +4,7 @@
import sys
import os
import os.path as op
import os.path as op
import subprocess as sp
outDir = sys.argv[1]
......@@ -16,5 +16,5 @@ refimg = op.join(fslDir, 'data', 'standard', 'MNI152_T1_2mm_brain')
outimg = op.join(outDir, 'input_xformed')
outxform = op.join(outDir, 'xform.mat')
sp.call('flirt -in {} -ref {} -out {} -omat {}'.format(
inimg, refimg, outimg, outxform).split())
sys.exit(sp.call('flirt -in {} -ref {} -out {} -omat {}'.format(
inimg, refimg, outimg, outxform).split()))
exampleData/input.nii.gz
#!/usr/bin/env python
import os.path as op
import sys
import nibabel as nib
# Read in the command line arguments.
outdir = sys.argv[1]
indir = sys.argv[2]
inimg = nib.load(op.join(indir, 'exampleData', 'input.nii.gz'))
# Get access to the image data
# through the nibabel wrapper.
indata = inimg.get_data()
with open(op.join(outdir, 'result.txt'), 'wt') as f:
f.write('mean: {}'.format(indata.mean()))
#!/usr/bin/env python
import os.path as op
import sys
import nibabel as nib
# Read in the command line arguments.
outdir = sys.argv[1]
indir = sys.argv[2]
inimg = nib.load(op.join(indir, 'exampleData', 'input.nii.gz'))
# Get access to the image data
# through the nibabel wrapper.
indata = inimg.get_data()
with open(op.join(outdir, 'result.txt'), 'wt') as f:
f.write('minmax: {} {}'.format(indata.min(), indata.max()))
......@@ -5,7 +5,7 @@
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
__version__ = '0.8.1'
__version__ = '0.9.0'
"""The pyfeeds version number. """
......
......@@ -4,7 +4,7 @@
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""This module contains some miscellaneous utility functions uased throughout
"""This module contains some miscellaneous utility functions used throughout
pyfeeds, and made available to test scripts.
.. autosummary::
......@@ -273,7 +273,7 @@ def loadNumericText(filename):
# http://perldoc.perl.org/perlretut.html#Building-a-regexp
# http://stackoverflow.com/a/385597
numberPattern = '[+-]? *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?'
numberPattern = r'[+-]? *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?'
numberPattern = re.compile(numberPattern)
def stof(s):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment