Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.6 RC2 #135

Merged
merged 100 commits into from
Jun 30, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
dd70db6
Sample subclassing messaging and more information control in interact…
vreuter Jun 14, 2017
29dc0e0
amid pull-apart of pipelines Sample subclass search
vreuter Jun 14, 2017
b9923a9
remove old examples
vreuter Jun 14, 2017
49f1e5f
better failure for nonexistent pipelines location; pull apart search …
vreuter Jun 14, 2017
500b8a9
better message
vreuter Jun 14, 2017
0f77aee
simplify edge case handling in looper run; pause Sample subclass tests
vreuter Jun 14, 2017
322fe8d
reflect separated project init in test fixture; update requiremnets; …
vreuter Jun 15, 2017
cb3a838
type cast for config value for inequality comparison
vreuter Jun 15, 2017
a195362
reflect new requirements in changelog
vreuter Jun 15, 2017
5a7eaca
version bump to rc2
nsheff Jun 15, 2017
1f26297
Remove scripts directory
nsheff Jun 15, 2017
f58fc74
Fix version requirements
nsheff Jun 15, 2017
13d553b
enable pipeline_interfaces attribute alongside pipelines_dir
nsheff Jun 15, 2017
5410cd0
move extra attribute explanation to exception message; downgrade mess…
vreuter Jun 15, 2017
80611e6
Fix import of scripts dir
nsheff Jun 16, 2017
ea3f005
Move add_sample_sheet from looper back into models
nsheff Jun 16, 2017
1ea7642
inform about subtypes found
vreuter Jun 16, 2017
9926228
reflect addition of sample sheet in project ctor
vreuter Jun 16, 2017
91da40f
trigger build
vreuter Jun 16, 2017
1af7860
amid sample subclass overhaul
vreuter Jun 16, 2017
e358383
more work on Sample subclass support
vreuter Jun 17, 2017
cddc405
clarification of some of what's going on in the pipeline construction…
vreuter Jun 17, 2017
16fe836
more explanation
vreuter Jun 17, 2017
b60cc83
first pass at finished build_pipelines implementation
vreuter Jun 18, 2017
3eb2739
creating subtype for each pipeline submission
vreuter Jun 18, 2017
79c6e39
TODO items
vreuter Jun 18, 2017
258ee99
better control of when to build pipelines; iteration over protocols; …
vreuter Jun 18, 2017
136faec
slight cleanup and comments
vreuter Jun 18, 2017
eb3d39b
first pass at creating the Sample subtype in looper; getting YAML fil…
vreuter Jun 18, 2017
f1e947f
need to finalize pipelines directory before processing locations; bet…
vreuter Jun 18, 2017
eaccdff
Project representation restrictions; num_samples not working
vreuter Jun 19, 2017
f96a7e2
num_samples working; it's samples itself that's problematic, via df attr
vreuter Jun 19, 2017
5c382e2
bump up binding of Project to Sample
vreuter Jun 19, 2017
fa7989e
cutting the Sample-to-Project cord; removing functions that have been…
vreuter Jun 19, 2017
bc3edfd
fix establishment of default compute and environment settings
vreuter Jun 19, 2017
59121db
dot to underscore
nsheff Jun 19, 2017
d1c18c4
message format
vreuter Jun 19, 2017
4db285b
Merge branch '0.6-rc2' of github.com:epigen/looper into 0.6-rc2
vreuter Jun 19, 2017
ce4e9bf
remove punctuation and match case for protocol search; ask Sample abo…
vreuter Jun 20, 2017
bd83e57
check for read_type after pipeline attributes have been set; write Sa…
vreuter Jun 20, 2017
9a8323b
base Sample construction with Project by default
vreuter Jun 20, 2017
4d725d4
first pass at new subtype import logic
vreuter Jun 20, 2017
590751b
getitem for PipelineInterface; use submission bundle creation functio…
vreuter Jun 20, 2017
8bb9fd9
fix up the matching of protocol names/keys in mappings; provide funct…
vreuter Jun 20, 2017
5a1c447
earlier pipeline locations finalization to ensure a collection; fix t…
vreuter Jun 20, 2017
be6094b
sheet function and better names/messages
vreuter Jun 20, 2017
7b6614a
docstrings and cleanup
vreuter Jun 20, 2017
b5d7fab
pin down what needs to change in the Sample independent tests around …
vreuter Jun 20, 2017
4483f4e
fix the Sample tests based on column inference method signature change
vreuter Jun 20, 2017
a171117
update pipeline locations key in tests Project config data; update th…
vreuter Jun 20, 2017
4d0f331
fix handling of initial Sample creation for Project; update Project t…
vreuter Jun 21, 2017
341230a
account for new attribute fetch call and remove outdated test
vreuter Jun 21, 2017
a35868e
ensure Sample has merged flag; remove old tests and fix others
vreuter Jun 21, 2017
1e235f0
Merge branch 'master' of github.com:epigen/looper into 0.6-rc2
vreuter Jun 21, 2017
d76c70b
use Series as raw Sample data in case subtypes are restrictive; grab …
vreuter Jun 21, 2017
9f97b2a
improve the submission counting
vreuter Jun 21, 2017
d2bd807
accumulate missing attributes and files in the required inputs confir…
vreuter Jun 21, 2017
c7b2d11
update tests to reflect new function name
vreuter Jun 21, 2017
aab1f54
check for null merge table
vreuter Jun 21, 2017
ca118fa
prevent nulls in sample YAML; generate Sample filename from subtype
vreuter Jun 21, 2017
dbfa23d
fix pipeline interface tests
vreuter Jun 22, 2017
1bdb471
trace messages
vreuter Jun 22, 2017
54c76c4
Update cluster docs
nsheff Jun 22, 2017
500e4a2
Merge branch '0.6-rc2' of github.com:epigen/looper into 0.6-rc2
nsheff Jun 22, 2017
be09c63
put merge and column derivation in proper order
vreuter Jun 22, 2017
6bb271e
Merge branch '0.6-rc2' of github.com:epigen/looper into 0.6-rc2
vreuter Jun 22, 2017
075ec4b
cleaner handling of merge call from Sample builder; return the column…
vreuter Jun 22, 2017
04036e3
MERGE HAPPENS BEFORE COLUMN DERIVATION (via set_file_paths); account …
vreuter Jun 22, 2017
73038e9
handle Sample subtype resolution and pipeline module imports; first-p…
vreuter Jun 23, 2017
6ac4f17
pull the docs changes
vreuter Jun 23, 2017
bae47df
fix import handling and improve exception catching; microtest working…
vreuter Jun 23, 2017
5588b0e
Fix doc bugs
nsheff Jun 23, 2017
b190e02
Add examples folder back in
nsheff Jun 23, 2017
53f2868
update examples to implied cols
nsheff Jun 23, 2017
780063c
remove docs from example config and simplify
nsheff Jun 23, 2017
ce9ade1
enforce __repr__ implementation and validate call safety
vreuter Jun 23, 2017
c1d4dc8
Merge branch '0.6-rc2' of github.com:epigen/looper into 0.6-rc2
vreuter Jun 23, 2017
6fbb7f5
better handling of path expansion in PipelineInterface; tests for con…
vreuter Jun 24, 2017
c1ceca9
reorganize to facilitate fixture reuse
vreuter Jun 24, 2017
86deccd
first ProtocolInterface test implemented
vreuter Jun 24, 2017
eb7ac19
better function name; more tests and expose lack of leading-dot relat…
vreuter Jun 24, 2017
89c5895
little more info about the path expansion should it ever fail; fix up…
vreuter Jun 25, 2017
db3cf18
finish protocol interface pipeline path tests, passing
vreuter Jun 25, 2017
fae6656
add path expansion tests for PipelineInterface, passing
vreuter Jun 25, 2017
8d4d5e6
add tests to check for warning message about nonexistent pipeline scr…
vreuter Jun 25, 2017
a95591d
better separation of concerns in handling of creation of submission b…
vreuter Jun 25, 2017
923a4ab
catch more exceptions and add explanation; add tests and stub others,…
vreuter Jun 26, 2017
6b9dcfb
account for possibility of null return value being introduced into th…
vreuter Jun 26, 2017
4706892
ensure that sys.modules is cleaned up; make sure that we account for …
vreuter Jun 26, 2017
be7c8a1
python 3, less verbosity, better messaging, fix format errors, random…
vreuter Jun 26, 2017
9977f14
descriptions, cleanup, better organization
vreuter Jun 26, 2017
09c6b63
add the sample name collision tests
vreuter Jun 26, 2017
36b46b8
separate concerns; add unimplemented subtype class tests
vreuter Jun 26, 2017
838669b
add the proper fixture hook for parameterization
vreuter Jun 26, 2017
e65254d
stricter subtype enforcement, cleanup, add tests
vreuter Jun 26, 2017
e310833
first pass at finishing off tests
vreuter Jun 27, 2017
33ea9c1
fix the few test mistakes
vreuter Jun 27, 2017
65b2efc
broader fixture sharing
vreuter Jun 27, 2017
f7cc27e
fixing the smokes and adding sample sheet tests
vreuter Jun 27, 2017
966286b
cleaner protocol-based selection in sheet construction; better test o…
vreuter Jun 27, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
account for possibility of null return value being introduced into th…
…e protected import function by guarding with a final default Sample fallback; add tests for protocol matching
  • Loading branch information
vreuter committed Jun 26, 2017
commit 6b9dcfb62b801d1d9dd9c94117c5f3004b14cf0f
59 changes: 42 additions & 17 deletions looper/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,7 @@ def build_submission_bundles(self, protocol, priority=True):
if priority and len(job_submission_bundles) > 0:
return job_submission_bundles[0]

this_protocol_pipelines = proto_iface.fetch(protocol)
this_protocol_pipelines = proto_iface.fetch_pipelines(protocol)
if not this_protocol_pipelines:
_LOGGER.warn("No mapping for protocol '%s' in %s",
protocol, proto_iface)
Expand Down Expand Up @@ -2465,6 +2465,18 @@ def __repr__(self):
return "ProtocolInterface from '{}'".format(self.source or "Mapping")


def fetch_pipelines(self, protocol):
"""
Fetch the mapping for a particular protocol, null if unmapped.

:param str protocol: name/key for the protocol for which to fetch the
pipeline(s)
:return str | Iterable[str] | NoneType: pipeline(s) to which the given
protocol is mapped, otherwise null
"""
return self.protomap.mappings.get(alpha_cased(protocol))


def fetch_sample_subtype(
self, protocol, strict_pipe_key, full_pipe_path):
"""
Expand Down Expand Up @@ -2499,21 +2511,26 @@ def fetch_sample_subtype(
subtype_name = None
else:
if subtypes is None:
_LOGGER.debug("Null Sample subtypes specified for pipeline: "
"'%s'; using base Sample type", strict_pipe_key)
# Designate lack of need to attempt pipeline module import.
# Designate lack of need for import attempt and provide
# class with name to format message below.
subtype = Sample
_LOGGER.debug("Null %s subtype(s) section specified for "
"pipeline: '%s'; using base %s type",
subtype.__name__, strict_pipe_key,
subtype.__name__)
elif isinstance(subtypes, str):
subtype_name = subtypes
_LOGGER.debug("Single subtype name for pipeline '%s' "
"in interface from '%s': '%s'", subtype_name,
strict_pipe_key, self.source)
else:
temp_subtypes = {
alpha_cased(p): st for p, st in subtypes.items()}
try:
temp_subtypes = {alpha_cased(p): st
for p, st in subtypes.items()}
subtype_name = temp_subtypes[alpha_cased(protocol)]
except KeyError:
# Designate lack of need for import attempt and provide
# class with name to format message below.
subtype = Sample
_LOGGER.debug("No %s subtype specified in interface from "
"'%s': '%s', '%s'; known: %s",
Expand All @@ -2523,24 +2540,32 @@ def fetch_sample_subtype(

# subtype_name is defined if and only if subtype remained null.
subtype = subtype or \
_import_sample_subtype(full_pipe_path, subtype_name)
_import_sample_subtype(full_pipe_path, subtype_name) or \
Sample
_LOGGER.debug("Using Sample subtype: %s", subtype.__name__)
return subtype


def fetch(self, protocol):
"""
Fetch the mapping for a particular protocol, null if unmapped.

:param str protocol:
:return str | Iterable[str] | NoneType: pipeline(s) to which the given
protocol is mapped, otherwise null
@classmethod
def _parse_iface_data(cls, pipe_iface_data):
"""
return self.protomap.mappings.get(alpha_cased(protocol))
Parse data from mappings to set instance attributes.

The data that define a ProtocolInterface are a "protocol_mapping"
Mapping and a "pipelines" Mapping, which are used to create a
ProtocolMapper and a PipelineInterface, representing the configuration
data for pipeline(s) from a single location. There are a couple of
different ways (file, folder, and eventually, raw Mapping) to provide
this data, and this function provides some standardization to how
those data are processed, independent of input type/format.

@classmethod
def _parse_iface_data(cls, pipe_iface_data):
:param Mapping[str, Mapping] pipe_iface_data: mapping from section
name to section data mapping; more specifically, the protocol
mappings Mapping and the PipelineInterface mapping
:return list[(str, ProtocolMapper | PipelineInterface)]: pairs of
attribute name for the ProtocolInterface being created, and the
value for that attribute,
"""
assignments = [("protocol_mapping", ProtocolMapper, "protomap"),
("pipelines", PipelineInterface, "pipe_iface")]
attribute_values = []
Expand Down
95 changes: 79 additions & 16 deletions tests/models/independent/test_ProtocolInterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

import __builtin__
import inspect
import itertools
import logging
import mock
import os
import pytest
import yaml
import looper
from looper import models, DEV_LOGGING_FMT
from looper.models import ProtocolInterface
from looper.models import ProtocolInterface, Sample


__author__ = "Vince Reuter"
Expand Down Expand Up @@ -192,6 +193,12 @@ class SampleSubtypeTests:
# 2b -- named class is in module but isn't defined
#

PROTOCOL_NAME_VARIANTS = [
"ATAC-Seq", "ATACSeq", "ATACseq", "ATAC-seq", "ATAC",
"ATACSEQ", "ATAC-SEQ", "atac", "atacseq", "atac-seq"]



@pytest.fixture(scope="function")
def subtypes_section_single(self, atac_pipe_name):
pass
Expand All @@ -204,33 +211,86 @@ def subtypes_section_multiple(self, atac_pipe_name):

@pytest.mark.parametrize(
argnames="pipe_key",
argvalues=["ATAC-Seq.py", "atacseq.py", "ATACSEQ.py", "ATACSEQ",
"atacseq", "ATAC-seq.py", "ATACseq.py"])
argvalues=["{}.py".format(proto) for proto
in PROTOCOL_NAME_VARIANTS])
@pytest.mark.parametrize(
argnames="protocol",
argvalues=["ATAC-Seq", "ATACSeq", "ATACseq", "ATAC-seq", "ATAC",
"ATACSEQ", "ATAC-SEQ", "atac", "atacseq", "atac-seq"])
def test_pipeline_key_close_matches_dont_count(
argvalues=PROTOCOL_NAME_VARIANTS)
def test_pipeline_key_match_is_strict(
self, tmpdir, pipe_key, protocol, atac_pipe_name,
atacseq_iface_with_resources):
""" Request for Sample subtype for unmapped pipeline is KeyError. """

# Create the ProtocolInterface.
strict_pipe_key = atac_pipe_name
protocol_mapping = {protocol: strict_pipe_key}
path_config_file = _write_config_data(
protomap=protocol_mapping,
conf_data={strict_pipe_key: atacseq_iface_with_resources},
dirpath=tmpdir.strpath)
piface = ProtocolInterface(path_config_file)
confpath = _write_config_data(
protomap=protocol_mapping, dirpath=tmpdir.strpath,
conf_data={strict_pipe_key: atacseq_iface_with_resources})
piface = ProtocolInterface(confpath)

# The absolute pipeline path is the pipeline name, joined to the
# ProtocolInterface's pipelines location. This location is the
# location from which a Sample subtype import is attempted.
full_pipe_path = os.path.join(tmpdir.strpath, atac_pipe_name)
with pytest.raises(KeyError):
# Mismatch between pipeline key arg and strict key --> KeyError.

# TODO: update to pytest.raises(None) if/when 3.1 adoption.
# Match between pipeline key specified and the strict key used in
# the mapping --> no error while mismatch --> error.
if pipe_key == atac_pipe_name:
piface.fetch_sample_subtype(
protocol, pipe_key, full_pipe_path=full_pipe_path)
protocol, pipe_key, full_pipe_path=full_pipe_path)
else:
with pytest.raises(KeyError):
piface.fetch_sample_subtype(
protocol, pipe_key, full_pipe_path=full_pipe_path)


def test_protocol_match_is_fuzzy(self):
@pytest.mark.parametrize(
argnames=["mapped_protocol", "requested_protocol"],
argvalues=itertools.combinations(PROTOCOL_NAME_VARIANTS, 2))
def test_protocol_match_is_fuzzy(
self, tmpdir, mapped_protocol, atac_pipe_name,
requested_protocol, atacseq_piface_data):
""" Punctuation and case mismatches are tolerated in protocol name. """
pass

# Needed to create the ProtocolInterface.
protomap = {mapped_protocol: atac_pipe_name}
# Needed to invoke the function under test.
full_pipe_path = os.path.join(tmpdir.strpath, atac_pipe_name)

# PipelineInterface data provided maps name to actual interface data
# Mapping, so modify the ATAC-Seq mapping within that.
# In this test, we're interested in the resolution of the protocol
# name, that with it we can grab the name of a class. Thus, we
# need only an arbitrary class name about which we can make the
# relevant assertion(s).
test_class_name = "TotallyArbitrary"
atacseq_piface_data[atac_pipe_name]["sample_subtypes"] = \
test_class_name

# Write out configuration data and create the ProtocolInterface.
conf_path = _write_config_data(
protomap=protomap, conf_data=atacseq_piface_data,
dirpath=tmpdir.strpath)
piface = ProtocolInterface(conf_path)

# Make the call under test, patching the function protected
# function that's called iff the protocol name match succeeds.
with mock.patch("looper.models._import_sample_subtype",
return_value=None) as mocked_import:
# Return value is irrelevant; the effect of the protocol name
# match/resolution is entirely observable via the argument to the
# protected import function.
piface.fetch_sample_subtype(
protocol=requested_protocol,
strict_pipe_key=atac_pipe_name,
full_pipe_path=full_pipe_path)
# When the protocol name match/resolution succeeds, the name of the
# Sample subtype class to which it was mapped is passed as an
# argument to the protected import function.
mocked_import.assert_called_with(full_pipe_path, test_class_name)



@pytest.mark.parametrize(
Expand All @@ -239,6 +299,7 @@ def test_protocol_match_is_fuzzy(self):
__builtin__, lambda o: inspect.isclass(o) and
issubclass(o, BaseException)))[1])
def test_problematic_import_builtin_exception(self, error_type):
""" Base Sample is used if builtin exception on pipeline import. """
pass


Expand All @@ -248,10 +309,12 @@ def test_problematic_import_builtin_exception(self, error_type):
looper.models, lambda o: inspect.isclass(o) and
issubclass(o, Exception)))[1])
def test_problematic_import_custom_exception(self, error_type):
""" Base Sample is used if custom exception on pipeline import. """
pass


def test_no_subtypes_section(self):
""" """
pass


Expand Down