Skip to content

Commit 3366d08

Browse files
author
Alan B. Christie
authored
34 add file selector utility (#35)
* - Adds a utility to get the caller's module - Adds file-Utils to allow selection of packaged files (based on module name) * - pick_sdf now exposes `namespace` * - file -> filename * - Moved Python 3 files to new test directory * - An attempt to fix the Python 2.7 tests * - Separated tests that need Python3 * - Adds missing files * - Refactored * - removed unused requirements * - Fixed travis.yml * - Experiment with file-encoding * - Removed back-ticks * - Removed back-ticks * - Removing file * - File returned * - Moved test_utils to python3 * - Now just the base file is returned in the SDF picker * - pick now returns module and its full path * - Minor typo * - Adjusted for Python 2 tests * - Now returns full path
1 parent c0da665 commit 3366d08

22 files changed

+178
-11
lines changed

.travis.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ branches:
3232
# Installation steps.
3333
# We have more than one requirements file.
3434
install:
35-
- pip install -r requirements.txt
3635
- pip install -r package-requirements.txt
3736

3837
# Test/build execution steps...

requirements.txt

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2018 Informatics Matters Ltd.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
from __future__ import print_function
18+
import os
19+
from . import utils
20+
21+
# Files are normally located in sub-directories of the pipeline module path.
22+
# For example a pipeline module 'pipeline_a.py' that expects to use a file
23+
# or SDF picker would place its files in the directory
24+
# 'pipelines/demo/pipeline_a'.
25+
26+
27+
def pick(filename, directory=None):
28+
"""Returns the named file. If directory is not specified the file is
29+
expected to be located in a sub-directory whose name matches
30+
that of the calling module otherwise the file is expected to be found in
31+
the named directory.
32+
33+
:param filename: The file, whose path is required.
34+
:type filename: ``str``
35+
:param directory: An optional directory.
36+
If not provided it is calculated automatically.
37+
:type directory: ``str``
38+
:return: The full path to the file, or None if it does not exist
39+
:rtype: ``str``
40+
"""
41+
if directory is None:
42+
directory = utils.get_undecorated_calling_module()
43+
# Remove the CWD and the anticipated '/' from the front of the module
44+
directory = directory[len(os.getcwd()) + 1:]
45+
46+
file_path = os.path.join(directory, filename)
47+
return file_path if os.path.isfile(file_path) else None
48+
49+
50+
def pick_sdf(filename, directory=None):
51+
"""Returns a full path to the chosen SDF file. The supplied file
52+
is not expected to contain a recognised SDF extension, this is added
53+
automatically.
54+
If a file with the extension `.sdf.gz` or `.sdf` is found the path to it
55+
(excluding the extension) is returned. If this fails, `None` is returned.
56+
57+
:param filename: The SDF file basename, whose path is required.
58+
:type filename: ``str``
59+
:param directory: An optional directory.
60+
If not provided it is calculated automatically.
61+
:type directory: ``str``
62+
:return: The full path to the file without extension,
63+
or None if it does not exist
64+
:rtype: ``str``
65+
"""
66+
if directory is None:
67+
directory = utils.get_undecorated_calling_module()
68+
# Remove the CWD and the anticipated '/' from the front of the module
69+
directory = directory[len(os.getcwd()) + 1:]
70+
71+
file_path = os.path.join(directory, filename)
72+
if os.path.isfile(file_path + '.sdf.gz'):
73+
return file_path + '.sdf.gz'
74+
elif os.path.isfile(file_path + '.sdf'):
75+
return file_path + '.sdf'
76+
# Couldn't find a suitable SDF file
77+
return None

src/python/pipelines_utils/utils.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# limitations under the License.
1616

1717
from __future__ import print_function
18-
import sys, gzip, json, uuid
18+
import inspect, os, sys, gzip, json, uuid
1919
from math import log10, floor
2020
from pipelines_utils.BasicObjectWriter import BasicObjectWriter
2121
from pipelines_utils.TsvWriter import TsvWriter
@@ -132,7 +132,7 @@ def write_metrics(baseName, values):
132132

133133
def generate_molecule_object_dict(source, format, values):
134134
"""Generate a dictionary that represents a Squonk MoleculeObject when
135-
writen as JSON
135+
written as JSON
136136
137137
:param source: Molecules in molfile or smiles format
138138
:param format: The format of the molecule. Either 'mol' or 'smiles'
@@ -142,3 +142,20 @@ def generate_molecule_object_dict(source, format, values):
142142
if values:
143143
m["values"] = values
144144
return m
145+
146+
147+
def get_undecorated_calling_module():
148+
"""Returns the module name of the caller's calling module.
149+
If a.py makes a call to b() in b.py, b() can get the name of the
150+
calling module (i.e. a) by calling get_undecorated_calling_module().
151+
152+
The module also includes its full path.
153+
154+
As the name suggests, this does not work for decorated functions.
155+
"""
156+
frame = inspect.stack()[2]
157+
module = inspect.getmodule(frame[0])
158+
# Return the module's file and its path
159+
# and omit the extension...
160+
# so /a/c.py becomes /a/c
161+
return module.__file__.rsplit('.', 1)[0]

src/python/setup.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,24 @@
55
#
66
# Jan 2018
77

8+
import platform
89
from setuptools import setup, find_packages
910

11+
# By default the test suite is the root test suite.
12+
# Unless it's Python 2.
13+
_TEST_SUITE = 'test'
14+
if int(platform.python_version_tuple()[0]) == 2:
15+
_TEST_SUITE = 'test.python2_3'
16+
17+
1018
def get_long_description():
1119
return open('README.rst').read()
1220

21+
1322
setup(
1423

1524
name='im-pipelines-utils',
16-
version='2.2.2',
25+
version='2.3.0',
1726
author='Alan Christie',
1827
author_email='[email protected]',
1928
url='https://github.com/InformaticsMatters/pipelines-utils',
@@ -48,7 +57,7 @@ def get_long_description():
4857
],
4958

5059
# Root of the test suite
51-
test_suite = 'test',
60+
test_suite=_TEST_SUITE,
5261

5362
zip_safe=False,
5463

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# python2_3
2+
A directory of unit tests that are happy on Python 2.
3+
All tests would normally go in here unless they have
4+
specific needs for Python 3 (where they can be put in
5+
the python3 directory)
File renamed without changes.

src/python/test/python2_3/pipelines_utils/__init__.py

Whitespace-only changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)