Commit a02c84e1 authored by Sander Bollen's avatar Sander Bollen
Browse files

Generate settings dict from supplied json, with defaults from schema

parent 646885c5
"""
prinia.primer3
~~~~~~~~~~~~~~
:copyright: (c) 2017-2018 Sander Bollen
:copyright: (c) 2017-2018 Leiden University Medical Center
:license: MIT
"""
from pathlib import Path
from tempfile import NamedTemporaryFile
from subprocess import check_call
from typing import Optional
import os
import json
import re
from jsonschema import validate
from .models import Primer
SETTINGS_SCHEMA = (Path(__file__).parent / Path("static") /
Path("primer3_settings_schema.json"))
def parse_settings(settings_file: Optional[Path] = None) -> dict:
"""
Parse settings file to settings dictionary.
Parameters not specified in settings_file will be taken from default values
in schema. If settings_file is None, all values will be the default values
in schema
:param settings_file: Optional path to settings file
:return: dict with settings
:raises: ValidationError if settings_file does not conform to schema
"""
with SETTINGS_SCHEMA.open("r") as schema_handle:
schema_dict = json.load(schema_handle)
defaults = {k: v['default'] for k, v in schema_dict['properties'].items()}
if settings_file is None:
return defaults
with settings_file.open("r") as settings_handle:
settings_dict = json.load(settings_handle)
validate(settings_dict, schema_dict) # raises ValidationError if failure
default_keys = defaults.keys() - settings_dict.keys()
default_dict = {k: defaults[k] for k in default_keys}
generated_dict = {**settings_dict, **default_dict}
# if range is set, but optimum size is not, calculate opt size
if ('primer_product_opt_size' in default_dict and
"primer_product_size_range" in settings_dict):
product_range = settings_dict['primer_product_size_range']
min_size, max_size = product_range.split("-")
opt_size = int((int(min_size) + (int(max_size) - int(min_size))) // 2)
generated_dict['primer_product_opt_size'] = opt_size
return generated_dict
class Primer3(object):
def __init__(self, primer3_exe, template, target, excluded_region,
......
SEQUENCE_ID=prinia_template
SEQUENCE_TEMPLATE={{ seq }}
SEQUENCE_TARGET={{ target }}
SEQUENCE_EXCLUDED_REGION={{ excluded_region }}
PRIMER_TASK=pick_detection_primers
PRIMER_PICK_LEFT_PRIMER=1
PRIMER_PICK_INTERNAL_OLIGO=0
PRIMER_PICK_RIGHT_PRIMER=1
PRIMER_MIN_GC={{ settings.primer_min_gc }}
PRIMER_INTERNAL_MIN_GC={{ settings.primer_internal_min_gc }}
PRIMER_OPT_GC_PERCENT={{ settings.primer_opt_gc_percent }}
PRIMER_MAX_GC={{ settings.primer_max_gc }}
PRIMER_INTERNAL_MAX_GC={{ settings.primer_internal_max_gc }}
PRIMER_WT_GC_PERCENT_LT={{ settings.primer_wt_gc_percent_lt }}
PRIMER_INTERNAL_WT_GC_PERCENT_LT={{ settings.primer_internal_wt_gc_percent_lt }}
PRIMER_WT_GC_PERCENT_GT={{ settings.primer_wt_gc_percent_gt }}
PRIMER_INTERNAL_WT_GC_PERCENT_GT={{ settings.primer_internal_wc_gc_percent_gt }}
PRIMER_GC_CLAMP={{ settings.primer_gc_clamp }}
PRIMER_MAX_END_GC={{ settings.primer_max_end_gc }}
PRIMER_OPT_SIZE={{ settings.primer_opt_size }}
PRIMER_MIN_SIZE={{ settings.primer_min_size }}
PRIMER_MAX_SIZE={{ settings.primer_max_size }}
PRIMER_MAX_NS_ACCEPTED={{ settings.primer_max_ns_accepted }}
PRIMER_PRODUCT_SIZE_RANGE={{ settings.primer_product_size_range }}
PRIMER_PRODUCT_OPT_SIZE={{ settings.primer_product_opt_size }}
PRIMER_PAIR_WT_PRODUCT_SIZE_GT={{ settings.primer_pair_wt_product_size_gt }}
PRIMER_PAIR_WT_PRODUCT_SIZE_LT={{ settings.primer_pair_wt_product_size_gt }}
P3_FILE_FLAG=1
SEQUENCE_INTERNAL_EXCLUDED_REGION=37,21
PRIMER_EXPLAIN_FLAG=1
PRIMER_MIN_TM={{ settings.primer_min_tm }}
PRIMER_MAX_TM={{ settings.primer_max_tm }}
PRIMER_NUM_RETURN={{ settings.primer_num_return }}
\ No newline at end of file
......@@ -95,7 +95,7 @@
"primer_max_ns_accepted": {
"description": "Maximum number of unknown bases (N) accepted in a primer",
"type": "integer",
"default:": 0,
"default": 0,
"minimum": 0
},
"primer_product_size_range": {
......
{
"primer_gc_clamp": 1,
"primer_max_end_gc": 0,
"primer_opt_size": 21,
"primer_min_size": 19,
"primer_max_size": 29,
"primer_max_ns_accepted": 1,
"primer_product_size_range": "300-500",
"primer_pair_wt_product_size_gt": 0.12,
"primer_pair_wt_product_size_lt": 0.12,
"primer_min_tm": 55,
"primer_max_tm": 75,
"primer_num_return": 100
}
\ No newline at end of file
"""
test_primer3.py
~~~~~~~~~~~~~~~
:copyright: (c) 2018 Sander Bollen
:copyright: (c) 2018 Leiden University Medical Center
:license: MIT
"""
from pathlib import Path
from pytest import fixture
from prinia.primer3 import parse_settings
data_dir = Path(__file__).parent / Path("data")
@fixture
def valid_settings():
return data_dir / Path("valid_settings.json")
@fixture
def valid_partial_settings():
return data_dir / Path("valid_partial_settings.json")
def test_none_settings():
parsed = parse_settings()
assert parsed == {
"primer_min_gc": 20,
"primer_internal_min_gc": 20,
"primer_opt_gc_percent": 50,
"primer_max_gc": 80,
"primer_internal_max_gc": 80,
"primer_wt_gc_percent_lt": 0,
"primer_internal_wt_gc_percent_lt": 0,
"primer_wt_gc_percent_gt": 0,
"primer_internal_wt_gc_percent_gt": 0,
"primer_gc_clamp": 0,
"primer_max_end_gc": 5,
"primer_opt_size": 25,
"primer_min_size": 20,
"primer_max_size": 30,
"primer_max_ns_accepted": 0,
"primer_product_size_range": "200-450",
"primer_product_opt_size": 325,
"primer_pair_wt_product_size_gt": 0.1,
"primer_pair_wt_product_size_lt": 0.1,
"primer_min_tm": 58,
"primer_max_tm": 62,
"primer_num_return": 200
}
def test_complete_settings(valid_settings):
parsed = parse_settings(valid_settings)
# TODO: work out
def test_partial_settings(valid_partial_settings):
parsed = parse_settings(valid_partial_settings)
# TODO: work out
......@@ -25,6 +25,7 @@ data_dir = Path(__file__).parent / Path("data")
setting_jsons_data = [
(data_dir / Path("valid_settings.json"), True),
(data_dir / Path("valid_partial_settings.json"), True),
(data_dir / Path("settings_wrong_types.json"), False),
(data_dir / Path("settings_invalid_values.json"), False)
]
......
[tox]
envlist = py27, py34
envlist = py35
[testenv]
usedevelop = True
......
Markdown is supported
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