<commit_before># coding: utf-8
"""
Routines for printing a report.
"""
from __future__ import print_function, division, absolute_import

import sys
from contextlib import contextmanager
import textwrap
from .adapters import BACK, FRONT, PREFIX, SUFFIX, ANYWHERE, LINKED
from .modifiers import QualityTrimmer, AdapterCutter
from .filters import (NoFilter, PairedNoFilter, TooShortReadFilter, TooLongReadFilter,
	DiscardTrimmedFilter, DiscardUntrimmedFilter, PairedEndDemultiplexer, Demultiplexer,
	NContentFilter, InfoFileWriter, WildcardFileWriter, RestFileWriter)


def safe_divide(numerator, denominator):
	if numerator is None or not denominator:
		return 0.0
	else:
		return numerator / denominator


class Statistics:
	def __init__(self):
		"""
		"""
		self.paired = None
		self.too_short = None
		self.too_long = None
		self.too_many_n = None
		self.did_quality_trimming = None
		self.n = 0
		self.written = 0
		self.total_bp = [0, 0]
		self.written_bp = [0, 0]
		self.with_adapters = [0, 0]
		self.quality_trimmed_bp = [0, 0]
		self.adapter_stats = [[], []]

	def __iadd__(self, other):
		self.n += other.n
		self.written += other.written

		if self.paired is None:
			self.paired = other.paired
		elif self.paired != other.paired:
			raise ValueError('Incompatible Statistics: paired is not equal')
		if self.did_quality_trimming is None:
			self.did_quality_trimming = other.did_quality_trimming
		elif self.did_quality_trimming != other.did_quality_trimming:
			raise ValueError('Incompatible Statistics: did_quality_trimming is not equal')

		def add_if_not_none(a, b):
			if a is None:
				return b
			if b is None:
				return a
			return a + b
		self.too_short = add_if_not_none(self.too_short, other.too_short)
		self.too_long = add_if_not_none(self.too_long, other.too_long)
		self.too_many_n = add_if_not_none(self.too_many_n, other.too_many_n)
		for i in (0, 1):
			self.total_bp[i] += other.total_bp[i]
			self.written_bp[i] += other.written_bp[i]
			self.with_adapters[i] += other.with_adapters[i]
			self.quality_trimmed_bp[i] += other.quality_trimmed_bp[i]
			if self.adapter_stats[i] and other.adapter_stats[i]:
				if len(self.adapter_stats[i]) != len(other.adapter_stats[i]):
					raise ValueError('Incompatible Statistics objects (adapter_stats length)')
				for j in range(len(self.adapter_stats[i])):
					self.adapter_stats[i][j] += other.adapter_stats[i][j]
			elif other.adapter_stats[i]:
				assert self.adapter_stats[i] == []
				self.adapter_stats[i] = other.adapter_stats[i]
		return self

	def collect(self, n, total_bp1, total_bp2, modifiers, modifiers2, writers):
		"""
		n -- total number of reads
		total_bp1 -- number of bases in first reads
		total_bp2 -- number of bases in second reads. None for single-end data.
		"""
		self.n = n
		self.total_bp[0] = total_bp1
		if total_bp2 is None:
			self.paired = False
		else:
			self.paired = True
			self.total_bp[1] = total_bp2

		# Collect statistics from writers/filters
		for w in writers:
			if isinstance(w, (InfoFileWriter, RestFileWriter, WildcardFileWriter)):
				pass
			elif isinstance(w, (NoFilter, PairedNoFilter, PairedEndDemultiplexer, Demultiplexer)) or \
					isinstance(w.filter, (DiscardTrimmedFilter, DiscardUntrimmedFilter)):
				self.written += w.written
				self.written_bp[0] += w.written_bp[0]
				self.written_bp[1] += w.written_bp[1]
			elif isinstance(w.filter, TooShortReadFilter):
				self.too_short = w.filtered
			elif isinstance(w.filter, TooLongReadFilter):
				self.too_long = w.filtered
			elif isinstance(w.filter, NContentFilter):
				self.too_many_n = w.filtered
		assert self.written is not None

		# Collect statistics from modifiers
		for i, modifiers_list in [(0, modifiers), (1, modifiers2)]:
			for modifier in modifiers_list:
				if isinstance(modifier, QualityTrimmer):
					self.quality_trimmed_bp[i] = modifier.trimmed_bases
					self.did_quality_trimming = True
				elif isinstance(modifier, AdapterCutter):
					self.with_adapters[i] += modifier.with_adapters
					self.adapter_stats[i] = list(modifier.adapter_statistics.values())

	@property<commit_msg>Print quality-trimming statistics also for --nextseq-trim<commit_after># coding: utf-8
"""
Routines for printing a report.
"""
from __future__ import print_function, division, absolute_import

import sys
from contextlib import contextmanager
import textwrap
from .adapters import BACK, FRONT, PREFIX, SUFFIX, ANYWHERE, LINKED
from .modifiers import QualityTrimmer, NextseqQualityTrimmer, AdapterCutter
from .filters import (NoFilter, PairedNoFilter, TooShortReadFilter, TooLongReadFilter,
	DiscardTrimmedFilter, DiscardUntrimmedFilter, PairedEndDemultiplexer, Demultiplexer,
	NContentFilter, InfoFileWriter, WildcardFileWriter, RestFileWriter)


def safe_divide(numerator, denominator):
	if numerator is None or not denominator:
		return 0.0
	else:
		return numerator / denominator


class Statistics:
	def __init__(self):
		"""
		"""
		self.paired = None
		self.too_short = None
		self.too_long = None
		self.too_many_n = None
		self.did_quality_trimming = None
		self.n = 0
		self.written = 0
		self.total_bp = [0, 0]
		self.written_bp = [0, 0]
		self.with_adapters = [0, 0]
		self.quality_trimmed_bp = [0, 0]
		self.adapter_stats = [[], []]

	def __iadd__(self, other):
		self.n += other.n
		self.written += other.written

		if self.paired is None:
			self.paired = other.paired
		elif self.paired != other.paired:
			raise ValueError('Incompatible Statistics: paired is not equal')
		if self.did_quality_trimming is None:
			self.did_quality_trimming = other.did_quality_trimming
		elif self.did_quality_trimming != other.did_quality_trimming:
			raise ValueError('Incompatible Statistics: did_quality_trimming is not equal')

		def add_if_not_none(a, b):
			if a is None:
				return b
			if b is None:
				return a
			return a + b
		self.too_short = add_if_not_none(self.too_short, other.too_short)
		self.too_long = add_if_not_none(self.too_long, other.too_long)
		self.too_many_n = add_if_not_none(self.too_many_n, other.too_many_n)
		for i in (0, 1):
			self.total_bp[i] += other.total_bp[i]
			self.written_bp[i] += other.written_bp[i]
			self.with_adapters[i] += other.with_adapters[i]
			self.quality_trimmed_bp[i] += other.quality_trimmed_bp[i]
			if self.adapter_stats[i] and other.adapter_stats[i]:
				if len(self.adapter_stats[i]) != len(other.adapter_stats[i]):
					raise ValueError('Incompatible Statistics objects (adapter_stats length)')
				for j in range(len(self.adapter_stats[i])):
					self.adapter_stats[i][j] += other.adapter_stats[i][j]
			elif other.adapter_stats[i]:
				assert self.adapter_stats[i] == []
				self.adapter_stats[i] = other.adapter_stats[i]
		return self

	def collect(self, n, total_bp1, total_bp2, modifiers, modifiers2, writers):
		"""
		n -- total number of reads
		total_bp1 -- number of bases in first reads
		total_bp2 -- number of bases in second reads. None for single-end data.
		"""
		self.n = n
		self.total_bp[0] = total_bp1
		if total_bp2 is None:
			self.paired = False
		else:
			self.paired = True
			self.total_bp[1] = total_bp2

		# Collect statistics from writers/filters
		for w in writers:
			if isinstance(w, (InfoFileWriter, RestFileWriter, WildcardFileWriter)):
				pass
			elif isinstance(w, (NoFilter, PairedNoFilter, PairedEndDemultiplexer, Demultiplexer)) or \
					isinstance(w.filter, (DiscardTrimmedFilter, DiscardUntrimmedFilter)):
				self.written += w.written
				self.written_bp[0] += w.written_bp[0]
				self.written_bp[1] += w.written_bp[1]
			elif isinstance(w.filter, TooShortReadFilter):
				self.too_short = w.filtered
			elif isinstance(w.filter, TooLongReadFilter):
				self.too_long = w.filtered
			elif isinstance(w.filter, NContentFilter):
				self.too_many_n = w.filtered
		assert self.written is not None

		# Collect statistics from modifiers
		for i, modifiers_list in [(0, modifiers), (1, modifiers2)]:
			for modifier in modifiers_list:
				if isinstance(modifier, (QualityTrimmer, NextseqQualityTrimmer)):
					self.quality_trimmed_bp[i] = modifier.trimmed_bases
					self.did_quality_trimming = True
				elif isinstance(modifier, AdapterCutter):
					self.with_adapters[i] += modifier.with_adapters
					self.adapter_stats[i] = list(modifier.adapter_statistics.values())

	@property
{'fraction_non_alphanumeric': 0.10391493475108748, 'fraction_numerical': 0.007733204446592557, 'mean_word_length': 4.416884816753926, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4296182', 'n_tokens_mistral': 3227, 'n_tokens_neox': 2805, 'n_words': 668}