Merge branch 'django1.7' of mus.cacr.caltech.edu:htsworkflow into django1.7
authorDiane Trout <diane@caltech.edu>
Sat, 13 Dec 2014 00:36:36 +0000 (16:36 -0800)
committerDiane Trout <diane@caltech.edu>
Sat, 13 Dec 2014 00:36:36 +0000 (16:36 -0800)
Conflicts:
htsworkflow/submission/encoded.py

Prefer the multi line
if 'string' in object:
   del object['string']

13 files changed:
.gitignore
experiments/models.py
htsworkflow/settings/felcat.py [new file with mode: 0644]
htsworkflow/submission/encoded.py
pgmigration [new file with mode: 0644]
requirements/base.txt
samples/changelist.py
samples/fixtures/initial_data.json [deleted file]
samples/fixtures/test_samples.json [deleted file]
samples/migrations/0001_initial.py [new file with mode: 0644]
samples/migrations/__init__.py [new file with mode: 0644]
samples/samples_factory.py [new file with mode: 0644]
samples/test_samples.py

index 6b1d69947426e7180d43aae6ed10ba7ca127cbff..da5f41740212f3908d9480d753b5f34e1ed94aac 100644 (file)
@@ -13,3 +13,5 @@ htsworkflow.kdev4
 RELEASE-VERSION
 .ropeproject
 .tox
+fctracker.db
+
index 38411ef0a4309a80b1f87a0795d64cedbf713feb..6b92a1845dc334b2fa6a1ae3e8a68f2371186253 100644 (file)
@@ -61,16 +61,6 @@ class ClusterStation(models.Model):
     def __unicode__(self):
         return unicode(self.name)
 
-    @classmethod
-    def default(cls):
-        d = cls.objects.filter(isdefault=True).all()
-        if len(d) > 0:
-            return d[0]
-        d = cls.objects.order_by('-id').all()
-        if len(d) > 0:
-            return d[0]
-        return None
-
     @staticmethod
     def update_isdefault(sender, instance, **kwargs):
         """Clear default if needed
@@ -81,6 +71,15 @@ class ClusterStation(models.Model):
                     c.isdefault = False
                     c.save()
 
+def cluster_station_default():
+    d = ClusterStation.objects.filter(isdefault=True).all()
+    if len(d) > 0:
+        return d[0]
+    d = ClusterStation.objects.order_by('-id').all()
+    if len(d) > 0:
+        return d[0]
+    return None
+
 pre_save.connect(ClusterStation.update_isdefault, sender=ClusterStation)
 
 class Sequencer(models.Model):
@@ -108,16 +107,6 @@ class Sequencer(models.Model):
         return ('experiments.views.sequencer',
                 [self.id])
 
-    @classmethod
-    def default(cls):
-        d = cls.objects.filter(isdefault=True).all()
-        if len(d) > 0:
-            return d[0]
-        d = cls.objects.order_by('active', '-id').all()
-        if len(d) > 0:
-            return d[0]
-        return None
-
     @staticmethod
     def update_isdefault(sender, instance, **kwargs):
         """Clear default if needed
@@ -130,6 +119,14 @@ class Sequencer(models.Model):
 
 pre_save.connect(Sequencer.update_isdefault, sender=Sequencer)
 
+def sequencer_default():
+    d = Sequencer.objects.filter(isdefault=True).all()
+    if len(d) > 0:
+        return d[0]
+    d = Sequencer.objects.order_by('active', '-id').all()
+    if len(d) > 0:
+        return d[0]
+    return None
 
 class FlowCell(models.Model):
     flowcell_id = models.CharField(max_length=20, unique=True, db_index=True)
@@ -149,8 +146,9 @@ class FlowCell(models.Model):
                                        null=True,
                                        blank=True)
 
-    cluster_station = models.ForeignKey(ClusterStation, default=ClusterStation.default)
-    sequencer = models.ForeignKey(Sequencer, default=Sequencer.default)
+    cluster_station = models.ForeignKey(ClusterStation,
+                                        default=cluster_station_default)
+    sequencer = models.ForeignKey(Sequencer, default=sequencer_default)
 
     notes = models.TextField(blank=True)
 
diff --git a/htsworkflow/settings/felcat.py b/htsworkflow/settings/felcat.py
new file mode 100644 (file)
index 0000000..e27a33f
--- /dev/null
@@ -0,0 +1,27 @@
+# configure debugging
+import os
+from .local import *
+
+DEBUG=True
+TEMPLATE_DEBUG = True
+
+INTERNAL_IPS = ('127.0.0.1',)
+
+MIDDLEWARE_CLASSES.extend([
+    #'debug_toolbar.middleware.DebugToolbarMiddleware',
+])
+
+DATABASES = {
+    'fctracker': {
+        'ENGINE': 'django.db.backends.sqlite3',
+        'NAME': '/var/htsworkflow/htsworkflow/fctracker.db',
+    },
+    'default': {
+        'ENGINE': 'django.db.backends.postgresql_psycopg2',
+        'HOST': 'felcat.caltech.edu',
+        'USER': 'jumpgate',
+        'NAME': 'htsworkflow',
+    }
+
+}
+
index 977995d0668896ad73996cb349b45b69fe87de07..d4067583e0c3b1ba6514b2fc87e35964c8d77e12 100644 (file)
@@ -222,10 +222,8 @@ class ENCODED:
             raise ValueError('@type is not a sequence')
         return obj_type[0]
 
-    def get_schema_url(self, obj):
-        obj_type = self.get_object_type(obj)
-        if obj_type:
-            return self.prepare_url(ENCODED_SCHEMA_ROOT + obj_type + '.json') + '#'
+    def get_schema_url(self, object_type):
+        return self.prepare_url(ENCODED_SCHEMA_ROOT + object_type + '.json') + '#'
 
     def _is_encoded_object(self, obj):
         '''Test to see if an object is a JSON-LD object
@@ -320,18 +318,75 @@ class ENCODED:
         self.add_jsonld_context(result, self.prepare_url(result['@id']))
         return result
 
-    def validate(self, obj):
-        obj_type = self.get_object_type(obj)
-        schema_url = self.get_schema_url(obj)
+    def validate(self, obj, object_type=None):
+        object_type = object_type if object_type else self.get_object_type(obj)
+        schema_url = self.get_schema_url(object_type)
         if not schema_url:
             raise ValueError("Unable to construct schema url")
 
-        schema = self.schemas.setdefault(obj_type, self.get_json(schema_url))
+        schema = self.schemas.setdefault(object_type, self.get_json(schema_url))
         hidden = obj.copy()
-        if '@id' in hidden: del hidden['@id']
-        if '@type' in hidden: del hidden['@type']
+        if '@id' in hidden:
+            del hidden['@id']
+        if '@type' in hidden:
+            del hidden['@type']
         jsonschema.validate(hidden, schema)
 
+class TypedColumnParser(object):
+    @staticmethod
+    def parse_sheet_array_type(value):
+        """Helper function to parse :array columns in sheet
+        """
+        return value.split(', ')
+
+    @staticmethod
+    def parse_sheet_integer_type(value):
+        """Helper function to parse :integer columns in sheet
+        """
+        return int(value)
+
+    @staticmethod
+    def parse_sheet_boolean_type(value):
+        """Helper function to parse :boolean columns in sheet
+        """
+        return bool(value)
+
+    @staticmethod
+    def parse_sheet_timestamp_type(value):
+        """Helper function to parse :date columns in sheet
+        """
+        return value.strftime('%Y-%m-%d')
+
+    @staticmethod
+    def parse_sheet_string_type(value):
+        """Helper function to parse :string columns in sheet (the default)
+        """
+        return unicode(value)
+
+    def __getitem__(self, name):
+        parser = {
+            'array': self.parse_sheet_array_type,
+            'boolean': self.parse_sheet_boolean_type,
+            'integer': self.parse_sheet_integer_type,
+            'date': self.parse_sheet_timestamp_type,
+            'string': self.parse_sheet_string_type
+        }.get(name)
+        if parser:
+            return parser
+        else:
+            raise RuntimeError("unrecognized column type")
+
+    def __call__(self, header, value):
+        header = header.split(':')
+        column_type = 'string'
+        if len(header) > 1:
+            if header[1] == 'skip':
+                return None, None
+            else:
+                column_type = header[1]
+        return header[0], self[column_type](value)
+
+typed_column_parser = TypedColumnParser()
 
 class Document(object):
     """Helper class for registering documents
diff --git a/pgmigration b/pgmigration
new file mode 100644 (file)
index 0000000..5608383
--- /dev/null
@@ -0,0 +1,86 @@
+#!/usr/bin/python
+"""Migrate from sqlite to postgresql
+"""
+import argparse
+import logging
+import os
+import tempfile
+from subprocess import check_call, call
+
+logger = logging.getLogger('pgmigrate')
+
+if not 'DJANGO_SETTINGS_MODULE' in os.environ:
+    os.environ['DJANGO_SETTINGS_MODULE'] = 'htsworkflow.settings.felcat'
+
+import django
+from django.conf import settings
+from django.core import management
+
+def main(cmdline=None):
+    parser = make_parser()
+    args = parser.parse_args(cmdline)
+
+    level = logging.WARN
+    if args.debug:
+        level = logging.DEBUG
+    elif args.verbose:
+        level = logging.INFO
+    logging.basicConfig(level=level)
+        
+        
+    # needed for django 1.7
+    django.setup()
+
+    kinit()
+    recreate_database()
+    move_app_data('contenttypes')
+    move_app_data('auth')
+    move_app_data('admin')
+
+    move_app_data('eland_config')
+    move_app_data('samples')
+    move_app_data('experiments')
+    move_app_data('bcmagic')
+    move_app_data('inventory')
+    move_app_data('labels')
+
+def make_parser():
+    parser = argparse.ArgumentParser()
+    parser.add_argument('-v', '--verbose', action='store_true',
+                        help='turn on info messages level')
+    parser.add_argument('-d', '--debug', action='store_true',
+                        help='turn on debug level messages')
+    return parser
+
+def kinit():
+    check_call(['kinit', '-l', '10m', 
+                '-k', '-t', '/var/htsworkflow/jumpgate.keytab', 
+                'jumpgate@WOLDLAB.CALTECH.EDU'])
+
+def recreate_database():
+    dbserver = settings.DATABASES['default']['HOST']
+    dbname = settings.DATABASES['default']['NAME']
+    dbuser = settings.DATABASES['default']['USER']
+    call(['dropdb', '-U', dbuser, '-h', dbserver, dbname])
+    check_call(['createdb', '-U', dbuser, '-h', dbserver, dbname])
+    management.call_command('migrate', noinput=True)
+    #management.call_command('syncdb', '--noinput', '--no-initial-data')
+
+def move_app_data(appname):
+    cwd = os.getcwd()
+    tempdir = tempfile.mkdtemp(prefix='htsw-migrate-')
+    logger.info('migrate dir: %s', tempdir)
+    os.chdir(tempdir)
+    with tempfile.NamedTemporaryFile(prefix=appname+'-', suffix='.json', dir=tempdir) as f:
+        logger.info('tempfile: %s', f.name)
+        management.call_command('dumpdata', appname, database='fctracker', stdout=f)
+        f.flush()
+        dumpstat = os.stat(f.name)
+        if dumpstat.st_size > 5:
+            management.call_command('loaddata', f.name)
+        f.close()
+    os.chdir(cwd)
+    os.rmdir(tempdir)
+
+if __name__ == "__main__":
+    main()
index 5ae0a19df79de08b4063e2a9aa4e5f4b07ee5612..34f86923597aaa7f6991bfcda61f62a3e65f8011 100644 (file)
@@ -1,4 +1,4 @@
-Django==1.6.5
+Django>=1.7
 PyLD==0.5.4
 argparse>=1.1
 httplib2>=0.8
@@ -10,3 +10,4 @@ psycopg2>=2.4
 pytz>=2011
 requests>=2.0
 wsgiref==0.1.2
+factory_boy>=2.4
index 83bbb785bcf02eafacf0016c81481dd1dd41a01f..716713aa0d4042961b4dc22f585000c153c35213 100644 (file)
@@ -42,7 +42,7 @@ class HTSChangeList(ChangeList):
         if django.VERSION[0] >= 1 and django.VERSION[1] >= 4:
             args['request'] = request #list_max_show_all
 
-        qs = super(HTSChangeList, self).get_query_set(**args)
+        qs = super(HTSChangeList, self).get_queryset(**args)
         if self.extra_filters:
             new_qs = qs.filter(**self.extra_filters)
             if new_qs is not None:
diff --git a/samples/fixtures/initial_data.json b/samples/fixtures/initial_data.json
deleted file mode 100644 (file)
index ae22c1d..0000000
+++ /dev/null
@@ -1,929 +0,0 @@
-[
-  {
-     "model": "samples.Cellline",
-     "pk": 1,
-     "fields": {
-        "cellline_name": "Unknown",
-        "notes": "Unknown"
-     }
-  },
-  {
-     "model": "samples.Cellline",
-     "pk": 2,
-     "fields": {
-        "cellline_name": "C2C12",
-        "notes": ""
-     }
-  },
-  {
-     "model": "samples.Cellline",
-     "pk": 3,
-     "fields": {
-        "cellline_name": "C2C12 60 hrs",
-        "notes": "Unknown"
-     }
-  },
-  { "pk": 1, "model": "samples.Condition",
-    "fields": {
-        "condition_name": "Unknown",
-        "nickname": "",
-        "notes": "Unknown"
-    }
-  },
-  {
-     "model": "samples.LibraryType",
-     "pk": 1,
-     "fields": {
-        "name": "Single End (non-multiplexed)",
-        "can_multiplex": false,
-        "is_paired_end": false
-     }
-  },
-  {
-     "model": "samples.LibraryType",
-     "pk": 2,
-     "fields": {
-        "name": "Paired End (non-multiplexed)",
-        "can_multiplex": false,
-        "is_paired_end": true
-     }
-  },
-  {
-     "model": "samples.LibraryType",
-     "pk": 5,
-     "fields": {
-        "name": "Barcoded Illumina",
-        "can_multiplex": true,
-        "is_paired_end": true
-     }
-  },
-  {
-     "model": "samples.LibraryType",
-     "pk": 7,
-     "fields": {
-        "name": "Barcoded Small RNA",
-        "can_multiplex": true,
-        "is_paired_end": true
-     }
-  },
-  {
-     "model": "samples.LibraryType",
-     "pk": 8,
-     "fields": {
-        "name": "Nextera",
-        "can_multiplex": true,
-        "is_paired_end": true
-     }
-  },
-  {
-     "model": "samples.LibraryType",
-     "pk": 9,
-     "fields": {
-        "name": "Dual Index Illumina",
-        "can_multiplex": true,
-        "is_paired_end": true
-     }
-  },
-  {
-     "model": "samples.ExperimentType",
-     "pk": 1,
-     "fields": {
-        "name": "Unknown"
-     }
-  },
-  {
-     "model": "samples.ExperimentType",
-     "pk": 2,
-     "fields": {
-        "name": "ChIP-seq"
-     }
-  },
-  {
-     "model": "samples.ExperimentType",
-     "pk": 4,
-     "fields": {
-        "name": "RNA-seq"
-     }
-  },
-  {
-     "model": "samples.ExperimentType",
-     "pk": 7,
-     "fields": {
-        "name": "De Novo"
-     }
-  },
-  {
-     "model": "samples.ExperimentType",
-     "pk": 8,
-     "fields": {
-        "name": "Whole Genome"
-     }
-  },
-  {
-     "model": "samples.ExperimentType",
-     "pk": 9,
-     "fields": {
-        "name": "Small RNA"
-     }
-  },
-  {
-     "model": "samples.ExperimentType",
-     "pk": 10,
-     "fields": {
-        "name": "Multiplexed"
-     }
-  },
-  {
-     "model": "samples.Species",
-     "pk": 2,
-     "fields": {
-        "scientific_name": "Drosophila melanogaster",
-        "common_name": "fruit fly"
-     }
-  },
-  {
-     "model": "samples.Species",
-     "pk": 3,
-     "fields": {
-        "scientific_name": "Caenorhabditis elegans",
-        "common_name": ""
-     }
-  },
-  {
-     "model": "samples.Species",
-     "pk": 6,
-     "fields": {
-        "scientific_name": "Arabidopsis thaliana"
-     }
-  },
-  {
-     "model": "samples.Species",
-     "pk": 8,
-     "fields": {
-        "scientific_name": "Homo sapiens",
-        "common_name": "human"
-     }
-  },
-  {
-     "model": "samples.Species",
-     "pk": 9,
-     "fields": {
-        "scientific_name": "Mus musculus",
-        "common_name": "mouse"
-     }
-  },
-  {
-     "model": "samples.Species",
-     "pk": 10,
-     "fields": {
-        "scientific_name": "Strongylocentrotus purpuratus"
-     }
-  },
-  {
-    "pk": 1,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 1,
-      "adapter_type": 8,
-      "sequence": "ATCACG"
-    }
-  },
-  {
-    "pk": 2,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 2,
-      "adapter_type": 8,
-      "sequence": "CGATGT"
-    }
-  },
-  {
-    "pk": 3,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 3,
-      "adapter_type": 8,
-      "sequence": "TTAGGC"
-    }
-  },
-  {
-    "pk": 4,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 4,
-      "adapter_type": 8,
-      "sequence": "TGACCA"
-    }
-  },
-  {
-    "pk": 5,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 5,
-      "adapter_type": 8,
-      "sequence": "ACAGTG"
-    }
-  },
-  {
-    "pk": 6,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 6,
-      "adapter_type": 8,
-      "sequence": "GCCAAT"
-    }
-  },
-  {
-    "pk": 7,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 7,
-      "adapter_type": 8,
-      "sequence": "CAGATC"
-    }
-  },
-  {
-    "pk": 8,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 8,
-      "adapter_type": 8,
-      "sequence": "ACTTGA"
-    }
-  },
-  {
-    "pk": 9,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 9,
-      "adapter_type": 8,
-      "sequence": "GATCAG"
-    }
-  },
-  {
-    "pk": 10,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 10,
-      "adapter_type": 8,
-      "sequence": "TAGCTT"
-    }
-  },
-  {
-    "pk": 11,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 11,
-      "adapter_type": 8,
-      "sequence": "GGCTAC"
-    }
-  },
-  {
-    "pk": 12,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 12,
-      "adapter_type": 8,
-      "sequence": "CTTGTA"
-    }
-  },
-  {
-    "pk": 13,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 1,
-      "adapter_type": 7,
-      "sequence": "ATCACG"
-    }
-  },
-  {
-    "pk": 14,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 2,
-      "adapter_type": 7,
-      "sequence": "CGATGT"
-    }
-  },
-  {
-    "pk": 15,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 3,
-      "adapter_type": 7,
-      "sequence": "TTAGGC"
-    }
-  },
-  {
-    "pk": 16,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 4,
-      "adapter_type": 7,
-      "sequence": "TGACCA"
-    }
-  },
-  {
-    "pk": 17,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 5,
-      "adapter_type": 7,
-      "sequence": "ACAGTG"
-    }
-  },
-  {
-    "pk": 18,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 6,
-      "adapter_type": 7,
-      "sequence": "GCCAAT"
-    }
-  },
-  {
-    "pk": 19,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 7,
-      "adapter_type": 7,
-      "sequence": "CAGATC"
-    }
-  },
-  {
-    "pk": 20,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 8,
-      "adapter_type": 7,
-      "sequence": "ACTTGA"
-    }
-  },
-  {
-    "pk": 21,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 9,
-      "adapter_type": 7,
-      "sequence": "GATCAG"
-    }
-  },
-  {
-    "pk": 22,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 10,
-      "adapter_type": 7,
-      "sequence": "TAGCTT"
-    }
-  },
-  {
-    "pk": 23,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 11,
-      "adapter_type": 7,
-      "sequence": "GGCTAC"
-    }
-  },
-  {
-    "pk": 24,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 12,
-      "adapter_type": 7,
-      "sequence": "CTTGTA"
-    }
-  },
-  {
-    "pk": 25,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 13,
-      "adapter_type": 7,
-      "sequence": "AGTCAA"
-    }
-  },
-  {
-    "pk": 26,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 14,
-      "adapter_type": 7,
-      "sequence": "AGTTCC"
-    }
-  },
-  {
-    "pk": 27,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 15,
-      "adapter_type": 7,
-      "sequence": "ATGTCA"
-    }
-  },
-  {
-    "pk": 28,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 16,
-      "adapter_type": 7,
-      "sequence": "CCGTCC"
-    }
-  },
-  {
-    "pk": 29,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 17,
-      "adapter_type": 7,
-      "sequence": "GTAGAG"
-    }
-  },
-  {
-    "pk": 30,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 18,
-      "adapter_type": 7,
-      "sequence": "GTCCGC"
-    }
-  },
-  {
-    "pk": 31,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 19,
-      "adapter_type": 7,
-      "sequence": "GTGAAA"
-    }
-  },
-  {
-    "pk": 32,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 20,
-      "adapter_type": 7,
-      "sequence": "GTGGCC"
-    }
-  },
-  {
-    "pk": 33,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 21,
-      "adapter_type": 7,
-      "sequence": "GTTTCG"
-    }
-  },
-  {
-    "pk": 34,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 22,
-      "adapter_type": 7,
-      "sequence": "CGTACG"
-    }
-  },
-  {
-    "pk": 35,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 23,
-      "adapter_type": 7,
-      "sequence": "GAGTGG"
-    }
-  },
-  {
-    "pk": 36,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 24,
-      "adapter_type": 7,
-      "sequence": "GGTAGC"
-    }
-  },
-  {
-    "pk": 37,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 25,
-      "adapter_type": 7,
-      "sequence": "ACTGAT"
-    }
-  },
-  {
-    "pk": 38,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 26,
-      "adapter_type": 7,
-      "sequence": "ATGAGC"
-    }
-  },
-  {
-    "pk": 39,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 27,
-      "adapter_type": 7,
-      "sequence": "ATTCCT"
-    }
-  },
-  {
-    "pk": 40,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 28,
-      "adapter_type": 7,
-      "sequence": "CAAAAG"
-    }
-  },
-  {
-    "pk": 41,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 29,
-      "adapter_type": 7,
-      "sequence": "CAACTA"
-    }
-  },
-  {
-    "pk": 42,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 30,
-      "adapter_type": 7,
-      "sequence": "CACCGG"
-    }
-  },
-  {
-    "pk": 43,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 31,
-      "adapter_type": 7,
-      "sequence": "CACGAT"
-    }
-  },
-  {
-    "pk": 44,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 32,
-      "adapter_type": 7,
-      "sequence": "CACTCA"
-    }
-  },
-  {
-    "pk": 45,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 33,
-      "adapter_type": 7,
-      "sequence": "CAGGCG"
-    }
-  },
-  {
-    "pk": 46,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 34,
-      "adapter_type": 7,
-      "sequence": "CATGGC"
-    }
-  },
-  {
-    "pk": 47,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 35,
-      "adapter_type": 7,
-      "sequence": "CATTTT"
-    }
-  },
-  {
-    "pk": 48,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 36,
-      "adapter_type": 7,
-      "sequence": "CCAACA"
-    }
-  },
-  {
-    "pk": 49,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 37,
-      "adapter_type": 7,
-      "sequence": "CGGAAT"
-    }
-  },
-  {
-    "pk": 50,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 38,
-      "adapter_type": 7,
-      "sequence": "CTAGCT"
-    }
-  },
-  {
-    "pk": 51,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 39,
-      "adapter_type": 7,
-      "sequence": "CTATAC"
-    }
-  },
-  {
-    "pk": 52,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 40,
-      "adapter_type": 7,
-      "sequence": "CTCAGA"
-    }
-  },
-  {
-    "pk": 53,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 41,
-      "adapter_type": 7,
-      "sequence": "GACGAC"
-    }
-  },
-  {
-    "pk": 54,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 42,
-      "adapter_type": 7,
-      "sequence": "TAATCG"
-    }
-  },
-  {
-    "pk": 55,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 43,
-      "adapter_type": 7,
-      "sequence": "TACAGC"
-    }
-  },
-  {
-    "pk": 56,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 44,
-      "adapter_type": 7,
-      "sequence": "TATAAT"
-    }
-  },
-  {
-    "pk": 57,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 45,
-      "adapter_type": 7,
-      "sequence": "TCATTC"
-    }
-  },
-  {
-    "pk": 58,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 46,
-      "adapter_type": 7,
-      "sequence": "TCCCGA"
-    }
-  },
-  {
-    "pk": 59,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 47,
-      "adapter_type": 7,
-      "sequence": "TCGAAG"
-    }
-  },
-  {
-    "pk": 60,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 48,
-      "adapter_type": 7,
-      "sequence": "TCGGCA"
-    }
-  },
-  {
-    "pk": 61,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 1,
-      "adapter_type": 5,
-      "sequence": "ATCACG"
-    }
-  },
-  {
-    "pk": 62,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 2,
-      "adapter_type": 5,
-      "sequence": "CGATGT"
-    }
-  },
-  {
-    "pk": 63,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 3,
-      "adapter_type": 5,
-      "sequence": "TTAGGC"
-    }
-  },
-  {
-    "pk": 64,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 4,
-      "adapter_type": 5,
-      "sequence": "TGACCA"
-    }
-  },
-  {
-    "pk": 65,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 5,
-      "adapter_type": 5,
-      "sequence": "ACAGTG"
-    }
-  },
-  {
-    "pk": 66,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 6,
-      "adapter_type": 5,
-      "sequence": "GCCAAT"
-    }
-  },
-  {
-    "pk": 67,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 7,
-      "adapter_type": 5,
-      "sequence": "CAGATC"
-    }
-  },
-  {
-    "pk": 68,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 8,
-      "adapter_type": 5,
-      "sequence": "ACTTGA"
-    }
-  },
-  {
-    "pk": 69,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 9,
-      "adapter_type": 5,
-      "sequence": "GATCAG"
-    }
-  },
-  {
-    "pk": 70,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 10,
-      "adapter_type": 5,
-      "sequence": "TAGCTT"
-    }
-  },
-  {
-    "pk": 71,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 11,
-      "adapter_type": 5,
-      "sequence": "GGCTAC"
-    }
-  },
-  {
-    "pk": 72,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 12,
-      "adapter_type": 5,
-      "sequence": "CTTGTA"
-    }
-  },
-  {"fields": {"adapter_type": 9,
-             "multiplex_id": "N501",
-             "sequence": "TAGATCGC"},
-  "model": "samples.multiplexindex",
-  "pk": 74
-  },
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N502",
-             "sequence": "CTCTCTAT"},
-  "model": "samples.multiplexindex",
-  "pk": 75},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N503",
-             "sequence": "TATCCTCT"},
-  "model": "samples.multiplexindex",
-  "pk": 76},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N504",
-             "sequence": "AGAGTAGA"},
-  "model": "samples.multiplexindex",
-  "pk": 77},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N505",
-             "sequence": "GTAAGGAG"},
-  "model": "samples.multiplexindex",
-  "pk": 78},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N506",
-             "sequence": "ACTGCATA"},
-  "model": "samples.multiplexindex",
-  "pk": 79},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N507",
-             "sequence": "AAGGAGTA"},
-  "model": "samples.multiplexindex",
-  "pk": 80},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N508",
-             "sequence": "CTAAGCCT"},
-  "model": "samples.multiplexindex",
-  "pk": 81},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N701",
-             "sequence": "TAAGGCGA"},
-  "model": "samples.multiplexindex",
-  "pk": 82},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N702",
-             "sequence": "CGTACTAG"},
-  "model": "samples.multiplexindex",
-  "pk": 83},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N703",
-             "sequence": "AGGCAGAA"},
-  "model": "samples.multiplexindex",
-  "pk": 84},
- {"fields": {"adapter_type": 9, "multiplex_id": "N704", "sequence": "TCCTGA"},
-  "model": "samples.multiplexindex",
-  "pk": 85},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N705",
-             "sequence": "GGACTCCT"},
-  "model": "samples.multiplexindex",
-  "pk": 86},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N706",
-             "sequence": "TAGGCATG"},
-  "model": "samples.multiplexindex",
-  "pk": 87},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N707",
-             "sequence": "CTCTCTAC"},
-  "model": "samples.multiplexindex",
-  "pk": 88},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N708",
-             "sequence": "CAGAGAGG"},
-  "model": "samples.multiplexindex",
-  "pk": 89},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N709",
-             "sequence": "GCTACGCT"},
-  "model": "samples.multiplexindex",
-  "pk": 90},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N710",
-             "sequence": "CGAGGCTG"},
-  "model": "samples.multiplexindex",
-  "pk": 91},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N711",
-             "sequence": "AAGAGGCA"},
-  "model": "samples.multiplexindex",
-  "pk": 92},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N712",
-             "sequence": "GTAGAGGA"},
-  "model": "samples.multiplexindex",
-  "pk": 93}
-]
diff --git a/samples/fixtures/test_samples.json b/samples/fixtures/test_samples.json
deleted file mode 100644 (file)
index 41824e0..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-[
-  {"pk": 5, "model": "auth.user",
-   "fields": {
-       "username": "test",
-       "first_name": "",
-       "last_name": "",
-       "is_active": true,
-       "is_superuser": false,
-       "is_staff": false,
-       "last_login": "2009-01-01T00:00:01-0800",
-       "groups": [],
-       "user_permissions": [],
-       "password": "sha1$foo$5e4eefec1144a04becfb7da79244f07c487fc345",
-       "email": "",
-       "date_joined": "2009-01-01T00:01:01-0800"
-       }
-   },
-   {"pk": 1, "model": "samples.affiliation",
-    "fields": {
-        "users": [5],
-        "name": "Alice",
-        "contact": "Lab Boss",
-        "email": "alice@some.where.else."
-        }
-    },
-    {"pk": 2, "model": "samples.affiliation",
-     "fields": { "name": "Bob",
-                 "contact": "Other Lab Boss",
-                 "email": "bob@some.where.else"
-               }
-    },
-    {"pk": 3, "model": "samples.affiliation",
-     "fields": {
-         "users": [],
-         "contact": "group 3",
-         "name": "affiliation 3",
-         "email": "pk3@example.com"
-         }
-     },
-    {"pk": 4, "model": "samples.affiliation",
-     "fields": {
-         "users": [],
-         "contact": "group 4",
-         "name": "affiliation 4",
-         "email": "pk1@example.com"
-         }
-     },
-    {"pk": 5, "model": "samples.affiliation",
-     "fields": {
-         "users": [],
-         "contact": "group 5",
-         "name": "affiliation 5",
-         "email": "pk5@example.com"
-         }
-     },
- {"pk": 153, "model": "experiments.flowcell",
-  "fields": {
-      "paired_end": true,
-      "run_date": "2009-09-11T22:12:13-0800",
-      "read_length": 75,
-      "notes": "",
-      "advanced_run": false,
-      "control_lane": 2,
-      "cluster_station": 3,
-      "sequencer": 2,
-      "flowcell_id": "303TUAAXX"
-      }
-  },
-  {"pk": 1193, "model": "experiments.lane",
-   "fields": {
-       "comment": "No change in cluster numbers, despite slight increase in pM",
-       "library": "10981",
-       "cluster_estimate": 129000,
-       "flowcell": 153,
-       "lane_number": 1,
-       "pM": "8"
-       }
-   },
-  {"pk": 1197, "model": "experiments.lane",
-   "fields": {
-       "comment": "stuff",
-       "library": "11016",
-       "cluster_estimate": 140000,
-       "flowcell": 153,
-       "lane_number": 5,
-       "pM": "7",
-       "status": 2
-       }
-   },
-  {"pk": "10981", "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 400,
-            "library_name": "Paired End Multiplexed Sp-BAC",
-            "creation_date": "2009-07-21",
-            "cell_line": 1,
-            "library_species": 2,
-            "library_type": null,
-            "made_by": "Igor",
-            "affiliations": [
-                2
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "Done",
-            "tags": [],
-            "made_for": "Andy Cameron",
-            "amplified_from_sample": null,
-            "notes": "Combined 10957-10968",
-            "undiluted_concentration": "5.1",
-            "successful_pM": null,
-            "experiment_type": 10,
-            "antibody": null
-        }
-    },
-    {
-        "pk": "11016",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 325,
-            "library_name": "Paired End Pfl #3 MP 7/24/9 a",
-            "creation_date": "2009-08-06",
-            "cell_line": 1,
-            "library_species": 9,
-            "library_type": 2,
-            "made_by": "Lorian",
-            "affiliations": [
-                3
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "1Aa",
-            "tags": [],
-            "made_for": "",
-            "amplified_from_sample": "11003",
-            "notes": "7/31/2009 16:08:22\tColor: Blue",
-            "undiluted_concentration": "35.5",
-            "successful_pM": null,
-            "experiment_type": 8,
-            "antibody": null
-        }
-    },
-    {
-        "pk": "11039",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 300,
-            "library_name": "Paired ends 99 GM12892",
-            "creation_date": "2009-08-25",
-            "cell_line": 1,
-            "library_species": 8,
-            "library_type": 2,
-            "made_by": "Brian Williams",
-            "affiliations": [
-                1,
-                2,
-                4
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "1Aa",
-            "tags": [],
-            "made_for": "Brian Williams",
-            "amplified_from_sample": null,
-            "notes": "fragment size = 300 bp, Amicon filtered\r\nnanodrop: 56.3",
-            "undiluted_concentration": "28.7",
-            "successful_pM": null,
-            "experiment_type": 4,
-            "antibody": null
-        }
-    },
-    {
-        "pk": "11003",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 325,
-            "library_name": "Paired End Pfl #3 MP 7/24/9",
-            "creation_date": "2009-08-05",
-            "cell_line": 1,
-            "library_species": 8,
-            "library_type": 2,
-            "made_by": "Lorian",
-            "affiliations": [
-                4
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": true,
-            "stopping_point": "1A",
-            "tags": [],
-            "made_for": "",
-            "amplified_from_sample": null,
-            "notes": "7/31/2009 16:08:22\tColor: Blue",
-            "undiluted_concentration": null,
-            "successful_pM": null,
-            "experiment_type": 8,
-            "antibody": null
-        }
-    },
-    {
-        "pk": "11005",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 325,
-            "library_name": "null cell line",
-            "creation_date": "2009-08-05",
-            "cell_line": null,
-            "library_species": 8,
-            "library_type": 2,
-            "made_by": "Lorian",
-            "affiliations": [
-                4
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": true,
-            "stopping_point": "1A",
-            "tags": [],
-            "made_for": "",
-            "amplified_from_sample": null,
-            "notes": "7/31/2009 16:08:22\tColor: Blue",
-            "undiluted_concentration": null,
-            "successful_pM": null,
-            "experiment_type": 8,
-            "antibody": null
-        }
-    }
-]
diff --git a/samples/migrations/0001_initial.py b/samples/migrations/0001_initial.py
new file mode 100644 (file)
index 0000000..be78e51
--- /dev/null
@@ -0,0 +1,210 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+from django.conf import settings
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('auth', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Affiliation',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('name', models.CharField(max_length=256, verbose_name=b'Name', db_index=True)),
+                ('contact', models.CharField(max_length=256, null=True, verbose_name=b'Lab Name', blank=True)),
+                ('email', models.EmailField(max_length=75, null=True, blank=True)),
+            ],
+            options={
+                'ordering': ['name', 'contact'],
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Antibody',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('antigene', models.CharField(max_length=500, db_index=True)),
+                ('nickname', models.CharField(db_index=True, max_length=20, null=True, blank=True)),
+                ('catalog', models.CharField(max_length=50, null=True, blank=True)),
+                ('antibodies', models.CharField(max_length=500, db_index=True)),
+                ('source', models.CharField(db_index=True, max_length=500, null=True, blank=True)),
+                ('biology', models.TextField(null=True, blank=True)),
+                ('notes', models.TextField(null=True, blank=True)),
+            ],
+            options={
+                'ordering': ['antigene'],
+                'verbose_name_plural': 'antibodies',
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Cellline',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('cellline_name', models.CharField(unique=True, max_length=100, db_index=True)),
+                ('nickname', models.CharField(db_index=True, max_length=20, null=True, blank=True)),
+                ('notes', models.TextField(blank=True)),
+            ],
+            options={
+                'ordering': ['cellline_name'],
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Condition',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('condition_name', models.CharField(unique=True, max_length=2000, db_index=True)),
+                ('nickname', models.CharField(db_index=True, max_length=20, null=True, verbose_name=b'Short Name', blank=True)),
+                ('notes', models.TextField(blank=True)),
+            ],
+            options={
+                'ordering': ['condition_name'],
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ExperimentType',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('name', models.CharField(unique=True, max_length=50)),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='HTSUser',
+            fields=[
+                ('user_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)),
+            ],
+            options={
+                'ordering': ['first_name', 'last_name', 'username'],
+            },
+            bases=('auth.user',),
+        ),
+        migrations.CreateModel(
+            name='Library',
+            fields=[
+                ('id', models.CharField(max_length=10, serialize=False, primary_key=True)),
+                ('library_name', models.CharField(unique=True, max_length=100)),
+                ('hidden', models.BooleanField(default=False)),
+                ('account_number', models.CharField(max_length=100, null=True, blank=True)),
+                ('replicate', models.PositiveSmallIntegerField(blank=True, null=True, choices=[(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)])),
+                ('multiplex_id', models.CharField(max_length=128, null=True, verbose_name=b'Index ID', blank=True)),
+                ('creation_date', models.DateField(null=True, blank=True)),
+                ('made_for', models.CharField(max_length=50, verbose_name=b'ChIP/DNA/RNA Made By', blank=True)),
+                ('made_by', models.CharField(default=b'Lorian', max_length=50, blank=True)),
+                ('stopping_point', models.CharField(default=b'Done', max_length=25, choices=[(b'?', b'Unknown'), (b'Sample', b'Raw sample'), (b'Progress', b'In progress'), (b'1A', b'Ligation, then gel'), (b'PCR', b'Ligation, then PCR'), (b'1Ab', b'Ligation, PCR, then gel'), (b'1Ac', b'Ligation, gel, then 12x PCR'), (b'1Aa', b'Ligation, gel, then 18x PCR'), (b'2A', b'Ligation, PCR, gel, PCR'), (b'Done', b'Completed')])),
+                ('undiluted_concentration', models.DecimalField(decimal_places=2, max_digits=5, blank=True, help_text='Undiluted concentration (ng/\xb5l)', null=True, verbose_name=b'Concentration')),
+                ('successful_pM', models.DecimalField(null=True, max_digits=9, decimal_places=1, blank=True)),
+                ('ten_nM_dilution', models.BooleanField(default=False)),
+                ('gel_cut_size', models.IntegerField(default=225, null=True, blank=True)),
+                ('insert_size', models.IntegerField(null=True, blank=True)),
+                ('notes', models.TextField(blank=True)),
+                ('bioanalyzer_summary', models.TextField(default=b'', blank=True)),
+                ('bioanalyzer_concentration', models.DecimalField(help_text='(ng/\xb5l)', null=True, max_digits=5, decimal_places=2, blank=True)),
+                ('bioanalyzer_image_url', models.URLField(default=b'', blank=True)),
+                ('affiliations', models.ManyToManyField(related_name=b'library_affiliations', null=True, to='samples.Affiliation')),
+                ('amplified_from_sample', models.ForeignKey(related_name=b'amplified_into_sample', blank=True, to='samples.Library', null=True)),
+                ('antibody', models.ForeignKey(blank=True, to='samples.Antibody', null=True)),
+                ('cell_line', models.ForeignKey(verbose_name=b'Background', blank=True, to='samples.Cellline', null=True)),
+                ('condition', models.ForeignKey(blank=True, to='samples.Condition', null=True)),
+                ('experiment_type', models.ForeignKey(to='samples.ExperimentType')),
+            ],
+            options={
+                'ordering': ['-id'],
+                'verbose_name_plural': 'libraries',
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='LibraryType',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('name', models.CharField(unique=True, max_length=255, verbose_name=b'Adapter Type')),
+                ('is_paired_end', models.BooleanField(default=True, help_text=b'can you do a paired end run with this adapter')),
+                ('can_multiplex', models.BooleanField(default=True, help_text=b'Does this adapter provide multiplexing?')),
+            ],
+            options={
+                'ordering': ['-id'],
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='MultiplexIndex',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('multiplex_id', models.CharField(max_length=6)),
+                ('sequence', models.CharField(max_length=12, null=True, blank=True)),
+                ('adapter_type', models.ForeignKey(to='samples.LibraryType')),
+            ],
+            options={
+                'verbose_name_plural': 'multiplex indicies',
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Species',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('scientific_name', models.CharField(max_length=256, db_index=True)),
+                ('common_name', models.CharField(max_length=256, blank=True)),
+            ],
+            options={
+                'ordering': ['scientific_name'],
+                'verbose_name_plural': 'species',
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Tag',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('tag_name', models.CharField(max_length=100, db_index=True)),
+                ('context', models.CharField(default=b'Library', max_length=50, choices=[(b'Library', b'Library'), (b'ANY', b'ANY')])),
+            ],
+            options={
+                'ordering': ['context', 'tag_name'],
+            },
+            bases=(models.Model,),
+        ),
+        migrations.AlterUniqueTogether(
+            name='multiplexindex',
+            unique_together=set([('adapter_type', 'multiplex_id')]),
+        ),
+        migrations.AddField(
+            model_name='library',
+            name='library_species',
+            field=models.ForeignKey(to='samples.Species'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='library',
+            name='library_type',
+            field=models.ForeignKey(verbose_name=b'Adapter Type', blank=True, to='samples.LibraryType', null=True),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='library',
+            name='tags',
+            field=models.ManyToManyField(related_name=b'library_tags', null=True, to='samples.Tag', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='affiliation',
+            name='users',
+            field=models.ManyToManyField(to='samples.HTSUser', null=True, blank=True),
+            preserve_default=True,
+        ),
+        migrations.AlterUniqueTogether(
+            name='affiliation',
+            unique_together=set([('name', 'contact')]),
+        ),
+    ]
diff --git a/samples/migrations/__init__.py b/samples/migrations/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/samples/samples_factory.py b/samples/samples_factory.py
new file mode 100644 (file)
index 0000000..f5c00a3
--- /dev/null
@@ -0,0 +1,91 @@
+import datetime
+
+import factory
+from factory.django import DjangoModelFactory
+from . import models
+
+class AffiliationFactory(DjangoModelFactory):
+    class Meta:
+        model = models.Affiliation
+
+    name = 'affiliation'
+    contact = 'contact name'
+    email = factory.LazyAttribute(lambda obj: '%s@example.com' % obj.name)
+
+    @factory.post_generation
+    def users(self, create, extracted, **kwargs):
+        if not create:
+            return
+
+        if extracted:
+            for user in extracted:
+                self.users.add(user)
+                
+class AntibodyFactory(DjangoModelFactory):
+    class Meta:
+        model = models.Antibody
+
+    antigen = 'antigen'
+    nickname = 'short name'
+    catalog = 'catalog #'
+    antibodies = 'antibody'
+    source = 'source'
+    biology = 'some biological description'
+    notes = 'some notes'
+
+
+class CelllineFactory(DjangoModelFactory):
+    class Meta:
+        model = models.Cellline
+
+    cellline_name = 'Test'
+    nickname = 'Test'
+    notes = 'Notes'
+
+    
+class ConditionFactory(DjangoModelFactory):
+    class Meta:
+        model = models.Condition
+
+    condition_name = 'condition name'
+    nicname = 'nickname'
+    notes = 'notes'
+    
+class ExperimentTypeFactory(DjangoModelFactory):
+    class Meta:
+        model = models.ExperimentType
+
+    name = 'experiment type name'
+
+class HTSUserFactory(DjangoModelFactory):
+    class Meta:
+        model = models.HTSUser
+
+    username = 'username'
+    email = factory.LazyAttribute(lambda obj: '%s@example.org' % obj.username)
+    
+#class Tag
+
+class SpeciesFactory(DjangoModelFactory):
+    class Meta:
+        model = models.Species
+
+    scientific_name = 'test sapiens'
+    common_name = 'test human'
+
+        
+class LibraryFactory(DjangoModelFactory):
+    class Meta:
+        model = models.Library
+
+    id = '10001'
+    library_name = 'C1C1 test'
+    library_species = factory.SubFactory(SpeciesFactory)
+    experiment_type = factory.SubFactory(ExperimentTypeFactory)
+    creation_date = datetime.datetime.now()
+    gel_cut_size = 400
+    made_for = 'scientist unit 2007'
+    made_by = 'microfluidics bot 7321'
+    stopping_point = '2A'
+    undiluted_concentration = '5.01'
+    hidden = False
index b11fb943a2d845b0898284953e671b971d3536ba..70561349bde149c8cd9dd577fb2d8c98318007e3 100644 (file)
@@ -1,48 +1,45 @@
 from __future__ import absolute_import, print_function
 
 import datetime
+import unittest
+import json
 
-try:
-    import json
-except ImportError, e:
-    import simplejson as json
-
-from django.test import TestCase
-from django.test.utils import setup_test_environment, \
-     teardown_test_environment
-from django.db import connection
+from django.test import TestCase, RequestFactory
 from django.conf import settings
 
 from .models import Affiliation, ExperimentType, Species, Library
-
-from .views import library_dict, library_json
+from .views import library_dict, library_json, library
+from .samples_factory import *
 
 from htsworkflow.auth import apidata
 from htsworkflow.util.conversion import unicode_or_none
 from htsworkflow.util.ethelp import validate_xhtml
 
 class LibraryTestCase(TestCase):
-    fixtures = ['initial_data.json',
-                'woldlab.json',
-                'test_samples.json']
+    def testOrganism(self):
+        human = SpeciesFactory(common_name='human')
+        self.assertEquals(human.common_name, 'human')
+        library = LibraryFactory(library_species=human)
+        self.assertEquals(library.organism(), 'human')
 
-    def setUp(self):
-        create_db(self)
+    def testAddingOneAffiliation(self):
+        affiliation = AffiliationFactory.create(name='Alice')
+        library = LibraryFactory()
+        library.affiliations.add(affiliation)
 
-    def testOrganism(self):
-        self.assertEquals(self.library_10001.organism(), 'human')
+        self.assertEqual(len(library.affiliations.all()), 1)
+        self.assertEqual(library.affiliation(), 'Alice (contact name)')
+
+    def testMultipleAffiliations(self):
+        alice = AffiliationFactory.create(name='Alice')
+        bob = AffiliationFactory.create(name='Bob')
 
-    def testAffiliations(self):
-        self.library_10001.affiliations.add(self.affiliation_alice)
-        self.library_10002.affiliations.add(
-                self.affiliation_alice,
-                self.affiliation_bob
-        )
-        self.failUnless(len(self.library_10001.affiliations.all()), 1)
-        self.failUnless(self.library_10001.affiliation(), 'Alice')
+        library = LibraryFactory()
+        library.affiliations.add(alice, bob)
 
-        self.failUnless(len(self.library_10002.affiliations.all()), 2)
-        self.failUnless(self.library_10001.affiliation(), 'Alice, Bob')
+        self.assertEqual(len(library.affiliations.all()), 2)
+        self.assertEqual(library.affiliation(), 
+                         'Alice (contact name), Bob (contact name)')
 
 
 class SampleWebTestCase(TestCase):
@@ -50,52 +47,48 @@ class SampleWebTestCase(TestCase):
     Test returning data from our database in rest like ways.
     (like returning json objects)
     """
-    fixtures = ['initial_data.json',
-                'woldlab.json',
-                'test_samples.json']
-
-    def test_library_info(self):
-        for lib in Library.objects.all():
-            lib_dict = library_dict(lib.id)
-            url = '/samples/library/%s/json' % (lib.id,)
-            lib_response = self.client.get(url, apidata)
-            self.failUnlessEqual(lib_response.status_code, 200)
-            lib_json = json.loads(lib_response.content)
-
-            for d in [lib_dict, lib_json]:
-                # amplified_from_sample is a link to the library table,
-                # I want to use the "id" for the data lookups not
-                # the embedded primary key.
-                # It gets slightly confusing on how to implement sending the right id
-                # since amplified_from_sample can be null
-                #self.failUnlessEqual(d['amplified_from_sample'], lib.amplified_from_sample)
-                self.failUnlessEqual(d['antibody_id'], lib.antibody_id)
-                self.failUnlessEqual(d['cell_line_id'], lib.cell_line_id)
-                self.failUnlessEqual(d['cell_line'], unicode_or_none(lib.cell_line))
-                self.failUnlessEqual(d['experiment_type'], lib.experiment_type.name)
-                self.failUnlessEqual(d['experiment_type_id'], lib.experiment_type_id)
-                self.failUnlessEqual(d['gel_cut_size'], lib.gel_cut_size)
-                self.failUnlessEqual(d['hidden'], lib.hidden)
-                self.failUnlessEqual(d['id'], lib.id)
-                self.failUnlessEqual(d['insert_size'], lib.insert_size)
-                self.failUnlessEqual(d['library_name'], lib.library_name)
-                self.failUnlessEqual(d['library_species'], lib.library_species.scientific_name)
-                self.failUnlessEqual(d['library_species_id'], lib.library_species_id)
-                self.failUnlessEqual(d['library_type_id'], lib.library_type_id)
-                if lib.library_type_id is not None:
-                    self.failUnlessEqual(d['library_type'], lib.library_type.name)
-                else:
-                    self.failUnlessEqual(d['library_type'], None)
-                    self.failUnlessEqual(d['made_for'], lib.made_for)
-                    self.failUnlessEqual(d['made_by'], lib.made_by)
-                    self.failUnlessEqual(d['notes'], lib.notes)
-                    self.failUnlessEqual(d['replicate'], lib.replicate)
-                    self.failUnlessEqual(d['stopping_point'], lib.stopping_point)
-                    self.failUnlessEqual(d['successful_pM'], lib.successful_pM)
-                    self.failUnlessEqual(d['undiluted_concentration'],
-                                         unicode(lib.undiluted_concentration))
+    def test_library_dict(self):
+        library = LibraryFactory.create()
+        lib_dict = library_dict(library.id)
+        url = '/samples/library/%s/json' % (library.id,)
+        lib_response = self.client.get(url, apidata)
+        lib_json = json.loads(lib_response.content)
+        
+
+        for d in [lib_dict, lib_json]:
+            # amplified_from_sample is a link to the library table,
+            # I want to use the "id" for the data lookups not
+            # the embedded primary key.
+            # It gets slightly confusing on how to implement sending the right id
+            # since amplified_from_sample can be null
+            #self.failUnlessEqual(d['amplified_from_sample'], lib.amplified_from_sample)
+            self.failUnlessEqual(d['antibody_id'], library.antibody_id)
+            self.failUnlessEqual(d['cell_line_id'], library.cell_line_id)
+            self.failUnlessEqual(d['cell_line'], unicode_or_none(library.cell_line))
+            self.failUnlessEqual(d['experiment_type'], library.experiment_type.name)
+            self.failUnlessEqual(d['experiment_type_id'], library.experiment_type_id)
+            self.failUnlessEqual(d['gel_cut_size'], library.gel_cut_size)
+            self.failUnlessEqual(d['hidden'], library.hidden)
+            self.failUnlessEqual(d['id'], library.id)
+            self.failUnlessEqual(d['insert_size'], library.insert_size)
+            self.failUnlessEqual(d['library_name'], library.library_name)
+            self.failUnlessEqual(d['library_species'], library.library_species.scientific_name)
+            self.failUnlessEqual(d['library_species_id'], library.library_species_id)
+            self.failUnlessEqual(d['library_type_id'], library.library_type_id)
+            self.failUnlessEqual(d['library_type'], None)
+            self.failUnlessEqual(d['made_for'], library.made_for)
+            self.failUnlessEqual(d['made_by'], library.made_by)
+            self.failUnlessEqual(d['notes'], library.notes)
+            self.failUnlessEqual(d['replicate'], library.replicate)
+            self.failUnlessEqual(d['stopping_point'], library.stopping_point)
+            self.failUnlessEqual(d['successful_pM'], library.successful_pM)
+            self.failUnlessEqual(d['undiluted_concentration'],
+                                 unicode(library.undiluted_concentration))
+
+
+        def junk(self):
                 # some specific tests
-                if lib.id == '10981':
+                if library.id == '10981':
                     # test a case where there is no known status
                     lane_set = {u'status': u'Unknown',
                                 u'paired_end': True,
@@ -106,7 +99,7 @@ class SampleWebTestCase(TestCase):
                                 u'status_code': None}
                     self.failUnlessEqual(len(d['lane_set']), 1)
                     self.failUnlessEqual(d['lane_set'][0], lane_set)
-                elif lib.id == '11016':
+                elif library.id == '11016':
                     # test a case where there is a status
                     lane_set = {u'status': 'Good',
                                 u'paired_end': True,
@@ -134,14 +127,19 @@ class SampleWebTestCase(TestCase):
 
     def test_library_no_key(self):
         """
-        Make sure we get a 302 if we're not logged in
+        Make sure we get a 403 if we're not logged in
         """
-        response = self.client.get('/samples/library/10981/json')
-        self.failUnlessEqual(response.status_code, 403)
-        response = self.client.get('/samples/library/10981/json', apidata)
+        library = LibraryFactory.create()
+
+        url = '/samples/library/{}/json'.format(library.id)
+        response = self.client.get(url, apidata)
         self.failUnlessEqual(response.status_code, 200)
+        response = self.client.get(url)
+        self.failUnlessEqual(response.status_code, 403)
 
     def test_library_rdf(self):
+        library = LibraryFactory.create()
+        
         import RDF
         from htsworkflow.util.rdfhelp import get_model, \
              dump_model, \
@@ -151,7 +149,7 @@ class SampleWebTestCase(TestCase):
              libraryOntology
         model = get_model()
 
-        response = self.client.get('/library/10981/')
+        response = self.client.get(library.get_absolute_url())
         self.assertEqual(response.status_code, 200)
         content = response.content
         load_string_into_model(model, 'rdfa', content)
@@ -169,11 +167,14 @@ class SampleWebTestCase(TestCase):
         }"""
         query = RDF.SPARQLQuery(body)
         for r in query.execute(model):
-            self.assertEqual(fromTypedNode(r['library_id']), u'10981')
+            self.assertEqual(fromTypedNode(r['library_id']), 
+                             library.id)
             self.assertEqual(fromTypedNode(r['name']),
-                             u'Paired End Multiplexed Sp-BAC')
-            self.assertEqual(fromTypedNode(r['gel_cut']), 400)
-            self.assertEqual(fromTypedNode(r['made_by']), u'Igor')
+                             library.name)
+            self.assertEqual(fromTypedNode(r['gel_cut']), 
+                             library.gel_cut)
+            self.assertEqual(fromTypedNode(r['made_by']), 
+                             library.made_by)
 
         state = validate_xhtml(content)
         if state is not None:
@@ -274,41 +275,55 @@ try:
     rdfNS = RDF.NS("http://www.w3.org/1999/02/22-rdf-syntax-ns#")
     xsdNS = RDF.NS("http://www.w3.org/2001/XMLSchema#")
     libNS = RDF.NS("http://jumpgate.caltech.edu/wiki/LibraryOntology#")
+
+    from htsworkflow.util.rdfhelp import dump_model
 except ImportError,e:
     HAVE_RDF = False
 
 
 class TestRDFaLibrary(TestCase):
-    fixtures = ['initial_data.json',
-                'woldlab.json',
-                'test_samples.json']
 
+    def setUp(self):
+        self.request = RequestFactory()
+        
     def test_parse_rdfa(self):
+        
         model = get_rdf_memory_model()
         parser = RDF.Parser(name='rdfa')
-        url = '/library/10981/'
+
+        bob = AffiliationFactory.create(name='Bob')
+        
+        lib_object = LibraryFactory()
+        lib_object.affiliations.add(bob)
+        url = '/library/{}/'.format(lib_object.id)
+        ## request = self.request.get(url)
+        ## lib_response = library(request)
         lib_response = self.client.get(url)
+        with open('/tmp/body.html', 'w') as outstream:
+            outstream.write(lib_response.content)
         self.failIfEqual(len(lib_response.content), 0)
 
         parser.parse_string_into_model(model,
                                        lib_response.content,
                                        'http://localhost'+url)
+        with open('/tmp/test.ttl', 'w') as outstream:
+            dump_model(model, outstream)
         # http://jumpgate.caltech.edu/wiki/LibraryOntology#affiliation>
         self.check_literal_object(model, ['Bob'], p=libNS['affiliation'])
-        self.check_literal_object(model, ['Multiplexed'], p=libNS['experiment_type'])
+        self.check_literal_object(model, 
+                                  ['experiment type name'], 
+                                  p=libNS['experiment_type'])
         self.check_literal_object(model, ['400'], p=libNS['gel_cut'])
-        self.check_literal_object(model, ['Igor'], p=libNS['made_by'])
-        self.check_literal_object(model, ['Paired End Multiplexed Sp-BAC'], p=libNS['name'])
-        self.check_literal_object(model, ['Drosophila melanogaster'], p=libNS['species_name'])
-
-        self.check_uri_object(model,
-                              [u'http://localhost/lane/1193'],
-                              p=libNS['has_lane'])
-
-        fc_uri = RDF.Uri('http://localhost/flowcell/303TUAAXX/')
-        self.check_literal_object(model,
-                                  [u"303TUAAXX"],
-                                  s=fc_uri, p=libNS['flowcell_id'])
+        self.check_literal_object(model, 
+                                  ['microfluidics bot 7321'], 
+                                  p=libNS['made_by'])
+        self.check_literal_object(model, 
+                                  ['C1C1 test'], 
+                                  p=libNS['name'])
+        self.check_literal_object(model, 
+                                  ['test sapiens'], 
+                                  p=libNS['species_name'])
+
 
     def check_literal_object(self, model, values, s=None, p=None, o=None):
         statements = list(model.find_statements(