<commit_before>import contextlib
import blinker
import blinker._saferef
import pprint
import copy
import functools
import os
import typing
import textwrap

import ruamel.yaml

from mitmproxy import exceptions
from mitmproxy.utils import typecheck

"""
    The base implementation for Options.
"""

unset = object()


class _Option:
    __slots__ = ("name", "typespec", "value", "_default", "choices", "help")

    def __init__(
        self,
        name: str,
        typespec: type,
        default: typing.Any,
        help: str,
        choices: typing.Optional[typing.Sequence[str]]
    ) -> None:
        typecheck.check_option_type(name, default, typespec)
        self.name = name
        self.typespec = typespec
        self._default = default
        self.value = unset
        self.help = textwrap.dedent(help).strip().replace("\n", " ")
        self.choices = choices

    def __repr__(self):
        return "{value} [{type}]".format(value=self.current(), type=self.typespec)

    @property
    def default(self):
        return copy.deepcopy(self._default)

    def current(self) -> typing.Any:
        if self.value is unset:
            v = self.default
        else:
            v = self.value
        return copy.deepcopy(v)

    def set(self, value: typing.Any) -> None:
        typecheck.check_option_type(self.name, value, self.typespec)
        self.value = value

    def reset(self) -> None:
        self.value = unset

    def has_changed(self) -> bool:
        return self.current() != self.default

    def __eq__(self, other) -> bool:
        for i in self.__slots__:
            if getattr(self, i) != getattr(other, i):
                return False
        return True

    def __deepcopy__(self, _):
        o = _Option(
            self.name, self.typespec, self.default, self.help, self.choices
        )
        if self.has_changed():
            o.value = self.current()
        return o


class OptManager:
    """
        OptManager is the base class from which Options objects are derived.

        .changed is a blinker Signal that triggers whenever options are
        updated. If any handler in the chain raises an exceptions.OptionsError
        exception, all changes are rolled back, the exception is suppressed,
        and the .errored signal is notified.

        Optmanager always returns a deep copy of options to ensure that
        mutation doesn't change the option state inadvertently.
    """
    def __init__(self):
        self.deferred: typing.Dict[str, str] = {}
        self.changed = blinker.Signal()
        self.errored = blinker.Signal()
        # Options must be the last attribute here - after that, we raise an
        # error for attribute assigment to unknown options.
        self._options: typing.Dict[str, typing.Any] = {}

    def add_option(
        self,
        name: str,
        typespec: type,
        default: typing.Any,
        help: str,
        choices: typing.Optional[typing.Sequence[str]] = None
    ) -> None:<commit_msg>make mypy happy<commit_after>import contextlib
import blinker
import blinker._saferef
import pprint
import copy
import functools
import os
import typing
import textwrap

import ruamel.yaml

from mitmproxy import exceptions
from mitmproxy.utils import typecheck

"""
    The base implementation for Options.
"""

unset = object()


class _Option:
    __slots__ = ("name", "typespec", "value", "_default", "choices", "help")

    def __init__(
        self,
        name: str,
        typespec: typing.Union[type, object],  # object for Optional[x], which is not a type.
        default: typing.Any,
        help: str,
        choices: typing.Optional[typing.Sequence[str]]
    ) -> None:
        typecheck.check_option_type(name, default, typespec)
        self.name = name
        self.typespec = typespec
        self._default = default
        self.value = unset
        self.help = textwrap.dedent(help).strip().replace("\n", " ")
        self.choices = choices

    def __repr__(self):
        return "{value} [{type}]".format(value=self.current(), type=self.typespec)

    @property
    def default(self):
        return copy.deepcopy(self._default)

    def current(self) -> typing.Any:
        if self.value is unset:
            v = self.default
        else:
            v = self.value
        return copy.deepcopy(v)

    def set(self, value: typing.Any) -> None:
        typecheck.check_option_type(self.name, value, self.typespec)
        self.value = value

    def reset(self) -> None:
        self.value = unset

    def has_changed(self) -> bool:
        return self.current() != self.default

    def __eq__(self, other) -> bool:
        for i in self.__slots__:
            if getattr(self, i) != getattr(other, i):
                return False
        return True

    def __deepcopy__(self, _):
        o = _Option(
            self.name, self.typespec, self.default, self.help, self.choices
        )
        if self.has_changed():
            o.value = self.current()
        return o


class OptManager:
    """
        OptManager is the base class from which Options objects are derived.

        .changed is a blinker Signal that triggers whenever options are
        updated. If any handler in the chain raises an exceptions.OptionsError
        exception, all changes are rolled back, the exception is suppressed,
        and the .errored signal is notified.

        Optmanager always returns a deep copy of options to ensure that
        mutation doesn't change the option state inadvertently.
    """
    def __init__(self):
        self.deferred: typing.Dict[str, str] = {}
        self.changed = blinker.Signal()
        self.errored = blinker.Signal()
        # Options must be the last attribute here - after that, we raise an
        # error for attribute assigment to unknown options.
        self._options: typing.Dict[str, typing.Any] = {}

    def add_option(
        self,
        name: str,
        typespec: typing.Union[type, object],
        default: typing.Any,
        help: str,
        choices: typing.Optional[typing.Sequence[str]] = None
    ) -> None:
{'fraction_non_alphanumeric': 0.09738134206219312, 'fraction_numerical': 0.0, 'mean_word_length': 2.27843347639485, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 17, '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': '7284596', 'n_tokens_mistral': 1750, 'n_tokens_neox': 1703, 'n_words': 539}