codeinsult 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- codeinsult/CodeInsult.py +107 -0
- codeinsult/__init__.py +13 -0
- codeinsult/__version__.py +4 -0
- codeinsult/config.py +33 -0
- codeinsult/messages/__init__.py +4 -0
- codeinsult/messages/base.py +78 -0
- codeinsult/messages/pt_br.py +457 -0
- codeinsult/messages/registry.py +34 -0
- codeinsult-0.1.0.dist-info/METADATA +113 -0
- codeinsult-0.1.0.dist-info/RECORD +13 -0
- codeinsult-0.1.0.dist-info/WHEEL +5 -0
- codeinsult-0.1.0.dist-info/licenses/LICENSE +21 -0
- codeinsult-0.1.0.dist-info/top_level.txt +1 -0
codeinsult/CodeInsult.py
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import random
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from codeinsult.config import InsultLevel
|
|
5
|
+
from codeinsult.messages.registry import available_languages, get_provider
|
|
6
|
+
|
|
7
|
+
_default_lang: str = "pt_br"
|
|
8
|
+
_default_level: Optional[InsultLevel] = None
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def set_defaults(
|
|
12
|
+
*,
|
|
13
|
+
lang: str = "pt_br",
|
|
14
|
+
level: Optional[str] = None,
|
|
15
|
+
) -> None:
|
|
16
|
+
"""Configura o idioma e nível de severidade padrão globais.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
lang: Idioma padrão (ex: ``"pt_br"``).
|
|
20
|
+
level: Nível de severidade padrão (``"light"``, ``"medium"``,
|
|
21
|
+
``"heavy"``). ``None`` para usar todos os níveis.
|
|
22
|
+
|
|
23
|
+
Example:
|
|
24
|
+
>>> codeinsult.set_defaults(lang="pt_br", level="light")
|
|
25
|
+
>>> codeinsult.insult(404) # usa pt_br + LIGHT
|
|
26
|
+
"""
|
|
27
|
+
global _default_lang, _default_level
|
|
28
|
+
if lang not in available_languages():
|
|
29
|
+
raise ValueError(
|
|
30
|
+
f"Idioma '{lang}' não disponível. Disponíveis: {available_languages()}"
|
|
31
|
+
)
|
|
32
|
+
_default_lang = lang
|
|
33
|
+
_default_level = InsultLevel.from_str(level)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def insult(
|
|
37
|
+
status_code: int,
|
|
38
|
+
*,
|
|
39
|
+
level: Optional[str] = None,
|
|
40
|
+
lang: Optional[str] = None,
|
|
41
|
+
) -> str:
|
|
42
|
+
"""
|
|
43
|
+
Retorna uma mensagem engraçada para o código de status HTTP informado.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
status_code: Código de status HTTP (ex: 200, 404, 500).
|
|
47
|
+
level: Nível de severidade (``"light"``, ``"medium"``, ``"heavy"``).
|
|
48
|
+
Se None, usa TODOS os níveis.
|
|
49
|
+
lang: Idioma (ex: ``"pt_br"``). Se None, usa ``"pt_br"``.
|
|
50
|
+
"""
|
|
51
|
+
parsed_level = InsultLevel.from_str(level) if level is not None else _default_level
|
|
52
|
+
lang = lang if lang is not None else _default_lang
|
|
53
|
+
|
|
54
|
+
provider = get_provider(lang)
|
|
55
|
+
messages = provider.get_messages(status_code, parsed_level)
|
|
56
|
+
|
|
57
|
+
if not messages:
|
|
58
|
+
if parsed_level is None:
|
|
59
|
+
messages = []
|
|
60
|
+
for lvl in InsultLevel:
|
|
61
|
+
messages.extend(provider.catalog.default_messages.get(lvl, []))
|
|
62
|
+
else:
|
|
63
|
+
messages = provider.catalog.default_messages.get(
|
|
64
|
+
parsed_level, ["Erro desconhecido."]
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
if not messages:
|
|
68
|
+
return f"Status {status_code}: sem mensagem disponível."
|
|
69
|
+
return random.choice(messages)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def random_insult(
|
|
73
|
+
*,
|
|
74
|
+
level: Optional[str] = None,
|
|
75
|
+
lang: Optional[str] = None,
|
|
76
|
+
) -> str:
|
|
77
|
+
"""
|
|
78
|
+
Retorna uma mensagem aleatória de qualquer status code disponível.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
level: Nível de severidade (``"light"``, ``"medium"``, ``"heavy"``).
|
|
82
|
+
Se None, usa TODOS os níveis.
|
|
83
|
+
lang: Idioma (ex: ``"pt_br"``). Se None, usa ``"pt_br"``.
|
|
84
|
+
"""
|
|
85
|
+
parsed_level = InsultLevel.from_str(level) if level is not None else _default_level
|
|
86
|
+
lang = lang if lang is not None else _default_lang
|
|
87
|
+
|
|
88
|
+
provider = get_provider(lang)
|
|
89
|
+
catalog = provider.catalog
|
|
90
|
+
|
|
91
|
+
# Coleta todas as mensagens
|
|
92
|
+
all_msgs: list[str] = []
|
|
93
|
+
if parsed_level is None:
|
|
94
|
+
for code_msgs in catalog.messages.values():
|
|
95
|
+
for lvl in InsultLevel:
|
|
96
|
+
all_msgs.extend(code_msgs.get(lvl, []))
|
|
97
|
+
else:
|
|
98
|
+
for code_msgs in catalog.messages.values():
|
|
99
|
+
all_msgs.extend(code_msgs.get(parsed_level, []))
|
|
100
|
+
|
|
101
|
+
if not all_msgs:
|
|
102
|
+
if parsed_level is None:
|
|
103
|
+
for lvl in InsultLevel:
|
|
104
|
+
all_msgs.extend(catalog.default_messages.get(lvl, []))
|
|
105
|
+
else:
|
|
106
|
+
all_msgs = catalog.default_messages.get(parsed_level, ["Nada a declarar."])
|
|
107
|
+
return random.choice(all_msgs)
|
codeinsult/__init__.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# codeinsult/__init__.py
|
|
2
|
+
import codeinsult.messages.pt_br # noqa: F401, F811
|
|
3
|
+
from codeinsult.__version__ import __version__
|
|
4
|
+
from codeinsult.CodeInsult import insult, random_insult, set_defaults
|
|
5
|
+
from codeinsult.messages.registry import available_languages
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"__version__",
|
|
9
|
+
"insult",
|
|
10
|
+
"random_insult",
|
|
11
|
+
"set_defaults",
|
|
12
|
+
"available_languages",
|
|
13
|
+
]
|
codeinsult/config.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class InsultLevel(Enum):
|
|
6
|
+
"""
|
|
7
|
+
Níveis de severidade das mensagens.
|
|
8
|
+
|
|
9
|
+
LIGHT — Referências leves a filmes, séries, livros, memes. Sem palavrões.
|
|
10
|
+
MEDIUM — Sarcasmo e ironia. Pode conter linguagem levemente ofensiva.
|
|
11
|
+
HEAVY — Insultos pesados, com palavrões e xingamentos explícitos.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
LIGHT = "light"
|
|
15
|
+
MEDIUM = "medium"
|
|
16
|
+
HEAVY = "heavy"
|
|
17
|
+
|
|
18
|
+
@classmethod
|
|
19
|
+
def from_str(cls, level: Optional[str]) -> Optional["InsultLevel"]:
|
|
20
|
+
"""
|
|
21
|
+
Converte uma string para ``InsultLevel``.
|
|
22
|
+
|
|
23
|
+
Aceita ``"light"``, ``"medium"``, ``"heavy"``.
|
|
24
|
+
``None`` retorna ``None``.
|
|
25
|
+
"""
|
|
26
|
+
if level is None:
|
|
27
|
+
return None
|
|
28
|
+
try:
|
|
29
|
+
return cls(level.lower())
|
|
30
|
+
except ValueError:
|
|
31
|
+
raise ValueError(
|
|
32
|
+
f"Nível '{level}' inválido. Use: light, medium, heavy."
|
|
33
|
+
) from None
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from typing import Dict, List, Optional
|
|
4
|
+
|
|
5
|
+
from codeinsult.config import InsultLevel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class MessageCatalog:
|
|
10
|
+
"""
|
|
11
|
+
Catálogo de mensagens para um idioma.
|
|
12
|
+
|
|
13
|
+
Estrutura:
|
|
14
|
+
messages[status_code][InsultLevel] = [lista de frases]
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
lang: str
|
|
18
|
+
lang_name: str
|
|
19
|
+
messages: Dict[int, Dict[InsultLevel, List[str]]] = field(default_factory=dict)
|
|
20
|
+
default_messages: Dict[InsultLevel, List[str]] = field(default_factory=dict)
|
|
21
|
+
|
|
22
|
+
def get_messages(self, status_code: int, level: Optional[InsultLevel]) -> List[str]:
|
|
23
|
+
"""
|
|
24
|
+
Retorna as mensagens para um status code e nível.
|
|
25
|
+
Se level for None, retorna mensagens de TODOS os níveis.
|
|
26
|
+
Se não houver mensagens específicas, retorna as padrão.
|
|
27
|
+
"""
|
|
28
|
+
if level is None:
|
|
29
|
+
# Coleta mensagens de todos os níveis
|
|
30
|
+
code_msgs = self.messages.get(status_code, {})
|
|
31
|
+
msgs: List[str] = []
|
|
32
|
+
for lvl in InsultLevel:
|
|
33
|
+
msgs.extend(code_msgs.get(lvl, []))
|
|
34
|
+
if not msgs:
|
|
35
|
+
for lvl in InsultLevel:
|
|
36
|
+
msgs.extend(self.default_messages.get(lvl, []))
|
|
37
|
+
return msgs
|
|
38
|
+
|
|
39
|
+
code_msgs = self.messages.get(status_code, {})
|
|
40
|
+
msgs = code_msgs.get(level, [])
|
|
41
|
+
if not msgs:
|
|
42
|
+
msgs = self.default_messages.get(level, [])
|
|
43
|
+
return msgs
|
|
44
|
+
|
|
45
|
+
def has_messages(self, status_code: int, level: Optional[InsultLevel]) -> bool:
|
|
46
|
+
"""Verifica se existem mensagens para o status e nível."""
|
|
47
|
+
if level is None:
|
|
48
|
+
code_msgs = self.messages.get(status_code, {})
|
|
49
|
+
return any(code_msgs.get(lvl, []) for lvl in InsultLevel)
|
|
50
|
+
return bool(self.messages.get(status_code, {}).get(level, []))
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class BaseMessageProvider(ABC):
|
|
54
|
+
"""
|
|
55
|
+
Provider abstrato — cada idioma implementa um provider concreto.
|
|
56
|
+
|
|
57
|
+
Para adicionar um novo idioma:
|
|
58
|
+
|
|
59
|
+
class EnUSProvider(BaseMessageProvider):
|
|
60
|
+
@property
|
|
61
|
+
def catalog(self) -> MessageCatalog:
|
|
62
|
+
return _EN_US_CATALOG
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
@abstractmethod
|
|
67
|
+
def catalog(self) -> MessageCatalog:
|
|
68
|
+
"""Retorna o catálogo de mensagens para este idioma."""
|
|
69
|
+
...
|
|
70
|
+
|
|
71
|
+
@classmethod
|
|
72
|
+
@abstractmethod
|
|
73
|
+
def lang_code(cls) -> str:
|
|
74
|
+
"""Código do idioma (ex: 'pt_BR', 'en_US')."""
|
|
75
|
+
...
|
|
76
|
+
|
|
77
|
+
def get_messages(self, status_code: int, level: Optional[InsultLevel]) -> List[str]:
|
|
78
|
+
return self.catalog.get_messages(status_code, level)
|
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Catálogo de mensagens em Português Brasileiro (pt_BR).
|
|
3
|
+
|
|
4
|
+
Mensagens organizadas por:
|
|
5
|
+
- Código de status HTTP
|
|
6
|
+
- Nível de severidade (LIGHT, MEDIUM, HEAVY)
|
|
7
|
+
|
|
8
|
+
Referências incluem:
|
|
9
|
+
- Filmes: Star Wars, Matrix, Senhor dos Anéis, Tropa de Elite, Vingadores,
|
|
10
|
+
Harry Potter, Auto da Compadecida, Clube da Luta, De Volta para o Futuro,
|
|
11
|
+
Jurassic Park, O Poderoso Chefão, etc.
|
|
12
|
+
- Séries: Breaking Bad, Game of Thrones, The Office, Chaves, Chapolin,
|
|
13
|
+
Rick and Morty, Stranger Things, Black Mirror.
|
|
14
|
+
- Livros: 1984, Guia do Mochileiro das Galáxias, Duna.
|
|
15
|
+
- Memes brasileiros: Nazaré Confusa, "Pode pá", Gretchen, etc.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from codeinsult.config import InsultLevel
|
|
19
|
+
from codeinsult.messages.base import BaseMessageProvider, MessageCatalog
|
|
20
|
+
from codeinsult.messages.registry import register_provider
|
|
21
|
+
|
|
22
|
+
_STATUS_MESSAGES = {
|
|
23
|
+
# ═══ 2xx — Success ═══════════════════════════════════════════════════════════
|
|
24
|
+
200: {
|
|
25
|
+
InsultLevel.LIGHT: [
|
|
26
|
+
"Tudo certo, nada errado — e isso é raro o suficiente pra comemorar.",
|
|
27
|
+
"Deu bom! Até o Paulo Guedes aprovaria esse request.",
|
|
28
|
+
"200 OK: a paz reina neste reino. Por enquanto.",
|
|
29
|
+
'Como diria o Chapolin: "Não contavam com minha astúcia!" — Funcionou!',
|
|
30
|
+
"Sucesso. Até o Homer Simpson conseguiu. D'oh! ...quer dizer, Woo-hoo!",
|
|
31
|
+
"Status 200: o equivalente digital de um 'bom dia' sincero.",
|
|
32
|
+
],
|
|
33
|
+
InsultLevel.MEDIUM: [
|
|
34
|
+
"200 OK. Parabéns, você fez o mínimo. Quer um biscoito?",
|
|
35
|
+
"Funcionou. Vai comemorar ou vai continuar programando?",
|
|
36
|
+
"OK. Dessa vez. Mas não se acostume.",
|
|
37
|
+
"Sucesso absoluto. Até parece que foi de propósito.",
|
|
38
|
+
],
|
|
39
|
+
InsultLevel.HEAVY: [
|
|
40
|
+
"200? CARALHO, FUNCIONOU! Tira print e emoldura essa porra!",
|
|
41
|
+
"Deu certo, cacete! Deve ser bug. Testa de novo.",
|
|
42
|
+
"200 OK, seus lindos! Quem disse que código não presta?",
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
201: {
|
|
46
|
+
InsultLevel.LIGHT: [
|
|
47
|
+
"Criado com sucesso! Dr. Frankenstein ficaria orgulhoso.",
|
|
48
|
+
"201 Created: Nasceu! Já pode registrar no cartório digital.",
|
|
49
|
+
'"É um menino!" — e pesa 2.4 kilobytes.',
|
|
50
|
+
],
|
|
51
|
+
InsultLevel.MEDIUM: [
|
|
52
|
+
"Criado. Agora é sua responsabilidade. Não me culpe depois.",
|
|
53
|
+
"Recurso criado com sucesso. Já já alguém deleta.",
|
|
54
|
+
],
|
|
55
|
+
InsultLevel.HEAVY: [
|
|
56
|
+
"CRIADO, PORRA! Parabéns, você deu à luz um JSON!",
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
202: {
|
|
60
|
+
InsultLevel.LIGHT: [
|
|
61
|
+
"202 Accepted: O servidor aceitou... mas vai fazer quando? Só Deus sabe.",
|
|
62
|
+
"Recebido! Agora é sentar e esperar. Tipo processo na justiça brasileira.",
|
|
63
|
+
'Como diz o Guia do Mochileiro: "Não entre em pânico". Mas também não respire aliviado.',
|
|
64
|
+
],
|
|
65
|
+
InsultLevel.MEDIUM: [
|
|
66
|
+
"Aceito. Mas processar mesmo, só quando o servidor estiver de bom humor.",
|
|
67
|
+
"202: a versão digital do 'vou ver e te aviso'.",
|
|
68
|
+
],
|
|
69
|
+
InsultLevel.HEAVY: [
|
|
70
|
+
"Aceitou mas não processou. Igual promessa de político em ano eleitoral.",
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
204: {
|
|
74
|
+
InsultLevel.LIGHT: [
|
|
75
|
+
"204 No Content: O silêncio ensurdecedor do servidor. Nada a declarar.",
|
|
76
|
+
"Sem conteúdo. Igual o novo episódio de The Office que você já viu 40 vezes.",
|
|
77
|
+
"Vazio. Como o vácuo do espaço. Bowie estaria orgulhoso.",
|
|
78
|
+
],
|
|
79
|
+
InsultLevel.MEDIUM: [
|
|
80
|
+
"Nada. Zero. Null. Void. Quer uma mensagem? Não tem.",
|
|
81
|
+
"204: o servidor te deu um ghosting educado.",
|
|
82
|
+
],
|
|
83
|
+
InsultLevel.HEAVY: [
|
|
84
|
+
"NADA. O servidor respondeu o equivalente a um vácuo no WhatsApp.",
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
# ═══ 3xx — Redirection ══════════════════════════════════════════════════════
|
|
88
|
+
301: {
|
|
89
|
+
InsultLevel.LIGHT: [
|
|
90
|
+
'301: "Não estou mais aqui. Mudei. Supere." — Gandalf, depois de cair no abismo.',
|
|
91
|
+
"Redirecionamento permanente. Como o Michael Scott mudando de emprego. De novo.",
|
|
92
|
+
"Mudou pra sempre. Tipo quando o Orkut virou Facebook.",
|
|
93
|
+
],
|
|
94
|
+
InsultLevel.MEDIUM: [
|
|
95
|
+
"Mudou permanentemente. Assim como sua sanidade depois desse projeto.",
|
|
96
|
+
"301: pegue suas coisas e vá pra URL nova. Não volte.",
|
|
97
|
+
],
|
|
98
|
+
InsultLevel.HEAVY: [
|
|
99
|
+
"Mudou de vez, irmão. Para de bater na porta errada!",
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
302: {
|
|
103
|
+
InsultLevel.LIGHT: [
|
|
104
|
+
'302 Found: "Achei, mas não era bem aqui... tenta ali."',
|
|
105
|
+
"Redirecionamento temporário. Igual o Brasil na fila do pão.",
|
|
106
|
+
],
|
|
107
|
+
InsultLevel.MEDIUM: [
|
|
108
|
+
"Temporariamente movido. Tipo sua motivação às 18h de sexta.",
|
|
109
|
+
],
|
|
110
|
+
InsultLevel.HEAVY: [
|
|
111
|
+
"Vai pra lá, mas volta depois! Não é mudança, é passeio, cacete!",
|
|
112
|
+
],
|
|
113
|
+
},
|
|
114
|
+
304: {
|
|
115
|
+
InsultLevel.LIGHT: [
|
|
116
|
+
"304 Not Modified: Tá igualzinho. Nem uma ruga nova.",
|
|
117
|
+
"Não mudou nada. Dorian Gray aprovaria essa resposta.",
|
|
118
|
+
],
|
|
119
|
+
InsultLevel.MEDIUM: [
|
|
120
|
+
"Não modificado. Igual seu código desde o commit da semana passada.",
|
|
121
|
+
"304: a mesma coisa de sempre. E você esperava algo diferente?",
|
|
122
|
+
],
|
|
123
|
+
InsultLevel.HEAVY: [
|
|
124
|
+
"Não mudou PORRA NENHUMA. Cache tá aí pra isso, animal.",
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
# ═══ 4xx — Client Error ═════════════════════════════════════════════════════
|
|
128
|
+
400: {
|
|
129
|
+
InsultLevel.LIGHT: [
|
|
130
|
+
"400 Bad Request: O servidor olhou pro seu request e fez cara de Nazaré confusa.",
|
|
131
|
+
'"Isso não é um request, é um atentado à sintaxe." — O servidor, provavelmente.',
|
|
132
|
+
"Bad Request. Nem o ChatGPT entenderia o que você mandou.",
|
|
133
|
+
"400: O request tá tão torto que o Chapolin tropeçaria nele.",
|
|
134
|
+
],
|
|
135
|
+
InsultLevel.MEDIUM: [
|
|
136
|
+
"Request ruim. Tenta de novo, mas dessa vez com coerência.",
|
|
137
|
+
"400: Seu JSON veio mais quebrado que promessa de ano novo em janeiro.",
|
|
138
|
+
"O servidor entendeu... mas fingiu que não. Faz direito.",
|
|
139
|
+
],
|
|
140
|
+
InsultLevel.HEAVY: [
|
|
141
|
+
"QUE REQUEST DE MERDA É ESSE? Nem o Google Tradutor salva essa bagunça!",
|
|
142
|
+
"400: Tá de sacanagem? Isso aqui não é request, é lixo digital!",
|
|
143
|
+
"Bicho, teu request tá mais feio que briga de cachorro por comida!",
|
|
144
|
+
],
|
|
145
|
+
},
|
|
146
|
+
401: {
|
|
147
|
+
InsultLevel.LIGHT: [
|
|
148
|
+
'401 Unauthorized: "Você não vai passar!" — Gandalf, Servidor Edition.',
|
|
149
|
+
"Não autorizado. Senha errada. Ou você, ou sua tia, ou os dois.",
|
|
150
|
+
"401: O servidor pediu identidade e você mostrou a carteirinha do Clube do Bolinha.",
|
|
151
|
+
'"Essa não é a credencial que você está procurando." — Obi-Wan Kenobi',
|
|
152
|
+
],
|
|
153
|
+
InsultLevel.MEDIUM: [
|
|
154
|
+
"Não autorizado. Nem adianta fazer charme. Cadê o token?",
|
|
155
|
+
"401: sem senha, sem festa. Regras da casa.",
|
|
156
|
+
"Você não tem permissão. Nem o Darth Vader conseguiria acessar sem o token.",
|
|
157
|
+
],
|
|
158
|
+
InsultLevel.HEAVY: [
|
|
159
|
+
"TU NÃO TEM AUTORIZAÇÃO, ANIMAL! Quer entrar sem crachá? Tá na Disney?",
|
|
160
|
+
"401: Senha errada, seu cabeça de bagre! Quer que eu desenhe um login?",
|
|
161
|
+
],
|
|
162
|
+
},
|
|
163
|
+
403: {
|
|
164
|
+
InsultLevel.LIGHT: [
|
|
165
|
+
'403 Forbidden: "Isso é território proibido." — Mufasa, apontando pras terras sombrias.',
|
|
166
|
+
"Proibido! Nem o Harry Potter sem capa de invisibilidade entra aqui.",
|
|
167
|
+
"403: O servidor sabe quem você é. Só não gosta de você mesmo.",
|
|
168
|
+
"Acesso negado. Tipo aquele rolê que você não foi convidado.",
|
|
169
|
+
],
|
|
170
|
+
InsultLevel.MEDIUM: [
|
|
171
|
+
"Proibido. Não é falta de senha — é falta de credenciais. E talvez de caráter.",
|
|
172
|
+
"403: Você até tem senha, mas ninguém aqui vai abrir a porta.",
|
|
173
|
+
"Forbidden. Nem que você fosse o Keanu Reeves. (Ok, talvez ele pudesse.)",
|
|
174
|
+
],
|
|
175
|
+
InsultLevel.HEAVY: [
|
|
176
|
+
"PROIBIDO, CARALHO! Sai daqui! Nem Jesus Cristo entra sem autorização!",
|
|
177
|
+
"403: Não, não e NÃO! Tá surdo? Volta pro teu setor!",
|
|
178
|
+
],
|
|
179
|
+
},
|
|
180
|
+
404: {
|
|
181
|
+
InsultLevel.LIGHT: [
|
|
182
|
+
'404 Not Found: "Procurei em toda galáxia e não achei." — Baby Yoda.',
|
|
183
|
+
"404: O recurso sumiu. Como meias na máquina de lavar.",
|
|
184
|
+
"Não encontrado. Igual o Sétimo Sentido da deep web. Simplesmente não existe.",
|
|
185
|
+
'"O que você procura não está aqui." — Yoda, servindo HTTP.',
|
|
186
|
+
"404: Nem a Nazaré conseguiu achar. E olha que ela é confusa, não cega.",
|
|
187
|
+
],
|
|
188
|
+
InsultLevel.MEDIUM: [
|
|
189
|
+
"404: Não tá aqui. Não tá em lugar nenhum. Para de insistir.",
|
|
190
|
+
"Not Found. Igual a paciência do tech lead depois do deploy de sexta.",
|
|
191
|
+
"404: Isso não existe. E se existiu, já era. Supera.",
|
|
192
|
+
"Perdido como agulha no palheiro. Só que o palheiro também não existe.",
|
|
193
|
+
],
|
|
194
|
+
InsultLevel.HEAVY: [
|
|
195
|
+
"NÃO ACHEI, PORRA! Para de bater nessa URL que já morreu!",
|
|
196
|
+
"404: TÁ PROCURANDO O QUÊ, DESGRAÇA? Isso aqui já era! Foi de arrasta!",
|
|
197
|
+
"Perdido que nem virgindade em festa de faculdade de TI. Inexiste.",
|
|
198
|
+
],
|
|
199
|
+
},
|
|
200
|
+
405: {
|
|
201
|
+
InsultLevel.LIGHT: [
|
|
202
|
+
"405: GET onde era pra ser POST. É tipo tentar abrir uma porta empurrando quando era pra puxar.",
|
|
203
|
+
"Método não permitido. Como diria Raul Seixas: 'Tenta outra vez!'",
|
|
204
|
+
"405: 'Não é assim que se faz.' — Joel Santana, explicando HTTP.",
|
|
205
|
+
],
|
|
206
|
+
InsultLevel.MEDIUM: [
|
|
207
|
+
"Método errado, campeão. GET ≠ POST ≠ PUT ≠ DELETE. Tão difícil?",
|
|
208
|
+
"405: Você tá tentando enfiar um quadrado num buraco redondo.",
|
|
209
|
+
],
|
|
210
|
+
InsultLevel.HEAVY: [
|
|
211
|
+
"MÉTODO ERRADO, ANIMAL! Quer fazer DELETE num GET? Tá maluco?!",
|
|
212
|
+
],
|
|
213
|
+
},
|
|
214
|
+
408: {
|
|
215
|
+
InsultLevel.LIGHT: [
|
|
216
|
+
"408 Request Timeout: 'O tempo é uma ilusão.' — Einstein. Mas o timeout é real.",
|
|
217
|
+
"Demorou mais que intervalo do Lula pra responder pergunta de repórter.",
|
|
218
|
+
"Timeout: o servidor cansou de esperar. Foi tomar um café.",
|
|
219
|
+
],
|
|
220
|
+
InsultLevel.MEDIUM: [
|
|
221
|
+
"Timeout. Demorou tanto que o servidor já viu todas as temporadas de Friends.",
|
|
222
|
+
"408: Você perdeu a janela. Literalmente.",
|
|
223
|
+
],
|
|
224
|
+
InsultLevel.HEAVY: [
|
|
225
|
+
"DEMOROU, PORRA! O servidor já morreu de velho esperando!",
|
|
226
|
+
"408: Ô lesma, o timeout estourou! Tá usando internet discada?",
|
|
227
|
+
],
|
|
228
|
+
},
|
|
229
|
+
409: {
|
|
230
|
+
InsultLevel.LIGHT: [
|
|
231
|
+
'409 Conflict: "Só pode haver um!" — Highlander.',
|
|
232
|
+
"Conflito! Dois requests brigando pelo mesmo recurso. Que feio.",
|
|
233
|
+
"409: Briga de foice no escuro. Ninguém ganha.",
|
|
234
|
+
],
|
|
235
|
+
InsultLevel.MEDIUM: [
|
|
236
|
+
"Conflito de dados. Igual dois devs editando a mesma linha no Git.",
|
|
237
|
+
"409: Alguém chegou primeiro. Aceita que dói menos.",
|
|
238
|
+
],
|
|
239
|
+
InsultLevel.HEAVY: [
|
|
240
|
+
"CONFLITO, CACETE! Resolve essa treta aí antes de mandar de novo!",
|
|
241
|
+
],
|
|
242
|
+
},
|
|
243
|
+
410: {
|
|
244
|
+
InsultLevel.LIGHT: [
|
|
245
|
+
'410 Gone: "Foi. Não volta mais." — Thanos, depois do estalo.',
|
|
246
|
+
"Esse recurso já era. Foi de Americanas. Não volta nunca mais.",
|
|
247
|
+
"410: Deletado permanentemente. Igual sua conta do Fotolog.",
|
|
248
|
+
],
|
|
249
|
+
InsultLevel.MEDIUM: [
|
|
250
|
+
"Gone. Não adianta chorar. O recurso foi morar no céu dos bytes.",
|
|
251
|
+
"410: Isso morreu. Faz um velório e segue a vida.",
|
|
252
|
+
],
|
|
253
|
+
InsultLevel.HEAVY: [
|
|
254
|
+
"JÁ ERA, PORRA! Foi de arrasta pra cima! Não insiste!",
|
|
255
|
+
],
|
|
256
|
+
},
|
|
257
|
+
413: {
|
|
258
|
+
InsultLevel.LIGHT: [
|
|
259
|
+
"413 Content Too Large: 'Isso é grande demais até pra mim.' — Seu Madruga.",
|
|
260
|
+
"Payload muito grande. Nem o Flash entregaria isso a tempo.",
|
|
261
|
+
"413: Seu request tá mais pesado que o SPC do brasileiro médio.",
|
|
262
|
+
],
|
|
263
|
+
InsultLevel.MEDIUM: [
|
|
264
|
+
"Conteúdo grande demais. Isso é um request ou um dump do Instagram?",
|
|
265
|
+
"413: Tá mandando a Wikipedia inteira? Divide isso aí.",
|
|
266
|
+
],
|
|
267
|
+
InsultLevel.HEAVY: [
|
|
268
|
+
"TA MANDANDO O QUÊ, A BÍBLIA EM JSON?! Divide essa porra!",
|
|
269
|
+
],
|
|
270
|
+
},
|
|
271
|
+
414: {
|
|
272
|
+
InsultLevel.LIGHT: [
|
|
273
|
+
"414 URI Too Long: A URL tá maior que nome de família real europeia.",
|
|
274
|
+
"Essa URL é mais longa que filme do senhor dos anéis versão estendida.",
|
|
275
|
+
],
|
|
276
|
+
InsultLevel.MEDIUM: [
|
|
277
|
+
"URI muito longa. Isso é URL ou CPF com dígito verificador?",
|
|
278
|
+
],
|
|
279
|
+
InsultLevel.HEAVY: [
|
|
280
|
+
"TÁ DE SACANAGEM COM ESSA URL GIGANTE? Isso é request ou bíblia?!",
|
|
281
|
+
],
|
|
282
|
+
},
|
|
283
|
+
415: {
|
|
284
|
+
InsultLevel.LIGHT: [
|
|
285
|
+
"415 Unsupported Media Type: O servidor não fala esse idioma.",
|
|
286
|
+
'"Isso não é JSON." — O servidor, olhando com desprezo pro seu XML.',
|
|
287
|
+
],
|
|
288
|
+
InsultLevel.MEDIUM: [
|
|
289
|
+
"Formato não suportado. O servidor não sabe ler hieróglifos.",
|
|
290
|
+
"415: Tá mandando o quê, um .doc do Word 97?",
|
|
291
|
+
],
|
|
292
|
+
InsultLevel.HEAVY: [
|
|
293
|
+
"QUE FORMATO É ESSE, ANIMAL? Manda JSON ou cai fora!",
|
|
294
|
+
],
|
|
295
|
+
},
|
|
296
|
+
418: {
|
|
297
|
+
InsultLevel.LIGHT: [
|
|
298
|
+
"418 I'm a Teapot: Sou um bule, não uma cafeteira. Respeita minha profissão!",
|
|
299
|
+
'418: "Sou um bule, pô!" — O servidor, indignado com seu pedido de café.',
|
|
300
|
+
"I'm a teapot. Essa é a melhor resposta HTTP já inventada. Change my mind.",
|
|
301
|
+
],
|
|
302
|
+
InsultLevel.MEDIUM: [
|
|
303
|
+
"Sou um bule, não um engenheiro de software. Café? Ali na esquina.",
|
|
304
|
+
"418: o servidor decidiu que hoje ele é um bule. Respeita.",
|
|
305
|
+
],
|
|
306
|
+
InsultLevel.HEAVY: [
|
|
307
|
+
"SOU UM BULE, CARALHO! Quer café? Vai no Starbucks!",
|
|
308
|
+
],
|
|
309
|
+
},
|
|
310
|
+
422: {
|
|
311
|
+
InsultLevel.LIGHT: [
|
|
312
|
+
"422 Unprocessable: O JSON tá certo, mas a lógica... a lógica é triste.",
|
|
313
|
+
'422: "Faz sentido... mas não." — O servidor, coçando a cabeça.',
|
|
314
|
+
],
|
|
315
|
+
InsultLevel.MEDIUM: [
|
|
316
|
+
"422: Sintaxe ok, semântica ridícula. Tenta de novo.",
|
|
317
|
+
"Inprocessável. Tipo entender a trama de Dark de primeira.",
|
|
318
|
+
],
|
|
319
|
+
InsultLevel.HEAVY: [
|
|
320
|
+
"ISSO AÍ NÃO DÁ PRA PROCESSAR, JUMENTO! A sintaxe tá boa, mas a ideia é horrível!",
|
|
321
|
+
],
|
|
322
|
+
},
|
|
323
|
+
429: {
|
|
324
|
+
InsultLevel.LIGHT: [
|
|
325
|
+
"429 Too Many Requests: Calma, ansioso! O servidor não é sua mãe.",
|
|
326
|
+
'429: "Desacelera, campeão." — Ayrton Senna, se fosse servidor HTTP.',
|
|
327
|
+
"Muitos requests. O servidor tá tipo: 'pera aí, respira, conta até 10'.",
|
|
328
|
+
],
|
|
329
|
+
InsultLevel.MEDIUM: [
|
|
330
|
+
"Calma aí, Flash. Dá um tempo entre os requests, tá floodando.",
|
|
331
|
+
"429: Você foi bloqueado. Não pelo conteúdo, mas pela insistência chata.",
|
|
332
|
+
],
|
|
333
|
+
InsultLevel.HEAVY: [
|
|
334
|
+
"PARA DE ESPAMAR, DESGRAÇA! Isso não é boteco, tem limite!",
|
|
335
|
+
"429: Tá achando que aqui é farra? Toma um cooldown e volta depois!",
|
|
336
|
+
],
|
|
337
|
+
},
|
|
338
|
+
# ═══ 5xx — Server Error ═════════════════════════════════════════════════════
|
|
339
|
+
500: {
|
|
340
|
+
InsultLevel.LIGHT: [
|
|
341
|
+
'500 Internal Server Error: "Houston, nós temos um problema." — Apollo 13.',
|
|
342
|
+
"500: O servidor quebrou. Mas a culpa é do estagiário, sempre.",
|
|
343
|
+
"Erro interno. 'Isso é trabalho pro Chapolin Colorado!'",
|
|
344
|
+
"500: O servidor tá tipo 'não sei o que aconteceu, mas foi feio'.",
|
|
345
|
+
],
|
|
346
|
+
InsultLevel.MEDIUM: [
|
|
347
|
+
"Erro interno. Alguém commitou no sábado à noite, né?",
|
|
348
|
+
"500: O servidor teve um treco. Tenta de novo quando ele se recuperar.",
|
|
349
|
+
"Internal Server Error. Tradução: 'deu ruim e não sei explicar'.",
|
|
350
|
+
],
|
|
351
|
+
InsultLevel.HEAVY: [
|
|
352
|
+
"DEU MERDA NO SERVIDOR! Não foi você, foi a gente. Mas foi você também.",
|
|
353
|
+
"500: PUTA QUE PARIU, QUEBROU TUDO! Corre que o servidor explodiu!",
|
|
354
|
+
"Erro interno. Se prepare que o tech lead vai vir xingar todo mundo.",
|
|
355
|
+
],
|
|
356
|
+
},
|
|
357
|
+
501: {
|
|
358
|
+
InsultLevel.LIGHT: [
|
|
359
|
+
"501 Not Implemented: 'Um dia a gente chega lá.' — Criança Esperança.",
|
|
360
|
+
"Não implementado. Tá no backlog desde 2019.",
|
|
361
|
+
"501: O dev disse que ia fazer. Disse...",
|
|
362
|
+
],
|
|
363
|
+
InsultLevel.MEDIUM: [
|
|
364
|
+
"Não implementado. A feature ficou no 'vou ver e te aviso' eterno.",
|
|
365
|
+
"501: Isso aqui ainda não existe. Quem sabe no próximo sprint.",
|
|
366
|
+
],
|
|
367
|
+
InsultLevel.HEAVY: [
|
|
368
|
+
"NÃO FIZEMOS ESSA MERDA AINDA! Tá no Jira, paciência!",
|
|
369
|
+
],
|
|
370
|
+
},
|
|
371
|
+
502: {
|
|
372
|
+
InsultLevel.LIGHT: [
|
|
373
|
+
"502 Bad Gateway: O intermediário fez besteira. Culpa do meio-campo.",
|
|
374
|
+
"Bad Gateway: o proxy recebeu uma resposta que não entendeu. Tipo eu com física quântica.",
|
|
375
|
+
'502: "O mensageiro foi morto." — Game of Thrones, temporada do proxy.',
|
|
376
|
+
],
|
|
377
|
+
InsultLevel.MEDIUM: [
|
|
378
|
+
"502: O gateway tomou uma resposta torta e não soube lidar. Terapia já!",
|
|
379
|
+
"Bad Gateway. Nem o servidor, nem o proxy. Os dois a 80km/h.",
|
|
380
|
+
],
|
|
381
|
+
InsultLevel.HEAVY: [
|
|
382
|
+
"O GATEWAY CAGOU NO PAU! A resposta veio toda errada e ele engoliu!",
|
|
383
|
+
],
|
|
384
|
+
},
|
|
385
|
+
503: {
|
|
386
|
+
InsultLevel.LIGHT: [
|
|
387
|
+
"503 Service Unavailable: 'Voltei, mas não pra sempre.' — Crashed.",
|
|
388
|
+
"Serviço indisponível. O servidor tirou férias. Mercado Pago feelings.",
|
|
389
|
+
"503: O servidor foi dormir. Tenta amanhã, ou depois, ou nunca.",
|
|
390
|
+
],
|
|
391
|
+
InsultLevel.MEDIUM: [
|
|
392
|
+
"Indisponível. Deve ser hora do cafezinho do datacenter.",
|
|
393
|
+
"503: O servidor cansou. Todo mundo tem limite.",
|
|
394
|
+
],
|
|
395
|
+
InsultLevel.HEAVY: [
|
|
396
|
+
"CAIU, PORRA! O servidor foi de base! Liga pro NOC, rápido!",
|
|
397
|
+
"503: Serviço morreu. Quem mandou fazer deploy na sexta-feira?",
|
|
398
|
+
],
|
|
399
|
+
},
|
|
400
|
+
504: {
|
|
401
|
+
InsultLevel.LIGHT: [
|
|
402
|
+
"504 Gateway Timeout: O proxy cansou de esperar. Foi embora.",
|
|
403
|
+
'Gateway Timeout: "A espera acabou." — Django Livre, versão HTTP.',
|
|
404
|
+
"504: Demorou tanto que o gateway foi ver se tava chovendo.",
|
|
405
|
+
],
|
|
406
|
+
InsultLevel.MEDIUM: [
|
|
407
|
+
"Timeout no gateway. O proxy esperou, esperou, e disse: 'cansei'.",
|
|
408
|
+
"504: Resposta não veio. O gateway já fez as malas e foi pra casa.",
|
|
409
|
+
],
|
|
410
|
+
InsultLevel.HEAVY: [
|
|
411
|
+
"O GATEWAY ESPEROU ATÉ CRIAR BARBA E NADA! Timeout, cacete!",
|
|
412
|
+
],
|
|
413
|
+
},
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
# ── Default / Fallback messages ───────────────────────────────────────────────
|
|
417
|
+
|
|
418
|
+
_DEFAULT_MESSAGES = {
|
|
419
|
+
InsultLevel.LIGHT: [
|
|
420
|
+
"Resposta inesperada. Mas ei, pelo menos não é 500.",
|
|
421
|
+
'"A vida é como uma caixa de chocolates..." — mas esse status code não é um chocolate bom.',
|
|
422
|
+
],
|
|
423
|
+
InsultLevel.MEDIUM: [
|
|
424
|
+
"Status code estranho. Você tá inventando código novo?",
|
|
425
|
+
"Isso é um código HTTP ou você tá digitando aleatório?",
|
|
426
|
+
],
|
|
427
|
+
InsultLevel.HEAVY: [
|
|
428
|
+
"QUE STATUS CODE É ESSE, ANIMAL? Tá tirando da cartola?!",
|
|
429
|
+
"Isso não é HTTP, é hieróglifo. Para de inventar código!",
|
|
430
|
+
],
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
# ── Catalog ───────────────────────────────────────────────────────────────────
|
|
434
|
+
|
|
435
|
+
PT_BR_CATALOG = MessageCatalog(
|
|
436
|
+
lang="pt_br",
|
|
437
|
+
lang_name="Português Brasileiro",
|
|
438
|
+
messages=_STATUS_MESSAGES,
|
|
439
|
+
default_messages=_DEFAULT_MESSAGES,
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
class PtBRProvider(BaseMessageProvider):
|
|
444
|
+
"""
|
|
445
|
+
Provider de mensagens em Português Brasileiro.
|
|
446
|
+
"""
|
|
447
|
+
|
|
448
|
+
@property
|
|
449
|
+
def catalog(self) -> MessageCatalog:
|
|
450
|
+
return PT_BR_CATALOG
|
|
451
|
+
|
|
452
|
+
@classmethod
|
|
453
|
+
def lang_code(cls) -> str:
|
|
454
|
+
return "pt_br"
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
register_provider(PtBRProvider)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from codeinsult.messages.base import BaseMessageProvider
|
|
2
|
+
|
|
3
|
+
_registry: dict[str, BaseMessageProvider] = {}
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def register_provider(provider_cls: type[BaseMessageProvider]) -> None:
|
|
7
|
+
"""
|
|
8
|
+
Registra um novo provider de idioma.
|
|
9
|
+
|
|
10
|
+
Exemplo:
|
|
11
|
+
class EnUSProvider(BaseMessageProvider):
|
|
12
|
+
...
|
|
13
|
+
|
|
14
|
+
register_provider(EnUSProvider)
|
|
15
|
+
"""
|
|
16
|
+
if not issubclass(provider_cls, BaseMessageProvider):
|
|
17
|
+
raise TypeError(f"{provider_cls} must be a subclass of BaseMessageProvider")
|
|
18
|
+
_registry[provider_cls.lang_code()] = provider_cls()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_provider(lang: str) -> BaseMessageProvider:
|
|
22
|
+
"""Retorna o provider para o idioma especificado."""
|
|
23
|
+
if lang not in _registry:
|
|
24
|
+
raise ValueError(
|
|
25
|
+
f"Idioma '{lang}' não encontrado. "
|
|
26
|
+
f"Idiomas disponíveis: {list(_registry.keys())}. "
|
|
27
|
+
f"Use register_provider() para adicionar um novo idioma."
|
|
28
|
+
)
|
|
29
|
+
return _registry[lang]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def available_languages() -> list[str]:
|
|
33
|
+
"""Lista os idiomas disponíveis."""
|
|
34
|
+
return list(_registry.keys())
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: codeinsult
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Turn HTTP errors into laughter — funny, sarcastic & offensive messages for every status code.
|
|
5
|
+
Author: Vaz15k
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Source, https://github.com/Vaz15k/code-insult
|
|
8
|
+
Project-URL: Tracker, https://github.com/Vaz15k/code-insult/issues
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: pytest; extra == "dev"
|
|
23
|
+
Requires-Dist: ruff; extra == "dev"
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
# CodeInsult
|
|
27
|
+
|
|
28
|
+
> **Turn errors into laughter.** A Python library that maps HTTP status codes to funny, sarcastic, and offensive messages — from "cult reference" to "heavy insult" levels.
|
|
29
|
+
|
|
30
|
+
> **English 🇺🇸** | [Português 🇧🇷](docs/README.pt.md)
|
|
31
|
+
|
|
32
|
+
[](https://www.python.org/)
|
|
33
|
+
[](LICENSE)
|
|
34
|
+
[](codeinsult/__version__.py)
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install codeinsult
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
> *Requires Python 3.11 or higher.*
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Usage
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
import codeinsult
|
|
52
|
+
|
|
53
|
+
# Get a message for a status code
|
|
54
|
+
print(codeinsult.insult(404))
|
|
55
|
+
# "404: O recurso sumiu. Como meias na máquina de lavar."
|
|
56
|
+
|
|
57
|
+
# With severity level ("light", "medium", "heavy")
|
|
58
|
+
print(codeinsult.insult(500, level="heavy"))
|
|
59
|
+
# "DEU MERDA NO SERVIDOR! Não foi você, foi a gente. Mas foi você também."
|
|
60
|
+
|
|
61
|
+
# A completely random message
|
|
62
|
+
print(codeinsult.random_insult())
|
|
63
|
+
# "418 I'm a Teapot: Sou um bule, não uma cafeteira. Respeita minha profissão!"
|
|
64
|
+
|
|
65
|
+
# Configure global defaults
|
|
66
|
+
codeinsult.set_defaults(lang="pt_br", level="light")
|
|
67
|
+
print(codeinsult.insult(401))
|
|
68
|
+
# "401 Unauthorized: Você não vai passar! — Gandalf, Servidor Edition."
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Severity Levels
|
|
74
|
+
|
|
75
|
+
| Level | Description | Example |
|
|
76
|
+
| ---------- | ------------------------------------------------------------ | ----------------------------------------------------------------------------------- |
|
|
77
|
+
| `LIGHT` | References to movies, series, books, and memes. No swearing. | *"404: Procurei em toda galáxia e não achei. — Baby Yoda."* |
|
|
78
|
+
| `MEDIUM` | Sarcasm and irony. Mildly offensive language. | *"500: O servidor teve um treco. Tenta de novo quando ele se recuperar."* |
|
|
79
|
+
| `HEAVY` | Heavy insults, with explicit swear words and profanity. | *"400: QUE REQUEST DE MERDA É ESSE? Nem o Google Tradutor salva essa bagunça!"* |
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Development
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# Clone the repository
|
|
87
|
+
git clone https://github.com/Vaz15k/code-insult.git
|
|
88
|
+
cd code-insult
|
|
89
|
+
|
|
90
|
+
# Install dev dependencies
|
|
91
|
+
pip install -e ".[dev]"
|
|
92
|
+
|
|
93
|
+
# Run the tests
|
|
94
|
+
pytest tests/ -v
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Contributing
|
|
100
|
+
|
|
101
|
+
Contributions are very welcome! Some ideas:
|
|
102
|
+
|
|
103
|
+
- 🗣️ **Add new languages** — Spanish, French, etc.
|
|
104
|
+
- 💬 **Add more phrases** for existing status codes (Be Creative)
|
|
105
|
+
- 🐛 **Fix bugs** or improve documentation
|
|
106
|
+
- 📦 **New status codes** that don't have messages yet
|
|
107
|
+
|
|
108
|
+
To contribute:
|
|
109
|
+
|
|
110
|
+
1. Fork the project
|
|
111
|
+
2. Create a branch for your feature
|
|
112
|
+
3. Add your messages and tests
|
|
113
|
+
4. Submit a Pull Request
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
codeinsult/CodeInsult.py,sha256=cXBZ76m5tXTlo39JKJJvoSOyb2XomWMJSYCyZqxO5Kg,3449
|
|
2
|
+
codeinsult/__init__.py,sha256=-N4nlE71SUaAC6bh0R5YS5_KBxIgPuH4baaDLhVkuyk,372
|
|
3
|
+
codeinsult/__version__.py,sha256=3NYPHxH9x-Jsbw-UBL-kbm15zxJl4hxzFKlyc1LFTlo,67
|
|
4
|
+
codeinsult/config.py,sha256=CJvjS4DLw7CcECcggHtz3KUzqd6Y2CFcKalcFHteYuI,944
|
|
5
|
+
codeinsult/messages/__init__.py,sha256=rBFdCBciYJ8Ueek2ymI-CyIYprmYbEDo-NDMxhsdhc0,160
|
|
6
|
+
codeinsult/messages/base.py,sha256=SptR7N01vZyiatM1iSLoeEdFbak3MtPDD5Sj0L4b1Vs,2581
|
|
7
|
+
codeinsult/messages/pt_br.py,sha256=TWHOX9hxqGc-8bvNpWhyxhLkObWLMTFjIR1tf3ggfsY,20961
|
|
8
|
+
codeinsult/messages/registry.py,sha256=J0Rzpwpe_gv5tPBXMGTL_EwK7-byARNwhirBUYi6wMQ,1060
|
|
9
|
+
codeinsult-0.1.0.dist-info/licenses/LICENSE,sha256=8_yqDy7HBctUZY1NcF6O1EW3QyUuxS_TPdoJ42QjVbs,1063
|
|
10
|
+
codeinsult-0.1.0.dist-info/METADATA,sha256=yBDbyR68Hts8sQG37lST9sjRPPzhjPYdu2UyE_nbBzs,3744
|
|
11
|
+
codeinsult-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
12
|
+
codeinsult-0.1.0.dist-info/top_level.txt,sha256=IeTrEhZ-fLqh1QYI2FvqN_mwnwza57_amcDotJJ0-cA,11
|
|
13
|
+
codeinsult-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vaz15k
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
codeinsult
|