Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Scala 3 #28

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .scalafix.conf
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ OrganizeImports {
expandRelative = true
groups = ["re:javax?\\.", "scala.", "*"]
groupedImports = Merge
removeUnused = true
removeUnused = false
}
2 changes: 1 addition & 1 deletion .scalafmt.conf
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ rewrite.redundantBraces.generalExpressions = false
rewrite.redundantBraces.includeUnitMethods = false
rewrite.redundantBraces.maxBreaks = 16
rewrite.redundantBraces.stringInterpolation = true
runner.dialect = scala213source3
runner.dialect = scala3
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 3.9.0
* Remove unused BKTree implementation
* Port to Scala 3

## 3.8.0
* Replace kantan.csv with scala-csv

Expand Down
15 changes: 3 additions & 12 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@ val artifactId = "poolq"

inThisBuild(
List(
scalaVersion := "2.13.11",
scalaVersion := "3.3.1",
semanticdbEnabled := true,
semanticdbVersion := scalafixSemanticdb.revision,
versionScheme := Some("early-semver")
)
)

lazy val versions = new {
val acyclic = "0.2.1"
val betterFiles = "3.9.2"
val betterMonadicFor = "0.3.1"
val catsEffect3 = "3.5.2"
val cats = "2.10.0"
val commonsIo = "2.15.1"
Expand All @@ -28,15 +26,13 @@ lazy val versions = new {
val scalaCheck = "1.17.0"
val scalaCsv = "1.3.10"
val scalaTest = "3.2.17"
val scalaTestPlusScalaCheck = "3.2.2.0"
val scalaTestPlusScalaCheck = "3.2.17.0"
val scopt = "4.1.0"
val slf4j = "1.7.36"
}

lazy val libraries = new {
val acyclic = "com.lihaoyi" %% "acyclic" % versions.acyclic
val betterFiles = "com.github.pathikrit" %% "better-files" % versions.betterFiles
val betterMonadicFor = "com.olegpy" %% "better-monadic-for" % versions.betterMonadicFor
val cats = "org.typelevel" %% "cats-core" % versions.cats
val catsEffect3 = "org.typelevel" %% "cats-effect" % versions.catsEffect3
val commonsIo = "commons-io" % "commons-io" % versions.commonsIo
Expand All @@ -59,12 +55,11 @@ lazy val libraries = new {
val munitCatsEffect3 = "org.typelevel" %% "munit-cats-effect-3" % versions.munitCatsEffect3
val scalaTest = "org.scalatest" %% "scalatest" % versions.scalaTest
val scalaCheck = "org.scalacheck" %% "scalacheck" % versions.scalaCheck
val scalaTestPlusScalaCheck = "org.scalatestplus" %% "scalacheck-1-14" % versions.scalaTestPlusScalaCheck
val scalaTestPlusScalaCheck = "org.scalatestplus" %% "scalacheck-1-17" % versions.scalaTestPlusScalaCheck
}

lazy val dependencies =
List(
libraries.acyclic % "provided",
libraries.cats,
libraries.commonsIo,
libraries.commonsMath3,
Expand Down Expand Up @@ -130,13 +125,9 @@ lazy val poolq = project
name := "poolq3",
organization := "org.broadinstitute.gpp",
libraryDependencies := dependencies,
scalacOptions ++= List("-P:acyclic:force", "-Xsource:3"),
buildInfoKeys := Seq[BuildInfoKey](name, version),
buildInfoPackage := "org.broadinstitute.gpp.poolq3",
addCompilerPlugin(libraries.acyclic),
addCompilerPlugin(libraries.betterMonadicFor),
testFrameworks += new TestFramework("munit.Framework"),
scalacOptions += "-Yrangepos", // ensure munit clues work
// Tests pass in parallel, but SLF4J logging behaves weirdly. Disable this flag to examine test
// log output; leave this enabled for very fast test execution.
Test / parallelExecution := true
Expand Down
12 changes: 6 additions & 6 deletions src/main/scala/org/broadinstitute/gpp/poolq3/PoolQ.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import java.nio.file.{Files, Path}

import scala.util.{Failure, Success, Try, Using}

import cats.syntax.all._
import cats.syntax.all.*
import org.broadinstitute.gpp.poolq3.PoolQConfig.synthesizeArgs
import org.broadinstitute.gpp.poolq3.barcode.{BarcodePolicy, Barcodes, barcodeSource}
import org.broadinstitute.gpp.poolq3.parser.{BarcodeSet, CloseableIterable, ReferenceData}
Expand Down Expand Up @@ -122,7 +122,7 @@ object PoolQ {
barcodeSource(config.input, rowBarcodePolicy, revRowBarcodePolicyOpt, colBarcodePolicyOrLength, umiInfo.map(_._2))

lazy val unexpectedSequenceCacheDir: Option[Path] =
if (config.skipUnexpectedSequenceReport) None
if config.skipUnexpectedSequenceReport then None
else {
val ret = config.unexpectedSequenceCacheDir.map(Files.createDirectories(_)).orElse {
val ret: Path = Files.createTempDirectory("unexpected-sequence-cache")
Expand All @@ -133,7 +133,7 @@ object PoolQ {
}

val consumer =
if (config.noopConsumer) new NoOpConsumer
if config.noopConsumer then new NoOpConsumer
else
new ScoringConsumer(
rowReference,
Expand All @@ -145,7 +145,7 @@ object PoolQ {
config.isPairedEnd
)

for {
for
runSummary <- runProcess(barcodes, consumer)
state = runSummary.state
counts = state.known
Expand Down Expand Up @@ -195,7 +195,7 @@ object PoolQ {
globalReference
)
.as(UnexpectedSequencesFileType.some)
if (config.removeUnexpectedSequenceCache) {
if config.removeUnexpectedSequenceCache then {
log.info(s"Removing unexpected sequence cache ${config.unexpectedSequenceCacheDir}")
UnexpectedSequenceWriter.removeCache(dir)
}
Expand All @@ -204,7 +204,7 @@ object PoolQ {
_ = log.info(s"Writing run info ${config.output.unexpectedSequencesFile}")
_ <- RunInfoWriter.write(config.output.runInfoFile, config)
_ = log.info("PoolQ complete")
} yield PoolQSummary(runSummary, AlwaysWrittenFiles ++ Set(cfto, usfto).flatten)
yield PoolQSummary(runSummary, AlwaysWrittenFiles ++ Set(cfto, usfto).flatten)
}

def runProcess(barcodes: CloseableIterable[Barcodes], consumer: Consumer): Try[PoolQRunSummary] =
Expand Down
26 changes: 13 additions & 13 deletions src/main/scala/org/broadinstitute/gpp/poolq3/PoolQConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import java.nio.file.{Files, Path, Paths}
import scala.collection.mutable

import cats.data.{NonEmptyList => Nel}
import cats.syntax.all._
import cats.syntax.all.*
import org.broadinstitute.gpp.poolq3.PoolQConfig.DefaultPath
import org.broadinstitute.gpp.poolq3.reports.{GctDialect, PoolQ2Dialect, PoolQ3Dialect, ReportsDialect}
import org.broadinstitute.gpp.poolq3.types.{PoolQException, ReadIdCheckPolicy}
Expand Down Expand Up @@ -42,7 +42,7 @@ final case class PoolQInput(

case (Some(rr), None, Some(cr), None, false) =>
val rs = ReadsSource.Split(Nel(cr, addlColReads), Nel(rr._2, addlRowReads.view.map(_._2).toList))
if (rs.forward.length == rs.index.length) Right(rs)
if rs.forward.length == rs.index.length then Right(rs)
else Left(PoolQException("Number of row, column, and reverse reads files must match"))

case (Some(rr), Some(rrr), Some(cr), None, false) =>
Expand All @@ -51,15 +51,15 @@ final case class PoolQInput(
Nel(rr._2, addlRowReads.view.map(_._2).toList),
Nel(rrr._2, addlReverseRowReads.view.map(_._2).toList)
)
if (rs.forward.length == rs.index.length && rs.forward.length == rs.reverse.length) Right(rs)
if rs.forward.length == rs.index.length && rs.forward.length == rs.reverse.length then Right(rs)
else Left(PoolQException("Number of row and column reads files must match"))

case (Some(rr), None, None, None, true) =>
Right(ReadsSource.Dmuxed(Nel(rr, addlRowReads)))

case (Some(rr), Some(rrr), None, None, true) =>
val rs = ReadsSource.DmuxedPairedEnd(Nel(rr, addlRowReads), Nel(rrr, addlReverseRowReads))
if (rs.read1.map(_._1) == rs.read2.map(_._1)) Right(rs)
if rs.read1.map(_._1) == rs.read2.map(_._1) then Right(rs)
else Left(PoolQException("Row and column reads files must match"))

case _ => Left(PoolQException("Conflicting input options"))
Expand Down Expand Up @@ -147,8 +147,8 @@ object PoolQConfig {

val parser: OptionParser[PoolQConfig] = new OptionParser[PoolQConfig]("poolq") {
private[this] def existsAndIsReadable(f: Path): Either[String, Unit] =
if (!Files.exists(f)) failure(s"Could not find ${f.toAbsolutePath}")
else if (!Files.isReadable(f)) failure(s"Could not read ${f.toAbsolutePath}")
if !Files.exists(f) then failure(s"Could not find ${f.toAbsolutePath}")
else if !Files.isReadable(f) then failure(s"Could not read ${f.toAbsolutePath}")
else success

locally {
Expand Down Expand Up @@ -283,7 +283,7 @@ object PoolQConfig {
.valueName("<number>")
.action((n, c) => c.copy(unexpectedSequencesToReport = n))
.validate { n =>
if (n > 0) success
if n > 0 then success
else failure(s"Unexpected sequence threshold must be greater than 0, got: $n")
}

Expand Down Expand Up @@ -388,7 +388,7 @@ object PoolQConfig {
// run control
args += (("row-matcher", config.rowMatchFn))
args += (("col-matcher", config.colMatchFn))
if (config.countAmbiguous) {
if config.countAmbiguous then {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Braces with then?

args += (("count-ambiguous", ""))
}
args += (("row-barcode-policy", config.rowBarcodePolicyStr))
Expand All @@ -397,18 +397,18 @@ object PoolQConfig {
umiInfo.map(_._2).foreach(str => args += (("umi-barcode-policy", str)))

// deal with the unexpected sequence options
if (config.skipUnexpectedSequenceReport) {
if config.skipUnexpectedSequenceReport then {
args += (("skip-unexpected-sequence-report", ""))
} else {
// give whatever path we were given here - this _may_ not need to be included at all, honestly
config.unexpectedSequenceCacheDir.foreach(file => args += (("unexpected-sequence-cache", file.toString)))
args += (("unexpected-sequence-threshold", config.unexpectedSequencesToReport.toString))
}

if (config.skipShortReads) {
if config.skipShortReads then {
args += (("skip-short-reads", ""))
}
if (config.reportsDialect == PoolQ2Dialect) {
if config.reportsDialect == PoolQ2Dialect then {
args += (("compat", ""))
}

Expand All @@ -424,10 +424,10 @@ object PoolQConfig {
output.umiCountsFilesDir.foreach(d => args += (("umi-counts-dir", d.toString)))
output.umiBarcodeCountsFilesDir.foreach(d => args += (("umi-barcode-counts-dir", d.toString)))
}
if (!config.skipUnexpectedSequenceReport) {
if !config.skipUnexpectedSequenceReport then {
args += (("unexpected-sequences", output.unexpectedSequencesFile.getFileName.toString))
}
if (config.alwaysCountColumnBarcodes) {
if config.alwaysCountColumnBarcodes then {
args += (("always-count-col-barcodes", ""))
}
args += (("run-info", output.runInfoFile.getFileName.toString))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ final case class FixedOffsetPolicy(startPos0: Int, length: Int, skipShortReads:
private[this] val endPos0: Int = startPos0 + length

override def find(read: Read): Option[FoundBarcode] =
if (read.seq.length < minLength) {
if (skipShortReads) None
if read.seq.length < minLength then {
if skipShortReads then None
else throw ReadTooShortException(read.seq, startPos0, minLength)
} else Some(FoundBarcode(copyOfRange(read.seq.toCharArray, startPos0, endPos0), startPos0))

Expand Down Expand Up @@ -83,9 +83,9 @@ final case class IndexOfKnownPrefixPolicy(
override def find(read: Read): Option[FoundBarcode] = {
val index = read.seq.indexOf(prefix, minPrefixStartPosInt)
val barcodeStart = index + prefixLength
if (index < 0) None
else if (index > maxPrefixStartPosInt) None
else if ((read.seq.length - barcodeStart) < length) None
if index < 0 then None
else if index > maxPrefixStartPosInt then None
else if (read.seq.length - barcodeStart) < length then None
else Some(FoundBarcode(copyOfRange(read.seq.toCharArray, barcodeStart, barcodeStart + length), barcodeStart))
}

Expand Down Expand Up @@ -141,15 +141,15 @@ object TemplatePolicy {
case Regex1(ctx, minStr, maxStr) =>
ctx match {
case Regex2(p1, b1, gap, p2, b2) =>
if ((b1.length + b2.length) != refBarcodeLength) {
if (b1.length + b2.length) != refBarcodeLength then {
throw new IllegalArgumentException(s"$s is not compatible with the provided reference file")
}
val min = Option(minStr).map(_.toInt)
val max = Option(maxStr).map(_.tail.toInt)
SplitBarcodePolicy(p1.toUpperCase, b1.length, gap.length, p2.toUpperCase, b2.length, min, max)
case _ =>
val km = KeyMask(ctx)
if (km.keyLengthInBases != refBarcodeLength) {
if km.keyLengthInBases != refBarcodeLength then {
throw new IllegalArgumentException(s"$s is not compatible with the provided reference file")
}
val min = Option(minStr).map(_.toInt)
Expand Down Expand Up @@ -200,8 +200,8 @@ object TemplatePolicy {

final def satisfies(template: Array[Char], seq: String, seqOffset: Int): Boolean = {
var i = 0
while (i < template.length) {
if (!compatible(template(i), seq(seqOffset + i))) return false
while i < template.length do {
if !compatible(template(i), seq(seqOffset + i)) then return false
i += 1
}
true
Expand Down Expand Up @@ -230,8 +230,8 @@ final case class GeneralTemplatePolicy(template: KeyMask, minStartPos: Option[In

@tailrec
def find(i: Int): Option[Int] =
if (i > maxPos) None
else if (TemplatePolicy.satisfies(templateChars, read.seq, i)) Some(i)
if i > maxPos then None
else if TemplatePolicy.satisfies(templateChars, read.seq, i) then Some(i)
else find(i + 1)

find(minStartPosInt).map(i => extract(read, i))
Expand Down Expand Up @@ -273,13 +273,13 @@ final case class SplitBarcodePolicy(
@tailrec
def loop(start: Int): Option[FoundBarcode] = {
val e = math.min(maxPrefix1StartPosInt, read.seq.length - patternLength)
if (start > e) None
if start > e then None
else {
indexOf(prefix1, read.seq, start, e) match {
case None => None
case Some(p1Index) =>
val p2Index = p1Index + expectedP2Offset
if (matches(prefix2, read.seq, p2Index)) {
if matches(prefix2, read.seq, p2Index) then {
val dest = Array.ofDim[Char](length)
// copy in the the barcodes
read.seq.getChars(p1Index + p1Length, p1Index + p1Length + b1Length, dest, 0)
Expand All @@ -306,10 +306,10 @@ object SplitBarcodePolicy {
final private[barcode] def indexOf(needle: String, haystack: String, start: Int, end: Int): Option[Int] = {
@tailrec
def loop(i: Int): Option[Int] =
if (i > math.min(haystack.length - needle.length, end)) {
if i > math.min(haystack.length - needle.length, end) then {
None
} else {
if (matches(needle, haystack, i)) Some(i)
if matches(needle, haystack, i) then Some(i)
else loop(i + 1)
}
loop(start)
Expand All @@ -318,9 +318,9 @@ object SplitBarcodePolicy {
final private def matches(needle: String, haystack: String, haystackOffset: Int): Boolean = {
@tailrec
def loop(i: Int): Boolean =
if (i >= needle.length) true
if i >= needle.length then true
else {
if (needle(i) != haystack(haystackOffset + i)) false
if needle(i) != haystack(haystackOffset + i) then false
else loop(i + 1)
}
loop(0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ object KeyMask {
mergedRanges.length match {
case 1 =>
val r = mergedRanges.head
if (r.start0 == 0 && r.length == pattern.length)
KeyMask0(pattern)
if r.start0 == 0 && r.length == pattern.length then KeyMask0(pattern)
else KeyMask1(pattern, r)
case 2 =>
KeyMask2(pattern, mergedRanges(0), mergedRanges(1))
Expand All @@ -64,8 +63,7 @@ object KeyMask {
acc match {
case Nil => current :: Nil
case head :: tail =>
if (head.end0 >= current.start0 - 1)
KeyRange(head.start0, current.end0) :: tail
if head.end0 >= current.start0 - 1 then KeyRange(head.start0, current.end0) :: tail
else current :: acc
}
// but use an IndexedSeq for efficiency later
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ final case class KeyRange(start0: Int, end0: Int) {

def end1: Int = end0 + 1

override def toString: String = if (length == 1) start1.toString else s"$start1..$end1"
override def toString: String = if length == 1 then start1.toString else s"$start1..$end1"

}

Expand Down
Loading