├── requirements.txt
├── src
├── __init__.py
├── data
│ ├── __init__.py
│ ├── find_pet
│ │ ├── __init__.py
│ │ ├── find.py
│ │ └── find_test.py
│ ├── register_user
│ │ ├── __init__.py
│ │ ├── register.py
│ │ └── register_test.py
│ ├── find_user
│ │ ├── __init__.py
│ │ ├── find_test.py
│ │ └── find.py
│ ├── register_pet
│ │ ├── __init__.py
│ │ ├── register_test.py
│ │ └── register.py
│ ├── test
│ │ ├── __init__.py
│ │ ├── find_user_spy.py
│ │ └── register_pet_spy.py
│ └── interfaces
│ │ ├── __init__.py
│ │ ├── user_repository_interface.py
│ │ └── pet_repository_interface.py
├── domain
│ ├── __init__.py
│ ├── models
│ │ ├── __init__.py
│ │ ├── users.py
│ │ └── pets.py
│ ├── test
│ │ ├── __init__.py
│ │ ├── mock_user.py
│ │ └── mock_pet.py
│ └── use_cases
│ │ ├── __init__.py
│ │ ├── register_user.py
│ │ ├── register_pet.py
│ │ ├── find_user.py
│ │ └── find_pet.py
├── infra
│ ├── __init__.py
│ ├── repo
│ │ ├── __init__.py
│ │ ├── user_repository_test.py
│ │ ├── user_repository.py
│ │ ├── pet_repository_test.py
│ │ └── pet_repository.py
│ ├── entities
│ │ ├── __init__.py
│ │ ├── users.py
│ │ └── pets.py
│ ├── config
│ │ ├── __init__.py
│ │ ├── db_base.py
│ │ └── db_config.py
│ └── test
│ │ ├── __init__.py
│ │ ├── user_repository_spy.py
│ │ └── pet_repository_spy.py
├── main
│ ├── __init__.py
│ ├── configs
│ │ ├── __init__.py
│ │ └── app.py
│ ├── interface
│ │ ├── __init__.py
│ │ └── route.py
│ ├── routes
│ │ ├── __init__.py
│ │ └── api_route.py
│ └── composer
│ │ ├── __init__.py
│ │ └── register_pet_composite.py
└── presenters
│ ├── __init__.py
│ ├── errors
│ ├── __init__.py
│ └── http_errors.py
│ ├── helpers
│ ├── __init__.py
│ └── http_models.py
│ └── controllers
│ ├── __init__.py
│ ├── find_user_controller_test.py
│ ├── register_pet_controller_test.py
│ ├── find_user_controller.py
│ └── register_pet_controller.py
├── .gitignore
├── .flake8
├── run.py
├── .vscode
└── settings.json
├── .editorconfig
├── .pre-commit-config.yaml
├── README.md
└── .pylintrc
/requirements.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/data/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/domain/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/infra/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/infra/repo/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/presenters/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/data/find_pet/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/data/register_user/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/configs/__init__.py:
--------------------------------------------------------------------------------
1 | from .app import app
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | venv
2 | **/__pycache__
3 | *.db
4 | .pytest_cache
--------------------------------------------------------------------------------
/src/data/find_user/__init__.py:
--------------------------------------------------------------------------------
1 | from .find import FindUser
2 |
--------------------------------------------------------------------------------
/src/main/interface/__init__.py:
--------------------------------------------------------------------------------
1 | from .route import RouteInterface
2 |
--------------------------------------------------------------------------------
/src/main/routes/__init__.py:
--------------------------------------------------------------------------------
1 | from .api_route import api_route_bp
2 |
--------------------------------------------------------------------------------
/src/data/register_pet/__init__.py:
--------------------------------------------------------------------------------
1 | from .register import RegisterPet
2 |
--------------------------------------------------------------------------------
/src/presenters/errors/__init__.py:
--------------------------------------------------------------------------------
1 | from .http_errors import HttpErrors
2 |
--------------------------------------------------------------------------------
/src/domain/models/__init__.py:
--------------------------------------------------------------------------------
1 | from .users import Users
2 | from .pets import Pets
3 |
--------------------------------------------------------------------------------
/src/main/composer/__init__.py:
--------------------------------------------------------------------------------
1 | from .register_pet_composite import register_pet_compose
2 |
--------------------------------------------------------------------------------
/src/presenters/helpers/__init__.py:
--------------------------------------------------------------------------------
1 | from .http_models import HttpRequest, HttpResponse
2 |
--------------------------------------------------------------------------------
/src/domain/test/__init__.py:
--------------------------------------------------------------------------------
1 | from .mock_user import mock_user
2 | from .mock_pet import mock_pet
3 |
--------------------------------------------------------------------------------
/src/infra/entities/__init__.py:
--------------------------------------------------------------------------------
1 | from .pets import Pets, AnimalTypes
2 | from .users import Users
3 |
--------------------------------------------------------------------------------
/src/infra/config/__init__.py:
--------------------------------------------------------------------------------
1 | from .db_base import Base
2 | from .db_config import DatabaseConnectionHandler
3 |
--------------------------------------------------------------------------------
/.flake8:
--------------------------------------------------------------------------------
1 | [flake8]
2 | ignore = E722, W503
3 | max-line-length = 120
4 | per-file-ignores =
5 | __init__.py: F401
--------------------------------------------------------------------------------
/run.py:
--------------------------------------------------------------------------------
1 | from src.main.configs import app
2 |
3 | if __name__ == "main":
4 | app.run(host="0.0.0.0", port=3333)
5 |
--------------------------------------------------------------------------------
/src/data/test/__init__.py:
--------------------------------------------------------------------------------
1 | from .find_user_spy import FindUserSpy
2 | from .register_pet_spy import RegisterPetSpy
3 |
--------------------------------------------------------------------------------
/src/infra/config/db_base.py:
--------------------------------------------------------------------------------
1 | from sqlalchemy.ext.declarative import declarative_base
2 |
3 | Base = declarative_base()
4 |
--------------------------------------------------------------------------------
/src/domain/models/users.py:
--------------------------------------------------------------------------------
1 | from collections import namedtuple
2 |
3 | Users = namedtuple("Users", "id, name, password")
4 |
--------------------------------------------------------------------------------
/src/domain/models/pets.py:
--------------------------------------------------------------------------------
1 | from collections import namedtuple
2 |
3 | Pets = namedtuple("Pets", "id, name, specie, age, user_id")
4 |
--------------------------------------------------------------------------------
/src/infra/test/__init__.py:
--------------------------------------------------------------------------------
1 | from .user_repository_spy import UserRepositorySpy
2 | from .pet_repository_spy import PetRepositorySpy
3 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "python.pythonPath": "venv/bin/python",
3 | "python.linting.pylintEnabled": true,
4 | "python.linting.enabled": true
5 | }
--------------------------------------------------------------------------------
/src/presenters/controllers/__init__.py:
--------------------------------------------------------------------------------
1 | from .find_user_controller import FindUserController
2 | from .register_pet_controller import RegisterPetController
3 |
--------------------------------------------------------------------------------
/src/data/interfaces/__init__.py:
--------------------------------------------------------------------------------
1 | from .pet_repository_interface import PetRepositoryInterface
2 | from .user_repository_interface import UserRepositoryInterface
3 |
--------------------------------------------------------------------------------
/src/domain/use_cases/__init__.py:
--------------------------------------------------------------------------------
1 | from .register_user import RegisterUserInterface
2 | from .find_user import FindUser
3 | from .find_pet import FindPet
4 | from .register_pet import RegisterPetInterface
5 |
--------------------------------------------------------------------------------
/src/main/configs/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 | from flask_cors import CORS
3 | from src.main.routes import api_route_bp
4 |
5 | app = Flask(__name__)
6 | CORS(app)
7 |
8 | app.register_blueprint(api_route_bp)
9 |
--------------------------------------------------------------------------------
/src/main/routes/api_route.py:
--------------------------------------------------------------------------------
1 | from flask import Blueprint, jsonify
2 |
3 | api_route_bp = Blueprint("api_route", __name__)
4 |
5 |
6 | @api_route_bp.route("/api", methods=["GET"])
7 | def something():
8 | """teste"""
9 |
10 | return jsonify({"Success": True})
11 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: https://EditorConfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | [*]
7 | indent_style = space
8 | indent_size = 4
9 | end_of_line = lf
10 | charset = utf-8
11 | trim_trailing_whitespace = false
12 | insert_final_newline = false
--------------------------------------------------------------------------------
/src/domain/test/mock_user.py:
--------------------------------------------------------------------------------
1 | from faker import Faker
2 | from src.domain.models import Users
3 |
4 | faker = Faker()
5 |
6 |
7 | def mock_user() -> Users:
8 | """Mockging users"""
9 |
10 | return Users(
11 | id=faker.random_number(digits=5), name=faker.name(), password=faker.word()
12 | )
13 |
--------------------------------------------------------------------------------
/src/domain/use_cases/register_user.py:
--------------------------------------------------------------------------------
1 | from typing import Dict
2 | from abc import ABC, abstractmethod
3 | from src.domain.models import Users
4 |
5 |
6 | class RegisterUserInterface(ABC):
7 | """Interface to register an user"""
8 |
9 | @abstractmethod
10 | def execute(self, name: str, password: str) -> Dict[bool, Users]:
11 | """abstract method"""
12 |
13 | raise Exception("Method not implemented")
14 |
--------------------------------------------------------------------------------
/src/main/interface/route.py:
--------------------------------------------------------------------------------
1 | from typing import Type
2 | from abc import ABC, abstractmethod
3 | from src.presenters.helpers import HttpRequest, HttpResponse
4 |
5 |
6 | class RouteInterface(ABC):
7 | """Interface to routes"""
8 |
9 | @abstractmethod
10 | def handle(self, http_request: Type[HttpRequest]) -> HttpResponse:
11 | """Define route"""
12 |
13 | raise Exception("Should implement method: route")
14 |
--------------------------------------------------------------------------------
/src/presenters/errors/http_errors.py:
--------------------------------------------------------------------------------
1 | class HttpErrors:
2 | """Class to define HTTP Errors"""
3 |
4 | @staticmethod
5 | def error_400():
6 | """Define HTTP 400"""
7 |
8 | return {"status_code": 400, "body": {"error": "Bad Request"}}
9 |
10 | @staticmethod
11 | def error_422():
12 | """Define HTTP 422"""
13 |
14 | return {"status_code": 422, "body": {"error": "Unprocessable Entity"}}
15 |
--------------------------------------------------------------------------------
/src/domain/test/mock_pet.py:
--------------------------------------------------------------------------------
1 | from faker import Faker
2 | from src.domain.models import Pets
3 | from src.infra.entities import AnimalTypes
4 |
5 | faker = Faker()
6 |
7 |
8 | def mock_pet() -> Pets:
9 | """Mockging pets"""
10 |
11 | return Pets(
12 | id=faker.random_number(digits=5),
13 | name=faker.name(),
14 | specie=AnimalTypes.cat,
15 | age=faker.random_number(digits=1),
16 | user_id=faker.random_number(digits=5),
17 | )
18 |
--------------------------------------------------------------------------------
/src/domain/use_cases/register_pet.py:
--------------------------------------------------------------------------------
1 | from abc import ABC, abstractclassmethod
2 | from typing import Dict
3 | from src.domain.models import Pets
4 |
5 |
6 | class RegisterPetInterface(ABC):
7 | """Interface to Register Pet Use Case"""
8 |
9 | @abstractclassmethod
10 | def registry(
11 | cls, name: str, specie: str, user_information: Dict[int, str], age: int = None
12 | ) -> Dict[bool, Pets]:
13 | """Register pet method"""
14 |
15 | raise Exception("Should implement mehtod: registry")
16 |
--------------------------------------------------------------------------------
/src/domain/use_cases/find_user.py:
--------------------------------------------------------------------------------
1 | from abc import ABC, abstractclassmethod
2 | from typing import Dict
3 | from src.domain.models import Users
4 |
5 |
6 | class FindUser(ABC):
7 | """Interface to find user user case"""
8 |
9 | @abstractclassmethod
10 | def by_id(cls, user_id: int) -> Dict[bool, Users]:
11 | """Abstract method"""
12 |
13 | raise Exception("This method should be implemented")
14 |
15 | @abstractclassmethod
16 | def by_name(cls, name: str) -> Dict[bool, Users]:
17 | """Abstract method"""
18 |
19 | raise Exception("This method should be implemented")
20 |
--------------------------------------------------------------------------------
/src/data/interfaces/user_repository_interface.py:
--------------------------------------------------------------------------------
1 | from abc import ABC, abstractmethod
2 | from src.domain.models import Users
3 |
4 |
5 | class UserRepositoryInterface(ABC):
6 | """Interface to User Repository"""
7 |
8 | @abstractmethod
9 | def insert_user(self, name: str, password: str) -> Users:
10 | """abstract method"""
11 |
12 | raise Exception("Method not implemented")
13 |
14 | @abstractmethod
15 | def find_by_id(self, user_id: int) -> Users:
16 | """abstract method"""
17 |
18 | raise Exception("Method not implemented")
19 |
20 | @abstractmethod
21 | def find_by_name(self, name: str) -> Users:
22 | """abstract method"""
23 |
24 | raise Exception("Method not implemented")
25 |
--------------------------------------------------------------------------------
/src/main/composer/register_pet_composite.py:
--------------------------------------------------------------------------------
1 | from src.main.interface import RouteInterface
2 | from src.presenters.controllers import RegisterPetController
3 | from src.data.register_pet import RegisterPet
4 | from src.infra.repo.pet_repository import PetRepository
5 | from src.infra.repo.user_repository import UserRepository
6 |
7 |
8 | def register_pet_compose() -> RouteInterface:
9 | """Composing register user route
10 | :param - None
11 | :return - Object with registered user
12 | """
13 | pets_repository = PetRepository()
14 | users_repository = UserRepository()
15 | use_case = RegisterPet(pets_repository, users_repository)
16 | register_pet_route = RegisterPetController(use_case)
17 |
18 | return register_pet_route
19 |
--------------------------------------------------------------------------------
/src/infra/entities/users.py:
--------------------------------------------------------------------------------
1 | from sqlalchemy import Column, String, Integer
2 | from sqlalchemy.orm import relationship
3 | from src.infra.config import Base
4 |
5 |
6 | class Users(Base):
7 | """Users Entity"""
8 |
9 | __tablename__ = "users"
10 |
11 | id = Column(Integer, primary_key=True)
12 | name = Column(String, nullable=False, unique=True)
13 | password = Column(String, nullable=False)
14 | id_pet = relationship("Pets")
15 |
16 | def __rep__(self):
17 | return f"Usr [name={self.name}]"
18 |
19 | def __eq__(self, other):
20 | if (
21 | self.id == other.id
22 | and self.name == other.name
23 | and self.password == other.password
24 | ):
25 | return True
26 | return False
27 |
--------------------------------------------------------------------------------
/src/domain/use_cases/find_pet.py:
--------------------------------------------------------------------------------
1 | from abc import ABC, abstractclassmethod
2 | from typing import Dict, List
3 | from src.domain.models import Pets
4 |
5 |
6 | class FindPet(ABC):
7 | """Abstract to find pet use case"""
8 |
9 | @abstractclassmethod
10 | def by_id(cls, pet_id: int) -> Dict[bool, Pets]:
11 | """Abstract method"""
12 |
13 | raise Exception("This method should be implemented")
14 |
15 | @abstractclassmethod
16 | def by_name(cls, name: str) -> Dict[bool, Pets]:
17 | """Abstract method"""
18 |
19 | raise Exception("This method should be implemented")
20 |
21 | @abstractclassmethod
22 | def by_user_id(cls, user_id: int) -> Dict[bool, List[Pets]]:
23 | """Abstract method"""
24 |
25 | raise Exception("This method should be implemented")
26 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/ambv/black
3 | rev: stable
4 | hooks:
5 | - id: black
6 | language_version: python3.8
7 | stages: [commit]
8 | - repo: https://gitlab.com/pycqa/flake8
9 | rev: 3.7.9
10 | hooks:
11 | - id: flake8
12 | stages: [commit]
13 | - repo: local
14 | hooks:
15 | - id: pytest
16 | name: pytest
17 | language: system
18 | entry: pytest -v -s
19 | always_run: true
20 | pass_filenames: false
21 | stages: [commit]
22 | - repo: local
23 | hooks:
24 | - id: requirements
25 | name: requirements
26 | entry: bash -c 'venv/bin/pip3 freeze > requirements.txt; git add requirements.txt'
27 | language: system
28 | pass_filenames: false
29 | stages: [commit]
--------------------------------------------------------------------------------
/src/presenters/helpers/http_models.py:
--------------------------------------------------------------------------------
1 | from typing import Dict
2 |
3 |
4 | class HttpRequest:
5 | """Class to http requests representation"""
6 |
7 | def __init__(self, header: Dict = None, body: Dict = None, query: Dict = None):
8 | self.header = header
9 | self.body = body
10 | self.query = query
11 |
12 | def __repr__(self) -> str:
13 | return (
14 | f"HttpRequest (header={self.header}, body={self.body}, query={self.query}"
15 | )
16 |
17 |
18 | class HttpResponse:
19 | """Class to http response representation"""
20 |
21 | def __init__(self, status_code: int, body: any):
22 | self.status_code = status_code
23 | self.body = body
24 |
25 | def __repr__(self) -> str:
26 | return f"HttpResponse (status_code={self.status_code}, body={self.body}"
27 |
--------------------------------------------------------------------------------
/src/presenters/controllers/find_user_controller_test.py:
--------------------------------------------------------------------------------
1 | from faker import Faker
2 |
3 | from src.data.test import FindUserSpy
4 | from src.infra.test import UserRepositorySpy
5 | from src.presenters.helpers import HttpRequest
6 | from .find_user_controller import FindUserController
7 |
8 | faker = Faker()
9 |
10 |
11 | def test_handler():
12 | """Testing Handle Method"""
13 |
14 | find_user_use_case = FindUserSpy(UserRepositorySpy())
15 | find_user_controller = FindUserController(find_user_use_case)
16 |
17 | http_request = HttpRequest(query={"user_id": faker.random_number()})
18 |
19 | response = find_user_controller.handle(http_request)
20 |
21 | # Testing Inputs
22 | assert find_user_use_case.by_id_param["user_id"] == http_request.query["user_id"]
23 |
24 | # Testing Outputs
25 | assert response.status_code == 200
26 | assert response.body
27 |
--------------------------------------------------------------------------------
/src/infra/config/db_config.py:
--------------------------------------------------------------------------------
1 | from sqlalchemy import create_engine
2 | from sqlalchemy.orm import sessionmaker
3 |
4 |
5 | class DatabaseConnectionHandler:
6 | """ " Sqlalchemy database connection"""
7 |
8 | def __init__(self):
9 | self.__connection_string = "sqlite:///storage.db"
10 | self.session = None
11 |
12 | def get_engine(self):
13 | """Return connection engine
14 | :param - None
15 | :return - engine connection to Database
16 | """
17 | engine = create_engine(self.__connection_string)
18 | return engine
19 |
20 | def __enter__(self):
21 | engine = create_engine(self.__connection_string)
22 | session_maker = sessionmaker()
23 | self.session = session_maker(bind=engine)
24 | return self
25 |
26 | def __exit__(self, exc_type, exc_val, exc_tb):
27 | self.session.close() # pylint: disable=no-member
28 |
--------------------------------------------------------------------------------
/src/data/interfaces/pet_repository_interface.py:
--------------------------------------------------------------------------------
1 | from abc import ABC, abstractmethod
2 | from typing import List
3 | from src.domain.models import Pets
4 |
5 |
6 | class PetRepositoryInterface(ABC):
7 | """Interface to Pet Repository"""
8 |
9 | @abstractmethod
10 | def create(self, name: str, specie: str, age: int, user_id: int) -> Pets:
11 | """abstract method"""
12 |
13 | raise Exception("Method not implemented")
14 |
15 | @abstractmethod
16 | def find_by_id(self, pet_id: int) -> Pets:
17 | """abstract method"""
18 |
19 | raise Exception("Method not implemented")
20 |
21 | @abstractmethod
22 | def find_by_name(self, name: str) -> Pets:
23 | """abstract method"""
24 |
25 | raise Exception("Method not implemented")
26 |
27 | @abstractmethod
28 | def find_by_user_id(self, user_id: int) -> List[Pets]:
29 | """abstract method"""
30 |
31 | raise Exception("Method not implemented")
32 |
--------------------------------------------------------------------------------
/src/infra/test/user_repository_spy.py:
--------------------------------------------------------------------------------
1 | from src.domain.test import mock_user
2 | from src.domain.models import Users
3 |
4 |
5 | class UserRepositorySpy:
6 | """Spy to User Repository"""
7 |
8 | def __init__(self):
9 | self.insert_user_params = {}
10 | self.find_user_by_id_params = {}
11 | self.find_user_by_name_params = {}
12 |
13 | def insert_user(self, name: str, password: str) -> Users:
14 | """Spy to allthe attributes"""
15 |
16 | self.insert_user_params["name"] = name
17 | self.insert_user_params["password"] = password
18 |
19 | return mock_user()
20 |
21 | def find_by_name(self, name: str) -> Users:
22 | """Spy to user attributes"""
23 |
24 | self.find_user_by_name_params["name"] = name
25 |
26 | return mock_user()
27 |
28 | def find_by_id(self, user_id: int) -> Users:
29 | """Spy to user attributes"""
30 |
31 | self.find_user_by_id_params["user_id"] = user_id
32 |
33 | return mock_user()
34 |
--------------------------------------------------------------------------------
/src/data/register_user/register.py:
--------------------------------------------------------------------------------
1 | from typing import Type, Dict
2 | from src.domain.use_cases import RegisterUserInterface
3 | from src.domain.models import Users
4 | from src.data.interfaces import UserRepositoryInterface as UserRepository
5 |
6 |
7 | class RegisterUser(RegisterUserInterface):
8 | """Class to define use case: Register User"""
9 |
10 | def __init__(self, user_repository: Type[UserRepository]):
11 | self.user_repository = user_repository
12 |
13 | def execute(self, name: str, password: str) -> Dict[bool, Users]:
14 | """Register user use case
15 | :param - name: person name
16 | :param - password: user password
17 | :return - Dictionary with informations of the process
18 | """
19 |
20 | user = None
21 | validate_entry = isinstance(name, str) and isinstance(password, str)
22 |
23 | if validate_entry:
24 | user = self.user_repository.insert_user(name, password)
25 |
26 | return {"Success": validate_entry, "Data": user}
27 |
--------------------------------------------------------------------------------
/src/presenters/controllers/register_pet_controller_test.py:
--------------------------------------------------------------------------------
1 | from faker import Faker
2 | from src.data.test import RegisterPetSpy
3 | from src.infra.test import PetRepositorySpy
4 | from src.presenters.helpers import HttpRequest
5 | from .register_pet_controller import RegisterPetController
6 |
7 | faker = Faker()
8 |
9 |
10 | def test_route():
11 | """Test route RegisterPetController"""
12 |
13 | register_pet_use_case = RegisterPetSpy(PetRepositorySpy(), None)
14 | register_pet_route = RegisterPetController(register_pet_use_case)
15 |
16 | attributes = {
17 | "name": faker.word(),
18 | "specie": "dog",
19 | "age": faker.random_number(),
20 | "user_information": {
21 | "user_id": faker.random_number(),
22 | "user_name": faker.word(),
23 | },
24 | }
25 |
26 | register_pet_route.handle(HttpRequest(body=attributes))
27 |
28 | # Testing input
29 | assert register_pet_use_case.registry_param["name"] == attributes["name"]
30 | assert register_pet_use_case.registry_param["age"] == attributes["age"]
31 |
--------------------------------------------------------------------------------
/src/infra/entities/pets.py:
--------------------------------------------------------------------------------
1 | import enum
2 | from sqlalchemy import Column, String, Integer, Enum, ForeignKey
3 | from src.infra.config import Base
4 |
5 |
6 | class AnimalTypes(enum.Enum):
7 | """Define Animals Types"""
8 |
9 | dog = "dog"
10 | cat = "cat"
11 | fish = "fish"
12 | turtle = "turtle"
13 |
14 |
15 | class Pets(Base):
16 | """Pets Entity"""
17 |
18 | __tablename__ = "pets"
19 |
20 | id = Column(Integer, primary_key=True)
21 | name = Column(String(length=20), nullable=False, unique=True)
22 | specie = Column(Enum(AnimalTypes), nullable=False)
23 | age = Column(Integer)
24 | user_id = Column(Integer, ForeignKey("users.id"))
25 |
26 | def __repr__(self):
27 | return f"Pet: [name={self.name}, specie={self.specie}, user_id={self.user_id}]"
28 |
29 | def __eq__(self, other):
30 | if (
31 | self.id == other.id
32 | and self.name == other.name
33 | and self.specie == other.specie
34 | and self.age == other.age
35 | and self.user_id == other.user_id
36 | ):
37 | return True
38 | return False
39 |
--------------------------------------------------------------------------------
/src/data/test/find_user_spy.py:
--------------------------------------------------------------------------------
1 | from typing import Dict
2 | from src.domain.models import Users
3 | from src.domain.test import mock_user
4 |
5 |
6 | class FindUserSpy:
7 | """Class to define use case: Select User"""
8 |
9 | def __init__(self, user_repository: any) -> None:
10 | self.user_repository = user_repository
11 | self.by_id_param = {}
12 | self.by_name_param = {}
13 |
14 | def by_id(self, user_id: int) -> Dict[bool, Users]:
15 | """Select User By Id"""
16 |
17 | self.by_id_param["user_id"] = user_id
18 |
19 | response = None
20 |
21 | validate_entry = isinstance(user_id, int)
22 |
23 | if validate_entry:
24 | response = mock_user()
25 |
26 | return {"Success": validate_entry, "Data": response}
27 |
28 | def by_name(self, user_name: str) -> Dict[bool, Users]:
29 | """Select User By Id"""
30 |
31 | self.by_name_param["user_name"] = user_name
32 |
33 | response = None
34 |
35 | validate_entry = isinstance(user_name, str)
36 |
37 | if validate_entry:
38 | response = mock_user()
39 |
40 | return {"Success": validate_entry, "Data": response}
41 |
--------------------------------------------------------------------------------
/src/data/find_user/find_test.py:
--------------------------------------------------------------------------------
1 | from faker import Faker
2 | from src.infra.test import UserRepositorySpy
3 | from .find import FindUser
4 |
5 |
6 | faker = Faker()
7 |
8 |
9 | def test_by_id():
10 | "Should be able test the method by_id()"
11 |
12 | user_repository = UserRepositorySpy()
13 | find_user = FindUser(user_repository)
14 |
15 | attrbutes = {"id": faker.random_number(digits=3)}
16 |
17 | response = find_user.by_id(user_id=attrbutes["id"])
18 |
19 | # testing inputs
20 | assert user_repository.find_user_by_id_params["user_id"] == attrbutes["id"]
21 |
22 | # testing outputs
23 | assert response["Success"] is True
24 | assert response["Data"]
25 |
26 |
27 | def test_by_name():
28 | "Should be able test the method by_name()"
29 |
30 | user_repository = UserRepositorySpy()
31 | find_user = FindUser(user_repository)
32 |
33 | attrbutes = {"name": faker.name()}
34 |
35 | response = find_user.by_name(name=attrbutes["name"])
36 |
37 | # testing inputs
38 | assert user_repository.find_user_by_name_params["name"] == attrbutes["name"]
39 |
40 | # testing outputs
41 | assert response["Success"] is True
42 | assert response["Data"]
43 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Estudo e desenvolvimento de uma API REST
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ## :technologist: Tecnologias
18 |
19 | Esse projeto utilizará as seguintes tecnologias:
20 |
21 | - [Git](https://git-scm.com/)
22 | - [Python](https://www.python.org/downloads/release/python-380/)
23 | - **[Flask](https://flask.palletsprojects.com/en/2.0.x/)**
24 | - [DBeaver](https://dbeaver.io/download/)
25 | - [Vscode](https://code.visualstudio.com/)
26 | - [SQLite](https://www.sqlite.org/index.html)
27 |
28 | ## :dart: Metas
29 | ~ Aplicar conhecimentos de **Clean Architecture** no desenvolvimento de uma API REST.
30 |
31 | ~ Aprender sobre o framework web **Flask**.
32 |
33 | ~ Aprender sobre a linguagem de programção **Python** no desenvolvimento de aplicações Web.
34 |
--------------------------------------------------------------------------------
/src/data/find_user/find.py:
--------------------------------------------------------------------------------
1 | from typing import Dict, Type
2 | from src.domain.use_cases import FindUser as FindUserInterface
3 | from src.data.interfaces import UserRepositoryInterface as UserRepository
4 | from src.domain.models import Users
5 |
6 |
7 | class FindUser(FindUserInterface):
8 | """Class to define use case find user"""
9 |
10 | def __init__(self, user_repository: Type[UserRepository]):
11 | self.user_repository = user_repository
12 |
13 | def by_id(self, user_id: int) -> Dict[bool, Users]:
14 | """Select user by id
15 | :param - user_id: id of th user
16 | :return - Dictionary with proccess info
17 | """
18 |
19 | response = None
20 | input_is_valid = isinstance(user_id, int)
21 |
22 | if input_is_valid:
23 | response = self.user_repository.find_by_id(user_id=user_id)
24 |
25 | return {"Success": input_is_valid, "Data": response}
26 |
27 | def by_name(self, name: str) -> Dict[bool, Users]:
28 | """Select user by name
29 | :param - name: name of th user
30 | :return - Dictionary with proccess info
31 | """
32 |
33 | response = None
34 | input_is_valid = isinstance(name, str)
35 |
36 | if input_is_valid:
37 | response = self.user_repository.find_by_name(name=name)
38 |
39 | return {"Success": input_is_valid, "Data": response}
40 |
--------------------------------------------------------------------------------
/src/infra/test/pet_repository_spy.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 | from src.domain.test import mock_pet
3 | from src.domain.models import Pets
4 |
5 |
6 | class PetRepositorySpy:
7 | """Spy to Pet Repository"""
8 |
9 | def __init__(self):
10 | self.insert_pet_params = {}
11 | self.find_pet_by_id_params = {}
12 | self.find_pet_by_name_params = {}
13 | self.find_pet_by_user_id_params = {}
14 |
15 | def create(self, name: str, specie: str, age: int, user_id: int) -> Pets:
16 | """Spy to all the attributes"""
17 |
18 | self.insert_pet_params["name"] = name
19 | self.insert_pet_params["specie"] = specie
20 | self.insert_pet_params["age"] = age
21 | self.insert_pet_params["user_id"] = user_id
22 |
23 | return mock_pet()
24 |
25 | def find_by_id(self, pet_id: int) -> Pets:
26 | """Spy to all the attributes"""
27 |
28 | self.find_pet_by_id_params["pet_id"] = pet_id
29 |
30 | return mock_pet()
31 |
32 | def find_by_name(self, name: str) -> Pets:
33 | """Spy to all the attributes"""
34 |
35 | self.find_pet_by_name_params["name"] = name
36 |
37 | return mock_pet()
38 |
39 | def find_by_user_id(self, user_id: int) -> List[Pets]:
40 | """Spy to all the attributes"""
41 |
42 | self.find_pet_by_user_id_params["user_id"] = user_id
43 |
44 | return [mock_pet()]
45 |
--------------------------------------------------------------------------------
/src/data/register_pet/register_test.py:
--------------------------------------------------------------------------------
1 | from faker import Faker
2 |
3 | from src.infra.test import PetRepositorySpy, UserRepositorySpy
4 | from src.data.test import FindUserSpy
5 | from .register import RegisterPet
6 |
7 | faker = Faker()
8 |
9 |
10 | def test_registry():
11 | """Should be able register a pet"""
12 |
13 | pet_repo = PetRepositorySpy()
14 | find_user = FindUserSpy(UserRepositorySpy())
15 | register_pet = RegisterPet(pet_repo, find_user)
16 |
17 | attributes = {
18 | "name": faker.name(),
19 | "specie": faker.name(),
20 | "age": faker.random_number(digits=1),
21 | "user_information": {"user_id": faker.random_number(digits=5)},
22 | }
23 |
24 | response = register_pet.registry(
25 | name=attributes["name"],
26 | specie=attributes["specie"],
27 | age=attributes["age"],
28 | user_information=attributes["user_information"],
29 | )
30 |
31 | # Testing Inputs
32 | assert pet_repo.insert_pet_params["name"] == attributes["name"]
33 | assert pet_repo.insert_pet_params["specie"] == attributes["specie"]
34 | assert pet_repo.insert_pet_params["age"] == attributes["age"]
35 |
36 | # Testing FindUser Inputs
37 | assert find_user.by_id_param["user_id"] == attributes["user_information"]["user_id"]
38 |
39 | # Testing Outputs
40 | assert response["Success"] is True
41 | assert response["Data"] is not None
42 |
--------------------------------------------------------------------------------
/src/data/register_user/register_test.py:
--------------------------------------------------------------------------------
1 | from faker import Faker
2 | from src.infra.test import UserRepositorySpy
3 | from .register import RegisterUser
4 |
5 |
6 | faker = Faker()
7 |
8 |
9 | def test_register():
10 | """Should be able register a new user"""
11 |
12 | user_repo = UserRepositorySpy()
13 | register_user = RegisterUser(user_repo)
14 |
15 | attributes = {"name": faker.name(), "password": faker.word()}
16 |
17 | response = register_user.execute(
18 | name=attributes["name"], password=attributes["password"]
19 | )
20 |
21 | # testing inputs
22 | assert user_repo.insert_user_params["name"] == attributes["name"]
23 | assert user_repo.insert_user_params["password"] == attributes["password"]
24 |
25 | # testing outputs
26 | assert response["Success"] is True
27 | assert response["Data"]
28 |
29 |
30 | def test_register_fail():
31 | """Should not be able register a new user"""
32 |
33 | user_repo = UserRepositorySpy()
34 | register_user = RegisterUser(user_repo)
35 |
36 | attributes = {"name": faker.random_number(digits=3), "password": faker.word()}
37 |
38 | response = register_user.execute(
39 | name=attributes["name"], password=attributes["password"]
40 | )
41 |
42 | # testing inputs
43 | assert user_repo.insert_user_params == {}
44 |
45 | # testing outputs
46 | assert response["Success"] is False
47 | assert response["Data"] is None
48 |
--------------------------------------------------------------------------------
/src/infra/repo/user_repository_test.py:
--------------------------------------------------------------------------------
1 | from faker import Faker
2 | from src.infra.config import DatabaseConnectionHandler
3 | from .user_repository import UserRepository
4 |
5 | faker = Faker()
6 | user_repository = UserRepository()
7 | db_connection_handler = DatabaseConnectionHandler()
8 |
9 |
10 | def test_insert_user():
11 | """Should be able insert an user"""
12 |
13 | name = faker.name()
14 | password = faker.word()
15 |
16 | engine = db_connection_handler.get_engine()
17 |
18 | new_user = user_repository.insert_user(name, password)
19 | user = engine.execute(f"SELECT * FROM users WHERE id={new_user.id};").fetchone()
20 |
21 | engine.execute(f"DELETE FROM users WHERE id={new_user.id};")
22 |
23 | assert new_user.id == user.id
24 | assert new_user.name == user.name
25 | assert new_user.password == user.password
26 |
27 |
28 | def test_find_by_name():
29 | """Should be able return an user by your name"""
30 |
31 | name = faker.name()
32 | password = faker.word()
33 | user = user_repository.insert_user(name=name, password=password)
34 |
35 | created_user = user_repository.find_by_name(name=name)
36 |
37 | assert user == created_user
38 |
39 | engine = db_connection_handler.get_engine()
40 | engine.execute(f"DELETE FROM users WHERE id='{user.id}';")
41 |
42 |
43 | def test_find_by_id():
44 | """Should be able return an user by your id"""
45 |
46 | name = faker.name()
47 | password = faker.word()
48 | user = user_repository.insert_user(name=name, password=password)
49 |
50 | created_user = user_repository.find_by_id(user_id=user.id)
51 |
52 | assert user == created_user
53 |
54 | engine = db_connection_handler.get_engine()
55 | engine.execute(f"DELETE FROM users WHERE id='{user.id}';")
56 |
--------------------------------------------------------------------------------
/src/data/find_pet/find.py:
--------------------------------------------------------------------------------
1 | from typing import Dict, List, Type
2 | from src.domain.use_cases import FindPet as FindPetInterface
3 | from src.data.interfaces import PetRepositoryInterface as PetRepository
4 | from src.domain.models import Pets
5 |
6 |
7 | class FindPet(FindPetInterface):
8 | """Class to define use case find pet"""
9 |
10 | def __init__(self, pet_repository: Type[PetRepository]):
11 | self.pet_repository = pet_repository
12 |
13 | def by_id(self, pet_id: int) -> Dict[bool, Pets]:
14 | """Select pet by id
15 | :param - pet_id: id of the pet
16 | :return - Dictionary with proccess info
17 | """
18 |
19 | response = None
20 | input_is_valid = isinstance(pet_id, int)
21 |
22 | if input_is_valid:
23 | response = self.pet_repository.find_by_id(pet_id=pet_id)
24 |
25 | return {"Success": input_is_valid, "Data": response}
26 |
27 | def by_name(self, name: str) -> Dict[bool, Pets]:
28 | """Select pet by name
29 | :param - name: name of the pet
30 | :return - Dictionary with proccess info
31 | """
32 |
33 | response = None
34 | input_is_valid = isinstance(name, str)
35 |
36 | if input_is_valid:
37 | response = self.pet_repository.find_by_name(name=name)
38 |
39 | return {"Success": input_is_valid, "Data": response}
40 |
41 | def by_user_id(self, user_id: int) -> Dict[bool, List[Pets]]:
42 | """select all pets by user id
43 | :param - user_id: id of the user
44 | :return - Dictionary with proccess info
45 | """
46 |
47 | data = None
48 | input_is_valid = isinstance(user_id, int)
49 |
50 | if input_is_valid:
51 | data = self.pet_repository.find_by_user_id(user_id=user_id)
52 |
53 | return {"Success": input_is_valid, "Data": data}
54 |
--------------------------------------------------------------------------------
/src/data/test/register_pet_spy.py:
--------------------------------------------------------------------------------
1 | from typing import Dict
2 | from src.domain.models import Pets
3 | from src.domain.models.users import Users
4 | from src.domain.test import mock_user, mock_pet
5 |
6 |
7 | class RegisterPetSpy:
8 | """Spy to Class register pet"""
9 |
10 | def __init__(self, pet_repository: any, find_user: any) -> None:
11 | self.pet_repository = pet_repository
12 | self.find_user = find_user
13 | self.registry_param = {}
14 |
15 | def register(
16 | self, name: str, specie: str, user_information: Dict[int, str], age: int = None
17 | ) -> Dict[bool, Pets]:
18 | """Registry Pet"""
19 |
20 | self.registry_param["name"] = name
21 | self.registry_param["specie"] = specie
22 | self.registry_param["user_information"] = user_information
23 | self.registry_param["age"] = age
24 |
25 | response = None
26 |
27 | validate_entry = isinstance(name, str) and isinstance(specie, str)
28 | user = self.__find_user_information(user_information)
29 | checker = validate_entry and user["Success"]
30 |
31 | if checker:
32 | response = mock_pet()
33 |
34 | return {"Success": checker, "Data": response}
35 |
36 | def __find_user_information(
37 | self, user_information: Dict[int, str]
38 | ) -> Dict[bool, Users]:
39 | """Check user infos and select user"""
40 |
41 | user_founded = None
42 | user_params = user_information.keys()
43 |
44 | if "user_id" in user_params and "user_name" not in user_params:
45 | user_founded = {"Success": True, "Data": mock_user()}
46 |
47 | elif "user_id" not in user_params and "user_name" in user_params:
48 | user_founded = {"Success": True, "Data": mock_user()}
49 |
50 | elif "user_id" in user_params and "user_name" in user_params:
51 | user_founded = {"Success": True, "Data": mock_user()}
52 |
53 | else:
54 | return {"Success": False, "Data": None}
55 |
56 | return user_founded
57 |
--------------------------------------------------------------------------------
/src/data/register_pet/register.py:
--------------------------------------------------------------------------------
1 | from typing import Dict, Type
2 |
3 | from src.domain.models import Pets, Users
4 | from src.data.find_user import FindUser
5 | from src.data.interfaces import PetRepositoryInterface as PetRepository
6 | from src.domain.use_cases import RegisterPetInterface
7 |
8 |
9 | class RegisterPet(RegisterPetInterface):
10 | """Class to define use case: Register Pet"""
11 |
12 | def __init__(
13 | self, pet_repository: Type[PetRepository], find_user: Type[FindUser]
14 | ) -> None:
15 | self.pet_repository = pet_repository
16 | self.find_user = find_user
17 |
18 | def registry(
19 | self, name: str, specie: str, user_information: Dict[int, str], age: int = None
20 | ) -> Dict[bool, Pets]:
21 | """Registry Pet"""
22 |
23 | response = None
24 |
25 | validate_entry = isinstance(name, str) and isinstance(specie, str)
26 | user = self.__find_user_information(user_information)
27 | checker = validate_entry and user["Success"]
28 |
29 | if checker:
30 | response = self.pet_repository.create(
31 | name, specie, age, user_information["user_id"]
32 | )
33 |
34 | return {"Success": checker, "Data": response}
35 |
36 | def __find_user_information(
37 | self, user_information: Dict[int, str]
38 | ) -> Dict[bool, Users]:
39 | """Check user infos and selct user"""
40 |
41 | user_founded = None
42 | user_params = user_information.keys()
43 |
44 | if "user_id" in user_params and "user_name" not in user_params:
45 | user_founded = self.find_user.by_id(user_id=user_information["user_id"])
46 |
47 | elif "user_id" not in user_params and "user_name" in user_params:
48 | user_founded = self.find_user.by_name(user_id=user_information["user_name"])
49 |
50 | elif "user_id" in user_params and "user_name" in user_params:
51 | user_founded = self.find_user.by_id(user_id=user_information["user_id"])
52 |
53 | else:
54 | return {"Success": False, "Data": None}
55 |
56 | return user_founded
57 |
--------------------------------------------------------------------------------
/src/presenters/controllers/find_user_controller.py:
--------------------------------------------------------------------------------
1 | from typing import Type
2 | from src.main.interface import RouteInterface
3 | from src.domain.use_cases import FindUser
4 | from src.presenters.helpers import HttpRequest, HttpResponse
5 | from src.presenters.errors import HttpErrors
6 |
7 |
8 | class FindUserController(RouteInterface):
9 | """Class to define controller to find user use case"""
10 |
11 | def __init__(self, find_user_use_case: Type[FindUser]):
12 | self.find_user_use_case = find_user_use_case
13 |
14 | def handle(self, http_request: Type[HttpRequest]) -> HttpResponse:
15 | """Method to call use case"""
16 |
17 | data = None
18 |
19 | if http_request.query:
20 | query_string_params = http_request.query.keys()
21 |
22 | if (
23 | "user_id" in query_string_params
24 | and "user_name" not in query_string_params
25 | ):
26 | user_id = http_request.query["user_id"]
27 | data = self.find_user_use_case.by_id(user_id=user_id)
28 |
29 | elif (
30 | "user_name" in query_string_params
31 | and "user_id" not in query_string_params
32 | ):
33 | user_name = http_request.query["user_name"]
34 | data = self.find_user_use_case.by_name(name=user_name)
35 |
36 | elif (
37 | "user_name" in query_string_params and "user_id" in query_string_params
38 | ):
39 | user_id = http_request.query["user_id"]
40 | data = self.find_user_use_case.by_id(user_id=user_id)
41 |
42 | else:
43 | data = {"Success": False, "Data": None}
44 |
45 | if data["Success"] is False:
46 | http_error = HttpErrors.error_422()
47 | return HttpResponse(
48 | status_code=http_error["status_code"], body=http_error["body"]
49 | )
50 |
51 | return HttpResponse(status_code=200, body=data)
52 |
53 | # if no query in http request
54 | http_error = HttpErrors.error_400()
55 | return HttpResponse(
56 | status_code=http_error["status_code"], body=http_error["body"]
57 | )
58 |
--------------------------------------------------------------------------------
/src/infra/repo/user_repository.py:
--------------------------------------------------------------------------------
1 | # pylint: disable=E1101
2 |
3 | from src.domain.models import Users
4 | from src.data.interfaces import UserRepositoryInterface
5 | from src.infra.config import DatabaseConnectionHandler
6 | from src.infra.entities import Users as UsersModel
7 |
8 |
9 | class UserRepository(UserRepositoryInterface):
10 | """Class to manage User Repository"""
11 |
12 | @classmethod
13 | def insert_user(cls, name: str, password: str) -> Users:
14 | """insert data in user entity
15 | :param - name: user name
16 | : - password: user password
17 | :return - tuple with new user inserted
18 | """
19 |
20 | with DatabaseConnectionHandler() as db_connection:
21 | try:
22 | new_user = UsersModel(name=name, password=password)
23 | db_connection.session.add(new_user)
24 | db_connection.session.commit()
25 |
26 | return Users(
27 | id=new_user.id, name=new_user.name, password=new_user.password
28 | )
29 | except:
30 | db_connection.session.rollback()
31 | raise
32 | finally:
33 | db_connection.session.close()
34 |
35 | @classmethod
36 | def find_by_name(cls, name: str) -> Users:
37 | """Find an User by your name
38 | :param - name: User's name
39 | :return - Returns an user
40 | """
41 |
42 | with DatabaseConnectionHandler() as db_connection:
43 | try:
44 | user = (
45 | db_connection.session.query(UsersModel).filter_by(name=name).one()
46 | )
47 | return user
48 | except:
49 | db_connection.session.rollback()
50 | raise
51 | finally:
52 | db_connection.session.close()
53 |
54 | @classmethod
55 | def find_by_id(cls, user_id: str) -> Users:
56 | """Find an User by your id
57 | :param - user_id: User's id
58 | :return - Returns an user
59 | """
60 |
61 | with DatabaseConnectionHandler() as db_connection:
62 | try:
63 | user = (
64 | db_connection.session.query(UsersModel).filter_by(id=user_id).one()
65 | )
66 | return user
67 | except:
68 | db_connection.session.rollback()
69 | raise
70 | finally:
71 | db_connection.session.close()
72 |
--------------------------------------------------------------------------------
/src/presenters/controllers/register_pet_controller.py:
--------------------------------------------------------------------------------
1 | from typing import Type
2 | from src.main.interface import RouteInterface
3 | from src.domain.use_cases.register_pet import RegisterPetInterface
4 | from src.presenters.helpers import HttpRequest, HttpResponse
5 | from src.presenters.errors import HttpErrors
6 |
7 |
8 | class RegisterPetController(RouteInterface):
9 | """Class to define route to register a pet"""
10 |
11 | def __init__(self, register_pet_use_case: Type[RegisterPetInterface]):
12 | self.register_pet_use_case = register_pet_use_case
13 |
14 | def handle(self, http_request: Type[HttpRequest]) -> HttpResponse:
15 | """Method do call use case"""
16 |
17 | response = None
18 |
19 | if http_request.body:
20 | body_params = http_request.body.keys()
21 |
22 | if (
23 | "name" in body_params
24 | and "specie" in body_params
25 | and "user_information" in body_params
26 | ):
27 | user_information_params = http_request.body["user_information"].keys()
28 |
29 | if (
30 | "user_id" in user_information_params
31 | or "user_name" in user_information_params
32 | ):
33 | name = http_request.body["name"]
34 | specie = http_request.body["specie"]
35 |
36 | if "age" in body_params:
37 | age = http_request.body["age"]
38 | else:
39 | age = None
40 |
41 | response = self.register_pet_use_case.register(
42 | name=name,
43 | specie=specie,
44 | user_information=http_request.body["user_information"],
45 | age=age,
46 | )
47 |
48 | else:
49 | response = {"Success": False, "Data": None}
50 | else:
51 | response = {"Success": False, "Data": None}
52 |
53 | if response["Success"] is False:
54 | http_error = HttpErrors.error_422()
55 | return HttpResponse(
56 | status_code=http_error["status_code"], body=http_error["body"]
57 | )
58 |
59 | return HttpResponse(status_code=200, body=response["Data"])
60 |
61 | http_error = HttpErrors.error_400()
62 | return HttpResponse(
63 | status_code=http_error["status_code"], body=http_error["body"]
64 | )
65 |
--------------------------------------------------------------------------------
/src/data/find_pet/find_test.py:
--------------------------------------------------------------------------------
1 | from faker import Faker
2 | from src.infra.test import PetRepositorySpy
3 | from src.infra.entities import AnimalTypes
4 | from .find import FindPet
5 |
6 |
7 | faker = Faker()
8 |
9 |
10 | def test_by_pet_id():
11 | """Should be able find a pet by id"""
12 |
13 | pet_repository = PetRepositorySpy()
14 | find_pet = FindPet(pet_repository)
15 |
16 | attributes = {
17 | "id": faker.random_number(digits=5),
18 | "name": faker.name(),
19 | "specie": AnimalTypes.cat,
20 | "age": faker.random_number(digits=1),
21 | "user_id": faker.random_number(digits=5),
22 | }
23 |
24 | data = find_pet.by_id(pet_id=attributes["id"])
25 |
26 | # testing inputs
27 | assert pet_repository.find_pet_by_id_params["pet_id"] == attributes["id"]
28 |
29 | # testing outputs
30 | assert data["Success"] is True
31 | assert data["Data"]
32 |
33 |
34 | def test_find_by_invalid_id():
35 | """Should not be able find a pet with invalid input"""
36 |
37 | pet_repository = PetRepositorySpy()
38 | find_pet = FindPet(pet_repository)
39 |
40 | attributes = {
41 | "id": faker.name(),
42 | "name": faker.name(),
43 | "specie": AnimalTypes.cat,
44 | "age": faker.random_number(digits=1),
45 | "user_id": faker.random_number(digits=5),
46 | }
47 |
48 | data = find_pet.by_id(pet_id=attributes["id"])
49 |
50 | # testing outputs
51 | assert data["Success"] is False
52 | assert data["Data"] is None
53 |
54 |
55 | def test_by_name():
56 | """Should be able find a pet by name"""
57 |
58 | pet_repository = PetRepositorySpy()
59 | find_pet = FindPet(pet_repository)
60 |
61 | attributes = {
62 | "id": faker.random_number(digits=5),
63 | "name": faker.name(),
64 | "specie": AnimalTypes.cat,
65 | "age": faker.random_number(digits=1),
66 | "user_id": faker.random_number(digits=5),
67 | }
68 |
69 | data = find_pet.by_name(name=attributes["name"])
70 |
71 | # testing inputs
72 | assert pet_repository.find_pet_by_name_params["name"] == attributes["name"]
73 |
74 | # testing outputs
75 | assert data["Success"] is True
76 | assert data["Data"]
77 |
78 |
79 | def test_by_user_id():
80 | """Should be able find all pets by user id"""
81 |
82 | pet_repository = PetRepositorySpy()
83 | find_pet = FindPet(pet_repository)
84 |
85 | attributes = {
86 | "id": faker.random_number(digits=5),
87 | "name": faker.name(),
88 | "specie": AnimalTypes.cat,
89 | "age": faker.random_number(digits=1),
90 | "user_id": faker.random_number(digits=5),
91 | }
92 |
93 | data = find_pet.by_user_id(user_id=attributes["user_id"])
94 |
95 | # testing inputs
96 | assert pet_repository.find_pet_by_user_id_params["user_id"] == attributes["user_id"]
97 |
98 | # testing outputs
99 | assert data["Success"] is True
100 | assert isinstance(data["Data"], list)
101 |
--------------------------------------------------------------------------------
/src/infra/repo/pet_repository_test.py:
--------------------------------------------------------------------------------
1 | from faker import Faker
2 | from src.infra.config import DatabaseConnectionHandler
3 | from src.infra.entities import AnimalTypes, Pets
4 | from .pet_repository import PetRepository
5 |
6 | faker = Faker()
7 | pet_repository = PetRepository()
8 | db_connection_handler = DatabaseConnectionHandler()
9 |
10 |
11 | def test_create_pet():
12 | """Should be able create a new pet"""
13 |
14 | name = faker.name()
15 | specie = AnimalTypes("cat")
16 | age = faker.random_number(digits=1)
17 | user_id = faker.random_number()
18 |
19 | pet = pet_repository.create(name, specie, age, user_id)
20 |
21 | engine = db_connection_handler.get_engine()
22 | created_pet = engine.execute(f"SELECT * FROM pets WHERE id='{pet.id}';").fetchone()
23 |
24 | assert pet.id == created_pet.id
25 | assert pet.name == created_pet.name
26 | assert pet.specie == created_pet.specie
27 | assert pet.age == created_pet.age
28 |
29 | engine.execute(f"DELETE FROM pets WHERE id='{pet.id}';")
30 |
31 |
32 | def test_find_by_id():
33 | """Should be able return by your id"""
34 |
35 | name = faker.name()
36 | specie = AnimalTypes("cat")
37 | age = faker.random_number(digits=1)
38 | user_id = faker.random_number()
39 |
40 | pet = pet_repository.create(name, specie, age, user_id)
41 |
42 | engine = db_connection_handler.get_engine()
43 | created_pet = pet_repository.find_by_id(pet_id=pet.id)
44 |
45 | assert pet.id == created_pet.id
46 | assert pet.name == created_pet.name
47 | assert pet.specie == created_pet.specie
48 | assert pet.age == created_pet.age
49 |
50 | engine.execute(f"DELETE FROM pets WHERE id='{pet.id}';")
51 |
52 |
53 | def test_find_by_name():
54 | """Should be able return by your name"""
55 |
56 | name = faker.name()
57 | specie = AnimalTypes("cat")
58 | age = faker.random_number(digits=1)
59 | user_id = faker.random_number()
60 |
61 | pet = pet_repository.create(name, specie, age, user_id)
62 |
63 | engine = db_connection_handler.get_engine()
64 | created_pet = pet_repository.find_by_name(name=name)
65 |
66 | assert pet.id == created_pet.id
67 | assert pet.name == created_pet.name
68 | assert pet.specie == created_pet.specie
69 | assert pet.age == created_pet.age
70 |
71 | engine.execute(f"DELETE FROM pets WHERE id='{pet.id}';")
72 |
73 |
74 | def test_find_by_user_id():
75 | """Should be able return by your name"""
76 |
77 | pet_id = faker.random_number(digits=4)
78 | name = faker.name()
79 | specie = "dog"
80 | age = faker.random_number(digits=1)
81 | user_id = faker.random_number(digits=5)
82 |
83 | specie_mock = AnimalTypes("dog")
84 |
85 | data = Pets(id=pet_id, name=name, specie=specie_mock, age=age, user_id=user_id)
86 |
87 | engine = db_connection_handler.get_engine()
88 |
89 | engine.execute(
90 | "INSERT INTO pets (id, name, specie, age, user_id) VALUES ('{}', '{}', '{}', '{}', '{}');".format(
91 | pet_id, name, specie, age, user_id
92 | )
93 | )
94 |
95 | pets = pet_repository.find_by_user_id(user_id=user_id)
96 |
97 | assert data in pets
98 |
99 | engine.execute(f"DELETE FROM pets WHERE id='{pet_id}';")
100 |
--------------------------------------------------------------------------------
/src/infra/repo/pet_repository.py:
--------------------------------------------------------------------------------
1 | # pylint: disable=E1101
2 |
3 | from typing import List
4 | from src.data.interfaces import PetRepositoryInterface
5 | from src.domain.models import Pets
6 | from src.infra.config import DatabaseConnectionHandler
7 | from src.infra.entities import Pets as PetsModel
8 |
9 |
10 | class PetRepository(PetRepositoryInterface):
11 | """Class to manage Pet Repository"""
12 |
13 | @classmethod
14 | def create(cls, name: str, specie: str, age: int, user_id: int) -> Pets:
15 | """
16 | Create a new pet
17 | :param - name:
18 | :param - specie:
19 | :param - age:
20 | :param - user_id:
21 | :return - tuple with new pet
22 | """
23 |
24 | with DatabaseConnectionHandler() as db_connection:
25 | try:
26 | pet = PetsModel(name=name, specie=specie, age=age, user_id=user_id)
27 | db_connection.session.add(pet)
28 | db_connection.session.commit()
29 |
30 | return Pets(
31 | id=pet.id,
32 | name=pet.name,
33 | specie=pet.specie.value,
34 | age=pet.age,
35 | user_id=pet.user_id,
36 | )
37 | except:
38 | db_connection.session.rollback()
39 | raise
40 | finally:
41 | db_connection.session.close()
42 |
43 | @classmethod
44 | def find_by_id(cls, pet_id: int) -> Pets:
45 | """Return a pet by you id
46 | :param - pet_id: Pet's id
47 | return: Returns a pet
48 | """
49 |
50 | with DatabaseConnectionHandler() as db_connection:
51 | try:
52 | pet = db_connection.session.query(PetsModel).filter_by(id=pet_id).one()
53 |
54 | return PetsModel(
55 | id=pet.id,
56 | name=pet.name,
57 | specie=pet.specie.value,
58 | age=pet.age,
59 | user_id=pet.user_id,
60 | )
61 | except:
62 | db_connection.session.rollback()
63 | raise
64 | finally:
65 | db_connection.session.close()
66 |
67 | @classmethod
68 | def find_by_name(cls, name: str) -> Pets:
69 | """Return a pet by you name
70 | :param - name: Pet's name
71 | return: Returns a pet
72 | """
73 |
74 | with DatabaseConnectionHandler() as db_connection:
75 | try:
76 | pet = db_connection.session.query(PetsModel).filter_by(name=name).one()
77 |
78 | return PetsModel(
79 | id=pet.id,
80 | name=pet.name,
81 | specie=pet.specie.value,
82 | age=pet.age,
83 | user_id=pet.user_id,
84 | )
85 | except:
86 | db_connection.session.rollback()
87 | raise
88 | finally:
89 | db_connection.session.close()
90 |
91 | @classmethod
92 | def find_by_user_id(cls, user_id: int) -> List[Pets]:
93 | """Return a list of pets by user_id
94 | :param - user_id: Pet's user_id
95 | return: Returns a list with pets selecteds
96 | """
97 |
98 | with DatabaseConnectionHandler() as db_connection:
99 | try:
100 | pets = (
101 | db_connection.session.query(PetsModel)
102 | .filter_by(user_id=user_id)
103 | .all()
104 | )
105 |
106 | return pets
107 | except:
108 | db_connection.session.rollback()
109 | raise
110 | finally:
111 | db_connection.session.close()
112 |
--------------------------------------------------------------------------------
/.pylintrc:
--------------------------------------------------------------------------------
1 | [MASTER]
2 |
3 | disable=
4 | C0114 # missing-module-docstring
5 | # A comma-separated list of package or module names from where C extensions may
6 | # be loaded. Extensions are loading into the active Python interpreter and may
7 | # run arbitrary code.
8 | extension-pkg-allow-list=
9 |
10 | # A comma-separated list of package or module names from where C extensions may
11 | # be loaded. Extensions are loading into the active Python interpreter and may
12 | # run arbitrary code. (This is an alternative name to extension-pkg-allow-list
13 | # for backward compatibility.)
14 | extension-pkg-whitelist=
15 |
16 | # Specify a score threshold to be exceeded before program exits with error.
17 | fail-under=10.0
18 |
19 | # Files or directories to be skipped. They should be base names, not paths.
20 | ignore=CVS
21 |
22 | # Files or directories matching the regex patterns are skipped. The regex
23 | # matches against base names, not paths.
24 | ignore-patterns=
25 |
26 | # Python code to execute, usually for sys.path manipulation such as
27 | # pygtk.require().
28 | #init-hook=
29 |
30 | # Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
31 | # number of processors available to use.
32 | jobs=1
33 |
34 | # Control the amount of potential inferred values when inferring a single
35 | # object. This can help the performance when dealing with large functions or
36 | # complex, nested conditions.
37 | limit-inference-results=100
38 |
39 | # List of plugins (as comma separated values of python module names) to load,
40 | # usually to register additional checkers.
41 | load-plugins=
42 |
43 | # Pickle collected data for later comparisons.
44 | persistent=yes
45 |
46 | # When enabled, pylint would attempt to guess common misconfiguration and emit
47 | # user-friendly hints instead of false-positive error messages.
48 | suggestion-mode=yes
49 |
50 | # Allow loading of arbitrary C extensions. Extensions are imported into the
51 | # active Python interpreter and may run arbitrary code.
52 | unsafe-load-any-extension=no
53 |
54 |
55 | [MESSAGES CONTROL]
56 |
57 | # Only show warnings with the listed confidence levels. Leave empty to show
58 | # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED.
59 | confidence=
60 |
61 | # Disable the message, report, category or checker with the given id(s). You
62 | # can either give multiple identifiers separated by comma (,) or put this
63 | # option multiple times (only on the command line, not in the configuration
64 | # file where it should appear only once). You can also use "--disable=all" to
65 | # disable everything first and then reenable specific checks. For example, if
66 | # you want to run only the similarities checker, you can use "--disable=all
67 | # --enable=similarities". If you want to run only the classes checker, but have
68 | # no Warning level messages displayed, use "--disable=all --enable=classes
69 | # --disable=W".
70 | disable=print-statement,
71 | parameter-unpacking,
72 | unpacking-in-except,
73 | old-raise-syntax,
74 | backtick,
75 | long-suffix,
76 | old-ne-operator,
77 | old-octal-literal,
78 | import-star-module-level,
79 | non-ascii-bytes-literal,
80 | raw-checker-failed,
81 | bad-inline-option,
82 | locally-disabled,
83 | file-ignored,
84 | suppressed-message,
85 | useless-suppression,
86 | deprecated-pragma,
87 | use-symbolic-message-instead,
88 | apply-builtin,
89 | basestring-builtin,
90 | buffer-builtin,
91 | cmp-builtin,
92 | coerce-builtin,
93 | execfile-builtin,
94 | file-builtin,
95 | long-builtin,
96 | raw_input-builtin,
97 | reduce-builtin,
98 | standarderror-builtin,
99 | unicode-builtin,
100 | xrange-builtin,
101 | coerce-method,
102 | delslice-method,
103 | getslice-method,
104 | setslice-method,
105 | no-absolute-import,
106 | old-division,
107 | dict-iter-method,
108 | dict-view-method,
109 | next-method-called,
110 | metaclass-assignment,
111 | indexing-exception,
112 | raising-string,
113 | reload-builtin,
114 | oct-method,
115 | hex-method,
116 | nonzero-method,
117 | cmp-method,
118 | input-builtin,
119 | round-builtin,
120 | intern-builtin,
121 | unichr-builtin,
122 | map-builtin-not-iterating,
123 | zip-builtin-not-iterating,
124 | range-builtin-not-iterating,
125 | filter-builtin-not-iterating,
126 | using-cmp-argument,
127 | eq-without-hash,
128 | div-method,
129 | idiv-method,
130 | rdiv-method,
131 | exception-message-attribute,
132 | invalid-str-codec,
133 | sys-max-int,
134 | bad-python3-import,
135 | deprecated-string-function,
136 | deprecated-str-translate-call,
137 | deprecated-itertools-function,
138 | deprecated-types-field,
139 | next-method-defined,
140 | dict-items-not-iterating,
141 | dict-keys-not-iterating,
142 | dict-values-not-iterating,
143 | deprecated-operator-function,
144 | deprecated-urllib-function,
145 | xreadlines-attribute,
146 | deprecated-sys-function,
147 | exception-escape,
148 | comprehension-escape
149 |
150 | # Enable the message, report, category or checker with the given id(s). You can
151 | # either give multiple identifier separated by comma (,) or put this option
152 | # multiple time (only on the command line, not in the configuration file where
153 | # it should appear only once). See also the "--disable" option for examples.
154 | enable=c-extension-no-member
155 |
156 |
157 | [REPORTS]
158 |
159 | # Python expression which should return a score less than or equal to 10. You
160 | # have access to the variables 'error', 'warning', 'refactor', and 'convention'
161 | # which contain the number of messages in each category, as well as 'statement'
162 | # which is the total number of statements analyzed. This score is used by the
163 | # global evaluation report (RP0004).
164 | evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
165 |
166 | # Template used to display messages. This is a python new-style format string
167 | # used to format the message information. See doc for all details.
168 | #msg-template=
169 |
170 | # Set the output format. Available formats are text, parseable, colorized, json
171 | # and msvs (visual studio). You can also give a reporter class, e.g.
172 | # mypackage.mymodule.MyReporterClass.
173 | output-format=text
174 |
175 | # Tells whether to display a full report or only the messages.
176 | reports=no
177 |
178 | # Activate the evaluation score.
179 | score=yes
180 |
181 |
182 | [REFACTORING]
183 |
184 | # Maximum number of nested blocks for function / method body
185 | max-nested-blocks=5
186 |
187 | # Complete name of functions that never returns. When checking for
188 | # inconsistent-return-statements if a never returning function is called then
189 | # it will be considered as an explicit return statement and no message will be
190 | # printed.
191 | never-returning-functions=sys.exit,argparse.parse_error
192 |
193 |
194 | [VARIABLES]
195 |
196 | # List of additional names supposed to be defined in builtins. Remember that
197 | # you should avoid defining new builtins when possible.
198 | additional-builtins=
199 |
200 | # Tells whether unused global variables should be treated as a violation.
201 | allow-global-unused-variables=yes
202 |
203 | # List of names allowed to shadow builtins
204 | allowed-redefined-builtins=
205 |
206 | # List of strings which can identify a callback function by name. A callback
207 | # name must start or end with one of those strings.
208 | callbacks=cb_,
209 | _cb
210 |
211 | # A regular expression matching the name of dummy variables (i.e. expected to
212 | # not be used).
213 | dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
214 |
215 | # Argument names that match this expression will be ignored. Default to name
216 | # with leading underscore.
217 | ignored-argument-names=_.*|^ignored_|^unused_
218 |
219 | # Tells whether we should check for unused import in __init__ files.
220 | init-import=no
221 |
222 | # List of qualified module names which can have objects that can redefine
223 | # builtins.
224 | redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
225 |
226 |
227 | [SPELLING]
228 |
229 | # Limits count of emitted suggestions for spelling mistakes.
230 | max-spelling-suggestions=4
231 |
232 | # Spelling dictionary name. Available dictionaries: none. To make it work,
233 | # install the 'python-enchant' package.
234 | spelling-dict=
235 |
236 | # List of comma separated words that should be considered directives if they
237 | # appear and the beginning of a comment and should not be checked.
238 | spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy:
239 |
240 | # List of comma separated words that should not be checked.
241 | spelling-ignore-words=
242 |
243 | # A path to a file that contains the private dictionary; one word per line.
244 | spelling-private-dict-file=
245 |
246 | # Tells whether to store unknown words to the private dictionary (see the
247 | # --spelling-private-dict-file option) instead of raising a message.
248 | spelling-store-unknown-words=no
249 |
250 |
251 | [SIMILARITIES]
252 |
253 | # Ignore comments when computing similarities.
254 | ignore-comments=yes
255 |
256 | # Ignore docstrings when computing similarities.
257 | ignore-docstrings=yes
258 |
259 | # Ignore imports when computing similarities.
260 | ignore-imports=no
261 |
262 | # Minimum lines number of a similarity.
263 | min-similarity-lines=4
264 |
265 |
266 | [STRING]
267 |
268 | # This flag controls whether inconsistent-quotes generates a warning when the
269 | # character used as a quote delimiter is used inconsistently within a module.
270 | check-quote-consistency=no
271 |
272 | # This flag controls whether the implicit-str-concat should generate a warning
273 | # on implicit string concatenation in sequences defined over several lines.
274 | check-str-concat-over-line-jumps=no
275 |
276 |
277 | [LOGGING]
278 |
279 | # The type of string formatting that logging methods do. `old` means using %
280 | # formatting, `new` is for `{}` formatting.
281 | logging-format-style=old
282 |
283 | # Logging modules to check that the string format arguments are in logging
284 | # function parameter format.
285 | logging-modules=logging
286 |
287 |
288 | [FORMAT]
289 |
290 | # Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
291 | expected-line-ending-format=
292 |
293 | # Regexp for a line that is allowed to be longer than the limit.
294 | ignore-long-lines=^\s*(# )??$
295 |
296 | # Number of spaces of indent required inside a hanging or continued line.
297 | indent-after-paren=4
298 |
299 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
300 | # tab).
301 | indent-string=' '
302 |
303 | # Maximum number of characters on a single line.
304 | max-line-length=120
305 |
306 | # Maximum number of lines in a module.
307 | max-module-lines=1000
308 |
309 | # Allow the body of a class to be on the same line as the declaration if body
310 | # contains single statement.
311 | single-line-class-stmt=no
312 |
313 | # Allow the body of an if to be on the same line as the test if there is no
314 | # else.
315 | single-line-if-stmt=no
316 |
317 |
318 | [MISCELLANEOUS]
319 |
320 | # List of note tags to take in consideration, separated by a comma.
321 | notes=FIXME,
322 | XXX,
323 | TODO
324 |
325 | # Regular expression of note tags to take in consideration.
326 | #notes-rgx=
327 |
328 |
329 | [TYPECHECK]
330 |
331 | # List of decorators that produce context managers, such as
332 | # contextlib.contextmanager. Add to this list to register other decorators that
333 | # produce valid context managers.
334 | contextmanager-decorators=contextlib.contextmanager
335 |
336 | # List of members which are set dynamically and missed by pylint inference
337 | # system, and so shouldn't trigger E1101 when accessed. Python regular
338 | # expressions are accepted.
339 | generated-members=
340 |
341 | # Tells whether missing members accessed in mixin class should be ignored. A
342 | # mixin class is detected if its name ends with "mixin" (case insensitive).
343 | ignore-mixin-members=yes
344 |
345 | # Tells whether to warn about missing members when the owner of the attribute
346 | # is inferred to be None.
347 | ignore-none=yes
348 |
349 | # This flag controls whether pylint should warn about no-member and similar
350 | # checks whenever an opaque object is returned when inferring. The inference
351 | # can return multiple potential results while evaluating a Python object, but
352 | # some branches might not be evaluated, which results in partial inference. In
353 | # that case, it might be useful to still emit no-member and other checks for
354 | # the rest of the inferred objects.
355 | ignore-on-opaque-inference=yes
356 |
357 | # List of class names for which member attributes should not be checked (useful
358 | # for classes with dynamically set attributes). This supports the use of
359 | # qualified names.
360 | ignored-classes=optparse.Values,thread._local,_thread._local
361 |
362 | # List of module names for which member attributes should not be checked
363 | # (useful for modules/projects where namespaces are manipulated during runtime
364 | # and thus existing member attributes cannot be deduced by static analysis). It
365 | # supports qualified module names, as well as Unix pattern matching.
366 | ignored-modules=
367 |
368 | # Show a hint with possible names when a member name was not found. The aspect
369 | # of finding the hint is based on edit distance.
370 | missing-member-hint=yes
371 |
372 | # The minimum edit distance a name should have in order to be considered a
373 | # similar match for a missing member name.
374 | missing-member-hint-distance=1
375 |
376 | # The total number of similar names that should be taken in consideration when
377 | # showing a hint for a missing member.
378 | missing-member-max-choices=1
379 |
380 | # List of decorators that change the signature of a decorated function.
381 | signature-mutators=
382 |
383 |
384 | [BASIC]
385 |
386 | # Naming style matching correct argument names.
387 | argument-naming-style=snake_case
388 |
389 | # Regular expression matching correct argument names. Overrides argument-
390 | # naming-style.
391 | #argument-rgx=
392 |
393 | # Naming style matching correct attribute names.
394 | attr-naming-style=snake_case
395 |
396 | # Regular expression matching correct attribute names. Overrides attr-naming-
397 | # style.
398 | #attr-rgx=
399 |
400 | # Bad variable names which should always be refused, separated by a comma.
401 | bad-names=foo,
402 | bar,
403 | baz,
404 | toto,
405 | tutu,
406 | tata
407 |
408 | # Bad variable names regexes, separated by a comma. If names match any regex,
409 | # they will always be refused
410 | bad-names-rgxs=
411 |
412 | # Naming style matching correct class attribute names.
413 | class-attribute-naming-style=any
414 |
415 | # Regular expression matching correct class attribute names. Overrides class-
416 | # attribute-naming-style.
417 | #class-attribute-rgx=
418 |
419 | # Naming style matching correct class constant names.
420 | class-const-naming-style=UPPER_CASE
421 |
422 | # Regular expression matching correct class constant names. Overrides class-
423 | # const-naming-style.
424 | #class-const-rgx=
425 |
426 | # Naming style matching correct class names.
427 | class-naming-style=PascalCase
428 |
429 | # Regular expression matching correct class names. Overrides class-naming-
430 | # style.
431 | #class-rgx=
432 |
433 | # Naming style matching correct constant names.
434 | const-naming-style=UPPER_CASE
435 |
436 | # Regular expression matching correct constant names. Overrides const-naming-
437 | # style.
438 | #const-rgx=
439 |
440 | # Minimum line length for functions/classes that require docstrings, shorter
441 | # ones are exempt.
442 | docstring-min-length=-1
443 |
444 | # Naming style matching correct function names.
445 | function-naming-style=snake_case
446 |
447 | # Regular expression matching correct function names. Overrides function-
448 | # naming-style.
449 | #function-rgx=
450 |
451 | # Good variable names which should always be accepted, separated by a comma.
452 | good-names=i,
453 | j,
454 | k,
455 | ex,
456 | Run,
457 | _
458 |
459 | # Good variable names regexes, separated by a comma. If names match any regex,
460 | # they will always be accepted
461 | good-names-rgxs=
462 |
463 | # Include a hint for the correct naming format with invalid-name.
464 | include-naming-hint=no
465 |
466 | # Naming style matching correct inline iteration names.
467 | inlinevar-naming-style=any
468 |
469 | # Regular expression matching correct inline iteration names. Overrides
470 | # inlinevar-naming-style.
471 | #inlinevar-rgx=
472 |
473 | # Naming style matching correct method names.
474 | method-naming-style=snake_case
475 |
476 | # Regular expression matching correct method names. Overrides method-naming-
477 | # style.
478 | #method-rgx=
479 |
480 | # Naming style matching correct module names.
481 | module-naming-style=snake_case
482 |
483 | # Regular expression matching correct module names. Overrides module-naming-
484 | # style.
485 | #module-rgx=
486 |
487 | # Colon-delimited sets of names that determine each other's naming style when
488 | # the name regexes allow several styles.
489 | name-group=
490 |
491 | # Regular expression which should only match function or class names that do
492 | # not require a docstring.
493 | no-docstring-rgx=^_
494 |
495 | # List of decorators that produce properties, such as abc.abstractproperty. Add
496 | # to this list to register other decorators that produce valid properties.
497 | # These decorators are taken in consideration only for invalid-name.
498 | property-classes=abc.abstractproperty
499 |
500 | # Naming style matching correct variable names.
501 | variable-naming-style=snake_case
502 |
503 | # Regular expression matching correct variable names. Overrides variable-
504 | # naming-style.
505 | #variable-rgx=
506 |
507 |
508 | [CLASSES]
509 |
510 | # Warn about protected attribute access inside special methods
511 | check-protected-access-in-special-methods=no
512 |
513 | # List of method names used to declare (i.e. assign) instance attributes.
514 | defining-attr-methods=__init__,
515 | __new__,
516 | setUp,
517 | __post_init__
518 |
519 | # List of member names, which should be excluded from the protected access
520 | # warning.
521 | exclude-protected=_asdict,
522 | _fields,
523 | _replace,
524 | _source,
525 | _make
526 |
527 | # List of valid names for the first argument in a class method.
528 | valid-classmethod-first-arg=cls
529 |
530 | # List of valid names for the first argument in a metaclass class method.
531 | valid-metaclass-classmethod-first-arg=cls
532 |
533 |
534 | [IMPORTS]
535 |
536 | # List of modules that can be imported at any level, not just the top level
537 | # one.
538 | allow-any-import-level=
539 |
540 | # Allow wildcard imports from modules that define __all__.
541 | allow-wildcard-with-all=no
542 |
543 | # Analyse import fallback blocks. This can be used to support both Python 2 and
544 | # 3 compatible code, which means that the block might have code that exists
545 | # only in one or another interpreter, leading to false positives when analysed.
546 | analyse-fallback-blocks=no
547 |
548 | # Deprecated modules which should not be used, separated by a comma.
549 | deprecated-modules=optparse,tkinter.tix
550 |
551 | # Output a graph (.gv or any supported image format) of external dependencies
552 | # to the given file (report RP0402 must not be disabled).
553 | ext-import-graph=
554 |
555 | # Output a graph (.gv or any supported image format) of all (i.e. internal and
556 | # external) dependencies to the given file (report RP0402 must not be
557 | # disabled).
558 | import-graph=
559 |
560 | # Output a graph (.gv or any supported image format) of internal dependencies
561 | # to the given file (report RP0402 must not be disabled).
562 | int-import-graph=
563 |
564 | # Force import order to recognize a module as part of the standard
565 | # compatibility libraries.
566 | known-standard-library=
567 |
568 | # Force import order to recognize a module as part of a third party library.
569 | known-third-party=enchant
570 |
571 | # Couples of modules and preferred modules, separated by a comma.
572 | preferred-modules=
573 |
574 |
575 | [DESIGN]
576 |
577 | # Maximum number of arguments for function / method.
578 | max-args=5
579 |
580 | # Maximum number of attributes for a class (see R0902).
581 | max-attributes=7
582 |
583 | # Maximum number of boolean expressions in an if statement (see R0916).
584 | max-bool-expr=5
585 |
586 | # Maximum number of branch for function / method body.
587 | max-branches=12
588 |
589 | # Maximum number of locals for function / method body.
590 | max-locals=15
591 |
592 | # Maximum number of parents for a class (see R0901).
593 | max-parents=7
594 |
595 | # Maximum number of public methods for a class (see R0904).
596 | max-public-methods=20
597 |
598 | # Maximum number of return / yield for function / method body.
599 | max-returns=6
600 |
601 | # Maximum number of statements in function / method body.
602 | max-statements=50
603 |
604 | # Minimum number of public methods for a class (see R0903).
605 | min-public-methods=1
606 |
607 |
608 | [EXCEPTIONS]
609 |
610 | # Exceptions that will emit a warning when being caught. Defaults to
611 | # "BaseException, Exception".
612 | overgeneral-exceptions=BaseException,
613 | Exception
614 |
--------------------------------------------------------------------------------