"""Provides data related to payment."""

import re
import string
from typing import Optional

from mimesis.data import CREDIT_CARD_NETWORKS
from mimesis.enums import CardType, Gender
from mimesis.exceptions import NonEnumerableError
from mimesis.helpers import get_random_item
from mimesis.providers.base import BaseDataProvider
from mimesis.providers.person import Person
from mimesis.utils import luhn_checksum

__all__ = ['Payment']


class Payment(BaseDataProvider):
    """Class that provides data related to payments."""

    def __init__(self, *args, **kwargs) -> None:
        """Initialize attributes.

        :param args: Arguments.
        :param kwargs: Keyword arguments.
        """
        super().__init__(*args, **kwargs)
        self.__person = Person('en', seed=self.seed)

    def cid(self) -> int:
        """Generate a random CID.

        :return: CID code.

        :Example:
            7452
        """
        return self.random.randint(1000, 9999)

    def paypal(self) -> str:
        """Generate a random PayPal account.

        :return: Email of PapPal user.

        :Example:
            wolf235@gmail.com
        """
        return self.__person.email()

    def bitcoin_address(self) -> str:
        """Generate a random bitcoin address.

        :return: Bitcoin address.

        :Example:
            3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX
        """
        type_ = self.random.choice(['1', '3'])
        letters = string.ascii_letters + string.digits
        return type_ + ''.join(
            self.random.choice(letters) for _ in range(33))

    def ethereum_address(self) -> str:
        """Generate a random Ethereum address.

        .. Note: The address will look like Ethereum address,
        but keep in mind that it is not the valid address.

        :return: Ethereum address.

        :Example:
            0xe8ece9e6ff7dba52d4c07d37418036a89af9698d
        """
        bits = self.random.getrandbits(160)
        address = bits.to_bytes(20, byteorder='big')
        return '0x' + address.hex()

    def credit_card_network(self) -> str:
        """Generate a random credit card network.

        :return: Credit card network

        :Example:
            MasterCard
        """
        return self.random.choice(CREDIT_CARD_NETWORKS)

    def credit_card_number(self, card_type: Optional[CardType] = None) -> str:
        """Generate a random credit card number.

        :param card_type: Issuing Network. Default is Visa.
        :return: Credit card number.
        :raises NotImplementedError: if cart_type is not supported.

        :Example:
            4455 5299 1152 2450
        """
        length = 16
        regex = re.compile('(\d{4})(\d{4})(\d{4})(\d{4})')

        if card_type is None:
            card_type = get_random_item(CardType, rnd=self.random)

        if card_type == CardType.VISA:
            number = self.random.randint(4000, 4999)
        elif card_type == CardType.MASTER_CARD:
            number = self.random.choice([
                self.random.randint(2221, 2720),
                self.random.randint(5100, 5500),
            ])
        elif card_type == CardType.AMERICAN_EXPRESS:
            number = self.random.choice([34, 37])
            length = 15
            regex = re.compile('(\d{4})(\d{6})(\d{5})')
        else:
            raise NonEnumerableError(CardType)

        str_num = str(number)
        while len(str_num) < length - 1:
            str_num += self.random.choice(string.digits)

        groups = regex.search(str_num + luhn_checksum(str_num)).groups()
        card = ' '.join(groups)
        return card

    def credit_card_expiration_date(self, minimum: int = 16,
                                    maximum: int = 25) -> str:
        """Generate a random expiration date for credit card.

        :param minimum: Date of issue.
        :param maximum: Maximum of expiration_date.
        :return: Expiration date of credit card.

        :Example:
            03/19.
        """
        month = self.random.randint(1, 12)
        year = self.random.randint(minimum, maximum)
        return '{0:02d}/{1}'.format(month, year)

    def cvv(self) -> int:
        """Generate a random CVV.

        :return: CVV code.

        :Example:
            324
        """
        return self.random.randint(100, 999)

    def credit_card_owner(self, gender: Optional[Gender] = None) -> dict:
        """Generate credit card owner.

        :param gender: Gender of credit card owner.
        :type gender: Gender's enum object.
        :return:
        """
        owner = {
            'credit_card': self.credit_card_number(),
            'expiration_date': self.credit_card_expiration_date(),
            'owner': self.__person.full_name(gender=gender).upper(),
        }
        return owner

mimesis/providers/payment.py
"""Provides data related to payment."""

import re
import string
from typing import Optional

from mimesis.data import CREDIT_CARD_NETWORKS
from mimesis.enums import CardType, Gender
from mimesis.exceptions import NonEnumerableError
from mimesis.helpers import get_random_item
from mimesis.providers.base import BaseDataProvider
from mimesis.providers.person import Person
from mimesis.utils import luhn_checksum

__all__ = ['Payment']


class Payment(BaseDataProvider):
    """Class that provides data related to payments."""

    def __init__(self, *args, **kwargs) -> None:
        """Initialize attributes.

        :param args: Arguments.
        :param kwargs: Keyword arguments.
        """
        super().__init__(*args, **kwargs)
        self.__person = Person('en', seed=self.seed)

    def cid(self) -> int:
        """Generate a random CID.

        :return: CID code.

        :Example:
            7452
        """
        return self.random.randint(1000, 9999)

    def paypal(self) -> str:
        """Generate a random PayPal account.

        :return: Email of PapPal user.

        :Example:
            wolf235@gmail.com
        """
        return self.__person.email()

    def bitcoin_address(self) -> str:
        """Generate a random bitcoin address.

        :return: Bitcoin address.

        :Example:
            3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX
        """
        type_ = self.random.choice(['1', '3'])
        letters = string.ascii_letters + string.digits
        return type_ + ''.join(
            self.random.choice(letters) for _ in range(33))

    def ethereum_address(self) -> str:
        """Generate a random Ethereum address.

        .. Note: The address will look like Ethereum address,
        but keep in mind that it is not the valid address.

        :return: Ethereum address.

        :Example:
            0xe8ece9e6ff7dba52d4c07d37418036a89af9698d
        """
        bits = self.random.getrandbits(160)
        address = bits.to_bytes(20, byteorder='big')
        return '0x' + address.hex()

    def credit_card_network(self) -> str:
        """Generate a random credit card network.

        :return: Credit card network

        :Example:
            MasterCard
        """
        return self.random.choice(CREDIT_CARD_NETWORKS)

    def credit_card_number(self, card_type: Optional[CardType] = None) -> str:
        """Generate a random credit card number.

        :param card_type: Issuing Network. Default is Visa.
        :return: Credit card number.
        :raises NotImplementedError: if cart_type is not supported.

        :Example:
            4455 5299 1152 2450
        """
        length = 16
        regex = re.compile('(\d{4})(\d{4})(\d{4})(\d{4})')

        if card_type is None:
            card_type = get_random_item(CardType, rnd=self.random)

        if card_type == CardType.VISA:
            number = self.random.randint(4000, 4999)
        elif card_type == CardType.MASTER_CARD:
            number = self.random.choice([
                self.random.randint(2221, 2720),
                self.random.randint(5100, 5500),
            ])
        elif card_type == CardType.AMERICAN_EXPRESS:
            number = self.random.choice([34, 37])
            length = 15
            regex = re.compile('(\d{4})(\d{6})(\d{5})')
        else:
            raise NonEnumerableError(CardType)

        str_num = str(number)
        while len(str_num) < length - 1:
            str_num += self.random.choice(string.digits)

        groups = regex.search(  # type: ignore
            str_num + luhn_checksum(str_num),
        ).groups()
        card = ' '.join(groups)
        return card

    def credit_card_expiration_date(self, minimum: int = 16,
                                    maximum: int = 25) -> str:
        """Generate a random expiration date for credit card.

        :param minimum: Date of issue.
        :param maximum: Maximum of expiration_date.
        :return: Expiration date of credit card.

        :Example:
            03/19.
        """
        month = self.random.randint(1, 12)
        year = self.random.randint(minimum, maximum)
        return '{0:02d}/{1}'.format(month, year)

    def cvv(self) -> int:
        """Generate a random CVV.

        :return: CVV code.

        :Example:
            324
        """
        return self.random.randint(100, 999)

    def credit_card_owner(self, gender: Optional[Gender] = None) -> dict:
        """Generate credit card owner.

        :param gender: Gender of credit card owner.
        :type gender: Gender's enum object.
        :return:
        """
        owner = {
            'credit_card': self.credit_card_number(),
            'expiration_date': self.credit_card_expiration_date(),
            'owner': self.__person.full_name(gender=gender).upper(),
        }
        return owner

mimesis/providers/payment.py
diff --git a/.travis.yml b/.travis.yml
index 5c2fe6f6d..c7018864c 100755
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,11 +8,11 @@ python:
 
 install:
   - pip install pipenv
-  - pipenv install --dev --deploy
+  - pipenv install --dev --ignore-pipfile
 
 script:
-  - pipenv run py.test --maxfail=2 --durations=3 --cov=mimesis --benchmark-skip
-  - pipenv run mypy mimesis
+  - pipenv run py.test --cov=mimesis
+  - pipenv run mypy mimesis/ tests/
   - pipenv run pyroma -d .
 
 after_success:
diff --git a/Makefile b/Makefile
index 7eb1b6fab..b9ec2d5fa 100755
--- a/Makefile
+++ b/Makefile
@@ -48,12 +48,12 @@ clean: clean-pyc clean-build
 .PHONY: test
 test:
 	py.test --benchmark-skip --color=yes ./
-	mypy mimesis/
+	mypy mimesis/ tests/
 
 
 .PHONY: type-check
 type-check:
-	mypy mimesis/
+	mypy mimesis/ tests/
 
 
 .PHONY: benchmarks
diff --git a/appveyor.yml b/appveyor.yml
index ce86c8857..afdc20f6c 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -20,17 +20,18 @@ environment:
 install:
   - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
   - "python --version"
-  
+
   # Upgrade to the latest version of pip to avoid it displaying warnings
   # about it being out of date.
   - "pip install --disable-pip-version-check --user --upgrade pip"
-  
+
   # Setting up enviroment
   - "pip install pipenv"
-  - "pipenv install --dev"
+  - "pipenv install --dev --ignore-pipfile"
 
 build: off
 
 test_script:
-  - "pipenv run mypy mimesis"
+  - "pipenv run mypy mimesis tests"
   - "pipenv run py.test --maxfail=2 --durations=3 --cov=mimesis --benchmark-skip"
+  - "pipenv run pyroma -d ."
diff --git a/mimesis/providers/payment.py b/mimesis/providers/payment.py
index 25acc19bf..d8b6e6070 100644
--- a/mimesis/providers/payment.py
+++ b/mimesis/providers/payment.py
@@ -119,7 +119,9 @@ def credit_card_number(self, card_type: Optional[CardType] = None) -> str:
         while len(str_num) < length - 1:
             str_num += self.random.choice(string.digits)
 
-        groups = regex.search(str_num + luhn_checksum(str_num)).groups()
+        groups = regex.search(  # type: ignore
+            str_num + luhn_checksum(str_num),
+        ).groups()
         card = ' '.join(groups)
         return card
 
diff --git a/setup.cfg b/setup.cfg
index 858464111..fbeb81314 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -22,9 +22,11 @@ addopts =
 
 
 [mypy]
-python_version = 3.5
-
-warn_no_return = False
 strict_optional = True
 check_untyped_defs = True
-
+ignore_errors = False
+ignore_missing_imports = True
+warn_no_return = False
+warn_unused_ignores = True
+warn_redundant_casts = True
+warn_unused_configs = True
diff --git a/tests/test_builtins/ru/test_russia_spec.py b/tests/test_builtins/ru/test_russia_spec.py
index d38a809ea..3f93e5b08 100755
--- a/tests/test_builtins/ru/test_russia_spec.py
+++ b/tests/test_builtins/ru/test_russia_spec.py
@@ -11,15 +11,15 @@ def russia():
 
 
 def test_passport_series(russia):
-    result = russia.passport_series()
-    assert result is not None
-    result = result.split(' ')
-    assert isinstance(result, list)
+    series = russia.passport_series()
+    assert isinstance(series.split(' '), list)
+
 
-    result = russia.passport_series(year=10)
-    region, year = result.split(' ')
+def test_passport_series_parametrized(russia):
+    series = russia.passport_series(year=10)
+    region, year = series.split(' ')
     assert int(year) == 10
-    assert region is not None
+    assert 0 < int(region) < 100
 
 
 def test_passport_number(russia):
diff --git a/tests/test_providers/test_path.py b/tests/test_providers/test_path.py
index 5bd48e0e8..5cd7d92f0 100755
--- a/tests/test_providers/test_path.py
+++ b/tests/test_providers/test_path.py
@@ -28,10 +28,12 @@ def test_user(self, path):
             'win32': '(C)(:)(\\\\)(Users)(\\\\).*[^(\\\\)]',
             'linux': '(/)(home)(/).*',
         }
+
         if path.platform == 'win32':
-            pattern = pattern_dictionary.get('win32')
+            pattern = pattern_dictionary['win32']
         else:
-            pattern = pattern_dictionary.get('linux')
+            pattern = pattern_dictionary['linux']
+
         result = re.search(pattern, user)
         assert isinstance(result, type(re.search('', ''))) is True
 
diff --git a/tests/test_schema.py b/tests/test_schema.py
index eea4b18dd..6ad564400 100644
--- a/tests/test_schema.py
+++ b/tests/test_schema.py
@@ -73,7 +73,7 @@ def test_fill(_, valid_schema):
     assert isinstance(result[0], dict)
 
     with pytest.raises(UndefinedSchema):
-        Schema(schema=None).create()
+        Schema(schema=None).create()  # type: ignore
 
 
 def test_field_with_key(_):

Fix mypy issues
There are several things to consider:

1. Fixing bugs like this one: https://travis-ci.org/lk-geimfari/mimesis/jobs/361128185#L600
2. Adding new options to `mypy` to make it stricter: https://github.com/wemake-services/wemake-django-template/blob/master/%7B%7Bcookiecutter.project_name%7D%7D/setup.cfg#L67
3. Add `tests` folder to be checked by `mypy` (not only `mimesis/` folder is checked)

I can do it, if @lk-geimfari does not have anything to add/comment.
