cutseq 0.0.6__tar.gz → 0.0.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cutseq
3
- Version: 0.0.6
3
+ Version: 0.0.8
4
4
  Summary: Automatically cut adapter / barcode / UMI from NGS data
5
5
  Home-page: https://github.com/y9c/cutseq
6
6
  License: MIT
@@ -27,6 +27,7 @@ from cutadapt.modifiers import (
27
27
  PairedEndRenamer,
28
28
  QualityTrimmer,
29
29
  Renamer,
30
+ SingleEndModifier,
30
31
  SuffixRemover,
31
32
  UnconditionalCutter,
32
33
  )
@@ -55,6 +56,38 @@ def patched_problematic_method(self, *args, **kwargs):
55
56
 
56
57
  Statistics._collect_modifier = patched_problematic_method
57
58
 
59
+ ## Enhnace function for cutadapt
60
+
61
+
62
+ class IsUntrimmedAny(Predicate):
63
+ """
64
+ Select reads for which no adapter match was found
65
+ """
66
+
67
+ def __init__(self, ref_adapters):
68
+ self.ref_adapters = ref_adapters
69
+
70
+ def __repr__(self):
71
+ return "IsUntrimmedAny()"
72
+
73
+ def test(self, read, info):
74
+ # check not all adapters with ref_adapters are exist in the matches
75
+ match_adapters = [match.adapter for match in info.matches]
76
+ if any([adapter not in match_adapters for adapter in self.ref_adapters]):
77
+ return True
78
+ return False
79
+
80
+
81
+ class ReverseComplementConverter(SingleEndModifier):
82
+ def __init__(self):
83
+ self.rcd = False
84
+
85
+ def __repr__(self):
86
+ return "ReverseComplementConverter()"
87
+
88
+ def __call__(self, read, info):
89
+ return read.reverse_complement()
90
+
58
91
 
59
92
  __version__ = importlib.metadata.version(__package__ or __name__)
60
93
 
@@ -143,25 +176,6 @@ class CutadaptConfig:
143
176
  self.threads = 1
144
177
 
145
178
 
146
- class IsUntrimmedAny(Predicate):
147
- """
148
- Select reads for which no adapter match was found
149
- """
150
-
151
- def __init__(self, ref_adapters):
152
- self.ref_adapters = ref_adapters
153
-
154
- def __repr__(self):
155
- return "IsUntrimmedAny()"
156
-
157
- def test(self, read, info):
158
- # check not all adapters with ref_adapters are exist in the matches
159
- match_adapters = [match.adapter for match in info.matches]
160
- if any([adapter not in match_adapters for adapter in self.ref_adapters]):
161
- return True
162
- return False
163
-
164
-
165
179
  def run_steps(steps, dry_run=False):
166
180
  if dry_run:
167
181
  print(
@@ -240,6 +254,12 @@ def pipeline_single(input1, output1, short1, untrimmed1, barcode, settings):
240
254
  QualityTrimmer(cutoff_front=0, cutoff_back=settings.min_quality),
241
255
  )
242
256
 
257
+ # step 9: reverse complement the read
258
+ if settings.reverse_complement:
259
+ if barcode.strand == "+":
260
+ logging.warn("Library is + strand, but reverse complement is enabled.")
261
+ modifiers.append(ReverseComplementConverter())
262
+
243
263
  inpaths = InputPaths(input1)
244
264
 
245
265
  with make_runner(inpaths, cores=settings.threads) as runner:
@@ -249,14 +269,16 @@ def pipeline_single(input1, output1, short1, untrimmed1, barcode, settings):
249
269
  interleaved=False,
250
270
  )
251
271
  steps = []
272
+ # TODO: report info
273
+ # --info-file=info.txt
274
+ # PairedSingleEndStep(InfoFileWriter(outfiles.open_text("info.txt"))),
252
275
  steps.append(
253
- # --info-file=info.txt
254
- # PairedSingleEndStep(InfoFileWriter(outfiles.open_text("info.txt"))),
255
276
  # -m 10
256
277
  SingleEndFilter(
257
278
  TooShort(settings.min_length), outfiles.open_record_writer(short1)
258
279
  ),
259
280
  )
281
+ # TODO: --max-n=0 support
260
282
  if (
261
283
  settings.ensure_inline_barcode
262
284
  and barcode.inline5.len + barcode.inline3.len > 0
@@ -267,7 +289,6 @@ def pipeline_single(input1, output1, short1, untrimmed1, barcode, settings):
267
289
  if barcode.inline3.len > 0:
268
290
  ref_adapters.append(adapter_inline3)
269
291
  steps.append(
270
- # TODO: --max-n=0 support
271
292
  SingleEndFilter(
272
293
  IsUntrimmedAny(ref_adapters),
273
294
  outfiles.open_record_writer(untrimmed1, interleaved=False),
@@ -424,6 +445,12 @@ def pipeline_paired(
424
445
  )
425
446
  )
426
447
 
448
+ # step 9: reverse complement the read
449
+ if settings.reverse_complement:
450
+ if barcode.strand == "+":
451
+ logging.warn("Library is + strand, but reverse complement is enabled.")
452
+ modifiers.append((ReverseComplementConverter(), ReverseComplementConverter()))
453
+
427
454
  inpaths = InputPaths(input1, input2)
428
455
 
429
456
  with make_runner(inpaths, cores=settings.threads) as runner:
@@ -443,12 +470,12 @@ def pipeline_paired(
443
470
  outfiles.open_record_writer(short1, short2, interleaved=False),
444
471
  )
445
472
  )
473
+ # TODO: --max-n=0 support
446
474
  if (
447
475
  settings.ensure_inline_barcode
448
476
  and barcode.inline5.len + barcode.inline3.len > 0
449
477
  ):
450
478
  steps.append(
451
- # TODO: --max-n=0 support
452
479
  PairedEndFilter(
453
480
  IsUntrimmedAny([adapter_inline5])
454
481
  if barcode.inline5.len > 0
@@ -473,7 +500,7 @@ def pipeline_paired(
473
500
 
474
501
 
475
502
  def run_cutseq(args):
476
- barcode_config = BarcodeConfig(args.adapter_scheme.upper())
503
+ barcode_config = BarcodeConfig(args.replace(" ", "").adapter_scheme.upper())
477
504
  settings = CutadaptConfig()
478
505
  settings.rname_suffix = args.with_rname_suffix
479
506
  settings.ensure_inline_barcode = args.ensure_inline_barcode
@@ -481,6 +508,7 @@ def run_cutseq(args):
481
508
  settings.threads = args.threads
482
509
  settings.min_length = args.min_length
483
510
  settings.dry_run = args.dry_run
511
+ settings.reverse_complement = args.reverse_complement
484
512
  if len(args.input_file) == 1:
485
513
  pipeline_single(
486
514
  args.input_file[0],
@@ -583,6 +611,12 @@ def main():
583
611
 
584
612
  parser.add_argument("--trim-polyA", action="store_true", help="Trim polyA tail.")
585
613
 
614
+ parser.add_argument(
615
+ "--reverse-complement",
616
+ action="store_true",
617
+ help="Reverse complement the reads.",
618
+ )
619
+
586
620
  parser.add_argument(
587
621
  "-t",
588
622
  "--threads",
@@ -601,6 +635,11 @@ def main():
601
635
  "-V", "--version", action="version", version=f"%(prog)s {__version__}"
602
636
  )
603
637
 
638
+ # Check if no arguments were provided
639
+ if len(sys.argv) == 1:
640
+ parser.print_help(sys.stdout)
641
+ sys.exit(0)
642
+
604
643
  args = parser.parse_args()
605
644
 
606
645
  if args.adapter_name is not None:
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "cutseq"
3
- version = "0.0.6"
3
+ version = "0.0.8"
4
4
  description = "Automatically cut adapter / barcode / UMI from NGS data"
5
5
  authors = ["Ye Chang <yech1990@gmail.com>"]
6
6
  license = "MIT"
File without changes
File without changes