packages feed

BiobaseInfernal 0.5.0.0 → 0.5.1.0

raw patch · 7 files changed

+257/−211 lines, 7 filesdep +attoparsec-iterateedep +either-unwrapdep +iterateedep −attoparsec-enumeratordep −enumeratorPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: attoparsec-iteratee, either-unwrap, iteratee

Dependencies removed: attoparsec-enumerator, enumerator

API changes (from Hackage documentation)

- Biobase.Infernal.Taxonomy.Import: eeImport :: Monad m => Enumeratee ByteString Species m b
- Biobase.Infernal.VerboseHit.Export: StreamCM :: ByteString -> HitStream a
- Biobase.Infernal.VerboseHit.Export: StreamInsertion :: a -> HitStream a
- Biobase.Infernal.VerboseHit.Export: StreamScaffold :: ByteString -> HitStream a
- Biobase.Infernal.VerboseHit.Export: StreamStrand :: Char -> HitStream a
- Biobase.Infernal.VerboseHit.Export: StreamVerboseHit :: VerboseHit -> HitStream a
- Biobase.Infernal.VerboseHit.Export: data HitStream a
- Biobase.Infernal.VerboseHit.Export: eeFlattenStream :: Monad m => Enumeratee [HitStream z] (HitStream z) m a
- Biobase.Infernal.VerboseHit.Export: eeHitToStream :: Monad m => Enumeratee VerboseHit [HitStream z] m a
- Biobase.Infernal.VerboseHit.Export: eeStreamToByteString :: (Monad m, Show z) => StreamToByteString m z
- Biobase.Infernal.VerboseHit.Export: eeStreamToByteString' :: Monad m => StreamToByteString m ()
- Biobase.Infernal.VerboseHit.Export: instance Show a => Show (HitStream a)
- Biobase.Infernal.VerboseHit.Export: showCM :: ByteString -> ByteString
- Biobase.Infernal.VerboseHit.Export: showScaffold :: ByteString -> ByteString
- Biobase.Infernal.VerboseHit.Export: showStrand :: Char -> ByteString
- Biobase.Infernal.VerboseHit.Export: streamCM :: HitStream a -> ByteString
- Biobase.Infernal.VerboseHit.Export: streamInsertion :: HitStream a -> a
- Biobase.Infernal.VerboseHit.Export: streamScaffold :: HitStream a -> ByteString
- Biobase.Infernal.VerboseHit.Export: streamStrand :: HitStream a -> Char
- Biobase.Infernal.VerboseHit.Export: streamVerboseHit :: HitStream a -> VerboseHit
- Biobase.Infernal.VerboseHit.Export: type StreamToByteString m z = forall a. Enumeratee (HitStream z) ByteString m a
- Biobase.Infernal.VerboseHit.Import: eeToVerboseHit :: MonadIO m => Enumeratee ByteString VerboseHit m b
+ Biobase.Infernal: Species :: ByteString -> [ByteString] -> Int -> Species
+ Biobase.Infernal: TabularHit :: ByteString -> ByteString -> Int -> Int -> Int -> Int -> Double -> Double -> Int -> TabularHit
+ Biobase.Infernal: VerboseHit :: (Int, Int) -> (Int, Int) -> ByteString -> Strand -> Double -> Double -> Double -> Int -> ByteString -> ByteString -> ByteString -> ByteString -> ByteString -> VerboseHit
+ Biobase.Infernal: classification :: Species -> [ByteString]
+ Biobase.Infernal: data Species
+ Biobase.Infernal: data TabularHit
+ Biobase.Infernal: data VerboseHit
+ Biobase.Infernal: eneeTabularHit :: (Functor m, Monad m) => Enumeratee ByteString [TabularHit] m a
+ Biobase.Infernal: eneeVerboseHit :: (Functor m, Monad m) => Enumeratee ByteString [VerboseHit] m a
+ Biobase.Infernal: name :: Species -> ByteString
+ Biobase.Infernal: taxid :: Species -> Int
+ Biobase.Infernal: thBitScore :: TabularHit -> Double
+ Biobase.Infernal: thEvalue :: TabularHit -> Double
+ Biobase.Infernal: thFromFile :: FilePath -> IO [TabularHit]
+ Biobase.Infernal: thGCpercent :: TabularHit -> Int
+ Biobase.Infernal: thModel :: TabularHit -> ByteString
+ Biobase.Infernal: thQueryStart :: TabularHit -> Int
+ Biobase.Infernal: thQueryStop :: TabularHit -> Int
+ Biobase.Infernal: thScaffoldStart :: TabularHit -> Int
+ Biobase.Infernal: thScaffoldStop :: TabularHit -> Int
+ Biobase.Infernal: thTarget :: TabularHit -> ByteString
+ Biobase.Infernal: vhCM :: VerboseHit -> ByteString
+ Biobase.Infernal: vhConsensus :: VerboseHit -> ByteString
+ Biobase.Infernal: vhEneeByteString :: Monad m => Enumeratee [VerboseHit] ByteString m a
+ Biobase.Infernal: vhEvalue :: VerboseHit -> Double
+ Biobase.Infernal: vhFromFile :: FilePath -> IO [VerboseHit]
+ Biobase.Infernal: vhGC :: VerboseHit -> Int
+ Biobase.Infernal: vhPvalue :: VerboseHit -> Double
+ Biobase.Infernal: vhQuery :: VerboseHit -> (Int, Int)
+ Biobase.Infernal: vhScaffold :: VerboseHit -> ByteString
+ Biobase.Infernal: vhScore :: VerboseHit -> Double
+ Biobase.Infernal: vhScoring :: VerboseHit -> ByteString
+ Biobase.Infernal: vhSequence :: VerboseHit -> ByteString
+ Biobase.Infernal: vhStrand :: VerboseHit -> Strand
+ Biobase.Infernal: vhTarget :: VerboseHit -> (Int, Int)
+ Biobase.Infernal: vhWuss :: VerboseHit -> ByteString
+ Biobase.Infernal.TabularHit: TabularHit :: ByteString -> ByteString -> Int -> Int -> Int -> Int -> Double -> Double -> Int -> TabularHit
+ Biobase.Infernal.TabularHit: data TabularHit
+ Biobase.Infernal.TabularHit: instance Read TabularHit
+ Biobase.Infernal.TabularHit: instance Show TabularHit
+ Biobase.Infernal.TabularHit: thBitScore :: TabularHit -> Double
+ Biobase.Infernal.TabularHit: thEvalue :: TabularHit -> Double
+ Biobase.Infernal.TabularHit: thGCpercent :: TabularHit -> Int
+ Biobase.Infernal.TabularHit: thModel :: TabularHit -> ByteString
+ Biobase.Infernal.TabularHit: thQueryStart :: TabularHit -> Int
+ Biobase.Infernal.TabularHit: thQueryStop :: TabularHit -> Int
+ Biobase.Infernal.TabularHit: thScaffoldStart :: TabularHit -> Int
+ Biobase.Infernal.TabularHit: thScaffoldStop :: TabularHit -> Int
+ Biobase.Infernal.TabularHit: thTarget :: TabularHit -> ByteString
+ Biobase.Infernal.TabularHit.Import: eneeTabularHit :: (Functor m, Monad m) => Enumeratee ByteString [TabularHit] m a
+ Biobase.Infernal.TabularHit.Import: fromFile :: FilePath -> IO [TabularHit]
+ Biobase.Infernal.Taxonomy.Import: eneeSpecies :: Monad m => Enumeratee ByteString [Either String Species] m a
+ Biobase.Infernal.Taxonomy.Import: fromFile :: FilePath -> IO (Map ByteString Species, Map Int Species)
+ Biobase.Infernal.Taxonomy.Import: mkSpecies :: Parser Species
+ Biobase.Infernal.VerboseHit.Export: eneeByteString :: Monad m => Enumeratee [VerboseHit] ByteString m a
+ Biobase.Infernal.VerboseHit.Import: eneeVerboseHit :: (Functor m, Monad m) => Enumeratee ByteString [VerboseHit] m a
+ Biobase.Infernal.VerboseHit.Import: fromFile :: FilePath -> IO [VerboseHit]
- Biobase.Infernal.Taxonomy.Import: iSpeciesMap :: Monad m => Iteratee Species m (Map ByteString Species)
+ Biobase.Infernal.Taxonomy.Import: iSpeciesMap :: Monad m => Iteratee [Species] m (Map ByteString Species)
- Biobase.Infernal.Taxonomy.Import: iTaxIdMap :: Monad m => Iteratee Species m (Map Int Species)
+ Biobase.Infernal.Taxonomy.Import: iTaxIdMap :: Monad m => Iteratee [Species] m (Map Int Species)

Files

+ Biobase/Infernal.hs view
@@ -0,0 +1,32 @@++-- | Re-export the most import parts.++module Biobase.Infernal+  ( TabularHit(..)+  , thFromFile+  , eneeTabularHit+  , VerboseHit(..)+  , vhFromFile+  , eneeVerboseHit+  , vhEneeByteString+  , Species(..)+  ) where++import Data.ByteString as BS+import Data.Iteratee as I++import Biobase.Infernal.TabularHit+import Biobase.Infernal.TabularHit.Import as TH+import Biobase.Infernal.VerboseHit+import Biobase.Infernal.VerboseHit.Import as VH+import Biobase.Infernal.VerboseHit.Export as VH+import Biobase.Infernal.Taxonomy+import Biobase.Infernal.Taxonomy.Import as T++thFromFile = TH.fromFile++vhFromFile = VH.fromFile+vhEneeByteString :: Monad m => Enumeratee [VerboseHit] ByteString m a+vhEneeByteString = VH.eneeByteString++tFromFile = T.fromFile
+ Biobase/Infernal/TabularHit.hs view
@@ -0,0 +1,19 @@++-- | Simple tabular hits as returned by Infernal.++module Biobase.Infernal.TabularHit where++import Data.ByteString.Char8 as BS+++data TabularHit = TabularHit+  { thModel :: ByteString+  , thTarget :: ByteString+  , thScaffoldStart :: Int+  , thScaffoldStop :: Int+  , thQueryStart :: Int+  , thQueryStop :: Int+  , thBitScore :: Double+  , thEvalue :: Double+  , thGCpercent :: Int+  } deriving (Read,Show)
+ Biobase/Infernal/TabularHit/Import.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE OverloadedStrings #-}++-- Importing tabular hits is rather easy, as they are one entry per line.++module Biobase.Infernal.TabularHit.Import where++import Data.ByteString.Char8 as BS+import Data.Iteratee as I+import Data.Iteratee.Iteratee as I+import Data.Iteratee.ListLike as I+import Data.Iteratee.Char as I+import Data.Either.Unwrap+import Data.Attoparsec as A hiding (takeTill)+import Data.Attoparsec.Char8 as A+import Control.Applicative+import Data.Iteratee.IO as I++import Biobase.Infernal.TabularHit++++-- | Transform a stream into tabular hits.++eneeTabularHit :: (Functor m, Monad m) => Enumeratee ByteString [TabularHit] m a+eneeTabularHit = enumLinesBS ><> I.filter (\x -> not $ BS.null x || isPrefixOf "#" x) ><> mapStream f where+  f = fromRight . parseOnly p+  p = TabularHit <$> pString -- model name+                 <*> pString -- target name+                 <*> pDecimal -- target start+                 <*> pDecimal -- target stop+                 <*> pDecimal -- query start+                 <*> pDecimal -- query stop+                 <*> pDouble -- bit score+                 <*> pDouble -- evalue+                 <*> pDecimal -- gc content+  pString = A.skipSpace *> A.takeTill A.isSpace+  pDecimal = A.skipSpace *> A.decimal+  pDouble = A.skipSpace *> A.double++-- | Convenience function to load from file and return a big list of tabular+-- hits.++fromFile :: FilePath -> IO [TabularHit]+fromFile fp = do+  i <- enumFile 8192 fp . joinI $ eneeTabularHit stream2stream+  run i
Biobase/Infernal/Taxonomy/Import.hs view
@@ -1,68 +1,79 @@+{-# LANGUAGE BangPatterns #-} -module Biobase.Infernal.Taxonomy.Import-  ( eeImport-  , iSpeciesMap-  , iTaxIdMap-  ) where+-- | Iteratee-based importer. Provides a simple "fromFile" function that+-- produces both maps in one pass. -import qualified Data.Enumerator as E-import qualified Data.Enumerator.List as EL-import qualified Data.ByteString.Char8 as BS-import qualified Data.Attoparsec as A+module Biobase.Infernal.Taxonomy.Import where+ import Control.Applicative-import qualified Data.Attoparsec.Char8 as A8-import qualified Data.Attoparsec.Enumerator as EAP-import qualified Data.Map as M+import Data.Attoparsec as A+import Data.Attoparsec.Char8 as A8+import Data.Attoparsec.Iteratee+import Data.ByteString.Char8 as BS+import Data.Either.Unwrap as E+import Data.Iteratee as I+import Data.Iteratee.Char as I+import Data.Iteratee.IO as I+import Data.Iteratee.ListLike as I+import Data.List as L+import Data.Map as M  import Biobase.Infernal.Taxonomy -import qualified Data.Enumerator.Binary as EB  - -- | Provide name-based lookup as the most-common usage scenario. -- -- TODO there are 9 duplicates in the names, let's find them and see what is -- going on -iSpeciesMap :: Monad m => E.Iteratee Species m (M.Map BS.ByteString Species)-iSpeciesMap = EL.fold (\m x -> M.insert (name x) x m) M.empty+iSpeciesMap :: Monad m => Iteratee [Species] m (M.Map ByteString Species)+iSpeciesMap = I.foldl' f M.empty where+  f !m x = M.insert (name x) x m  -- | And a map based on taxon id -iTaxIdMap :: Monad m => E.Iteratee Species m (M.Map Int Species)-iTaxIdMap = EL.fold (\m x -> M.insert (taxid x) x m) M.empty+iTaxIdMap :: Monad m => Iteratee [Species] m (M.Map Int Species)+iTaxIdMap = I.foldl' f M.empty where+  f !m x = M.insert (taxid x) x m  -- | Imports taxonomy data.++eneeSpecies :: Monad m => Enumeratee ByteString [Either String Species] m a+eneeSpecies = enumLinesBS ><> mapStream (parseOnly mkSpecies)++-- | Given a 'ByteString', create a species entry. -- -- NOTE The taxonomy format is, for each species, a line consisting of: taxid - -- tab - species name - tab - semicolon separated list of classification names -- - dot - end of line. -eeImport :: Monad m => E.Enumeratee BS.ByteString Species m b-eeImport = E.sequence $ EAP.iterParser mkSpecies---- | Given a 'ByteString', create a species entry.--mkSpecies :: A.Parser Species-mkSpecies = f <$> ptaxid <* tab <*> pname <* tab <*> A8.takeWhile (/='\n') <* A8.endOfLine where+mkSpecies :: Parser Species+mkSpecies = f <$> ptaxid <* tab <*> pname <* tab <*> takeByteString where   f k n xs = let-               cs = map (BS.copy . BS.dropWhile (==' ')) . BS.split ';' . BS.init $ xs-             in Species (BS.copy n) cs k-  ptaxid   = A8.decimal+               cs = L.map (copy . BS.dropWhile (==' ')) . BS.split ';' . BS.init $ xs+             in Species (copy n) cs k+  ptaxid   = decimal   pname    = A8.takeWhile (/='\t')-  tab      = A8.char '\t'+  tab      = char '\t' +-- | Convenience function: given a taxonomy file, produce both maps simultanously. +fromFile :: FilePath -> IO (M.Map ByteString Species, M.Map Int Species)+fromFile fp = do+  i <- enumFile 8192 fp+    . joinI+    . (eneeSpecies ><> I.filter isRight ><> mapStream fromRight)+    $ I.zip iSpeciesMap iTaxIdMap+  run i  -- * Testing +{- test :: IO () test = do-  m1 <- E.run_ $ (EB.enumFile "./Tests/Infernal/taxonomy" E.$$ (eeImport E.=$ iSpeciesMap))-  m2 <- E.run_ $ (EB.enumFile "./Tests/Infernal/taxonomy" E.$$ (eeImport E.=$ iTaxIdMap))-  print $ M.size m1-  print $ m1 M.! BS.pack "Cenarchaeum symbiosum B"-  -- print $ M.size $ M.mapKeys shortenName m1-  -- print $ M.size m2+  (s,t) <- fromFile "/home/choener/tmp/taxonomy"+  print $ M.size s+  print $ M.size t   return ()+-}
Biobase/Infernal/VerboseHit/Export.hs view
@@ -9,15 +9,12 @@ -- use printVerboseHit.  module Biobase.Infernal.VerboseHit.Export where-{--  ( eeFromVerboseHit-  ) where--}  import Control.Monad.Trans.Class (lift)-import qualified Data.ByteString.Char8 as BS-import qualified Data.Enumerator as E-import qualified Data.Enumerator.List as EL+import Data.ByteString.Char8 as BS+import Data.Iteratee as I+import Data.Maybe+import Prelude as P import Text.Printf  import Biobase.Infernal.VerboseHit@@ -25,51 +22,31 @@   --- | Takes a list of 'VerboseHit's and produces a list of bytestrings. Unlining--- those bytestrings produces a file that is \in essence\ an Infernal--- verbose-hit output file and should be parse-able by ours and other--- importers.------ TODO block length (for the alignment of query/sequenc) ?!+-- | Transforms a list of verbose hits into a bytestring. ----- TODO is there a more elegant treatment of the eof condition than asking at--- every verbose hit that is created?+-- TOOD How to append the last line "//" to the finished stream, if at least+-- one element was printed? -{--eeFromVerboseHit :: Monad m => E.Enumeratee VerboseHit BS.ByteString m a-eeFromVerboseHit = goS (AliGo "" "" '?') where-  goS s (E.Continue k) = EL.head >>= go s where-    go s Nothing = return $ E.Continue k-    go s@AliGo{..} (Just l@VerboseHit{..}) = do-      eof <- E.isEOF-      let res =  [ "\n//\n" | vhCM /= aliCM && aliCM /= "" ]-              ++ [ "\nCM: " `BS.append` vhCM `BS.append` "\n" | vhCM /= aliCM]-              ++ [ "\n>" `BS.append` vhSeqName `BS.append` "\n" | vhSeqName /= aliScaffold]-              ++ [ strand vhStrand | vhStrand /= aliStrand]-              ++ [ BS.pack $ printf " Query = %d - %d, Target = %d - %d"-                              (fst vhQuery) (snd vhQuery) (fst vhTarget) (snd vhTarget)-                 , BS.pack $ printf " Score = %.2f, E = %f, P = %.4e, GC = %d"-                              vhScore vhEvalue vhPvalue vhGC-                 , ""-                 , ws11 `BS.append` vhWuss-                 , (BS.pack $ printf "%10d " (fst vhQuery))-                      `BS.append` vhConsensus-                      `BS.append` (BS.pack $ printf " %d" (snd vhQuery))-                 , ws11 `BS.append` vhScoring-                 , (BS.pack $ printf "%10d " (fst vhTarget))-                      `BS.append` vhSequence-                      `BS.append` (BS.pack $ printf " %d" (snd vhTarget))-                 ]-              ++ [ "\n//" | eof]-      newStep <- lift $ E.runIteratee $ k $ E.Chunks res-      goS (AliGo vhCM vhSequence vhStrand) newStep-    strand '+' = "  Plus strand results:\n"-    strand '-' = "  Minus strand results:\n"-    strand _   = "  Unknown strand results:\n"-    ws11 = BS.pack $ replicate 11 ' '-  goS _ step = return step--}+eneeByteString :: Monad m => Enumeratee [VerboseHit] BS.ByteString m a+eneeByteString = unfoldConvStream f (AliGo BS.empty BS.empty '?') where+  f acc = do+    h <- I.head+    let na = newAcc acc h+    return (fst na , BS.unlines $ snd na ++ [showVerboseHit h]) +newAcc a@(AliGo{..}) h@VerboseHit{..}+  | otherwise = ( AliGo vhCM vhScaffold vhStrand, ls )+  where ls = [ "//" | aliCM /= BS.empty && aliCM /= vhCM ] +++             [ "CM: " `BS.append` vhCM | aliCM /= vhCM ] +++             [ ">" `BS.append` vhScaffold `BS.append` "\n" | aliScaffold /= vhScaffold ] +++             [ str `BS.append` " strand results:\n" | aliStrand /= vhStrand ]+        str+          | vhStrand == '+' = "Plus"+          | vhStrand == '-' = "Minus"+          | otherwise       = "Unknown"+++ -- | Convert a 'VerboseHit' to a string, ready for printing as in the input -- file. @@ -89,82 +66,19 @@     `BS.append` vhSequence     `BS.append` (BS.pack $ printf " %d" (snd vhTarget))   ] where-    ws11 = BS.pack $ replicate 11 ' '+    ws11 = BS.pack $ P.replicate 11 ' ' --- | CM information, ready for printing. -showCM :: BS.ByteString -> BS.ByteString-showCM cm = "CM: " `BS.append` cm --- | Scaffold information--showScaffold :: BS.ByteString -> BS.ByteString-showScaffold sc = ">" `BS.append` sc---- | Strand information--showStrand :: Char -> BS.ByteString-showStrand = f where-  f '+' = "  Plus strand results:"-  f '-' = "  Minus strand results:"-  f _   = "  Unknown strand results:"---- | Turning a list of 'VerboseHit's back into lines of characters is, in--- principle, not too hard. But just before we actually stream out, we might--- want to inject arbitrary data into the stream. This is done via--- 'StreamInsertion'. The other constructors merely wrap certain data.------ One way to, say, tag verbose hits is like this (note the output type of--- 'eeHitToStream'):------ > tag [s@(StreamVerboseHit _)] = [StreamInsertion (), s]--- > tag xs = xs--data HitStream a-  = StreamVerboseHit {streamVerboseHit :: VerboseHit}-  | StreamCM {streamCM :: BS.ByteString}-  | StreamScaffold {streamScaffold :: BS.ByteString}-  | StreamStrand {streamStrand :: Char}-  | StreamInsertion {streamInsertion :: a}-  deriving (Show)---- | This enumeratee turns 'VerboseHit's into a 'HitStream'. Each VerboseHit--- can emit one or more elements, depending on if the CM, scaffold, or strand--- changes.------ TODO try to rewrite use Control.Monad.State--eeHitToStream :: Monad m => E.Enumeratee VerboseHit [HitStream z] m a-eeHitToStream = EL.mapAccum go (AliGo "" "" '?') where-  go AliGo{..} vh@VerboseHit{..} = (AliGo vhCM vhScaffold vhStrand,-    [StreamCM vhCM | aliCM /= vhCM] ++-    [StreamScaffold vhScaffold | aliCM /= vhCM || aliScaffold /= vhScaffold] ++-    [StreamStrand vhStrand | aliCM /= vhCM || aliScaffold /= vhScaffold || aliStrand /= vhStrand] ++-    [StreamVerboseHit vh]-    )---- | Flattens a stream from a list of lists to a single list. After this point,--- you probably want to insert elements into the stream, then flatten again.--eeFlattenStream :: Monad m => E.Enumeratee [HitStream z] (HitStream z) m a-eeFlattenStream = EL.concatMap id---- | If the 'HitStream' contains 'StreamInsertion's that are an instance of--- 'Show', this provides a default method to turn the stream into a bytestring.------ TODO add some newline characters for good measure------ TODO on end-of-stream, we should print out "//"--eeStreamToByteString :: (Monad m, Show z) => StreamToByteString m z-eeStreamToByteString = EL.map f where-  f StreamVerboseHit{..} = showVerboseHit streamVerboseHit `BS.snoc` '\n'-  f StreamCM{..} = showCM streamCM `BS.append` "\n\n"-  f StreamScaffold{..} = showScaffold streamScaffold `BS.append` "\n\n"-  f StreamStrand{..} = showStrand streamStrand `BS.append` "\n\n"-  f StreamInsertion{..} = BS.pack . show $ streamInsertion--eeStreamToByteString' :: (Monad m) => StreamToByteString m ()-eeStreamToByteString' = eeStreamToByteString+{-+import Biobase.Infernal.VerboseHit.Import -type StreamToByteString m z = forall a . E.Enumeratee (HitStream z) BS.ByteString m a+test = do+  xs <- fromFile "/home/choener/tmp/infernal-1.0.2/tutorial/tmp.res"+  i <- enumList [xs] $ joinI $ eneeByteString stream2stream+  ys <- run i+  BS.putStrLn ys+  print $ BS.length ys+  print $ P.length $ BS.lines ys+  return ()+-}
Biobase/Infernal/VerboseHit/Import.hs view
@@ -6,59 +6,57 @@ -- | Enumeratee that transforms a stream of 'ByteString's into a stream of -- 'VerboseHit's. -module Biobase.Infernal.VerboseHit.Import -  ( eeToVerboseHit+module Biobase.Infernal.VerboseHit.Import+  ( eneeVerboseHit+  , fromFile   ) where  import Control.Applicative-import Control.Monad.IO.Class (MonadIO)-import Control.Monad.Trans.Class (lift)-import Data.Char (isSpace)+import Data.Attoparsec as A+import Data.Attoparsec.Char8 as A8+import Data.Attoparsec.Iteratee as EAP+import Data.ByteString.Char8 as BS+import Data.Either.Unwrap+import Data.Iteratee as I+import Data.Iteratee.Char as I+import Data.Iteratee.IO as I+import Data.Iteratee.Iteratee as I+import Data.Iteratee.ListLike as I import Data.Tuple.Select-import qualified Data.Attoparsec as A-import qualified Data.Attoparsec.Char8 as A8-import qualified Data.Attoparsec.Enumerator as EAP-import qualified Data.ByteString.Char8 as BS-import qualified Data.Enumerator as E-import qualified Data.Enumerator.List as EL+import Prelude as P  import Biobase.Infernal.VerboseHit import Biobase.Infernal.VerboseHit.Internal   --- | Stateful reading of 'VerboseHit's. This pipe groups certain lines and--- condenses them to one hit. As multiple hits share certain state (cm,--- scaffold, and strand), we thread some state through using "goS" internally.------ TODO is MonadIO really necessary?+-- | Transforms a stream into verbose hits. We need to keep a state in the+-- accumulator to keep track of the current CM, scaffold and strand. -eeToVerboseHit :: MonadIO m => E.Enumeratee BS.ByteString VerboseHit m b-eeToVerboseHit = goS (AliGo "" "" '?') where-  goS s (E.Continue k) = EL.dropWhile BS.null >> E.peek >>= go s where-    go s Nothing = return $ E.Continue k -- ???-    go s (Just (l :: BS.ByteString))-      | "CM: "    `BS.isInfixOf` l = drops >> E.peek >>= go s{aliCM = BS.copy $ BS.drop 4 l}-      | ">"       `BS.isInfixOf` l = drops >> E.peek >>= go s{aliScaffold = BS.copy $ BS.drop 1 l}-      | "  Plus"  `BS.isInfixOf` l = drops >> E.peek >>= go s{aliStrand = '+'}-      | "  Minus" `BS.isInfixOf` l = drops >> E.peek >>= go s{aliStrand = '-'}-      | " Query"  `BS.isInfixOf` l = do-          x <- qs (aliCM s) (aliScaffold s) (aliStrand s)-          newStep <- lift $ E.runIteratee $ k $ E.Chunks [x]-          goS s newStep-    go s l = drops >> E.peek >>= go s-    drops = EL.drop 1 >> EL.dropWhile BS.null-  goS _ step = return step+eneeVerboseHit :: (Functor m, Monad m) => Enumeratee BS.ByteString [VerboseHit] m a+eneeVerboseHit = enumLinesBS ><> I.filter (not . BS.null) ><> unfoldConvStream f (AliGo BS.empty BS.empty '?') where+  f acc = do+    h' <- tryHead+    case h' of+      Nothing -> return (acc, [])+      (Just h)+        | "CM: "    `BS.isInfixOf` h -> return (acc{aliCM = BS.copy $ BS.drop 4 h}, [])+        | ">"       `BS.isInfixOf` h -> return (acc{aliScaffold = BS.copy $ BS.drop 1 h}, [])+        | "  Plus"  `BS.isInfixOf` h -> return (acc{aliStrand = '+'}, [])+        | "  Minus" `BS.isInfixOf` h -> return (acc{aliStrand = '-'}, [])+        | " Query"  `BS.isInfixOf` h -> do+            x <- qs h (aliCM acc) (aliScaffold acc) (aliStrand acc)+            return (acc,x)+        | otherwise -> return (acc,[]) --- | Parses one "Alignment". This is build by Query/Score lines and multiple--- 4-tuples or strings with the actual alignment.+-- | Parses one CM query result. -qs :: Monad m => BS.ByteString -> BS.ByteString -> Char -> E.Iteratee BS.ByteString m VerboseHit-qs cm scaf pm = do-  q <- EAP.iterParser qt-  s <- EAP.iterParser sepg+qs :: Monad m => BS.ByteString -> BS.ByteString -> BS.ByteString -> Char -> Iteratee [BS.ByteString] m [VerboseHit]+qs query cm scaf pm = do+  let q = fromRight . parseOnly qt $ query+  s <- I.head >>= return . fromRight . parseOnly sepg   l <- fourLines $ sel4 q-  return $ VerboseHit+  return . pure $ VerboseHit     { vhScaffold = scaf     , vhCM = cm     , vhStrand = pm@@ -77,20 +75,38 @@     cpy = BS.copy . BS.concat     qt = (,,,) <$ A.string " Query = "   <*> A8.decimal <* A.string " - " <*> A8.decimal                <* A.string ", Target = " <*> A8.decimal <* A.string " - " <*> A8.decimal+               <?> "qt"     sepg = (,,,) <$ A.string " Score = " <*> A8.double                  <* A.string ", E = "    <*> A8.double                  <* A.string ", P = "    <*> A8.double                  <* A.string ", GC = " <* A8.skipSpace <*> A8.decimal+                 <?> "sepg" --- | Parse 4-tuples of cmsearch alignment output until we have hit the last, or--- "to", 4-tuple. Assumes that "to" is correct+-- | Parses multiple four-line elements.  fourLines to = do-  EL.dropWhile BS.null-  ls <- EL.take 4-  let ws = BS.length . BS.takeWhile isSpace . head $ ls-  let cs = BS.length . BS.dropWhile isSpace . head $ ls-  let xs = map (BS.take cs . BS.drop ws) ls-  if (to == (read . BS.unpack . last . BS.words . last $ ls))-  then return . map (:[]) $ xs-  else fourLines to >>= return . (zipWith (:) xs)+  I.dropWhile BS.null+  ls <- joinI $ I.take 4 stream2stream+  let ws = BS.length . BS.takeWhile isSpace . P.head $ ls+  let cs = BS.length . BS.dropWhile isSpace . P.head $ ls+  let xs = P.map (BS.take cs . BS.drop ws) ls+  if (to == (read . BS.unpack . P.last . BS.words . P.last $ ls))+  then return . P.map (:[]) $ xs+  else fourLines to >>= return . (P.zipWith (:) xs)++-- | Convenience function: read all results into a single list.++fromFile :: FilePath -> IO [VerboseHit]+fromFile fp = do+  i <- enumFile 8192 fp . joinI $ eneeVerboseHit stream2list+  run i++{- How to use this enumeratee.+++test = do+  i <- enumFile 8192 "/home/choener/tmp/infernal-1.0.2/tutorial/tmp.res" $ joinI $ eneeVerboseHit stream2list+  xs <- run i+  print xs+  print $ P.length xs+-}
BiobaseInfernal.cabal view
@@ -1,5 +1,5 @@ name:           BiobaseInfernal-version:        0.5.0.0+version:        0.5.1.0 author:         Christian Hoener zu Siederdissen maintainer:     choener@tbi.univie.ac.at homepage:       http://www.tbi.univie.ac.at/~choener/@@ -19,6 +19,10 @@                 With the BioHaskell library split, this package is officially                 back! And the package is not feature-complete yet, take the                 above as a will-include-soon list.+                .+                The taxonomy importer makes use of Iteratee.zip, hence the+                switch from Enumerator. (See the Biohaskell wiki pages for+                discussion on Iteratee/Enumerator).  extra-source-files: @@ -26,14 +30,18 @@   build-depends:     base >3 && <5,     attoparsec,-    attoparsec-enumerator,+    attoparsec-iteratee,     bytestring,     containers,-    enumerator,+    either-unwrap,+    iteratee,     transformers,     tuple    exposed-modules:+    Biobase.Infernal+    Biobase.Infernal.TabularHit+    Biobase.Infernal.TabularHit.Import     Biobase.Infernal.Taxonomy     Biobase.Infernal.Taxonomy.Import     Biobase.Infernal.VerboseHit