packages feed

cobot-io 0.1.3.20 → 0.1.4.2

raw patch · 19 files changed

+1152/−381 lines, 19 filesdep +cobotdep +megaparsecdep +parser-combinatorsdep ~attoparsecdep ~basedep ~hspecnew-uploaderPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: cobot, megaparsec, parser-combinators

Dependency ranges changed: attoparsec, base, hspec, hyraxAbif, lens

API changes (from Hackage documentation)

- Bio.GB.Type: [fStrand53] :: Feature -> Bool
- Bio.Sequence: type Range = (Int, Int)
- Bio.Sequence.Class: type Range = (Int, Int)
- Bio.Sequence.Utilities: checkRange :: Int -> Range -> Bool
- Bio.Sequence.Utilities: type Range = (Int, Int)
+ Bio.GB.Parser: rangeP :: Parser Range
+ Bio.GB.Type: instance Control.DeepSeq.NFData Bio.GB.Type.Feature
+ Bio.GB.Type: instance Control.DeepSeq.NFData Bio.GB.Type.Form
+ Bio.GB.Type: instance Control.DeepSeq.NFData Bio.GB.Type.GenBankSequence
+ Bio.GB.Type: instance Control.DeepSeq.NFData Bio.GB.Type.Locus
+ Bio.GB.Type: instance Control.DeepSeq.NFData Bio.GB.Type.Meta
+ Bio.GB.Type: instance Control.DeepSeq.NFData Bio.GB.Type.Reference
+ Bio.GB.Type: instance Control.DeepSeq.NFData Bio.GB.Type.Source
+ Bio.GB.Type: instance Control.DeepSeq.NFData Bio.GB.Type.Version
+ Bio.GB.Type: instance GHC.Generics.Generic Bio.GB.Type.Feature
+ Bio.GB.Type: instance GHC.Generics.Generic Bio.GB.Type.Form
+ Bio.GB.Type: instance GHC.Generics.Generic Bio.GB.Type.GenBankSequence
+ Bio.GB.Type: instance GHC.Generics.Generic Bio.GB.Type.Locus
+ Bio.GB.Type: instance GHC.Generics.Generic Bio.GB.Type.Meta
+ Bio.GB.Type: instance GHC.Generics.Generic Bio.GB.Type.Reference
+ Bio.GB.Type: instance GHC.Generics.Generic Bio.GB.Type.Source
+ Bio.GB.Type: instance GHC.Generics.Generic Bio.GB.Type.Version
+ Bio.GB.Type: type Parser = Parsec Void Text
+ Bio.Sequence: data Range
+ Bio.Sequence.Class: data Range
+ Bio.Sequence.Class: instance (Control.DeepSeq.NFData a, Control.DeepSeq.NFData mk, Control.DeepSeq.NFData w) => Control.DeepSeq.NFData (Bio.Sequence.Class.Sequence mk w a)
+ Bio.Sequence.Range: Between :: Int -> Int -> Range
+ Bio.Sequence.Range: Complement :: Range -> Range
+ Bio.Sequence.Range: Exceeded :: Border
+ Bio.Sequence.Range: Join :: [Range] -> Range
+ Bio.Sequence.Range: Point :: Int -> Range
+ Bio.Sequence.Range: Precise :: Border
+ Bio.Sequence.Range: RangeBorder :: Border -> Int -> RangeBorder
+ Bio.Sequence.Range: Span :: RangeBorder -> RangeBorder -> Range
+ Bio.Sequence.Range: [_after] :: Range -> Int
+ Bio.Sequence.Range: [_before] :: Range -> Int
+ Bio.Sequence.Range: [_borderLocation] :: RangeBorder -> Int
+ Bio.Sequence.Range: [_borderType] :: RangeBorder -> Border
+ Bio.Sequence.Range: [_location] :: Range -> Int
+ Bio.Sequence.Range: [_lower] :: Range -> RangeBorder
+ Bio.Sequence.Range: [_range] :: Range -> Range
+ Bio.Sequence.Range: [_ranges] :: Range -> [Range]
+ Bio.Sequence.Range: [_upper] :: Range -> RangeBorder
+ Bio.Sequence.Range: after :: Traversal' Range Int
+ Bio.Sequence.Range: before :: Traversal' Range Int
+ Bio.Sequence.Range: between :: (Int, Int) -> Range
+ Bio.Sequence.Range: borderLocation :: Lens' RangeBorder Int
+ Bio.Sequence.Range: borderType :: Lens' RangeBorder Border
+ Bio.Sequence.Range: checkRange :: Int -> Range -> Bool
+ Bio.Sequence.Range: data Border
+ Bio.Sequence.Range: data Range
+ Bio.Sequence.Range: data RangeBorder
+ Bio.Sequence.Range: extendLeft :: Int -> Range -> Range
+ Bio.Sequence.Range: extendRight :: Int -> Range -> Range
+ Bio.Sequence.Range: instance Control.DeepSeq.NFData Bio.Sequence.Range.Border
+ Bio.Sequence.Range: instance Control.DeepSeq.NFData Bio.Sequence.Range.Range
+ Bio.Sequence.Range: instance Control.DeepSeq.NFData Bio.Sequence.Range.RangeBorder
+ Bio.Sequence.Range: instance GHC.Classes.Eq Bio.Sequence.Range.Border
+ Bio.Sequence.Range: instance GHC.Classes.Eq Bio.Sequence.Range.Range
+ Bio.Sequence.Range: instance GHC.Classes.Eq Bio.Sequence.Range.RangeBorder
+ Bio.Sequence.Range: instance GHC.Generics.Generic Bio.Sequence.Range.Border
+ Bio.Sequence.Range: instance GHC.Generics.Generic Bio.Sequence.Range.Range
+ Bio.Sequence.Range: instance GHC.Generics.Generic Bio.Sequence.Range.RangeBorder
+ Bio.Sequence.Range: instance GHC.Show.Show Bio.Sequence.Range.Border
+ Bio.Sequence.Range: instance GHC.Show.Show Bio.Sequence.Range.Range
+ Bio.Sequence.Range: instance GHC.Show.Show Bio.Sequence.Range.RangeBorder
+ Bio.Sequence.Range: location :: Traversal' Range Int
+ Bio.Sequence.Range: lower :: Traversal' Range RangeBorder
+ Bio.Sequence.Range: mapRange :: (Int -> Int) -> Range -> Range
+ Bio.Sequence.Range: overlap :: Range -> Range -> Bool
+ Bio.Sequence.Range: point :: Int -> Range
+ Bio.Sequence.Range: preciseSpan :: (Int, Int) -> Range
+ Bio.Sequence.Range: range :: Traversal' Range Range
+ Bio.Sequence.Range: rangeMargins :: Range -> (Int, Int)
+ Bio.Sequence.Range: ranges :: Traversal' Range [Range]
+ Bio.Sequence.Range: shiftRange :: Int -> Range -> Range
+ Bio.Sequence.Range: swapRange :: Range -> Range
+ Bio.Sequence.Range: upper :: Traversal' Range RangeBorder
- Bio.GB.Type: Feature :: Text -> Bool -> [(Text, Text)] -> Feature
+ Bio.GB.Type: Feature :: Text -> [(Text, Text)] -> Feature
- Bio.Sequence: type family Weight s :: *;
+ Bio.Sequence: type family Weight s :: Type;
- Bio.Sequence.Class: type family Weight s :: *;
+ Bio.Sequence.Class: type family Weight s :: Type;
- Bio.Sequence.Functions.Marking: getMarking :: (ContainsMarking s, MonadError Text m) => s -> Marking s -> m (NonEmpty [Element s])
+ Bio.Sequence.Functions.Marking: getMarking :: (ContainsMarking s, MonadError Text m, Complementary (Element s)) => s -> Marking s -> m (NonEmpty [Element s])
- Bio.Sequence.Functions.Marking: unsafeGetMarking :: ContainsMarking s => s -> Marking s -> NonEmpty [Element s]
+ Bio.Sequence.Functions.Marking: unsafeGetMarking :: (ContainsMarking s, Complementary (Element s)) => s -> Marking s -> NonEmpty [Element s]
- Bio.Sequence.Functions.Sequence: getRange :: (IsSequence s, MonadError Text m) => s -> Range -> m [Element s]
+ Bio.Sequence.Functions.Sequence: getRange :: (IsSequence s, MonadError Text m, Complementary (Element s)) => s -> Range -> m [Element s]
- Bio.Sequence.Functions.Sequence: unsafeGetRange :: IsSequence s => s -> Range -> [Element s]
+ Bio.Sequence.Functions.Sequence: unsafeGetRange :: (IsSequence s, Complementary (Element s)) => s -> Range -> [Element s]

Files

ChangeLog.md view
@@ -2,6 +2,39 @@  ## [Unreleased] +## [0.1.4.2] - 2021-10-14+### Changed+- More types of multiline properties are supported.++## [0.1.4.1] - 2021-10-07+### Changed+- CI fix++## [0.1.4.0] - 2021-09-27+### Changed+- Redesigned the Range type to reflect all possible cases.+- Switched to Megaparsec.++## [0.1.3.25] - 2021-09-15+### Added+- Pedantic build and CI++## [0.1.3.24] - 2021-09-10+### Changed+- GB parser made more verbose.++## [0.1.3.23] - 2021-07-06+### Added+Added ASN hydrogen names sometimes set by Scho++## [0.1.3.22] - 2021-07-06+### Changed+- `*` -> `Type` for GHC-9.++## [0.1.3.21] - 2021-07-03+### Changed+- Update dependency versions.+ ## [0.1.3.20] - 2021-06-04 ### Changed  - YLAB2-629: Fasta parser is now able to parse empty lines in the beginning. 
cobot-io.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           cobot-io-version:        0.1.3.20+version:        0.1.4.2 synopsis:       Biological data file formats and IO description:    Please see the README on GitHub at <https://github.com/biocad/cobot-io#readme> category:       Bio@@ -61,6 +61,7 @@       Bio.Sequence.Functions.Marking       Bio.Sequence.Functions.Sequence       Bio.Sequence.Functions.Weight+      Bio.Sequence.Range       Bio.Sequence.Utilities       Bio.Structure       Bio.Structure.Functions@@ -93,18 +94,21 @@       FlexibleContexts   build-depends:       array ==0.5.*-    , attoparsec >=0.10 && <0.14-    , base >=4.7 && <5+    , attoparsec >=0.10 && <0.15+    , base >=4.14 && <5     , binary >=0.8.3.0 && <1.0     , bytestring >=0.10.8.1 && <0.11+    , cobot >=0.1.1.7     , containers >=0.5.7.1 && <0.7     , data-msgpack >=0.0.9 && <0.1     , deepseq ==1.4.*     , http-conduit ==2.3.*-    , hyraxAbif >=0.2.3.15 && <0.2.4.0-    , lens >=4.16 && <5.0+    , hyraxAbif >=0.2.3.27 && <0.2.4.0+    , lens >=4.16 && <5.1     , linear >=1.20 && <1.22+    , megaparsec >=9.0.1     , mtl >=2.2.1 && <2.3.0+    , parser-combinators >=1.2.1     , split     , text >=1.2.2.1 && <1.3     , vector@@ -126,6 +130,7 @@       PDBParserSpec       PDBSpec       PDBWriterSpec+      RangeSpec       SequenceSpec       StructureSpec       UniprotSpec@@ -139,22 +144,25 @@   build-depends:       QuickCheck >=2.9.2 && <2.15     , array ==0.5.*-    , attoparsec >=0.10 && <0.14-    , base >=4.7 && <5+    , attoparsec >=0.10 && <0.15+    , base >=4.14 && <5     , binary >=0.8.3.0 && <1.0     , bytestring >=0.10.8.1 && <0.11+    , cobot >=0.1.1.7     , cobot-io     , containers >=0.5.7.1 && <0.7     , data-msgpack >=0.0.9 && <0.1     , deepseq ==1.4.*     , directory-    , hspec >=2.4.1 && <2.8+    , hspec >=2.4.1 && <2.9     , http-conduit ==2.3.*-    , hyraxAbif >=0.2.3.15 && <0.2.4.0-    , lens >=4.16 && <5.0+    , hyraxAbif >=0.2.3.27 && <0.2.4.0+    , lens >=4.16 && <5.1     , linear+    , megaparsec >=9.0.1     , mtl >=2.2.1 && <2.3.0     , neat-interpolation >=0.3+    , parser-combinators >=1.2.1     , split     , text >=1.2.2.1 && <1.3     , vector
src/Bio/GB.hs view
@@ -1,5 +1,3 @@-{-# LANGUAGE CPP #-}- module Bio.GB   ( module T   , fromFile@@ -13,19 +11,15 @@ import           Bio.GB.Type            as T import           Bio.GB.Writer          (genBankToText) import           Control.Monad.IO.Class (MonadIO, liftIO)-import           Data.Attoparsec.Text   (parseOnly) import           Data.Bifunctor         (first) import           Data.Text              (Text, pack) import qualified Data.Text.IO           as TIO (readFile, writeFile)-#if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail     (MonadFail(..))-import           Prelude                hiding (fail)-#endif+import           Text.Megaparsec        (eof, errorBundlePretty, parse)  -- | Reads 'GenBankSequence' from givem file. -- fromFile :: (MonadFail m, MonadIO m) => FilePath -> m GenBankSequence-fromFile f = liftIO (TIO.readFile f) >>= either fail pure . parseOnly genBankP+fromFile f = liftIO (TIO.readFile f) >>= either (fail . errorBundlePretty) pure . parse (genBankP <* eof) ""  -- | Writes 'GenBankSequence' to file. --@@ -35,7 +29,7 @@ -- | Reads 'GenBankSequence' from 'Text'. -- fromText :: Text -> Either Text GenBankSequence-fromText = first pack . parseOnly genBankP+fromText = first (pack . errorBundlePretty) . parse (genBankP <* eof) ""  -- | Writes 'GenBankSequence' to 'Text'. --
src/Bio/GB/Parser.hs view
@@ -2,28 +2,31 @@  module Bio.GB.Parser   ( genBankP+  , rangeP   ) where -import Bio.GB.Type                (Feature (..), Form (..), GenBankSequence (..), Locus (..),-                                   Meta (..), Reference (..), Source (..), Version (..))-import Bio.Sequence               (MarkedSequence, Range, markedSequence)-import Control.Applicative        ((<|>))-import Data.Attoparsec.Combinator (manyTill)-import Data.Attoparsec.Text       (Parser, char, decimal, digit, endOfInput, endOfLine, letter,-                                   many', many1', satisfy, string, takeWhile, takeWhile1)-import Data.Bifunctor             (bimap)-import Data.Char                  (isAlphaNum, isSpace, isUpper)-import Data.Functor               (($>))-import Data.Text                  (Text, intercalate, pack, splitOn, unpack)-import Prelude                    hiding (takeWhile)+import           Bio.GB.Type                (Feature (..), Form (..), GenBankSequence (..),+                                             Locus (..), Meta (..), Parser, Reference (..),+                                             Source (..), Version (..))+import           Bio.Sequence               (Border (..), MarkedSequence, Range (..),+                                             RangeBorder (..), markedSequence, shiftRange)+import           Control.Monad.Combinators  (many, manyTill, optional, some, (<|>))+import           Data.Char                  (isAlphaNum, isSpace, isUpper)+import           Data.Functor               (($>))+import           Data.Text                  (Text, intercalate, pack, splitOn, unpack)+import qualified Data.Text                  as T+import           Text.Megaparsec            (notFollowedBy, option, satisfy, sepBy1, takeWhile1P,+                                             takeWhileP, try, (<?>))+import           Text.Megaparsec.Char       (char, digitChar, eol, letterChar, string)+import           Text.Megaparsec.Char.Lexer (decimal)  -- | Parser of .gb file. -- genBankP :: Parser GenBankSequence genBankP =  GenBankSequence-        <$> metaP-        <*> gbSeqP-        <*  string "//" <* eolSpaceP <* endOfInput+        <$> (metaP <?> "Meta parser")+        <*> (gbSeqP <?> "GB sequence parser")+        <*  string "//" <* eolSpaceP   -------------------------------------------------------------------------------- -- Block with meta-information.@@ -31,15 +34,15 @@  metaP :: Parser Meta metaP = do-  locus'      <- locusP+  locus'      <- locusP <?> "Locus parser" -  definitionM <- wrapMP definitionP-  accessionM  <- wrapMP accessionP-  versionM    <- wrapMP versionP-  keywordsM   <- wrapMP keywordsP-  sourceM     <- wrapMP sourceP-  referencesL <- many' referenceP-  commentsL   <- many' commentP+  definitionM <- optional definitionP <?> "Definition parser"+  accessionM  <- optional accessionP <?> "Accession parser"+  versionM    <- optional versionP <?> "Version parser"+  keywordsM   <- optional keywordsP <?> "Keywords parser"+  sourceM     <- optional sourceP <?> "Source parser"+  referencesL <- many referenceP <?> "References parser"+  commentsL   <- many commentP <?> "Comments parser"    pure $ Meta locus' definitionM accessionM versionM keywordsM sourceM referencesL commentsL @@ -48,43 +51,43 @@        <$> textP <* space                                      -- name        <*> decimal <* space <* string "bp" <* space            -- sequence length        <*> textP <* space                                      -- molecule type-       <*> wrapMP formP <* space                               -- form of sequence-       <*> wrapMP (pack <$> many1' (satisfy isUpper)) <* space -- GenBank division+       <*> optional formP <* space                               -- form of sequence+       <*> optional (pack <$> some (satisfy isUpper)) <* space   -- GenBank division        <*> textP                                               -- modification date        <*  eolSpaceP)   where-    textP = takeWhile1 $ not . isSpace+    textP = takeWhile1P Nothing $ not . isSpace      formP :: Parser Form-    formP = (string "linear" $> Linear) <|> (string "circular" $> Circular)+    formP = try (string "linear" $> Linear) <|> (string "circular" $> Circular)  definitionP :: Parser Text-definitionP =  string "DEFINITION" *> space *> (emptyP <|> someLinesP)+definitionP =  string "DEFINITION" *> space *> (try emptyP <|> someLinesP)  accessionP :: Parser Text-accessionP =  string "ACCESSION" *> space *> (emptyP <|> (pack-          <$> many1' (alphaNumChar <|> char '_')+accessionP =  string "ACCESSION" *> space *> (try emptyP <|> (pack+          <$> some (try alphaNumChar <|> char '_')           <*  eolSpaceP))  versionP :: Parser Version versionP =  string "VERSION" *> space          *> ((Version <$> emptyP <*> pure Nothing) <|> (Version-        <$> (pack <$> many1' versionP')-        <*> wrapMP (pack <$> (space *> string "GI:" *> many1' versionP'))+        <$> (pack <$> some versionP')+        <*> optional (pack <$> (space *> string "GI:" *> some versionP'))         <*  eolSpaceP))   where-    versionP' = alphaNumChar <|> char '_' <|> char '.'+    versionP' = try alphaNumChar <|> try (char '_') <|> char '.'  keywordsP :: Parser Text keywordsP =  string "KEYWORDS"-          *> (emptyP+          *> (try emptyP          <|> (space *> textWithSpacesP <* eolSpaceP))  sourceP :: Parser Source sourceP =  string "SOURCE" *> space         *> (Source        <$> someLinesP-       <*> wrapMP organismP)+       <*> optional organismP)   where     organismP = string "  ORGANISM" *> space *> someLinesP @@ -92,13 +95,13 @@ referenceP = string "REFERENCE" *> space            *> (((\x -> Reference x Nothing Nothing Nothing Nothing) <$> emptyP) <|> (Reference           <$> someLinesP-          <*> wrapMP (string "  AUTHORS" *> space *> someLinesP)-          <*> wrapMP (string "  TITLE" *> space *> someLinesP)-          <*> wrapMP (string "  JOURNAL" *> space *> someLinesP)-          <*> wrapMP (string "  PUBMED" *> space *> someLinesP)))+          <*> optional (string "  AUTHORS" *> space *> someLinesP)+          <*> optional (string "  TITLE" *> space *> someLinesP)+          <*> optional (string "  JOURNAL" *> space *> someLinesP)+          <*> optional (string "  PUBMED" *> space *> someLinesP)))  commentP :: Parser Text-commentP = string "COMMENT" *> (emptyP <|> (many' (char ' ') *> someLinesP))+commentP = string "COMMENT" *> (try emptyP <|> (many (char ' ') *> someLinesP))  -------------------------------------------------------------------------------- -- Block with FEATURES table.@@ -108,42 +111,85 @@ featuresP = -- skip unknown fields and stop on line with "FEATURES"            manyTill (textWithSpacesP <* eolSpaceP) (string "FEATURES") *> space           *> textWithSpacesP <* eolSpaceP-          *> many1' featureP+          *> some (featureP <?> "Single feature parser")  featureP :: Parser (Feature, Range) featureP = do     _ <- string featureIndent1 -    featureName'      <- takeWhile (not . isSpace) <* space-    (strand53, range) <- rangeP <* eolSpaceP+    featureName'      <- takeWhileP Nothing (not . isSpace) <* space+    range <- rangeP <* eolSpaceP -    props <- many1' propsP+    props <- some propsP -    pure (Feature featureName' strand53 props, range)+    -- Ranges are 1-based, but the underlying Vector in the Feature is 0-based.+    -- We shift the range left so the numberings match.+    --+    pure (Feature featureName' props, shiftRange (-1) range) -rangeP :: Parser (Bool, Range)-rangeP =  (string "complement(" *> rP False <* char ')') <|> rP True+rangeP :: Parser Range+rangeP =  try spanP +      <|> try betweenP +      <|> try pointP+      <|> try joinP+      <|> complementP   where-    rP :: Bool -> Parser (Bool, Range)-    rP b =  fmap (bimap pred id)-        <$> (,) b-        <$> (((,) <$> decimal <* string ".." <*> decimal) <|> ((\x -> (x, x)) <$> decimal))+    spanP :: Parser Range+    spanP = do+        lowerBorderType <- option Precise (try $ char '<' *> pure Exceeded)+        lowerBorderLocation <- decimal+        _ <- string ".."+        upperBorderType <- option Precise (try $ char '>' *> pure Exceeded)+        upperBorderLocation <- decimal+        pure $ Span (RangeBorder lowerBorderType lowerBorderLocation) (RangeBorder upperBorderType upperBorderLocation) +                +    betweenP :: Parser Range+    betweenP = do+        before <- decimal+        _ <- char '^'+        after <- decimal+        pure $ Between before after +    pointP :: Parser Range+    pointP = fmap Point decimal+   +    joinP :: Parser Range+    joinP = string "join(" *> fmap Join (rangeP `sepBy1` char ',') <* char ')'++    complementP :: Parser Range+    complementP = fmap Complement $ string "complement(" *> rangeP <* char ')'+        + propsP :: Parser (Text, Text) propsP = do     _ <- string featureIndent2     _ <- char '/'-    propName <- takeWhile1 (/= '=')+    propName <- takeWhile1P Nothing (/= '=')     _ <- char '=' -    propText <- ((char '\"' *> takeWhile1 (/= '\"') <* char '\"')-             <|> textWithSpacesP)-             <* eolSpaceP+    propText <- try ((char '\"' *> takeWhile1P Nothing (/= '\"') <* char '\"' <* eolSpaceP)+             <|> multiLineProp)      let propTextCorrect = mconcat $ filter (/= featureIndent2) $ splitOn featureIndent2 propText      pure (propName, propTextCorrect)+  where+    indLine :: Parser Text+    indLine = do+        _ <- string featureIndent2+        notFollowedBy (char '/')+        text <- textWithSpacesP +        eolSpaceP+        pure text +    multiLineProp :: Parser Text+    multiLineProp = do+        fstText <- textWithSpacesP <* eolSpaceP +        rest <- many (try indLine)+        pure $ T.concat (fstText : rest) ++    + -- | First level of identation in FEATURES table file. -- featureIndent1 :: Text@@ -159,10 +205,10 @@ --------------------------------------------------------------------------------  originP :: Parser String-originP =  string "ORIGIN" *> eolSpaceP+originP =  (string "ORIGIN" <?> "String ORIGIN") *> eolSpaceP         *> pure toText-       <*> many1' (space *> many1' digit *> space1-        *> many1' (many1' letter <* (space1 <|> eolSpaceP)))+       <*> some (space *> some digitChar *> space1+        *> some (some letterChar <* (try space1 <|> eolSpaceP)))   where     toText :: [[String]] -> String     toText = concat . fmap concat@@ -172,9 +218,17 @@ -------------------------------------------------------------------------------- gbSeqP :: Parser (MarkedSequence Feature Char) gbSeqP = do-    features <- featuresP-    origin   <- originP+    features <- (featuresP <?> "Features parser") +    -- An extract from the GB specification (https://www.ncbi.nlm.nih.gov/genbank/release/current/):+    --    NOTE: The BASE COUNT linetype is obsolete and was removed+    --    from the GenBank flatfile format in October 2003.+    --  Anyway, here, in 2021, we still might get plasmids with the BASE COUNT line present.+    --+    _ <- optional $ try (string "BASE COUNT" *> textWithSpacesP *> eol)++    origin   <- (originP <?> "Origin parser")+     either (fail . unpack) pure (markedSequence origin features)  --------------------------------------------------------------------------------@@ -187,29 +241,26 @@ firstIndent = pack $ replicate 12 ' '  eolSpaceP :: Parser ()-eolSpaceP = () <$ many' (char ' ') <* endOfLine+eolSpaceP = () <$ many (char ' ') <* eol  emptyP :: Parser Text-emptyP = many' (char ' ') *> char '.' *> eolSpaceP *> pure "."+emptyP = many (char ' ') *> char '.' *> eolSpaceP *> pure "."  textWithSpacesP :: Parser Text-textWithSpacesP = takeWhile (`notElem` ['\n', '\r'])+textWithSpacesP = takeWhileP Nothing (`notElem` ['\n', '\r'])  someLinesP :: Parser Text someLinesP = intercalate "\n" <$> someLinesIndentP firstIndent  someLinesIndentP :: Text -> Parser [Text] someLinesIndentP indent =  (:) <$> textWithSpacesP <* eolSpaceP-                       <*> (many' (string indent *> textWithSpacesP <* eolSpaceP))--wrapMP :: Parser a -> Parser (Maybe a)-wrapMP p = fmap Just p <|> pure Nothing+                       <*> (many (string indent *> textWithSpacesP <* eolSpaceP))  space :: Parser ()-space = () <$ (many' $ satisfy isSpace)+space = () <$ (many $ satisfy isSpace)  space1 :: Parser ()-space1 = () <$ (many1' $ satisfy isSpace)+space1 = () <$ (some $ satisfy isSpace)  alphaNumChar :: Parser Char alphaNumChar = satisfy isAlphaNum
src/Bio/GB/Type.hs view
@@ -7,18 +7,29 @@   , Source (..)   , Reference (..)   , Feature (..)+  , Parser   ) where -import           Bio.Sequence (IsMarking, MarkedSequence)-import           Data.Text    (Text)+import Bio.Sequence    (IsMarking, MarkedSequence)+import Control.DeepSeq (NFData)+import Data.Text       (Text)+import Data.Void       (Void)+import GHC.Generics    (Generic)+import Text.Megaparsec (Parsec) +type Parser = Parsec Void Text+ -- | Type that represents contents of .gb file that is used to store information about -- genetic constructions. ---data GenBankSequence = GenBankSequence { meta  :: Meta                        -- ^ meta-information about the sequence-                                       , gbSeq :: MarkedSequence Feature Char -- ^ sequence that is marked by 'Feature's-                                       }-  deriving (Eq, Show)+data GenBankSequence+  = GenBankSequence+      { meta  :: Meta+        -- ^ meta-information about the sequence+      , gbSeq :: MarkedSequence Feature Char+        -- ^ sequence that is marked by 'Feature's+      }+  deriving (Eq, Show, Generic, NFData)  -------------------------------------------------------------------------------- -- Block with meta-information.@@ -26,60 +37,95 @@  -- | Meta-information about sequence. ---data Meta = Meta { locus      :: Locus         -- ^ general info about sequence-                 , definition :: Maybe Text    -- ^ brief description of sequence-                 , accession  :: Maybe Text    -- ^ the unique identifier for a sequence record-                 , version    :: Maybe Version -- ^ id of sequence in GenBank database-                 , keywords   :: Maybe Text    -- ^ word or phrase describing the sequence-                 , source     :: Maybe Source  -- ^ free-format information including an abbreviated form of the organism name,-                                               --   sometimes followed by a molecule type-                 , references :: [Reference]   -- ^ publications by the authors of the sequence that discuss the data reported in the record-                 , comments   :: [Text]        -- ^ comments about the sequence (note that there can be (!!!) empty comments)-                 }-  deriving (Eq, Show)+data Meta+  = Meta+      { locus      :: Locus+        -- ^ general info about sequence+      , definition :: Maybe Text+        -- ^ brief description of sequence+      , accession  :: Maybe Text+        -- ^ the unique identifier for a sequence record+      , version    :: Maybe Version+        -- ^ id of sequence in GenBank database+      , keywords   :: Maybe Text+        -- ^ word or phrase describing the sequence+      , source     :: Maybe Source+        -- ^ free-format information including an abbreviated form of the organism name,+        --   sometimes followed by a molecule type+      , references :: [Reference]+        -- ^ publications by the authors of the sequence that discuss the data reported in the record+      , comments   :: [Text]+        -- ^ comments about the sequence (note that there can be (!!!) empty comments)+      }+  deriving (Eq, Show, Generic, NFData)  -- | First line that should be present in every .gb file. Contains general info about sequence. ---data Locus = Locus { name             :: Text       -- ^ name of sequence-                   , len              :: Int        -- ^ length of sequence-                   , molType          :: Text       -- ^ type of molecule that is sequenced-                   , form             :: Maybe Form -- ^ form of sequence-                   , gbDivision       :: Maybe Text -- ^ GenBank division to which a record belongs-                   , modificationDate :: Text       -- ^ date of last modification of sequence-                   }-  deriving (Eq, Show)+data Locus+  = Locus+      { name             :: Text+        -- ^ name of sequence+      , len              :: Int+        -- ^ length of sequence+      , molType          :: Text+        -- ^ type of molecule that is sequenced+      , form             :: Maybe Form+        -- ^ form of sequence+      , gbDivision       :: Maybe Text+        -- ^ GenBank division to which a record belongs+      , modificationDate :: Text+        -- ^ date of last modification of sequence+      }+  deriving (Eq, Show, Generic, NFData)  -- | At this moment there are two known (to me) -- forms of seuqences that can be present in .gb file. ---data Form = Linear | Circular-  deriving (Eq, Show)+data Form+  = Linear+  | Circular+  deriving (Eq, Show, Generic, NFData)  -- | Id of sequence in GenBank database. ---data Version = Version { versionT :: Text       -- ^ id itself-                       , gbId     :: Maybe Text -- ^ GenInfo Identifier that is assigned when sequence changes-                       }-  deriving (Eq, Show)+data Version+  = Version+      { versionT :: Text+        -- ^ id itself+      , gbId     :: Maybe Text+        -- ^ GenInfo Identifier that is assigned when sequence changes+      }+  deriving (Eq, Show, Generic, NFData)  -- | Information about source of this sequence. ---data Source = Source { sourceT  :: Text       -- ^ free-format (as if all this format is not too much "free format") information-                                              -- including an abbreviated form of the organism name,-                                              -- sometimes followed by a molecule type-                     , organism :: Maybe Text -- ^ the formal scientific name for the source organism-                     }-  deriving (Eq, Show)+data Source+  = Source+      { sourceT  :: Text+        -- ^ free-format (as if all this format is not too much "free format") information+        -- including an abbreviated form of the organism name,+        -- sometimes followed by a molecule type+      , organism :: Maybe Text+        -- ^ the formal scientific name for the source organism+      }+  deriving (Eq, Show, Generic, NFData)  -- | Publications by the authors of the sequence that discuss the data reported in the record. ---data Reference = Reference { referenceT :: Text       -- ^ reference itself-                           , authors    :: Maybe Text -- ^ list of authors in the order in which they appear in the cited article-                           , title      :: Maybe Text -- ^ title of the published work-                           , journal    :: Maybe Text -- ^ MEDLINE abbreviation of the journal name-                           , pubmed     :: Maybe Text -- ^ PubMed Identifier-                           }-  deriving (Eq, Show)+data Reference+  = Reference+      { referenceT :: Text+        -- ^ reference itself+      , authors    :: Maybe Text+        -- ^ list of authors in the order in which they appear in the cited article+      , title      :: Maybe Text+        -- ^ title of the published work+      , journal    :: Maybe Text+        -- ^ MEDLINE abbreviation of the journal name+      , pubmed     :: Maybe Text+        -- ^ PubMed Identifier+      }+  deriving (Eq, Show, Generic, NFData)  -------------------------------------------------------------------------------- -- Block with FEATURES table.@@ -92,11 +138,13 @@  -- | One single feature. ---data Feature = Feature { fName     :: Text           -- ^ main information about feature-                       , fStrand53 :: Bool           -- ^ set to True if sequence is contained on 5'-3' strand.-                                                     --   Set to False otherwise-                       , fProps    :: [(Text, Text)] -- ^ properties of feature (such as "label", "gene", "note" etc.)-                       }-  deriving (Eq, Show, Ord)+data Feature+  = Feature+      { fName  :: Text+        -- ^ main information about feature+      , fProps :: [(Text, Text)]+        -- ^ properties of feature (such as "label", "gene", "note" etc.)+      }+  deriving (Eq, Show, Ord, Generic, NFData)  instance IsMarking Feature
src/Bio/GB/Writer.hs view
@@ -2,16 +2,16 @@   ( genBankToText   ) where -import           Bio.GB.Type     (Feature (..), GenBankSequence (..),-                                  Locus (..), Meta (..), Reference (..),-                                  Source (..), Version (..))-import           Bio.Sequence    (Range, markings, toList)+import           Bio.GB.Type     (Feature (..), GenBankSequence (..), Locus (..), Meta (..),+                                  Reference (..), Source (..), Version (..))+import           Bio.Sequence    (Border (..), Range (..), RangeBorder (..), markings, shiftRange,+                                  toList) import           Control.Lens    ((^.)) import qualified Data.List.Split as S (chunksOf) import           Data.Maybe      (fromMaybe) import           Data.Text       (Text)-import qualified Data.Text       as T (append, chunksOf, intercalate, length,-                                       lines, null, pack, toLower, unwords)+import qualified Data.Text       as T (append, chunksOf, intercalate, length, lines, null, pack,+                                       toLower, unwords)  genBankToText :: GenBankSequence -> Text genBankToText GenBankSequence{..} = interNewLine parts <> "\n"@@ -99,7 +99,7 @@ featureToText :: (Feature, Range) -> Text featureToText (Feature{..}, range) = interNewLine $ mainPart : sections   where-    mainPart = processMany featuresIndent (prependIndent featuresPreIndent fName) (featureRangeToText fStrand53 range)+    mainPart = processMany featuresIndent (prependIndent featuresPreIndent fName) (featureRangeToText $ shiftRange 1 range)     sections = fmap featurePropToText fProps  featurePropToText :: (Text, Text) -> Text@@ -107,13 +107,17 @@   where     mainPart = processMany featuresIndent mempty ("/" <> nameF <> "=\"" <> textF <> "\"") -featureRangeToText :: Bool -> Range -> Text-featureRangeToText complement (l, r) | l == r - 1 = processComplement complement $ showText (l + 1)-                                     | otherwise  = processComplement complement $ showText (l + 1) <> ".." <> showText r+featureRangeToText :: Range -> Text+featureRangeToText (Point pos) = showText pos +featureRangeToText (Span (RangeBorder rbLo lo) (RangeBorder rbHi hi)) = borderToText True rbLo <> showText lo <> ".." <> borderToText False rbHi <> showText hi    where-    processComplement :: Bool -> Text -> Text-    processComplement True  text = text-    processComplement False text = "complement(" <> text <> ")"+    borderToText :: Bool -> Border -> Text+    borderToText _ Precise      = ""+    borderToText True Exceeded  = "<"+    borderToText False Exceeded = ">"+featureRangeToText (Between lo hi) = showText lo <> "^" <> showText hi+featureRangeToText (Join ranges) = "join(" <> T.intercalate "," (featureRangeToText <$> ranges) <> ")"+featureRangeToText (Complement range) = "complement(" <> featureRangeToText range <> ")"  -- | Indentation of feature's properties in FEATURES section. --
src/Bio/PDB/BondRestoring.hs view
@@ -168,7 +168,7 @@ sideChainBonds :: Text -> [(Text, Text)] sideChainBonds "ALA" = bwhMany [("CB", ["HB1", "HB2", "HB3"])] sideChainBonds "ARG" = [("CB", "CG"), ("CG", "CD"), ("CD", "NE"), ("NE", "CZ"), ("CZ", "NH2"), ("CZ", "NH1")] ++ bwhMany[("CB", ["HB3", "HB2"]), ("CG", ["HG3", "HG2"]), ("CD", ["HD3", "HD2"]), ("NE", ["HE"]), ("NH1", ["HH12", "HH11"]), ("NH2", ["HH22", "HH21"])]-sideChainBonds "ASN" = [("CB", "CG"), ("CG", "OD1"), ("CG", "ND2")] ++ bwhMany [("CB", ["HB3", "HB2"]), ("ND2", ["HD22", "HD21"])]+sideChainBonds "ASN" = [("CB", "CG"), ("CG", "OD1"), ("CG", "ND2")] ++ bwhMany [("CB", ["HB3", "HB2"]), ("ND2", ["HD22", "HD21"]), ("ND2", ["HD2", "HD1"])] sideChainBonds "ASP" = [("CB", "CG"), ("CG", "OD1"), ("CG", "OD2")] ++ bwhMany [("CB", ["HB3", "HB2"]), ("OD2", ["HD2"])] -- in fact, these are bonds for ASH, but sometimes ASH called just ASP... sideChainBonds "ASH" = [("CB", "CG"), ("CG", "OD1"), ("CG", "OD2")] ++ bwhMany [("CB", ["HB3", "HB2"]), ("OD2", ["HD2"])] sideChainBonds "CYS" = [("CB", "SG")] ++ bwhMany [("CB", ["HB3", "HB2"]), ("SG", ["HG"])]
src/Bio/Sequence.hs view
@@ -5,11 +5,13 @@   , module Bio.Sequence.Functions.Sequence   , module Bio.Sequence.Functions.Weight   , module Bio.Sequence.Functions.Marking+  , module Bio.Sequence.Range   ) where -import           Bio.Sequence.Class              hiding (_sequenceInner)-import           Bio.Sequence.Functions.Marking-import           Bio.Sequence.Functions.Sequence-import           Bio.Sequence.Functions.Weight+import Bio.Sequence.Class              hiding (_sequenceInner)+import Bio.Sequence.Functions.Marking+import Bio.Sequence.Functions.Sequence+import Bio.Sequence.Functions.Weight+import Bio.Sequence.Range  
src/Bio/Sequence/Class.hs view
@@ -43,12 +43,15 @@   , _sequenceInner   ) where -import           Bio.Sequence.Utilities (Range, checkRange, unsafeEither)+import           Bio.Sequence.Range     (Range, checkRange, shiftRange)+import           Bio.Sequence.Utilities (unsafeEither)+import           Control.DeepSeq        (NFData) import           Control.Lens import           Control.Monad.Except   (MonadError, throwError)-import           Data.Kind              (Constraint)+import           Data.Kind              (Constraint, Type) import qualified Data.List              as L (length, null) import           Data.Text              (Text)+import qualified Data.Text              as T import           Data.Vector            (Vector) import qualified Data.Vector            as V (fromList, length) import           GHC.Generics           (Generic)@@ -61,23 +64,28 @@ -- 'Sequence' represents sequence of objects of type 'a' that -- can have different markings of type 'mk' and weights of type 'w'. ---data Sequence mk w a = Sequence { _sequ     :: Vector a      -- ^ sequence itself-                                , _markings :: [(mk, Range)] -- ^ list of pairs containing marking and 'Range', that corresponds to it-                                , _weights  :: Vector w      -- ^ weights for all elements in sequence-                                }-  deriving (Eq, Show, Generic, Functor)+data Sequence mk w a+  = Sequence+      { _sequ     :: Vector a+        -- ^ sequence itself+      , _markings :: [(mk, Range)]+        -- ^ list of pairs containing marking and 'Range', that corresponds to it+      , _weights  :: Vector w+        -- ^ weights for all elements in sequence+      }+  deriving (Eq, Show, Generic, NFData, Functor)  instance Semigroup (Sequence mk w a) where   sequA <> sequB = res     where       newSequ     = sequA ^. sequ     <> sequB ^. sequ-      newMarkings = sequA ^. markings <> fmap (fmap (bimap addInd addInd)) (sequB ^. markings)+      newMarkings = sequA ^. markings <> fmap (fmap (shiftRange addInd)) (sequB ^. markings)       newWeights  = sequA ^. weights  <> sequB ^. weights        res = Sequence newSequ newMarkings newWeights -      addInd :: Int -> Int-      addInd = (+ V.length (sequA ^. sequ))+      addInd :: Int +      addInd = V.length (sequA ^. sequ)  instance Monoid (Sequence mk () a) where   mempty = Sequence mempty mempty mempty@@ -189,9 +197,9 @@ -- having not null weights type-safe. -- class (IsMarking (Marking s), IsWeight (Weight s)) => IsSequence s where-  type Element s :: *-  type Marking s :: *-  type Weight  s :: *+  type Element s :: Type+  type Marking s :: Type+  type Weight  s :: Type    toSequence :: s -> Sequence (Marking s) (Weight s) (Element s)   fromSequence :: Sequence (Marking s) (Weight s) (Element s) -> s@@ -302,7 +310,7 @@   Unit _  = TypeError ('Text "cobot-io: this function doesn't work with when not parametrized by ().")  createSequenceInner :: (IsSequence s, MonadError Text m) => Bool -> Bool -> [Element s] -> [(Marking s, Range)] -> [Weight s] -> m s-createSequenceInner checkMk checkW s markings' weights' | checkMk && not checkRanges     = throwError rangesError+createSequenceInner checkMk checkW s markings' weights' | checkMk && not checkRanges     = throwError rangesError                                                          | checkW && not checkNullWeights = throwError weightsNullError                                                         | checkW && not checkLenWeights  = throwError weightsLenError                                                         | otherwise                      = pure resSequence@@ -313,8 +321,11 @@     resSequence = fromSequence $ Sequence seqVector markings' weightsVector      checkRanges :: Bool-    checkRanges = all (checkRange (L.length s)) $ fmap snd markings'+    checkRanges = null faultyRanges  +    faultyRanges :: [Range]+    faultyRanges = filter (not . checkRange (L.length s)) $ fmap snd markings'+     checkNullWeights :: Bool     checkNullWeights = not (L.null weights') @@ -322,7 +333,7 @@     checkLenWeights = L.length s == L.length weights'      rangesError :: Text-    rangesError = "Bio.Sequence.Class: invalid 'Range' found in sequence's marking."+    rangesError = "Bio.Sequence.Class: invalid 'Range' found in sequence's marking: \n" <> T.pack (unlines (show <$> faultyRanges))      weightsNullError :: Text     weightsNullError = "Bio.Sequence.Class: weights are null for sequence."
src/Bio/Sequence/Functions/Marking.hs view
@@ -10,26 +10,22 @@   , listMarkings   ) where -import           Bio.Sequence.Class              (ContainsMarking,-                                                  IsBareSequence,-                                                  IsMarkedSequence,-                                                  IsSequence (..),-                                                  markedSequence, markings,-                                                  sequ, unsafeMarkedSequence,-                                                  weights, _sequenceInner)-import           Bio.Sequence.Functions.Sequence (length, unsafeGetRange)-import           Bio.Sequence.Utilities          (Range, checkRange,-                                                  unsafeEither) import           Control.Lens-import           Control.Monad.Except            (MonadError, throwError)-import           Data.List                       (nub)-import           Data.List.NonEmpty              (NonEmpty (..))-import           Data.Text                       (Text)-import qualified Data.Vector                     as V (toList)-import           Prelude                         hiding (drop, head, length,-                                                  null, reverse, tail, take,-                                                  (!!))+import           Control.Monad.Except (MonadError, throwError)+import           Data.List            (nub)+import           Data.List.NonEmpty   (NonEmpty (..))+import           Data.Text            (Text)+import qualified Data.Vector          as V (toList)+import           Prelude              hiding (drop, head, length, null, reverse, tail, take, (!!)) +import Bio.NucleicAcid.Nucleotide      (Complementary (..))+import Bio.Sequence.Class              (ContainsMarking, IsBareSequence, IsMarkedSequence,+                                        IsSequence (..), _sequenceInner, markedSequence, markings,+                                        sequ, unsafeMarkedSequence, weights)+import Bio.Sequence.Functions.Sequence (length, unsafeGetRange)+import Bio.Sequence.Range              (Range, checkRange)+import Bio.Sequence.Utilities          (unsafeEither)+ -- | Function that retrieves all elements in 'IsSequence' @s@ that are covered by given 'Marking'' @s@. -- Returns 'NonEmpty' list, because if 'Marking' is present in @s@, then list of -- all 'Marking's for @s@ can't be empty. If given 'Marking is not found in @s@, an@@ -38,7 +34,7 @@ -- > sequ = Sequence ['a', 'a', 'b', 'a'] [("Letter A", (0, 2)), ("Letter A", (3, 4)), ("Letter B", (2, 3))] mempty -- > getMarking sequ "Letter A" == ['a', 'a'] :| [['a']] ---getMarking :: (ContainsMarking s, MonadError Text m) => s -> Marking s -> m (NonEmpty [Element s])+getMarking :: (ContainsMarking s, MonadError Text m, Complementary (Element s)) => s -> Marking s -> m (NonEmpty [Element s]) getMarking (toSequence -> s) mk | not $ mk `member` (s ^. markings) = throwError markingNotFoundError                                 | otherwise                         = pure $ res   where@@ -47,7 +43,7 @@     markingNotFoundError :: Text     markingNotFoundError = "Bio.Sequence.Functions.Marking: given marking not found in Sequence." -unsafeGetMarking :: ContainsMarking s => s -> Marking s -> NonEmpty [Element s]+unsafeGetMarking :: (ContainsMarking s, Complementary (Element s)) => s -> Marking s -> NonEmpty [Element s] unsafeGetMarking mk = unsafeEither . getMarking mk  -- | Converts 'IsBareSequence' @s@ to 'IsMarkedSequence' @s'@ that is marked using provided list
src/Bio/Sequence/Functions/Sequence.hs view
@@ -12,32 +12,40 @@   , (!), (!?)   ) where -import           Bio.Sequence.Class     (ContainsNoMarking, IsSequence (..),-                                         markings, sequ, weights,-                                         _sequenceInner)-import           Bio.Sequence.Utilities (Range, checkRange, unsafeEither) import           Control.Lens-import           Control.Monad.Except   (MonadError, throwError)-import qualified Data.Foldable          as F (length, null, toList)-import qualified Data.List              as L (drop, take)-import           Data.Maybe             (fromMaybe)-import           Data.Text              (Text)-import           Data.Tuple             (swap)-import qualified Data.Vector            as V (drop, reverse, take, (!?))-import           Prelude                hiding (drop, length, null, reverse,-                                         tail, take)+import           Control.Monad.Except (MonadError, throwError)+import qualified Data.Foldable        as F (length, null, toList)+import qualified Data.List            as L (drop, take)+import           Data.Maybe           (fromMaybe)+import           Data.Text            (Text)+import qualified Data.Vector          as V+import           Prelude              hiding (drop, length, null, reverse, tail, take) --- | Get elements from sequence that belong to given 'Range' (format of range is [a; b)).++import Bio.NucleicAcid.Nucleotide (Complementary (..))+import Bio.Sequence.Class         (ContainsNoMarking, IsSequence (..), _sequenceInner, markings,+                                   sequ, weights)+import Bio.Sequence.Range         (Range (..), RangeBorder (..), checkRange, mapRange, swapRange)+import Bio.Sequence.Utilities     (unsafeEither)++-- | Get elements from sequence that belong to given 'Range'. If the range is a Span, then both lower and upper bounds are included. -- If given 'Range' is out of bounds, an error will be thrown. -- -- > sequ = Sequence ['a', 'a', 'b', 'a'] [("Letter A", (0, 2)), ("Letter A", (3, 4)), ("Letter B", (2, 3))] mempty -- > getRange sequ (0, 3) == Just ['a', 'a', 'b'] ---getRange :: (IsSequence s, MonadError Text m) => s -> Range -> m [Element s]-getRange s r@(lInd, rInd) | checkRange (length s) r = pure $ L.take (rInd - lInd) $ L.drop lInd $ toList s-                          | otherwise               = throwError "Bio.Sequence.Functions.Sequence: invalid range in getRange."+getRange :: (IsSequence s, MonadError Text m, Complementary (Element s)) => s -> Range -> m [Element s]+getRange s r | checkRange (length s) r = pure $ extractRange s r +             | otherwise               = throwError "Bio.Sequence.Functions.Sequence: invalid range in getRange." -unsafeGetRange :: IsSequence s => s -> Range -> [Element s]+extractRange :: (IsSequence s, Complementary (Element s)) => s -> Range -> [Element s]+extractRange s (Point pos)                                  = [s ! pos]+extractRange s (Span (RangeBorder _ lo) (RangeBorder _ hi)) = L.drop lo . L.take (hi + 1) . toList $ s+extractRange _ (Between _ _)                                = []+extractRange s (Join ranges)                                = concatMap (extractRange s) ranges+extractRange s (Complement range)                           = rcNA $ extractRange s range++unsafeGetRange :: (IsSequence s, Complementary (Element s)) => s -> Range -> [Element s] unsafeGetRange s = unsafeEither . getRange s  -- | Unsafe operator to get elemnt at given position in @s@.@@ -75,10 +83,10 @@ reverse :: IsSequence s => s -> s reverse (toSequence -> s) = res   where-    newMaxInd = length s+    newMaxInd = length s - 1      newSequ     = V.reverse $ s ^. sequ-    newMarkings = fmap (fmap $ swap . bimap ((-) newMaxInd) ((-) newMaxInd)) $ s ^. markings+    newMarkings = fmap (fmap $ swapRange . mapRange ((-) newMaxInd)) $ s ^. markings     newWeights  = V.reverse $ s ^. weights      res = fromSequence $ _sequenceInner newSequ newMarkings newWeights
+ src/Bio/Sequence/Range.hs view
@@ -0,0 +1,161 @@+module Bio.Sequence.Range +  ( Range (..)+  , Border (..)+  , RangeBorder (..)+  , borderType+  , borderLocation+  , location+  , lower+  , upper+  , before+  , after+  , ranges+  , range+  , checkRange+  , shiftRange+  , mapRange+  , swapRange+  , point+  , preciseSpan+  , between+  , extendRight+  , extendLeft+  , overlap+  , rangeMargins+  ) where++import Control.DeepSeq (NFData)+import Control.Lens    (makeLenses)+import GHC.Generics    (Generic)++-- | The type of range border. A border is @Exceeded@ when its end point is beyond the+-- specified base number, otherwise it is @Precise@.+-- In GenBank, for example, @Exceeded@ borders are marked with < and >.+--+data Border+  = Precise+  | Exceeded+  deriving (Eq, Show, Generic, NFData)++-- | The end point of a range with indication whether it is @Precise@ of @Exceeded@ (see @Border@).+--+data RangeBorder+  = RangeBorder+      { _borderType     :: Border+      , _borderLocation :: Int+      }+  deriving (Eq, Show, Generic, NFData)++makeLenses ''RangeBorder++data Range+  = Point+      { _location :: Int+      }+  -- ^ The exact location of a single base feature+  -- Example in GB:  conf            258+  | Span+      { _lower :: RangeBorder+      , _upper :: RangeBorder+      }+  -- ^ A region consisting of a simple span of bases.+  -- The symbols `<`and `>' are used to indicate that the beginning or end of the+  -- feature is beyond the range of the presented sequence.+  -- Examples in GB: tRNA            1..87+  --                 tRNA            <1..87     +  --                 tRNA            1..>87  +  | Between+      { _before :: Int+      , _after  :: Int+      }+  -- ^ The feature is between bases.+  -- Example in GB:  misc_recomb     105^106+  | Join+      { _ranges :: [Range]+      }+  -- ^ The feature consists of the union of several ranges.+  -- Example in GB:  origin          join(1, 23..50, 77..>100)+  | Complement+      { _range :: Range+      }+  -- ^ Indicates that the range is complementary.+  -- Example in GB:  rep             complement(69..420)+  deriving (Eq, Show, Generic, NFData)++makeLenses ''Range++point :: Int -> Range+point = Point++preciseSpan :: (Int, Int) -> Range+preciseSpan (lo, hi) = Span (RangeBorder Precise lo) (RangeBorder Precise hi)++between :: (Int, Int) -> Range+between = uncurry Between++checkRange :: Int -> Range -> Bool+checkRange len (Point pos) = 0 <= pos && pos < len+checkRange len (Span (RangeBorder _ lInd) (RangeBorder _ rInd)) = lInd < rInd && 0 <= lInd && rInd < len+checkRange len (Between lInd rInd) = lInd < rInd && 0 <= lInd && rInd <= len+checkRange len (Join ranges') = all (checkRange len) ranges'+checkRange len (Complement range') = checkRange len range'++mapRange :: (Int -> Int) -> Range -> Range+mapRange f (Point pos) = Point (f pos)+mapRange f (Span (RangeBorder bLo lo) (RangeBorder bHi hi)) = Span (RangeBorder bLo (f lo)) (RangeBorder bHi (f hi))+mapRange f (Between lo hi) = Between (f lo) (f hi)+mapRange f (Join ranges') = Join $ fmap (mapRange f) ranges'+mapRange f (Complement range') = Complement $ mapRange f range'++shiftRange :: Int -> Range -> Range+shiftRange delta = mapRange (+ delta) ++swapRange :: Range -> Range+swapRange r@Point{}           = r+swapRange (Span brLo brHi)    = Span brHi brLo+swapRange (Between lo hi)     = Between hi lo+swapRange (Join ranges')      = Join $ fmap swapRange ranges'+swapRange (Complement range') = Complement $ swapRange range'++extendRight :: Int -> Range -> Range+extendRight delta (Point a) = Span (RangeBorder Precise a) (RangeBorder Precise (a + delta))+extendRight delta (Span lo (RangeBorder r hi)) = Span lo (RangeBorder r (hi + delta))+extendRight _ b@Between{} = b+extendRight delta (Join ranges') = Join $ extendRight delta <$> ranges'+extendRight delta (Complement range') = Complement $ extendRight delta range'++extendLeft :: Int -> Range -> Range+extendLeft delta (Point a) = Span (RangeBorder Precise (a - delta)) (RangeBorder Precise a)+extendLeft delta (Span (RangeBorder r lo) hi) = Span (RangeBorder r (lo - delta)) hi+extendLeft _ b@Between{} = b+extendLeft delta (Join ranges') = Join $ extendLeft delta <$> ranges'+extendLeft delta (Complement range') = Complement $ extendLeft delta range'++overlap :: Range -> Range -> Bool+overlap (Point a) (Point b) = a == b+overlap (Point a) (Span (RangeBorder _ lo) (RangeBorder _ hi)) = lo <= a && a <= hi+overlap (Point _) (Between _ _) = False++overlap (Span (RangeBorder _ lo1) (RangeBorder _ hi1)) (Span (RangeBorder _ lo2) (RangeBorder _ hi2)) = +    (lo1 <= lo2 && hi1 >= lo2) ||+    (lo1 >= lo2 && lo1 <= hi2) ||+    (lo1 <= lo2 && hi1 >= hi2)+overlap (Span (RangeBorder _ lo) (RangeBorder _ hi)) (Between b1 b2) = b1 >= lo && b2 <= hi++overlap b1@Between{} b2@Between{} = b1 == b2++overlap r1 (Join ranges') = any (overlap r1) ranges'+overlap r1 (Complement range') = overlap r1 range'++overlap r1 r2 = overlap r2 r1++rangeMargins :: Range -> (Int, Int)+rangeMargins rng = +    case rng of+      Point x -> (x, x)+      Span (RangeBorder _ lo) (RangeBorder _ hi) -> (lo, hi)+      Between lo hi -> (lo, hi)+      Join children -> let (los, his) = unzip (rangeMargins <$> children) +                        in (minimum los, maximum his)+      Complement child -> rangeMargins child+
src/Bio/Sequence/Utilities.hs view
@@ -1,18 +1,9 @@ module Bio.Sequence.Utilities-  ( Range-  , checkRange-  , unsafeEither+  ( unsafeEither   ) where  import           Data.Text (Text) import qualified Data.Text as T (unpack)---- | Range of form [a, b).----type Range = (Int, Int)--checkRange :: Int -> Range -> Bool-checkRange len (lInd, rInd) = lInd < rInd && 0 <= lInd && rInd <= len  unsafeEither :: Either Text a -> a unsafeEither = either (error . T.unpack) id
test/FastaParserSpec.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}  module FastaParserSpec where @@ -36,25 +37,25 @@ onlyName = describe "onlyName" $ do     it "correctly parses fasta without sequence" $ do         let res = parseOnly fastaP ">3HMX:A|PDBID|CHAIN|SEQUENCE"-        res `shouldBe` Right [FastaItem "3HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "")]+        res `shouldBe` Right [FastaItem @Char "3HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "")]  oneSequence :: Spec oneSequence = describe "oneSequence" $ do     it "correctly parses one correct sequence" $ do         let res = parseOnly fastaP ">3HMX:A|PDBID|CHAIN|SEQUENCE\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSE\nVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL\n"-        res `shouldBe` Right [FastaItem "3HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL")]+        res `shouldBe` Right [FastaItem @Char "3HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL")]  twoSequences :: Spec twoSequences = describe "twoSequences" $ do     it "correctly parses two correct sequences" $ do         let res = parseOnly fastaP ">3HMX:A|PDBID|CHAIN|SEQUENCE\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSE\nVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL\n>7HMX:A|PDBID|CHAIN|SEQUENCE\nEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\nVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL"-        res `shouldBe` Right [FastaItem "3HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL"), FastaItem "7HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL")]+        res `shouldBe` Right [FastaItem @Char "3HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL"), FastaItem @Char "7HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL")]  sequenceWithDigit :: Spec sequenceWithDigit = describe "sequenceWithDigit" $ do     it "correctly parses incorrect sequence with digit" $ do         let res = parseOnly fastaP ">123\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEE4GITWTLDQSSE"-        res `shouldBe` Right [FastaItem "123" (bareSequence "")]+        res `shouldBe` Right [FastaItem @Char "123" (bareSequence "")]  sequenceWithWrongName :: Spec sequenceWithWrongName = describe "sequenceWithWrongName" $ do@@ -66,31 +67,31 @@ sequenceWithSpacesInName = describe "sequenceWithSpacesInName" $ do     it "correctly parses sequence with spaces in name" $ do         let res = parseOnly fastaP ">  this is my sequence   \nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSE"-        res `shouldBe` Right [FastaItem "this is my sequence" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSE")]+        res `shouldBe` Right [FastaItem @Char "this is my sequence" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSE")]  sequenceWithSeveralEndOfLine :: Spec sequenceWithSeveralEndOfLine = describe "sequenceWithSeveralEndOfLine" $ do     it "correctly parses sequence with several \n after name" $ do         let res = parseOnly fastaP ">this is my sequence\n\n\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSE"-        res `shouldBe` Right [FastaItem "this is my sequence" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSE")]+        res `shouldBe` Right [FastaItem @Char "this is my sequence" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSE")]  sequenceWithSeveralEndOfLineInSequence :: Spec sequenceWithSeveralEndOfLineInSequence = describe "sequenceWithSeveralEndOfLineInSequence" $ do     it "correctly parses sequence with several \n between sequence parts" $ do         let res = parseOnly fastaP ">this is my sequence\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSE\n\n\nYYYYYYYYYYYYYYYYYYYYYYYY"-        res `shouldBe` Right [FastaItem "this is my sequence" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSEYYYYYYYYYYYYYYYYYYYYYYYY")]+        res `shouldBe` Right [FastaItem @Char "this is my sequence" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSEYYYYYYYYYYYYYYYYYYYYYYYY")]  sequenceWithTabsInName :: Spec sequenceWithTabsInName = describe "sequenceWithTabsInName" $ do     it "correctly parses sequence with tabs in name" $ do         let res = parseOnly fastaP ">\tthis\tis\tmy\tsequence\t\t\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSE"-        res `shouldBe` Right [FastaItem "this\tis\tmy\tsequence" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSE")]+        res `shouldBe` Right [FastaItem @Char "this\tis\tmy\tsequence" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSE")]  sequenceWithTabsInSequence :: Spec sequenceWithTabsInSequence = describe "sequenceWithTabsInSequence" $ do     it "correctly parses sequence with tabs between sequence parts" $ do         let res = parseOnly fastaP ">this is my sequence\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSE\t\t\nYYYYYYYYYYYYYYYYYYYYYYYY\t\n"-        res `shouldBe` Right [FastaItem "this is my sequence" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSEYYYYYYYYYYYYYYYYYYYYYYYY")]+        res `shouldBe` Right [FastaItem @Char "this is my sequence" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSEYYYYYYYYYYYYYYYYYYYYYYYY")]  sequenceWithModifications :: Spec sequenceWithModifications = describe "sequenceWithModifications" $ do
test/FastaWriterSpec.hs view
@@ -1,9 +1,11 @@+{-# LANGUAGE TypeApplications #-}+ module FastaWriterSpec where -import           Bio.FASTA.Writer       (fastaToText)-import           Bio.FASTA.Type         (FastaItem(..))-import           Bio.Sequence           (bareSequence)-import           Test.Hspec+import Bio.FASTA.Type   (FastaItem (..))+import Bio.FASTA.Writer (fastaToText)+import Bio.Sequence     (bareSequence)+import Test.Hspec  fastaWriterSpec :: Spec fastaWriterSpec = describe "Fasta format parser." $ do@@ -21,17 +23,17 @@ oneShortSequence :: Spec oneShortSequence = describe "oneShortSequence" $ do     it "correctly write one correct short (less than 80 chars) sequence" $ do-        let res = fastaToText [FastaItem "3HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL")]+        let res = fastaToText [FastaItem @Char "3HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL")]         res `shouldBe` ">3HMX:A|PDBID|CHAIN|SEQUENCE\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL\n"  oneLongSequence :: Spec oneLongSequence = describe "oneLongSequence" $ do     it "correctly write one correct long (more than 80 chars) sequence" $ do-        let res = fastaToText [FastaItem "3HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLLLLHKKEDGIWSTDILKDQKEPKNKTFLRCEAKNYSGRFTCWWLTTISTDLTFSVKSSRGSSDPQGVTCGAATLSAERVRGDNKEYEYSVECQEDSACPAAEESLPIEVMVDAVHKLKYENYTSSFFIRDIIKPDPPKNLQLKPLKNSRQVEVSWEYPDTWSTPHSYFSLTFCVQVQGKSKREKKDRVFTDKTSATVICRKNASISVRAQDRYYSSSWSEWASVPCS")]+        let res = fastaToText [FastaItem @Char "3HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLLLLHKKEDGIWSTDILKDQKEPKNKTFLRCEAKNYSGRFTCWWLTTISTDLTFSVKSSRGSSDPQGVTCGAATLSAERVRGDNKEYEYSVECQEDSACPAAEESLPIEVMVDAVHKLKYENYTSSFFIRDIIKPDPPKNLQLKPLKNSRQVEVSWEYPDTWSTPHSYFSLTFCVQVQGKSKREKKDRVFTDKTSATVICRKNASISVRAQDRYYSSSWSEWASVPCS")]         res `shouldBe` ">3HMX:A|PDBID|CHAIN|SEQUENCE\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL\nLLHKKEDGIWSTDILKDQKEPKNKTFLRCEAKNYSGRFTCWWLTTISTDLTFSVKSSRGSSDPQGVTCGAATLSAERVRG\nDNKEYEYSVECQEDSACPAAEESLPIEVMVDAVHKLKYENYTSSFFIRDIIKPDPPKNLQLKPLKNSRQVEVSWEYPDTW\nSTPHSYFSLTFCVQVQGKSKREKKDRVFTDKTSATVICRKNASISVRAQDRYYSSSWSEWASVPCS\n"  twoSequences :: Spec twoSequences = describe "twoSequences" $ do     it "correctly write two correct sequences" $ do-        let res = fastaToText [FastaItem "3HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL"), FastaItem "7HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLLLLHKKEDGIWSTDILKDQKEPKNKTFLRCEAKNYSGRFTCWWLTTISTDLTFSVKSSRGSSDPQGVTCGAATLSAERVRGDNKEYEYSVECQEDSACPAAEESLPIEVMVDAVHKLKYENYTSSFFIRDIIKPDPPKNLQLKPLKNSRQVEVSWEYPDTWSTPHSYFSLTFCVQVQGKSKREKKDRVFTDKTSATVICRKNASISVRAQDRYYSSSWSEWASVPCS")]+        let res = fastaToText [FastaItem @Char "3HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL"), FastaItem @Char "7HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLLLLHKKEDGIWSTDILKDQKEPKNKTFLRCEAKNYSGRFTCWWLTTISTDLTFSVKSSRGSSDPQGVTCGAATLSAERVRGDNKEYEYSVECQEDSACPAAEESLPIEVMVDAVHKLKYENYTSSFFIRDIIKPDPPKNLQLKPLKNSRQVEVSWEYPDTWSTPHSYFSLTFCVQVQGKSKREKKDRVFTDKTSATVICRKNASISVRAQDRYYSSSWSEWASVPCS")]         res `shouldBe` ">3HMX:A|PDBID|CHAIN|SEQUENCE\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL\n>7HMX:A|PDBID|CHAIN|SEQUENCE\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL\nLLHKKEDGIWSTDILKDQKEPKNKTFLRCEAKNYSGRFTCWWLTTISTDLTFSVKSSRGSSDPQGVTCGAATLSAERVRG\nDNKEYEYSVECQEDSACPAAEESLPIEVMVDAVHKLKYENYTSSFFIRDIIKPDPPKNLQLKPLKNSRQVEVSWEYPDTW\nSTPHSYFSLTFCVQVQGKSKREKKDRVFTDKTSATVICRKNASISVRAQDRYYSSSWSEWASVPCS\n"
test/GBParserSpec.hs view
@@ -2,19 +2,69 @@  module GBParserSpec where -import           Bio.GB       (Feature (..), Form (..), GenBankSequence (..),-                               Locus (..), Meta (..), Reference (..),-                               Source (..), Version (..), fromFile)-import           Bio.Sequence (Range, unsafeMarkedSequence)-import           Test.Hspec+import Bio.GB          (Feature (..), Form (..), GenBankSequence (..), Locus (..), Meta (..),+                        Reference (..), Source (..), Version (..), fromFile)+import Bio.GB.Parser   (rangeP)+import Bio.Sequence    (Border (..), Range (..), RangeBorder (..), preciseSpan,+                        unsafeMarkedSequence)+import Control.Lens    (_Left, over)+import Data.Text       (Text)+import Test.Hspec+import Text.Megaparsec (eof, errorBundlePretty, parse)  gbParserSpec :: Spec gbParserSpec = describe "GenBank format parser." $ do+    rangeTests     pAAVGFPSpecP "test/GB/pAAV-GFP-CellBioLab.gb"     pAAVCMVSpecP "test/GB/pAAV_CMV_RPE65_PolyA_linkers.gb"     dottedMetaSpecP "test/GB/pAAV-GFP-CellBioLab-dots.gb"     unknownFieldsSpecP "test/GB/pIntA-TRBV.gb"+    baseCountWithSophisticatedRangesAndMultilineFeatures "test/GB/fromYanaWithLove.gb" +rangeTests :: Spec+rangeTests = describe "Range parser" $ do+    it "correctly parses a simple span" $ +        greedyRangeP "69..420" `shouldBe` successful (Span (RangeBorder Precise 69) (RangeBorder Precise 420))+    it "correctly parses a span with the lower border exceeded" $+        greedyRangeP "<69..420" `shouldBe` successful (Span (RangeBorder Exceeded 69) (RangeBorder Precise 420))+    it "correctly parses a span with the upper border exceeded" $+        greedyRangeP "69..>420" `shouldBe` successful (Span (RangeBorder Precise 69) (RangeBorder Exceeded 420))+    it "correctly parses a span with both border exceeded" $ +        greedyRangeP "<69..>420" `shouldBe` successful (Span (RangeBorder Exceeded 69) (RangeBorder Exceeded 420))+    it "does not parse a span with the lower border exceeded incorrectly" $ +        greedyRangeP ">69..420" `shouldSatisfy` isFail+    it "does not parse a span with the upper border exceeded incorrectly" $ +        greedyRangeP "69..<420" `shouldSatisfy` isFail++    it "correctly parses a 'between' statement" $ +        greedyRangeP "41^42" `shouldBe` successful (Between 41 42)+    it "does not parse a 'between' statement witn border excession marks" $ +        greedyRangeP "<41^42" `shouldSatisfy` isFail++    it "correctly parses a single point feature" $ +        greedyRangeP "42" `shouldBe` successful (Point 42)+    it "does not parse a single point feature with border excession marks" $ +        greedyRangeP "<3" `shouldSatisfy` isFail++    it "correctly parses a join() statement" $ +        greedyRangeP "join(2,12..56)" `shouldBe` successful (Join [Point 2, Span (RangeBorder Precise 12) (RangeBorder Precise 56)])+    it "correctly parses a sophisticated join() statement" $ +        greedyRangeP "join(2^3,<5..10,15,20..>28)" `shouldBe` successful (Join [Between 2 3, Span (RangeBorder Exceeded 5) (RangeBorder Precise 10), Point 15, Span (RangeBorder Precise 20) (RangeBorder Exceeded 28)])++    it "correctly parses a complement() statement" $ +        greedyRangeP "complement(69..>420)" `shouldBe` successful (Complement (Span (RangeBorder Precise 69) (RangeBorder Exceeded 420)))+    it "correctly parses a join() incorporated into a complement()" $ +        greedyRangeP "complement(join(2^3,<5..10,15,20..>28))" `shouldBe` successful (Complement (Join [Between 2 3, Span (RangeBorder Exceeded 5) (RangeBorder Precise 10), Point 15, Span (RangeBorder Precise 20) (RangeBorder Exceeded 28)]))+  where+    greedyRangeP :: Text -> Either String Range+    greedyRangeP = over _Left errorBundlePretty . parse (rangeP <* eof) ""+    +    successful :: a -> Either String a+    successful = Right++    isFail :: Either String a -> Bool+    isFail = null + pAAVGFPSpecP :: FilePath -> Spec pAAVGFPSpecP path = describe "pAAVGFP" $ do     it "correctly parses meta information" $ do@@ -47,7 +97,15 @@         mt <- meta <$> fromFile path         name (locus mt) `shouldBe` "P2-32_pIntA-TRBV5-1_J1-1-Fc-lama-knob-EPEA" +baseCountWithSophisticatedRangesAndMultilineFeatures :: FilePath -> Spec+baseCountWithSophisticatedRangesAndMultilineFeatures path = describe "" $ do+    it "correctly parses the 'BASE COUNT' line and features with sophisticated ranges" $ do+        gbS <- gbSeq <$> fromFile path+        gbS `shouldBe`  unsafeMarkedSequence sophisticatedFeaturesSeq sophisticatedFeatures  +compPreciseSpan :: (Int, Int) -> Range+compPreciseSpan = Complement . preciseSpan+ pAAVGFPMeta :: Meta pAAVGFPMeta = Meta { locus=Locus "pAAV-GFP-CellBio" 5374 "ds-DNA" (Just Circular) (Just "SYN") "15-AUG-2016"                    , definition=Just $ "Saccharomyces cerevisiae TCP1-beta gene, partial cds, and Axl2p\n(AXL2) and Rev7p (REV7) genes, complete cds."@@ -63,31 +121,29 @@                    }  pAAVGFPFeatures :: [(Feature, Range)]-pAAVGFPFeatures = [ ( (Feature "misc_feature" True [ ("label", "Right ITR")-                                                                        ]-                                           ), (0, 130))-                                       , ( (Feature "enhancer" True [ ("label", "CMV enhancer")-                                                                    , ("note", "human cytomegalovirus immediate early enhancer")+pAAVGFPFeatures = [ ( (Feature "misc_feature" [ ("label", "Right ITR") ]+                                           ), preciseSpan (0, 129))+                                       , ( (Feature "enhancer" [ ("label", "CMV enhancer")+                                                               , ("note", "human cytomegalovirus immediate early enhancer")+                                                               ]+                                           ), preciseSpan (205, 508))+                                       , ( (Feature "promoter" [ ("label", "CMV promoter")+                                                               , ("note", "human cytomegalovirus (CMV) immediate early \npromoter")+                                                               ]+                                           ), preciseSpan (509, 711))+                                       , ( (Feature "misc_feature" [ ("label", "Human beta-globin Intron") ]+                                           ), preciseSpan (804, 1296))+                                       , ( (Feature "CDS" [ ("codon_start", "1")+                                                          , ("product", "enhanced GFP")+                                                          , ("label", "EGFP")+                                                          , ("note", "mammalian codon-optimized")+                                                          ]+                                           ), preciseSpan (1319, 2035))+                                       , ( (Feature "repeat_region" [ ("label", "Left ITR")+                                                                    , ("note", "inverted terminal repeat of adeno-associated virus \nserotype 2\noooooo")+                                                                    , ("prop", "1")                                                                     ]-                                           ), (205, 509))-                                       , ( (Feature "promoter" True [ ("label", "CMV promoter")-                                                                                                   , ("note", "human cytomegalovirus (CMV) immediate early \npromoter")-                                                                                                   ]-                                           ), (509, 712))-                                       , ( (Feature "misc_feature" True [ ("label", "Human beta-globin Intron")-                                                                                                            ]-                                           ), (804, 1297))-                                       , ( (Feature "CDS" True [ ("codon_start", "1")-                                                                                                , ("product", "enhanced GFP")-                                                                                                , ("label", "EGFP")-                                                                                                , ("note", "mammalian codon-optimized")-                                                                                                ]-                                           ), (1319, 2036))-                                       , ( (Feature "repeat_region" False [ ("label", "Left ITR")-                                                                                                         , ("note", "inverted terminal repeat of adeno-associated virus \nserotype 2\noooooo")-                                                                                                         , ("prop", "1")-                                                                                                         ]-                                           ), (2636, 2777))+                                           ), compPreciseSpan (2636, 2776))                                        ]  pAAVGFPOrigin :: String@@ -106,41 +162,40 @@                    }  pAAVCMVFeatures :: [(Feature, Range)]-pAAVCMVFeatures = [ ( (Feature "rep_origin" True [ ("direction", "RIGHT")-                                                                                                       , ("note", "f1 bacteriophage origin of replication; arrow\r\nindicates direction of (+) strand synthesis")-                                                                                                       , ("label", "f1 ori")-                                                                                                       , ("ApEinfo_fwdcolor", "#999999")-                                                                                                       , ("ApEinfo_revcolor", "#999999")-                                                                                                       , ("ApEinfo_graphicformat", "arrow_data {{0 1 2 0 0 -1} {} 0}\r\nwidth 5 offset 0")-                                                                                                       ]-                      ), (3742, 4198))-                    , ( (Feature "promoter" True [ ("gene", "bla")-                                                                                                     , ("label", "AmpR promoter")-                                                                                                     , ("ApEinfo_fwdcolor", "#346ee0")-                                                                                                     , ("ApEinfo_revcolor", "#346ee0")-                                                                                                     , ("ApEinfo_graphicformat", "arrow_data {{0 1 2 0 0 -1} {} 0}\r\nwidth 5 offset 0")-                                                                                                     ]-                        ), (4479, 4584))-                    , ( (Feature "CDS" True [ ("codon_start", "1")-                                                                                                , ("gene", "bla")-                                                                                                , ("product", "beta-lactamase")-                                                                                                , ("note", "confers resistance to ampicillin, carbenicillin,\r\nand related antibiotics")-                                                                                                , ("label", "AmpR")-                                                                                                , ("ApEinfo_fwdcolor", "#e9d024")-                                                                                                , ("ApEinfo_revcolor", "#e9d024")-                                                                                                , ("ApEinfo_graphicformat", "arrow_data {{0 1 2 0 0 -1} {} 0}\r\nwidth 5 offset 0")-                                                                                                ]-                        ), (4584, 5445))-                     , ( (Feature "misc_feature" True [ ("label", "RightITR2")-                                                                                                         , ("ApEinfo_fwdcolor", "#7eff74")-                                                                                                         , ("ApEinfo_revcolor", "#7eff74")-                                                                                                         , ("ApEinfo_graphicformat", "arrow_data {{0 1 2 0 0 -1} {} 0}\r\nwidth 5 offset 0")-                                                                                                         ]-                         ), (3527, 3668))-                      , ( (Feature "misc_feature" False [ ("label", "A->T")-                                                                                                ]-                          ), (199, 200))+pAAVCMVFeatures = [ ( (Feature "rep_origin" [ ("direction", "RIGHT")+                                            , ("note", "f1 bacteriophage origin of replication; arrow\r\nindicates direction of (+) strand synthesis")+                                            , ("label", "f1 ori")+                                            , ("ApEinfo_fwdcolor", "#999999")+                                            , ("ApEinfo_revcolor", "#999999")+                                            , ("ApEinfo_graphicformat", "arrow_data {{0 1 2 0 0 -1} {} 0}\r\nwidth 5 offset 0")+                                            ]+                      ), preciseSpan (3742, 4197))+                    , ( (Feature "promoter" [ ("gene", "bla")+                                            , ("label", "AmpR promoter")+                                            , ("ApEinfo_fwdcolor", "#346ee0")+                                            , ("ApEinfo_revcolor", "#346ee0")+                                            , ("ApEinfo_graphicformat", "arrow_data {{0 1 2 0 0 -1} {} 0}\r\nwidth 5 offset 0")+                                            ]+                        ), preciseSpan (4479, 4583))+                    , ( (Feature "CDS" [ ("codon_start", "1")+                                       , ("gene", "bla")+                                       , ("product", "beta-lactamase")+                                       , ("note", "confers resistance to ampicillin, carbenicillin,\r\nand related antibiotics")+                                       , ("label", "AmpR")+                                       , ("ApEinfo_fwdcolor", "#e9d024")+                                       , ("ApEinfo_revcolor", "#e9d024")+                                       , ("ApEinfo_graphicformat", "arrow_data {{0 1 2 0 0 -1} {} 0}\r\nwidth 5 offset 0")                                        ]+                        ), preciseSpan (4584, 5444))+                     , ( (Feature "misc_feature" [ ("label", "RightITR2")+                                                 , ("ApEinfo_fwdcolor", "#7eff74")+                                                 , ("ApEinfo_revcolor", "#7eff74")+                                                 , ("ApEinfo_graphicformat", "arrow_data {{0 1 2 0 0 -1} {} 0}\r\nwidth 5 offset 0")+                                                 ]+                         ), preciseSpan (3527, 3667))+                      , ( (Feature "misc_feature" [ ("label", "A->T") ]+                          ), Complement (Point 199))+                      ]  pAAVCMVOrigin :: String pAAVCMVOrigin =@@ -158,3 +213,118 @@                                ]                   , comments=["."]                   }++sophisticatedFeaturesSeq :: String+sophisticatedFeaturesSeq = "cctacagcgtgagctatgagaaagcgccacgcttcccgaagggagaaaggcggacaggtatccggtaagcggcagggtcggaacaggagagcgcacgagggagcttccagggggaaacgcctggtatctttatagtcctgtcgggtttcgccacctctgacttgagcgtcgatttttgtgatgctcgtcaggggggcggagcctatggaaaaacgccagcaacgcggcctttttacggttcctggccttttgctggccttttgctcacatgttctttcctgcgttatcccctgattctgtggataaccgtattaccgcctttgagtgagctgataccgctcgccgcagccgaacgaccgagcgcagcgagtcagtgagcgaggaagcgtacatttatattggctcatgtccaatatgaccgccatgttgacattgattattgactagaccgcgttacataacttacggtaaatggcccgcctggctgaccgcccaacgacccccgcccattgacgtcaataatgacgtatgttcccatagtaacgccaatagggactttccattgacgtcaatgggtggagtatttacggtaaactgcccacttggcagtacatcaagtgtatcatatgccaagtacgccccctattgacgtcaatgacggtaaatggcccgcctggcattatgcccagtacatgaccttatgggactttcctacttggcagtacatctacgtattagtcatcgctattaccatggtgatgcggttttggcagtacatcaatgggcgtggatagcggtttgactcacggggatttccaagtctccaccccattgacgtcaatgggagtttgttttggcaccaaaatcaacgggactttccaaaatgtcgtaacaactccgccccattgacgcaaatgggcggtaggcgtgtacggtgggaggtctatataagcagagctcgtttagtgaaccgtcagatcgcctggagacgccatccacgctgttttgacctccatagaagacaccgggaccgatccagcctccgcggccgggaacggtgcattggaacgcggattccccgtgccaagagtgacgtaagtaccgcctatagagtctataggcccacccccttggcttcttatgcatgctatactgtttttggcttggggtctatacacccccgcttcctcatgttataggtgatggtatagcttagcctataggtgtgggttattgaccattattgaccactcccctattggtgacgatactttccattactaatccataacatggctctttgccacaactctctttattggctatatgccaatacactgtccttcagagactgacacggactctgtatttttacaggatggggtctcatttattatttacaaattcacatatacaacaccaccgtccccagtgcccgcagtttttattaaacataacgtgggatctccacgcgaatctcgggtacgtgttccggacatgggctcatctccggtagcggcggagcttctacatccgagccctgctcccatgcctccagcgactcatggtcgctcggcagctccttgctcctaacagtggaggccagacttaggcacagcacgatgcccaccaccaccagtgtgccgcacaaggccgtggcggtagggtatgtgtctgaaaatgagctcggggagcgggcttgcaccgctgacgcatttggaagacttaaggcagcggcagaagaagatgcaggcagctgagttgttgtgttctgataagagtcagaggtaactcccgttgcggtgctgttaacggtggagggcagtgtagtctgagcagtactcgttgctgccgcgcgcgccaccagacataatagctgacagactaacagactgttcctttccatgggtcttttctgcagtcaccgtccttgacacgaagcttgccgccaccatggagaccgacaccctgctgctgtgggtgctgctgctgtgggtgcccgggtcgacgaagagctcatgagcggatacatatttgaatgtatttagaaaaataaacaaataggggtcagtgttacaaccaattaaccaattctgaacattatcgcgagcccatttatacctgaatatggctcataacaccccttgtttgcctggcggcagtagcgcggtggtcccacctgaccccatgccgaactcagaagtgaaacgccgtagcgccgatggtagtgtggggactccccatgcgagagtagggaactgccaggcatcaaataaaacgaaaggctcagtcgaaagactgggcctttcgcccgggctaattatggggtgtcgcccttggggtgagaccctcgagtgtacagaattcttactgatacgtgtccagatcaaccgctttcacgacctctaccagacacatgtgatcacggcgctcgtcgcggtctttgctcagtttggtgtggtaggtaatgtgatgataacgcgggatatgcactgccgcggagcccgccaacggacgattcatttggctgcatttggtaaccagtttttcggtcacaccttcaatatcgtacgcctggttgaactcaacgcggatgccattgttaacggtgtcaggcagaatatacagaatgcttggcgggcattggaatgcaacgttcttacgcagaatgtgaccgtctttcttaaagttctcaccagtcagcgtgacacgattgtagatagaaccgcgttcgtaggtaaccatagcacgcgtcttgtacacgccgtcgccttcgaagctgatggtacgctcttgggtataaccttccggcatggcgctcttaaagaaatccttgatgtggctcgggtacttgcgaaacactgaacaccgtagctcagggtgctcaccagggttgcccacgggacccggcaggtcgcccgtagtgcagatgtatttcgctttaatggtacccgtggtcgcgtcacccggtaccctcgcctttaatgataaatttcataccttcgacgtcgccttccagttcggtgatatacgggatctctttctcaaacagttttgcaccttccgtcaatgccgtcatatgtttacctcctaaggtctcgaaaagttaaacaaaattatttctaaagggaaaccgttgtggaattgtgagcgctcacaattccacatattataattgttatccgctcacaaagcaaataaatttttcatgatttcactgtgcatgaagctcgtaattgttatccgctcacaattaagggcgacacaaaatttattctaaatgataataaatactgataacatcttatagtttgtattatattttgtattatcgttgacatgtataattttgatatcaaaaactgattttccctttattattttcgagatttattttcttaattctctttaacaaactagaaatattgtatatacaaaaaatcataaataatagatgaatagtttaattataggtgttcatcaatcgaaaaagcaacgtatcttatttaaagtgcgttgcttttttctcatttataaggttaaataattctcatatatcaagcaaagtgacaggcgcccttaaatattctgacaaatgctctttccctaaactccccccataaaaaaacccgccgaagcgggtttttacgttatttgcggattaacgattactcgttatcagaaccgcccagggggcccgagcttaagactggccgtcgttttacaacacaagctcttccgtacggtggctgcaccatctgtcttcatcttcccgccatctgatgagcagttgaaatctggaactgcctctgttgtgtgcctgctgaataacttctatcccagagaggccaaagtacagtggaaggtggataacgccctccaatcgggtaactcccaggagagtgtcacagagcaggacagcaaggacagcacctacagcctcagcagcaccctgacgctgagcaaagcagactacgagaaacacaaagtctacgcctgcgaagtcacccatcagggcctgagctcgcccgtcacaaagagcttcaacaggggagagtgttaatagtctagacctaggtgatcataatcagccataccacatttgtagaggttttacttgctttaaaaaacctcccacacctccccctgaacctgaaacataaaatgaatgcaattgttgttgttaacttgtttattgcagcttataatggttacaaataaagcaatagcatcacaaatttcacaaataaagcatttttttcactgcattctagttgtggtttgtccaaactcatcaatgtatcttatcatgtctggagatctctagctagaggatcgatccccgccccggacgaactaaacctgactacgacatctctgccccttcttcgcggggcagtgcatgtaatcccttcagttggttggtacaacttgccaactgaaccctaaacgggtagcatatgcttcccgggtagtagtatatactatccagactaaccctaattcaatagcatatgttacccaacgggaagcatatgctatcgaattagggttagtaaaagggtcctaaggaacagcgatgtaggtgggcgggccaagataggggcgcgattgctgcgatctggaggacaaattacacacacttgcgcctgagcgccaagcacagggttgttggtcctcatattcacgaggtcgctgagagcacggtgggctaatgttgccatgggtagcatatactacccaaatatctggatagcatatgctatcctaatctatatctgggtagcataggctatcctaatctatatctgggtagcatatgctatcctaatctatatctgggtagtatatgctatcctaatttatatctgggtagcataggctatcctaatctatatctgggtagcatatgctatcctaatctatatctgggtagtatatgctatcctaatctgtatccgggtagcatatgctatcctaatagagattagggtagtatatgctatcctaatttatatctgggtagcatatactacccaaatatctggatagcatatgctatcctaatctatatctgggtagcatatgctatcctaatctatatctgggtagcataggctatcctaatctatatctgggtagcatatgctatcctaatctatatctgggtagtatatgctatcctaatttatatctgggtagcataggctatcctaatctatatctgggtagcatatgctatcctaatctatatctgggtagtatatgctatcctaatctgtatccgggtagcatatgctatcctcatgataagctgtcaaacatgagaattaattcttgaagacgaaagggcctcgtgatacgcctatttttataggttaatgtcatgataataatggtttcttagacgtcaggtggcacttttcggggaaatgtgcgcggaacccctatttgtttatttttctaaatacattcaaatatgtatccgctcatgagacaataaccctgataaatgcttcaataatattgaaaaaggaagagtatgagtattcaacatttccgtgtcgcccttattcccttttttgcggcattttgccttcctgtttttgctcacccagaaacgctggtgaaagtaaaagatgctgaagatcagttgggtgcacgagtgggttacatcgaactggatctcaacagcggtaagatccttgagagttttcgccccgaagaacgttttccaatgatgagcacttttaaagttctgctatgtggcgcggtattatcccgtgttgacgccgggcaagagcaactcggtcgccgcatacactattctcagaatgacttggttgagtactcaccagtcacagaaaagcatcttacggatggcatgacagtaagagaattatgcagtgctgccataaccatgagtgataacactgcggccaacttacttctgacaacgatcggaggaccgaaggagctaaccgcttttttgcacaacatgggggatcatgtaactcgccttgatcgttgggaaccggagctgaatgaagccataccaaacgacgagcgtgacaccacgatgcctgcagcaatggcaacaacgttgcgcaaactattaactggcgaactacttactctagcttcccggcaacaattaatagactggatggaggcggataaagttgcaggaccacttctgcgctcggcccttccggctggctggtttattgctgataaatctggagccggtgagcgtgggtctcgcggtatcattgcagcactggggccagatggtaagccctcccgtatcgtagttatctacacgacggggagtcaggcaactatggatgaacgaaatagacagatcgctgagataggtgcctcactgattaagcattggtaactgtcagaccaagtttactcatatatactttagattgatttaaaacttcatttttaatttaaaaggatctaggtgaagatcctttttgataatctcatgaccaaaatcccttaacgtgagttttcgttccactgagcgtcagaccccgtagaaaagatcaaaggatcttcttgagatcctttttttctgcgcgtaatctgctgcttgcaaacaaaaaaaccaccgctaccagcggtggtttgtttgccggatcaagagctaccaactctttttccgaaggtaactggcttcagcagagcgcagataccaaatactgttcttctagtgtagccgtagttaggccaccacttcaagaactctgtagcaccgcctacatacctcgctctgctaatcctgttaccagtggctgctgccagtggcgataagtcgtgtcttaccgggttggactcaagacgatagttaccggataaggcgcagcggtcgggctgaacggggggttcgtgcacacagcccagcttggagcgaacgacctacaccgaactgagata"++sophisticatedFeatures :: [(Feature, Range)]+sophisticatedFeatures = +  [ (Feature "source" +      [ ("organism", "synthetic DNA construct")+      , ("mol_type", "other DNA")+      ]+    , preciseSpan (0, 6950))++  , (Feature "rep_origin" +      [ ("label", "pUCorigin and also a multiline property")+      , ("note", "/vntifkey=33")+      ]+    , Join [Point 0, preciseSpan (6550, 6950)])++  , (Feature "enhancer" +      [ ("label", "cmv enhanser")+      , ("label", "cmv\\enhanser")+      , ("note", "/vntifkey=9")+      ]+    , preciseSpan (448, 857))++  , (Feature "misc_feature"+      [ ("label", "hCMV promoter")+      , ("label", "hCMV\\promoter")+      , ("note", "/vntifkey=21")+      ]+    , preciseSpan (858, 983))++  , (Feature "intron"+      [ ("label", "IntronA")+      , ("note", "/vntifkey=15")+      ]+    , preciseSpan (1011, 1918))++  , (Feature "primer_bind" +      [ ("label", "inv olig1") ]+    , preciseSpan (1501, 1521))++  , (Feature "misc_feature"+      [ ("label", "Kozak")+      , ("note", "/vntifkey=21")+      ]+    , preciseSpan (1944, 1952))++  , (Feature "misc_feature"+      [ ("label", "Leader IgK")+      , ("note", "Leader IgK")+      , ("note", "/ugene_name=Leader\\ IgK")+      , ("note", "/vntifkey=21")+      ]+    , preciseSpan (1953, 2009))++  , (Feature "misc_feature"   +      [ ("label", "START")+      , ("note", "START")+      , ("note", "/ugene_name=START")+      , ("note", "/vntifkey=21")+      ]+    , preciseSpan (1953, 1955))++  , (Feature "misc_feature"   +      [ ("label", "GFP stuffer")+      , ("note", "GFP stuffer")+      , ("note", "/ugene_name=GFP\\ stuffer")+      , ("note", "/vntifkey=21")+      ]+    , preciseSpan (2010, 3738))++  , (Feature "misc_feature"   +      [ ("label", "CK")+      , ("note", "CK")+      , ("note", "/ugene_name=CK")+      , ("note", "/vntifkey=21")+      ]+    , preciseSpan (3739, 4059))++  , (Feature "misc_feature"   +      [ ("label", "STOP")+      , ("note", "STOP")+      , ("note", "/ugene_name=STOP")+      , ("note", "/vntifkey=21")+      ]+    , preciseSpan (4060, 4065))++  , (Feature "misc_feature"  +      [ ("gene", "SV40_PA term")+      , ("label", "SV40_PA term")+      , ("label", "SV40_PA\\term")+      , ("note", "/vntifkey=21")+      ]+    , preciseSpan (4078, 4316))++  , (Feature "primer_bind"   +      [ ("label", "pEE_Clab") ]+    , preciseSpan (4349, 4369))++  , (Feature "rep_origin"     +      [ ("label", "EBV ori")+      , ("label", "EBV\\ori")+      , ("note", "/vntifkey=33")+      ]+    , preciseSpan (4581, 4974))++  , (Feature "CDS"          +      [ ("codon_start", "1")+      , ("label", "AmpR")+      , ("note", "/vntifkey=4")+      , ("translation", "MSIQHFRVALIPFFAAFCLPVFAHPETLVKVKDAEDQLGARVGYI\nELDLNSGKILESFRPEERFPMMSTFKVLLCGAVLSRVDAGQEQLGRRIHYSQNDLVEYS\nPVTEKHLTDGMTVRELCSAAITMSDNTAANLLLTTIGGPKELTAFLHNMGDHVTRLDRW\nEPELNEAIPNDERDTTMPAAMATTLRKLLTGELLTLASRQQLIDWMEADKVAGPLLRSA\nLPAGWFIADKSGAGERGSRGIIAALGPDGKPSRIVVIYTTGSQATMDERNRQIAEIGAS\nLIKHW")+      ]+    , preciseSpan (5542, 6402))+  ]
+ test/RangeSpec.hs view
@@ -0,0 +1,290 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}++module RangeSpec where++import Bio.Sequence (Range (..), extendLeft, extendRight, mapRange, overlap, preciseSpan,+                     shiftRange)+import Test.Hspec+++rangeSpec :: Spec+rangeSpec = do+    rangeOverlapTests+    rangeShiftTests+    rangeMapTests+    rangeExtendTests++rangeOverlapTests :: Spec+rangeOverlapTests = describe "Range overlap tests" $ do+    it "Point-Point, should not overlap" $ +        overlap (Point 42) (Point 24) `shouldBe` False+    it "Point-Point, should overlap" $ +        overlap (Point 42) (Point 42) `shouldBe` True++    it "Point-Span, should not overlap" $ +        overlap (Point 42) (preciseSpan (14, 24)) `shouldBe` False+    it "Point-Span, should overlap" $ +        overlap (Point 42) (preciseSpan (14, 42)) `shouldBe` True+    it "Point-Span, should overlap" $ +        overlap (Point 42) (preciseSpan (14, 43)) `shouldBe` True+    it "Point-Span, should overlap" $ +        overlap (Point 42) (preciseSpan (42, 50)) `shouldBe` True+    it "Span-Point, should not overlap" $ +        overlap (preciseSpan (14, 24)) (Point 42) `shouldBe` False+    it "Span-Point, should overlap" $ +        overlap (preciseSpan (14, 42)) (Point 42) `shouldBe` True+    it "Span-Point, should overlap" $ +        overlap (preciseSpan (14, 43)) (Point 42) `shouldBe` True+    it "Span-Point, should overlap" $ +        overlap (preciseSpan (42, 50)) (Point 42) `shouldBe` True++    it "Point-Between, should not overlap" $ +        overlap (Point 42) (Between 42 43) `shouldBe` False+    it "Between-Point, should not overlap" $ +        overlap (Between 23 24) (Point 24) `shouldBe` False++    it "Point-Join, should not overlap" $ +        overlap (Point 42) (Join [Point 24, preciseSpan (29, 41), Between 42 43, preciseSpan (77, 99)]) `shouldBe` False+    it "Point-join, should overlap" $ +        overlap (Point 42) (Join [Point 10, Point 20, preciseSpan (30, 50), Between 88 89]) `shouldBe` True+    it "Join-Point, should not overlap" $ +        flip overlap (Point 42) (Join [Point 24, preciseSpan (29, 41), Between 42 43, preciseSpan (77, 99)]) `shouldBe` False+    it "Join-Point, should overlap" $ +        flip overlap (Point 42) (Join [Point 10, Point 20, preciseSpan (30, 50), Between 88 89]) `shouldBe` True++    it "Point-Complement, should not overlap" $ +        overlap (Point 42) (Join [Point 24, preciseSpan (29, 41), Between 42 43, preciseSpan (77, 99)]) `shouldBe` False+    it "Point-Complement, should overlap" $ +        overlap (Point 42) (Join [Point 10, Point 20, preciseSpan (30, 50), Between 88 89]) `shouldBe` True+    it "Complement-Point, should not overlap" $ +        flip overlap (Point 42) (Join [Point 24, preciseSpan (29, 41), Between 42 43, preciseSpan (77, 99)]) `shouldBe` False+    it "Complement-Point, should overlap" $ +        flip overlap (Point 42) (Join [Point 10, Point 20, preciseSpan (30, 50), Between 88 89]) `shouldBe` True++    it "Span-Span, should not overlap" $+        --  -----xxxxxxxxxxxxx---------------------------+        --  --------------------------xxxxxxxxxxxxx------+        overlap (preciseSpan (10, 20)) (preciseSpan (30, 40)) `shouldBe` False+    it "Span-Span, should not overlap" $+        --  -----xxxxxxxxxxxxx-------------------+        --  ------------------xxxxxxxxxxxxx------+        overlap (preciseSpan (10, 20)) (preciseSpan (21, 40)) `shouldBe` False+    it "Span-Span, should overlap" $+        --  -----xxxxxxxxxxxxx------------------+        --  -----------------xxxxxxxxxxxxx------+        overlap (preciseSpan (10, 20)) (preciseSpan (20, 40)) `shouldBe` True +    it "Span-Span, should overlap" $+        --  -----xxxxxxxxxxxxx---------------+        --  --------------xxxxxxxxxxxxx------+        overlap (preciseSpan (10, 20)) (preciseSpan (17, 40)) `shouldBe` True +    it "Span-Span, should overlap" $+        --  -----xxxxxxxxxxxxx----------------+        --  ---xxxxxxxxxxxxxxxxxxxxxxxxx------+        overlap (preciseSpan (10, 20)) (preciseSpan (5, 40)) `shouldBe` True +    it "Span-Span, should overlap" $+        --  ---xxxxxxxxxxxxxxxxxxxxxxxxx------+        --  -----xxxxxxxxxxxxx----------------+        overlap (preciseSpan (5, 40)) (preciseSpan (10, 20)) `shouldBe` True ++    it "Span-Join, should not overlap" $+        -- ---xxxxxxxx--------------------------+        -- -x---------|--xxxxx---xxxxxxxx-------+        overlap (preciseSpan (5, 10)) (Join [Point 2, Between 10 11, preciseSpan (15, 20), preciseSpan (30, 40)]) `shouldBe` False+    it "Span-Join, should overlap" $+        -- ----xxxxxxxx-------------------------+        -- -x---------|--xxxxx---xxxxxxxx-------+        overlap (preciseSpan (6, 11)) (Join [Point 2, Between 10 11, preciseSpan (15, 20), preciseSpan (30, 40)]) `shouldBe` True+    it "Span-Join, should overlap" $+        -- ----------xxxxxxxx-------------------+        -- -x---------|--xxxxx---xxxxxxxx-------+        overlap (preciseSpan (9, 18)) (Join [Point 2, Between 10 11, preciseSpan (15, 20), preciseSpan (30, 40)]) `shouldBe` True+    it "Span-Join, should overlap" $+        -- ------------------xxxxxxxx-----------+        -- -x---------|--xxxxx---xxxxxxxx-------+        overlap (preciseSpan (18, 32)) (Join [Point 2, Between 10 11, preciseSpan (15, 20), preciseSpan (30, 40)]) `shouldBe` True+    it "Span-Join, should overlap" $+        -- -----------------------------xxxxxxxx+        -- -x---------|--xxxxx---xxxxxxxx-------+        overlap (preciseSpan (40, 50)) (Join [Point 2, Between 10 11, preciseSpan (15, 20), preciseSpan (30, 40)]) `shouldBe` True+    it "Join-Span, should not overlap" $+        -- ---xxxxxxxx--------------------------+        -- -x---------|--xxxxx---xxxxxxxx-------+        flip overlap (preciseSpan (5, 10)) (Join [Point 2, Between 10 11, preciseSpan (15, 20), preciseSpan (30, 40)]) `shouldBe` False+    it "Join-Span, should overlap" $+        -- ----xxxxxxxx-------------------------+        -- -x---------|--xxxxx---xxxxxxxx-------+        flip overlap (preciseSpan (6, 11)) (Join [Point 2, Between 10 11, preciseSpan (15, 20), preciseSpan (30, 40)]) `shouldBe` True+    it "Join-Span, should overlap" $+        -- ----------xxxxxxxx-------------------+        -- -x---------|--xxxxx---xxxxxxxx-------+        flip overlap (preciseSpan (9, 18)) (Join [Point 2, Between 10 11, preciseSpan (15, 20), preciseSpan (30, 40)]) `shouldBe` True+    it "Join-Span, should overlap" $+        -- ------------------xxxxxxxx-----------+        -- -x---------|--xxxxx---xxxxxxxx-------+        flip overlap (preciseSpan (18, 32)) (Join [Point 2, Between 10 11, preciseSpan (15, 20), preciseSpan (30, 40)]) `shouldBe` True+    it "Join-Span, should overlap" $+        -- -----------------------------xxxxxxxx+        -- -x---------|--xxxxx---xxxxxxxx-------+        flip overlap (preciseSpan (40, 50)) (Join [Point 2, Between 10 11, preciseSpan (15, 20), preciseSpan (30, 40)]) `shouldBe` True++    it "Span-Complement, should not overlap" $+        --  -----xxxxxxxxxxxxx---------------------------+        --  --------------------------xxxxxxxxxxxxx------+        overlap (preciseSpan (10, 20)) (Complement $ preciseSpan (30, 40)) `shouldBe` False+    it "Span-Complement, should not overlap" $+        --  -----xxxxxxxxxxxxx-------------------+        --  ------------------xxxxxxxxxxxxx------+        overlap (preciseSpan (10, 20)) (Complement $ preciseSpan (21, 40)) `shouldBe` False+    it "Span-Complement, should overlap" $+        --  -----xxxxxxxxxxxxx------------------+        --  -----------------xxxxxxxxxxxxx------+        overlap (preciseSpan (10, 20)) (Complement $ preciseSpan (20, 40)) `shouldBe` True +    it "Span-Complement, should overlap" $+        --  -----xxxxxxxxxxxxx---------------+        --  --------------xxxxxxxxxxxxx------+        overlap (preciseSpan (10, 20)) (Complement $ preciseSpan (17, 40)) `shouldBe` True +    it "Span-Complement, should overlap" $+        --  -----xxxxxxxxxxxxx----------------+        --  ---xxxxxxxxxxxxxxxxxxxxxxxxx------+        overlap (preciseSpan (10, 20)) (Complement $ preciseSpan (5, 40)) `shouldBe` True +    it "Span-Complement, should overlap" $+        --  ---xxxxxxxxxxxxxxxxxxxxxxxxx------+        --  -----xxxxxxxxxxxxx----------------+        overlap (preciseSpan (5, 40)) (Complement $ preciseSpan (10, 20)) `shouldBe` True +    it "Complement-Span, should not overlap" $+        --  -----xxxxxxxxxxxxx---------------------------+        --  --------------------------xxxxxxxxxxxxx------+        flip overlap (preciseSpan (10, 20)) (Complement $ preciseSpan (30, 40)) `shouldBe` False+    it "Complement-Span, should not overlap" $+        --  -----xxxxxxxxxxxxx-------------------+        --  ------------------xxxxxxxxxxxxx------+        flip overlap (preciseSpan (10, 20)) (Complement $ preciseSpan (21, 40)) `shouldBe` False+    it "Complement-Span, should overlap" $+        --  -----xxxxxxxxxxxxx------------------+        --  -----------------xxxxxxxxxxxxx------+        flip overlap (preciseSpan (10, 20)) (Complement $ preciseSpan (20, 40)) `shouldBe` True +    it "Complement-Span, should overlap" $+        --  -----xxxxxxxxxxxxx---------------+        --  --------------xxxxxxxxxxxxx------+        flip overlap (preciseSpan (10, 20)) (Complement $ preciseSpan (17, 40)) `shouldBe` True +    it "Complement-Span, should overlap" $+        --  -----xxxxxxxxxxxxx----------------+        --  ---xxxxxxxxxxxxxxxxxxxxxxxxx------+        flip overlap (preciseSpan (10, 20)) (Complement $ preciseSpan (5, 40)) `shouldBe` True +    it "Complement-Span, should overlap" $+        --  ---xxxxxxxxxxxxxxxxxxxxxxxxx------+        --  -----xxxxxxxxxxxxx----------------+        flip overlap (preciseSpan (5, 40)) (Complement $ preciseSpan (10, 20)) `shouldBe` True ++    it "Join-Join, should not overlap" $+        -- ---xxx--|--xxxxx----x----xxxx------+        -- x|-----x---------xx---xx-------xxxx+        overlap (Join [preciseSpan (5, 10), Between 15 16, preciseSpan (30, 40), Point 50, preciseSpan (60, 70)]) (Join [Point 1, Between 1 2, Point 15, preciseSpan (42, 46), preciseSpan (52, 55), preciseSpan (80, 100)]) `shouldBe` False+    it "Join-Join, should overlap" $+        -- ---xxx--|--xxxxx----x----xxxx---+        -- x|-----x---------xx---xx----xxxx+        overlap (Join [preciseSpan (5, 10), Between 15 16, preciseSpan (30, 40), Point 50, preciseSpan (60, 70)]) (Join [Point 1, Between 1 2, Point 15, preciseSpan (42, 46), preciseSpan (52, 55), preciseSpan (70, 100)]) `shouldBe` True +    it "Join-Join, should overlap" $+        -- ---xxx--|--xxxxx--x------xxxx------+        -- x|-----x---------xx---xx-------xxxx+        overlap (Join [preciseSpan (5, 10), Between 15 16, preciseSpan (30, 40), Point 46, preciseSpan (60, 70)]) (Join [Point 1, Between 1 2, Point 15, preciseSpan (42, 46), preciseSpan (52, 55), preciseSpan (80, 100)]) `shouldBe` True ++    it "Join-Complement, should not overlap" $+        -- ---xxxxxxxx--------------------------+        -- -x---------|--xxxxx---xxxxxxxx-------+        flip overlap (Complement $ preciseSpan (5, 10)) (Join [Point 2, Between 10 11, preciseSpan (15, 20), preciseSpan (30, 40)]) `shouldBe` False+    it "Join-Complement, should overlap" $+        -- ----xxxxxxxx-------------------------+        -- -x---------|--xxxxx---xxxxxxxx-------+        flip overlap (Complement $ preciseSpan (6, 11)) (Join [Point 2, Between 10 11, preciseSpan (15, 20), preciseSpan (30, 40)]) `shouldBe` True+    it "Join-Complement, should overlap" $+        -- ----------xxxxxxxx-------------------+        -- -x---------|--xxxxx---xxxxxxxx-------+        flip overlap (Complement $ preciseSpan (9, 18)) (Join [Point 2, Between 10 11, preciseSpan (15, 20), preciseSpan (30, 40)]) `shouldBe` True+    it "Join-Complement, should overlap" $+        -- ------------------xxxxxxxx-----------+        -- -x---------|--xxxxx---xxxxxxxx-------+        flip overlap (Complement $ preciseSpan (18, 32)) (Join [Point 2, Between 10 11, preciseSpan (15, 20), preciseSpan (30, 40)]) `shouldBe` True+    it "Join-Complement, should overlap" $+        -- -----------------------------xxxxxxxx+        -- -x---------|--xxxxx---xxxxxxxx-------+        flip overlap (Complement $ preciseSpan (40, 50)) (Join [Point 2, Between 10 11, preciseSpan (15, 20), preciseSpan (30, 40)]) `shouldBe` True+    it "Complement-Join, should not overlap" $+        -- ---xxxxxxxx--------------------------+        -- -x---------|--xxxxx---xxxxxxxx-------+        overlap (Complement $ preciseSpan (5, 10)) (Join [Point 2, Between 10 11, preciseSpan (15, 20), preciseSpan (30, 40)]) `shouldBe` False+    it "Complement-Join, should overlap" $+        -- ----xxxxxxxx-------------------------+        -- -x---------|--xxxxx---xxxxxxxx-------+        overlap (Complement $ preciseSpan (6, 11)) (Join [Point 2, Between 10 11, preciseSpan (15, 20), preciseSpan (30, 40)]) `shouldBe` True+    it "Complement-Join, should overlap" $+        -- ----------xxxxxxxx-------------------+        -- -x---------|--xxxxx---xxxxxxxx-------+        overlap (Complement $ preciseSpan (9, 18)) (Join [Point 2, Between 10 11, preciseSpan (15, 20), preciseSpan (30, 40)]) `shouldBe` True+    it "Complement-Join, should overlap" $+        -- ------------------xxxxxxxx-----------+        -- -x---------|--xxxxx---xxxxxxxx-------+        overlap (Complement $ preciseSpan (18, 32)) (Join [Point 2, Between 10 11, preciseSpan (15, 20), preciseSpan (30, 40)]) `shouldBe` True+    it "Complement-Join, should overlap" $+        -- -----------------------------xxxxxxxx+        -- -x---------|--xxxxx---xxxxxxxx-------+        overlap (Complement $ preciseSpan (40, 50)) (Join [Point 2, Between 10 11, preciseSpan (15, 20), preciseSpan (30, 40)]) `shouldBe` True++    it "Complement-Complement, should not overlap" $+        --  -----xxxxxxxxxxxxx---------------------------+        --  --------------------------xxxxxxxxxxxxx------+        overlap (Complement $ preciseSpan (10, 20)) (Complement $ preciseSpan (30, 40)) `shouldBe` False+    it "Complement-Complement, should not overlap" $+        --  -----xxxxxxxxxxxxx-------------------+        --  ------------------xxxxxxxxxxxxx------+        overlap (Complement $ preciseSpan (10, 20)) (Complement $ preciseSpan (21, 40)) `shouldBe` False+    it "Complement-Complement, should overlap" $+        --  -----xxxxxxxxxxxxx------------------+        --  -----------------xxxxxxxxxxxxx------+        overlap (Complement $ preciseSpan (10, 20)) (Complement $ preciseSpan (20, 40)) `shouldBe` True +    it "Complement-Complement, should overlap" $+        --  -----xxxxxxxxxxxxx---------------+        --  --------------xxxxxxxxxxxxx------+        overlap (Complement $ preciseSpan (10, 20)) (Complement $ preciseSpan (17, 40)) `shouldBe` True +    it "Complement-Complement, should overlap" $+        --  -----xxxxxxxxxxxxx----------------+        --  ---xxxxxxxxxxxxxxxxxxxxxxxxx------+        overlap (Complement $ preciseSpan (10, 20)) (Complement $ preciseSpan (5, 40)) `shouldBe` True +    it "Complement-Complement, should overlap" $+        --  ---xxxxxxxxxxxxxxxxxxxxxxxxx------+        --  -----xxxxxxxxxxxxx----------------+        overlap (Complement $ preciseSpan (5, 40)) (Complement $ preciseSpan (10, 20)) `shouldBe` True +++rangeShiftTests :: Spec+rangeShiftTests = describe "Range shift tests" $ do+    it "Shifts a point" $ shiftRange 22 (Point 20) `shouldBe` Point 42+    it "Shifts a Between feature" $ shiftRange 22 (Between 20 21) `shouldBe` Between 42 43+    it "Shifts a span" $ shiftRange 22 (preciseSpan (20, 21)) `shouldBe` preciseSpan (42, 43)+    it "Shifts a Join feature" $ shiftRange 22 (Join [Point 10, Between 11 12, preciseSpan (13, 14)]) `shouldBe` Join [Point 32, Between 33 34, preciseSpan (35, 36)]+    it "Shifts a Complement feature" $ shiftRange 22 (Complement $ Point 20) `shouldBe` Complement (Point 42)++rangeMapTests :: Spec+rangeMapTests = describe "Range map tests" $ do+    it "Maps a point" $ mapRange ((-) 1) (Point 20) `shouldBe` Point (-19)+    it "Maps a Between feature" $ mapRange ((-) 1) (Between 20 21) `shouldBe` Between (-19) (-20) +    it "Maps a span" $ mapRange ((-) 1) (preciseSpan (20, 21)) `shouldBe` preciseSpan (-19, -20)+    it "Maps a Join feature" $ mapRange ((-) 1) (Join [Point 10, Between 11 12, preciseSpan (13, 14)]) `shouldBe` Join [Point (-9), Between (-10) (-11), preciseSpan (-12, -13)]+    it "Maps a Complement feature" $ mapRange ((-) 1) (Complement $ Point 20) `shouldBe` Complement (Point (-19))++rangeExtendTests :: Spec+rangeExtendTests = do+    describe "Range extend tests" $ do+        describe "Extend left" $ do+            it "Extends a point" $ extendLeft 10 (Point 10) `shouldBe` preciseSpan (0, 10)+            it "Extends a Between feature" $ extendLeft 10 (Between 10 11) `shouldBe` Between 10 11+            it "Extends a span" $ extendLeft 10 (preciseSpan (10, 20)) `shouldBe` preciseSpan (0, 20)+            it "Extends a Join feature" $ extendLeft 10 (Join [Point 10, Between 11 12, preciseSpan (13, 14)]) `shouldBe` Join [preciseSpan (0, 10), Between 11 12, preciseSpan (3, 14)]+            it "Extends a Complement feature" $ extendLeft 10 (Complement $ Point 10) `shouldBe` (Complement $ preciseSpan (0, 10))+        describe "Extend right" $ do+            it "Extends a point" $ extendRight 10 (Point 10) `shouldBe` preciseSpan (10, 20)+            it "Extends a Between feature" $ extendRight 10 (Between 10 11) `shouldBe` Between 10 11+            it "Extends a span" $ extendRight 10 (preciseSpan (10, 20)) `shouldBe` preciseSpan (10, 30)+            it "Extends a Join feature" $ extendRight 10 (Join [Point 10, Between 11 12, preciseSpan (13, 14)]) `shouldBe` Join [preciseSpan (10, 20), Between 11 12, preciseSpan (13, 24)]+            it "Extends a Complement feature" $ extendRight 10 (Complement $ Point 10) `shouldBe` (Complement $ preciseSpan (10, 20))
test/SequenceSpec.hs view
@@ -3,19 +3,18 @@  module SequenceSpec where -import           Bio.Sequence       (BareSequence, IsMarking, IsWeight (..),-                                     MarkedSequence, Sequence, WeightedSequence,-                                     addMarkings, bareSequence, createSequence,-                                     drop, getMarking, getRange, getWeight,-                                     markedSequence, mean, meanInRange, reverse,-                                     tail, take, toMarked, toWeighted,-                                     unsafeCreateSequence, unsafeMarkedSequence,-                                     unsafeWeightedSequence, weightedSequence) import qualified Data.List.NonEmpty as NE (fromList) import           Data.Text          (Text) import           Prelude            hiding (drop, reverse, tail, take) import           Test.Hspec +import Bio.Sequence               (BareSequence, IsMarking, IsWeight (..), MarkedSequence,+                                   Range (..), Sequence, WeightedSequence, addMarkings,+                                   bareSequence, createSequence, drop, getMarking, getRange,+                                   getWeight, markedSequence, mean, meanInRange, preciseSpan,+                                   reverse, tail, take, toMarked, toWeighted, unsafeCreateSequence,+                                   unsafeMarkedSequence, unsafeWeightedSequence, weightedSequence)+ instance IsWeight Int where   toDouble = fromIntegral @@ -44,7 +43,8 @@       let seqE = weightedSequence [] [] :: Either Text TestWeightedSequence       seqE `shouldBe` seqErr1 -newtype TestMarking = TestMarking Text+newtype TestMarking+  = TestMarking Text   deriving (Eq, Show, Ord)  instance IsMarking TestMarking@@ -55,11 +55,11 @@ markedSequenceSpec =   describe "Marked sequence" $ do     it "successful creation of marked sequence" $ do-      let seqE = markedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))] :: Either Text TestMarkedSequence-      seqE `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))])+      let seqE = markedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))] :: Either Text TestMarkedSequence+      seqE `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))]) -      let seqE = markedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "bca", (1, 5)), (TestMarking "a", (3, 5))] :: Either Text TestMarkedSequence-      seqE `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "bca", (1, 5)), (TestMarking "a", (3, 5))])+      let seqE = markedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "bca", preciseSpan (1, 4)), (TestMarking "a", preciseSpan (3, 4))] :: Either Text TestMarkedSequence+      seqE `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "bca", preciseSpan (1, 4)), (TestMarking "a", preciseSpan (3, 4))])        let seqE = markedSequence [] [] :: Either Text TestMarkedSequence       seqE `shouldBe` Right (unsafeMarkedSequence [] [])@@ -67,19 +67,18 @@       let seqE = markedSequence ['a', 'b', 'c', 'a', 'a'] [] :: Either Text TestMarkedSequence       seqE `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [])     it "unsuccessful creation of marked sequence" $ do-      let seqErr = Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking." -      let seqE = markedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (-1, 1))] :: Either Text TestMarkedSequence-      seqE `shouldBe` seqErr+      let seqE = markedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", preciseSpan (-1, 0))] :: Either Text TestMarkedSequence+      seqE `shouldBe` Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking: \nSpan {_lower = RangeBorder {_borderType = Precise, _borderLocation = -1}, _upper = RangeBorder {_borderType = Precise, _borderLocation = 0}}\n" -      let seqE = markedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "bca", (0, 6)), (TestMarking "a", (3, 5))] :: Either Text TestMarkedSequence-      seqE `shouldBe` seqErr+      let seqE = markedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "bca", preciseSpan (0, 5)), (TestMarking "a", preciseSpan (3, 4))] :: Either Text TestMarkedSequence+      seqE `shouldBe` Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking: \nSpan {_lower = RangeBorder {_borderType = Precise, _borderLocation = 0}, _upper = RangeBorder {_borderType = Precise, _borderLocation = 5}}\n" -      let seqE = markedSequence ['a'] [(TestMarking "a", (0, 0))] :: Either Text TestMarkedSequence-      seqE `shouldBe` seqErr+      let seqE = markedSequence ['a'] [(TestMarking "a", preciseSpan (0, -1))] :: Either Text TestMarkedSequence+      seqE `shouldBe` Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking: \nSpan {_lower = RangeBorder {_borderType = Precise, _borderLocation = 0}, _upper = RangeBorder {_borderType = Precise, _borderLocation = -1}}\n"  -      let seqE = markedSequence [] [(TestMarking "k", (0, 1))] :: Either Text TestMarkedSequence-      seqE `shouldBe` seqErr+      let seqE = markedSequence [] [(TestMarking "k", Point 0)] :: Either Text TestMarkedSequence+      seqE `shouldBe` Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking: \nPoint {_location = 0}\n"   type TestMarkedAndWeightedSequence = Sequence TestMarking Int Char @@ -87,38 +86,37 @@ markedAndWeightedSequenceSpec =   describe "Marked and weighted sequence" $ do     it "successful creation of marked and weighted sequence" $ do-      let seqE = createSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence-      seqE `shouldBe` Right (unsafeCreateSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))] [1, 2.. 5])+      let seqE = createSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence+      seqE `shouldBe` Right (unsafeCreateSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))] [1, 2.. 5])      it "unsuccessful creation of marked and weighted sequence" $ do-      let seqErr = Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking." -      let seqE = createSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (-1, 1))] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence-      seqE `shouldBe` seqErr+      let seqE = createSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", preciseSpan (-1, 0))] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence+      seqE `shouldBe` Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking: \nSpan {_lower = RangeBorder {_borderType = Precise, _borderLocation = -1}, _upper = RangeBorder {_borderType = Precise, _borderLocation = 0}}\n"  -      let seqE = createSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "bca", (0, 6)), (TestMarking "a", (3, 5))] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence-      seqE `shouldBe` seqErr+      let seqE = createSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "bca", preciseSpan (0, 5)), (TestMarking "a", preciseSpan (3, 4))] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence+      seqE `shouldBe` Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking: \nSpan {_lower = RangeBorder {_borderType = Precise, _borderLocation = 0}, _upper = RangeBorder {_borderType = Precise, _borderLocation = 5}}\n"  -      let seqE = createSequence ['a'] [(TestMarking "a", (0, 0))] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence-      seqE `shouldBe` seqErr+      let seqE = createSequence ['a'] [(TestMarking "a", preciseSpan (0, -1))] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence+      seqE `shouldBe` Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking: \nSpan {_lower = RangeBorder {_borderType = Precise, _borderLocation = 0}, _upper = RangeBorder {_borderType = Precise, _borderLocation = -1}}\n"  -      let seqE = createSequence [] [(TestMarking "k", (0, 1))] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence-      seqE `shouldBe` seqErr+      let seqE = createSequence [] [(TestMarking "k", Point 0)] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence+      seqE `shouldBe` Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking: \nPoint {_location = 0}\n"  -      let seqE = createSequence ['a', 'b', 'c', 'd'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))] [1, 2, 4] :: Either Text TestMarkedAndWeightedSequence-      seqE `shouldBe` seqErr+      let seqE = createSequence ['a', 'b', 'c', 'd'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))] [1, 2, 4] :: Either Text TestMarkedAndWeightedSequence+      seqE `shouldBe` Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking: \nSpan {_lower = RangeBorder {_borderType = Precise, _borderLocation = 3}, _upper = RangeBorder {_borderType = Precise, _borderLocation = 4}}\n"         let seqE = createSequence ['a', 'b', 'c', 'a', 'a'] [] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence       seqE `shouldBe` Right (unsafeCreateSequence ['a', 'b', 'c', 'a', 'a'] [] [1, 2.. 5])        let seqErr1 = Left "Bio.Sequence.Class: sequence and weights have different lengths." -      let seqE = createSequence ['a', 'b', 'c', 'd'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 4))] [1, 2] :: Either Text TestMarkedAndWeightedSequence+      let seqE = createSequence ['a', 'b', 'c', 'd'] [(TestMarking "a", Point 0), (TestMarking "a", Point 3)] [1, 2] :: Either Text TestMarkedAndWeightedSequence       seqE `shouldBe` seqErr1        let seqErr2 = Left "Bio.Sequence.Class: weights are null for sequence." -      let seqE = createSequence ['a', 'b', 'c', 'd'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 4))] [] :: Either Text TestMarkedAndWeightedSequence+      let seqE = createSequence ['a', 'b', 'c', 'd'] [(TestMarking "a", Point 0), (TestMarking "a", Point 3)] [] :: Either Text TestMarkedAndWeightedSequence       seqE `shouldBe` seqErr2  functionsSpec :: Spec@@ -145,32 +143,32 @@ getRangeSpec =   describe "getRange" $ do     let getRangeError = Left "Bio.Sequence.Functions.Sequence: invalid range in getRange."-    let s = unsafeCreateSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))] [1, 2.. 5] :: TestMarkedAndWeightedSequence+    let s = unsafeCreateSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))] [1, 2.. 5] :: TestMarkedAndWeightedSequence -    it "sequence: ['a', 'b', 'c', 'a', 'a']; range: (0, 1)" $ do-      getRange s (0, 1) `shouldBe` Right ['a']-    it "sequence: ['a', 'b', 'c', 'a', 'a']; range: (2, 5)" $ do-      getRange s (2, 5) `shouldBe` Right ['c', 'a', 'a']-    it "sequence: ['a', 'b', 'c', 'a', 'a', 'd', 'e']; range: (5, 7)" $ do-      let s = unsafeCreateSequence ['a', 'b', 'c', 'a', 'a', 'd', 'e'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))] [1, 2.. 7] :: TestMarkedAndWeightedSequence-      getRange s (5, 7) `shouldBe` Right ['d', 'e']-    it "sequence: ['a', 'b', 'c', 'a', 'a']; range: (0, 0)" $ do-      getRange s (0, 0) `shouldBe` getRangeError-    it "sequence: ['a', 'b', 'c', 'a', 'a']; range: (3, 8)" $ do-      getRange s (3, 8) `shouldBe` getRangeError+    it "sequence: ['a', 'b', 'c', 'a', 'a']; range: 0" $ do+      getRange s (Point 0) `shouldBe` Right ['a']+    it "sequence: ['a', 'b', 'c', 'a', 'a']; range: (2, 4)" $ do+      getRange s (preciseSpan (2, 4)) `shouldBe` Right ['c', 'a', 'a']+    it "sequence: ['a', 'b', 'c', 'a', 'a', 'd', 'e']; range: (5, 6)" $ do+      let s = unsafeCreateSequence ['a', 'b', 'c', 'a', 'a', 'd', 'e'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))] [1, 2.. 7] :: TestMarkedAndWeightedSequence+      getRange s (preciseSpan (5, 6)) `shouldBe` Right ['d', 'e']+    it "sequence: ['a', 'b', 'c', 'a', 'a']; range: (0, -1)" $ do+      getRange s (preciseSpan (0, -1)) `shouldBe` getRangeError+    it "sequence: ['a', 'b', 'c', 'a', 'a']; range: (3, 7)" $ do+      getRange s (preciseSpan (3, 7)) `shouldBe` getRangeError  reverseSpec :: Spec reverseSpec =   describe "reverse" $ do     it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 1)), (a, (3, 5))]; weights: [1, 2.. 5]" $ do-      let s = unsafeCreateSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))] [1, 2.. 5] :: TestMarkedAndWeightedSequence-      reverse s `shouldBe` unsafeCreateSequence ['a', 'a', 'c', 'b', 'a'] [(TestMarking "a", (4, 5)), (TestMarking "a", (0, 2))] [5, 4.. 1]+      let s = unsafeCreateSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))] [1, 2.. 5] :: TestMarkedAndWeightedSequence+      reverse s `shouldBe` unsafeCreateSequence ['a', 'a', 'c', 'b', 'a'] [(TestMarking "a", Point 4), (TestMarking "a", preciseSpan (0, 1))] [5, 4.. 1]     it "sequence: ['a', 'b']; markings: []; weights: [1, 2]" $ do       let s = unsafeWeightedSequence ['a', 'b'] [1, 2] :: TestWeightedSequence       reverse s `shouldBe` unsafeWeightedSequence ['b', 'a'] [2, 1]     it "sequence: ['a', 'b', 'c', 'd', 'e']; markings: [(abc, (0, 3)), (abcd, (0, 4)), (de, (3, 5)), (abcde, (0, 5))]; weights: []" $ do-      let s = unsafeMarkedSequence ['a', 'b', 'c', 'd', 'e'] [(TestMarking "abc", (0, 3)), (TestMarking "abcd", (0, 4)), (TestMarking "de", (3, 5)), (TestMarking "abcde", (0, 5))] :: TestMarkedSequence-      reverse s `shouldBe` unsafeMarkedSequence ['e', 'd', 'c', 'b', 'a'] [(TestMarking "abc", (2, 5)), (TestMarking "abcd", (1, 5)), (TestMarking "de", (0, 2)), (TestMarking "abcde", (0, 5))]+      let s = unsafeMarkedSequence ['a', 'b', 'c', 'd', 'e'] [(TestMarking "abc", preciseSpan (0, 2)), (TestMarking "abcd", preciseSpan (0, 3)), (TestMarking "de", preciseSpan (3, 4)), (TestMarking "abcde", preciseSpan (0, 4))] :: TestMarkedSequence+      reverse s `shouldBe` unsafeMarkedSequence ['e', 'd', 'c', 'b', 'a'] [(TestMarking "abc", preciseSpan (2, 4)), (TestMarking "abcd", preciseSpan (1, 4)), (TestMarking "de", preciseSpan (0, 1)), (TestMarking "abcde", preciseSpan (0, 4))]  dropSpec :: Spec dropSpec =@@ -214,11 +212,11 @@ getMarkingSpec :: Spec getMarkingSpec =   describe "getMarking" $ do-    it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 1)), (a, (3, 5))]; get: a" $ do-      let s = unsafeCreateSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))] [1, 2.. 5] :: TestMarkedAndWeightedSequence+    it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, 0), (a, (3, 4))]; get: a" $ do+      let s = unsafeCreateSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))] [1, 2.. 5] :: TestMarkedAndWeightedSequence       getMarking s (TestMarking "a") `shouldBe` Right (NE.fromList [['a'], ['a', 'a']])     it "sequence: ['a', 'b', 'c', 'd', 'e']; markings: [(abc, (0, 3)), (abcd, (0, 4)), (de, (3, 5)), (abcde, (0, 5))]; get: abcde" $ do-      let s = unsafeMarkedSequence ['a', 'b', 'c', 'd', 'e'] [(TestMarking "abc", (0, 3)), (TestMarking "abcd", (0, 4)), (TestMarking "de", (3, 5)), (TestMarking "abcde", (0, 5))] :: TestMarkedSequence+      let s = unsafeMarkedSequence ['a', 'b', 'c', 'd', 'e'] [(TestMarking "abc", preciseSpan (0, 2)), (TestMarking "abcd", preciseSpan (0, 3)), (TestMarking "de", preciseSpan (3, 4)), (TestMarking "abcde", preciseSpan (0, 4))] :: TestMarkedSequence       getMarking s (TestMarking "abcde") `shouldBe` Right (NE.fromList [['a', 'b', 'c', 'd', 'e']])  type TestBareSequence = BareSequence Char@@ -229,25 +227,25 @@     let s = bareSequence ['a', 'b', 'c', 'a', 'a'] :: TestBareSequence      it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 1)), (a, (3, 5))]" $ do-      (toMarked s [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))] :: Either Text TestMarkedSequence) `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))])+      (toMarked s [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))] :: Either Text TestMarkedSequence) `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))])     it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 6)), (a, (3, 5))]" $ do-      let rangesError = Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking."-      (toMarked s [(TestMarking "a", (0, 6)), (TestMarking "a", (3, 5))] :: Either Text TestMarkedSequence) `shouldBe` rangesError+      let rangesError = Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking: \nSpan {_lower = RangeBorder {_borderType = Precise, _borderLocation = 0}, _upper = RangeBorder {_borderType = Precise, _borderLocation = 5}}\n" +      (toMarked s [(TestMarking "a", preciseSpan (0, 5)), (TestMarking "a", preciseSpan (3, 4))] :: Either Text TestMarkedSequence) `shouldBe` rangesError  addMarkingsSpec :: Spec addMarkingsSpec =   describe "addMarkings" $ do-    let s = unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))] :: TestMarkedSequence+    let s = unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4))] :: TestMarkedSequence     let rangesError = Left "Bio.Sequence.Functions.Marking: can't add markings to Sequence, because some of them are out of range."      it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 1)), (a, (3, 5))]; add: [(b, (1, 2))]" $ do-      addMarkings s [(TestMarking "b", (1, 2))] `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5)), (TestMarking "b", (1, 2))])+      addMarkings s [(TestMarking "b", Point 1)] `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4)), (TestMarking "b", Point 1)])     it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 1)), (a, (3, 5))]; add: []" $ do       addMarkings s [] `shouldBe` Right s     it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 1)), (a, (3, 5))]; add: [(b, (1, 2)), (c, (2, 3)), (abcaa, (0, 5))]" $ do-      addMarkings s [(TestMarking "b", (1, 2)), (TestMarking "c", (2, 3)), (TestMarking "abcaa", (0, 5))] `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5)), (TestMarking "b", (1, 2)), (TestMarking "c", (2, 3)), (TestMarking "abcaa", (0, 5))])+      addMarkings s [(TestMarking "b", Point 1), (TestMarking "c", Point 2), (TestMarking "abcaa", preciseSpan (0, 4))] `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", Point 0), (TestMarking "a", preciseSpan (3, 4)), (TestMarking "b", Point 1), (TestMarking "c", Point 2), (TestMarking "abcaa", preciseSpan (0, 4))])     it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 1)), (a, (3, 5))]; add: [(b, (1, 2)), (c, (2, 3)), (abcaa, (0, 6))]" $ do-      addMarkings s [(TestMarking "b", (1, 2)), (TestMarking "c", (2, 3)), (TestMarking "abcaa", (0, 6))] `shouldBe` rangesError+      addMarkings s [(TestMarking "b", Point 1), (TestMarking "c", Point 2), (TestMarking "abcaa",preciseSpan  (0, 5))] `shouldBe` rangesError  meanAndMeanInRangeSpec :: Spec meanAndMeanInRangeSpec =
test/Spec.hs view
@@ -1,20 +1,21 @@-import           ABISpec-import           FastaParserSpec-import           FASTASpec-import           FastaWriterSpec-import           GBParserSpec-import           GBWriterSpec-import           MAEParserSpec-import           MAESpec-import           MMTFSpec-import           PDBParserSpec-import           PDBSpec-import           PDBWriterSpec-import           SequenceSpec-import           StructureSpec-import           System.IO-import           Test.Hspec-import           UniprotSpec+import ABISpec+import FASTASpec+import FastaParserSpec+import FastaWriterSpec+import GBParserSpec+import GBWriterSpec+import MAEParserSpec+import MAESpec+import MMTFSpec+import PDBParserSpec+import PDBSpec+import PDBWriterSpec+import RangeSpec+import SequenceSpec+import StructureSpec+import System.IO+import Test.Hspec+import UniprotSpec  main :: IO () main = do@@ -23,6 +24,8 @@          -- MMTF          mmtfCodecSpec          mmtfParserSpec+         -- Range+         rangeSpec          -- Sequence          weightedSequenceSpec          markedSequenceSpec