airev 1.1.0__py3-none-any.whl → 1.2.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.
- {airev-1.1.0.dist-info → airev-1.2.0.dist-info}/METADATA +1 -1
- {airev-1.1.0.dist-info → airev-1.2.0.dist-info}/RECORD +13 -11
- code_reviewer/__init__.py +1 -1
- code_reviewer/cli.py +6 -6
- code_reviewer/locales/en.yaml +61 -0
- code_reviewer/locales/pt-br.yaml +61 -0
- code_reviewer/updater/__init__.py +2 -1
- code_reviewer/updater/http_client.py +1 -1
- code_reviewer/updater/upgrade.py +102 -7
- code_reviewer/updater/version_check.py +18 -0
- {airev-1.1.0.dist-info → airev-1.2.0.dist-info}/WHEEL +0 -0
- {airev-1.1.0.dist-info → airev-1.2.0.dist-info}/entry_points.txt +0 -0
- {airev-1.1.0.dist-info → airev-1.2.0.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
code_reviewer/__init__.py,sha256=
|
|
2
|
-
code_reviewer/cli.py,sha256=
|
|
1
|
+
code_reviewer/__init__.py,sha256=39ZhaBH3qjYCSKVmeSRsf21d_-DPx9UOMUCaCnqVRCw,82
|
|
2
|
+
code_reviewer/cli.py,sha256=WaWoN5FFPhOtKoM1LTawCvdT6jb1eVEJyS_G69mYICA,6686
|
|
3
3
|
code_reviewer/context_builder.py,sha256=XJGsJpc5YOP3jhldpMFnrJ-hLc4uf9O6_efxZa3sbsc,8790
|
|
4
4
|
code_reviewer/diff_parser.py,sha256=07EO0kJFYuS6GRgDUHH0czYJBKcL8CxLR-jLdq6PShs,6896
|
|
5
5
|
code_reviewer/models.py,sha256=SUSudQx623zS15yUKd84qOI6zqO-736lu7gjbHSsYwY,4263
|
|
@@ -9,18 +9,20 @@ code_reviewer/formatters/__init__.py,sha256=LXkD8nK7yWGtbc6ox85SHWZdQX5sVr5xLXkk
|
|
|
9
9
|
code_reviewer/formatters/progress.py,sha256=mUmoB2xQYYuYz5IRJzn23wgOpiV7bXehXrPhP5rDT-g,8529
|
|
10
10
|
code_reviewer/formatters/terminal.py,sha256=lJohIyqav3QjGchjTUKxfCbuFtbtL3sbcW9glU3hwUM,5849
|
|
11
11
|
code_reviewer/i18n/__init__.py,sha256=Uzm_sic0_ehZQSpyzxI9-IFX_5Saxo5V-sLR35eqrIM,4696
|
|
12
|
+
code_reviewer/locales/en.yaml,sha256=CiVUrxIj9jnAhZjEw74pInWYljT-o2Luvo1mf1yOo14,1879
|
|
13
|
+
code_reviewer/locales/pt-br.yaml,sha256=iWtokdIjBEikUthPYh8oSYUuvgYA_02rcfgzFcB7tLI,2037
|
|
12
14
|
code_reviewer/prompts/review_system.md,sha256=9FDaIY8q2PdLh3p28cy2EJBi8olQhtw6I3TYgVG7fik,1995
|
|
13
15
|
code_reviewer/runners/__init__.py,sha256=cLxawmzHwhymN2xSC7nUWEOpHHvvSklzZOqjy2Q7HIM,1194
|
|
14
16
|
code_reviewer/runners/base.py,sha256=xikp7yI4IcOX86uNA7CUWTCL_oNuHSF9WIs6OP6rnx0,1491
|
|
15
17
|
code_reviewer/runners/copilot.py,sha256=GpBYO-Splmo66EaUBfCmU8Et-NRB0w2gn7XEtIq9THw,2433
|
|
16
18
|
code_reviewer/runners/gemini.py,sha256=dadONQIEb0d_y8V3KgYX65JH8IMYmNAP2jC22r0cWXY,2142
|
|
17
|
-
code_reviewer/updater/__init__.py,sha256=
|
|
18
|
-
code_reviewer/updater/http_client.py,sha256=
|
|
19
|
+
code_reviewer/updater/__init__.py,sha256=L4irTnOGif85M55jerbjczIr2SxXj74i_vfvWzvfPQo,374
|
|
20
|
+
code_reviewer/updater/http_client.py,sha256=g4PnuY5KKbsA0EqLtHhOK4sxg_6P0drzd1HKxWKJxZw,1746
|
|
19
21
|
code_reviewer/updater/notifier.py,sha256=o4crwJOnCOSnzqk5gMt0MkYP3xm-yEXIGSnix988YzA,992
|
|
20
|
-
code_reviewer/updater/upgrade.py,sha256=
|
|
21
|
-
code_reviewer/updater/version_check.py,sha256=
|
|
22
|
-
airev-1.
|
|
23
|
-
airev-1.
|
|
24
|
-
airev-1.
|
|
25
|
-
airev-1.
|
|
26
|
-
airev-1.
|
|
22
|
+
code_reviewer/updater/upgrade.py,sha256=xoAfpomMJA_K9t6myeXC6tLEBnKwAgxR9OD8tcJ4YXE,5842
|
|
23
|
+
code_reviewer/updater/version_check.py,sha256=2Zv35s5oeR0dHAGODPwO70dyshECaCzrQx7vEZAXYJM,4917
|
|
24
|
+
airev-1.2.0.dist-info/METADATA,sha256=IVqJfD0FVZFSrjWLHgbSywdE4mdR4a0UHQpynHGr5B8,6258
|
|
25
|
+
airev-1.2.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
26
|
+
airev-1.2.0.dist-info/entry_points.txt,sha256=LDd8UajxUO4QUs63xt6z635doU7E1XzBPFQZeMrlShU,49
|
|
27
|
+
airev-1.2.0.dist-info/top_level.txt,sha256=VqPHk5LmBEOeRJOUhXq1lkW5UiT48zW7a9h7NDy9N0E,14
|
|
28
|
+
airev-1.2.0.dist-info/RECORD,,
|
code_reviewer/__init__.py
CHANGED
code_reviewer/cli.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""CLI Entry Point - Comando principal do
|
|
1
|
+
"""CLI Entry Point - Comando principal do airev."""
|
|
2
2
|
|
|
3
3
|
import sys
|
|
4
4
|
import time
|
|
@@ -88,13 +88,13 @@ def review(
|
|
|
88
88
|
|
|
89
89
|
Exemplos:
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
airev review --base main
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
airev review --base develop --runner copilot
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
airev review --base main --json-output
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
airev review --base main --no-progress
|
|
98
98
|
"""
|
|
99
99
|
workdir = workdir or Path.cwd()
|
|
100
100
|
start_time = time.perf_counter()
|
|
@@ -232,7 +232,7 @@ def runners():
|
|
|
232
232
|
|
|
233
233
|
@main.command()
|
|
234
234
|
def upgrade():
|
|
235
|
-
"""Atualiza o
|
|
235
|
+
"""Atualiza o airev para a versão mais recente."""
|
|
236
236
|
from rich.console import Console
|
|
237
237
|
|
|
238
238
|
console = Console()
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# English translations
|
|
2
|
+
|
|
3
|
+
cli:
|
|
4
|
+
# Analysis messages
|
|
5
|
+
analyzing: "Analyzing: [bold]{branch}[/bold] → [bold]{base}[/bold]"
|
|
6
|
+
getting_diff: "Getting diff..."
|
|
7
|
+
analyzing_diff: "Analyzing diff..."
|
|
8
|
+
building_context: "Building context..."
|
|
9
|
+
building_prompt: "Building prompt..."
|
|
10
|
+
running_analysis: "Running analysis with {runner}..."
|
|
11
|
+
processing_response: "Processing response..."
|
|
12
|
+
analysis_complete: "Analysis completed in {elapsed:.1f}s"
|
|
13
|
+
|
|
14
|
+
# Error messages
|
|
15
|
+
error_branch: "Error getting current branch: {error}"
|
|
16
|
+
error_diff: "Error getting diff: {error}"
|
|
17
|
+
error_diff_help: "Check if branch '{base}' exists and you're in a git repository."
|
|
18
|
+
error_runner_invalid: "Invalid runner: {error}"
|
|
19
|
+
error_runner_unavailable: "Runner '{runner}' is not available."
|
|
20
|
+
error_runner_help: "Check if the CLI is installed and configured."
|
|
21
|
+
error_runner_not_found: "Runner not found: {error}"
|
|
22
|
+
error_execution: "Execution error: {error}"
|
|
23
|
+
|
|
24
|
+
# Warning messages
|
|
25
|
+
no_changes: "No changes found in diff."
|
|
26
|
+
no_files: "No relevant files to analyze."
|
|
27
|
+
|
|
28
|
+
# Dependencies
|
|
29
|
+
dependencies_found: "Dependencies found:"
|
|
30
|
+
|
|
31
|
+
progress:
|
|
32
|
+
# Summary labels
|
|
33
|
+
modified_files: "Modified files:"
|
|
34
|
+
files_label: "Files:"
|
|
35
|
+
lines_label: "Lines:"
|
|
36
|
+
no_dependencies: "No dependencies found"
|
|
37
|
+
callers: "Callers:"
|
|
38
|
+
callees: "Callees:"
|
|
39
|
+
more: "+{count} more"
|
|
40
|
+
|
|
41
|
+
terminal:
|
|
42
|
+
# Header
|
|
43
|
+
code_review: "CODE REVIEW"
|
|
44
|
+
compared_with: "Compared with:"
|
|
45
|
+
files_count: "{count} file(s)"
|
|
46
|
+
|
|
47
|
+
# Findings
|
|
48
|
+
suggestion: "Suggestion:"
|
|
49
|
+
|
|
50
|
+
# Summary
|
|
51
|
+
summary: "SUMMARY:"
|
|
52
|
+
findings_count: "{count} finding(s)"
|
|
53
|
+
no_problems: "✓ No issues found. Code approved!"
|
|
54
|
+
raw_response: "AI raw response:"
|
|
55
|
+
|
|
56
|
+
parser:
|
|
57
|
+
# Fallback
|
|
58
|
+
unstructured_response: "Unstructured response"
|
|
59
|
+
unstructured_description: "The AI returned text not formatted as JSON"
|
|
60
|
+
unstructured_suggestion: "Check the raw response for details"
|
|
61
|
+
no_title: "No title"
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Traduções em Português Brasileiro (padrão)
|
|
2
|
+
|
|
3
|
+
cli:
|
|
4
|
+
# Mensagens de análise
|
|
5
|
+
analyzing: "Analisando: [bold]{branch}[/bold] → [bold]{base}[/bold]"
|
|
6
|
+
getting_diff: "Obtendo diff..."
|
|
7
|
+
analyzing_diff: "Analisando diff..."
|
|
8
|
+
building_context: "Construindo contexto..."
|
|
9
|
+
building_prompt: "Montando prompt..."
|
|
10
|
+
running_analysis: "Executando análise com {runner}..."
|
|
11
|
+
processing_response: "Processando resposta..."
|
|
12
|
+
analysis_complete: "Análise concluída em {elapsed:.1f}s"
|
|
13
|
+
|
|
14
|
+
# Mensagens de erro
|
|
15
|
+
error_branch: "Erro ao obter branch atual: {error}"
|
|
16
|
+
error_diff: "Erro ao obter diff: {error}"
|
|
17
|
+
error_diff_help: "Verifique se a branch '{base}' existe e se você está em um repositório git."
|
|
18
|
+
error_runner_invalid: "Runner inválido: {error}"
|
|
19
|
+
error_runner_unavailable: "Runner '{runner}' não está disponível."
|
|
20
|
+
error_runner_help: "Verifique se o CLI está instalado e configurado."
|
|
21
|
+
error_runner_not_found: "Runner não encontrado: {error}"
|
|
22
|
+
error_execution: "Erro na execução: {error}"
|
|
23
|
+
|
|
24
|
+
# Mensagens de aviso
|
|
25
|
+
no_changes: "Nenhuma mudança encontrada no diff."
|
|
26
|
+
no_files: "Nenhum arquivo relevante para analisar."
|
|
27
|
+
|
|
28
|
+
# Dependências
|
|
29
|
+
dependencies_found: "Dependências encontradas:"
|
|
30
|
+
|
|
31
|
+
progress:
|
|
32
|
+
# Labels de resumo
|
|
33
|
+
modified_files: "Arquivos modificados:"
|
|
34
|
+
files_label: "Arquivos:"
|
|
35
|
+
lines_label: "Linhas:"
|
|
36
|
+
no_dependencies: "Sem dependências encontradas"
|
|
37
|
+
callers: "Callers:"
|
|
38
|
+
callees: "Callees:"
|
|
39
|
+
more: "+{count} mais"
|
|
40
|
+
|
|
41
|
+
terminal:
|
|
42
|
+
# Header
|
|
43
|
+
code_review: "CODE REVIEW"
|
|
44
|
+
compared_with: "Comparado com:"
|
|
45
|
+
files_count: "{count} arquivo(s)"
|
|
46
|
+
|
|
47
|
+
# Findings
|
|
48
|
+
suggestion: "Sugestão:"
|
|
49
|
+
|
|
50
|
+
# Resumo
|
|
51
|
+
summary: "RESUMO:"
|
|
52
|
+
findings_count: "{count} finding(s)"
|
|
53
|
+
no_problems: "✓ Nenhum problema encontrado. Código aprovado!"
|
|
54
|
+
raw_response: "Resposta raw da IA:"
|
|
55
|
+
|
|
56
|
+
parser:
|
|
57
|
+
# Fallback
|
|
58
|
+
unstructured_response: "Resposta não estruturada"
|
|
59
|
+
unstructured_description: "A IA retornou texto não formatado como JSON"
|
|
60
|
+
unstructured_suggestion: "Verifique a resposta raw para detalhes"
|
|
61
|
+
no_title: "Sem título"
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"""Módulo de auto-update para verificação e atualização de versões."""
|
|
2
2
|
|
|
3
|
-
from .version_check import check_for_update, UpdateInfo
|
|
3
|
+
from .version_check import check_for_update, clear_cache, UpdateInfo
|
|
4
4
|
from .notifier import notify_update
|
|
5
5
|
from .upgrade import detect_installer, run_upgrade
|
|
6
6
|
|
|
7
7
|
__all__ = [
|
|
8
8
|
"check_for_update",
|
|
9
|
+
"clear_cache",
|
|
9
10
|
"UpdateInfo",
|
|
10
11
|
"notify_update",
|
|
11
12
|
"detect_installer",
|
|
@@ -30,7 +30,7 @@ class UrllibClient:
|
|
|
30
30
|
try:
|
|
31
31
|
request = urllib.request.Request(
|
|
32
32
|
url,
|
|
33
|
-
headers={"Accept": "application/json", "User-Agent": "
|
|
33
|
+
headers={"Accept": "application/json", "User-Agent": "airev"},
|
|
34
34
|
)
|
|
35
35
|
with urllib.request.urlopen(request, timeout=timeout) as response:
|
|
36
36
|
data = response.read().decode("utf-8")
|
code_reviewer/updater/upgrade.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Funcionalidades de upgrade do pacote."""
|
|
2
2
|
|
|
3
|
+
import json
|
|
3
4
|
import subprocess
|
|
4
5
|
import sys
|
|
5
6
|
from pathlib import Path
|
|
@@ -7,7 +8,7 @@ from pathlib import Path
|
|
|
7
8
|
from rich.console import Console
|
|
8
9
|
|
|
9
10
|
from .. import __version__
|
|
10
|
-
from .version_check import check_for_update
|
|
11
|
+
from .version_check import check_for_update, clear_cache
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
def detect_installer() -> str:
|
|
@@ -25,6 +26,78 @@ def detect_installer() -> str:
|
|
|
25
26
|
return "pip"
|
|
26
27
|
|
|
27
28
|
|
|
29
|
+
def get_installed_version(installer: str) -> str | None:
|
|
30
|
+
"""Obtém a versão real instalada do airev consultando o instalador.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
installer: "pipx" ou "pip"
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
String com a versão instalada ou None se não conseguir obter
|
|
37
|
+
"""
|
|
38
|
+
try:
|
|
39
|
+
if installer == "pipx":
|
|
40
|
+
# Tenta usar pipx list --json
|
|
41
|
+
result = subprocess.run(
|
|
42
|
+
["pipx", "list", "--json"],
|
|
43
|
+
capture_output=True,
|
|
44
|
+
text=True,
|
|
45
|
+
check=False,
|
|
46
|
+
)
|
|
47
|
+
if result.returncode == 0:
|
|
48
|
+
data = json.loads(result.stdout)
|
|
49
|
+
venvs = data.get("venvs", {})
|
|
50
|
+
if "airev" in venvs:
|
|
51
|
+
metadata = venvs["airev"].get("metadata", {})
|
|
52
|
+
return metadata.get("main_package", {}).get("package_version")
|
|
53
|
+
# Fallback: tenta sem --json (versões antigas do pipx)
|
|
54
|
+
return _get_version_from_pipx_list_text()
|
|
55
|
+
else:
|
|
56
|
+
# pip show airev
|
|
57
|
+
result = subprocess.run(
|
|
58
|
+
[sys.executable, "-m", "pip", "show", "airev"],
|
|
59
|
+
capture_output=True,
|
|
60
|
+
text=True,
|
|
61
|
+
check=False,
|
|
62
|
+
)
|
|
63
|
+
if result.returncode == 0:
|
|
64
|
+
for line in result.stdout.splitlines():
|
|
65
|
+
if line.startswith("Version:"):
|
|
66
|
+
return line.split(":", 1)[1].strip()
|
|
67
|
+
except (subprocess.SubprocessError, json.JSONDecodeError, KeyError):
|
|
68
|
+
pass
|
|
69
|
+
return None
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _get_version_from_pipx_list_text() -> str | None:
|
|
73
|
+
"""Fallback para obter versão do pipx list sem --json.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
String com a versão ou None se não encontrar
|
|
77
|
+
"""
|
|
78
|
+
try:
|
|
79
|
+
result = subprocess.run(
|
|
80
|
+
["pipx", "list"],
|
|
81
|
+
capture_output=True,
|
|
82
|
+
text=True,
|
|
83
|
+
check=False,
|
|
84
|
+
)
|
|
85
|
+
if result.returncode == 0:
|
|
86
|
+
# Procura por linha como "airev 1.0.0" ou "package airev 1.0.0"
|
|
87
|
+
for line in result.stdout.splitlines():
|
|
88
|
+
if "airev" in line.lower():
|
|
89
|
+
parts = line.split()
|
|
90
|
+
for i, part in enumerate(parts):
|
|
91
|
+
if "airev" in part.lower() and i + 1 < len(parts):
|
|
92
|
+
version = parts[i + 1].strip(",")
|
|
93
|
+
# Verifica se parece uma versão
|
|
94
|
+
if version and version[0].isdigit():
|
|
95
|
+
return version
|
|
96
|
+
except subprocess.SubprocessError:
|
|
97
|
+
pass
|
|
98
|
+
return None
|
|
99
|
+
|
|
100
|
+
|
|
28
101
|
def run_upgrade(console: Console | None = None) -> bool:
|
|
29
102
|
"""Executa upgrade do pacote.
|
|
30
103
|
|
|
@@ -32,7 +105,7 @@ def run_upgrade(console: Console | None = None) -> bool:
|
|
|
32
105
|
console: Console Rich para output (opcional)
|
|
33
106
|
|
|
34
107
|
Returns:
|
|
35
|
-
True se upgrade foi executado, False
|
|
108
|
+
True se upgrade foi executado com sucesso, False caso contrário
|
|
36
109
|
"""
|
|
37
110
|
if console is None:
|
|
38
111
|
console = Console()
|
|
@@ -42,14 +115,20 @@ def run_upgrade(console: Console | None = None) -> bool:
|
|
|
42
115
|
update_info = check_for_update()
|
|
43
116
|
|
|
44
117
|
if update_info is None:
|
|
118
|
+
# Limpa cache mesmo quando não há atualização (garante consistência)
|
|
119
|
+
clear_cache()
|
|
45
120
|
console.print(
|
|
46
121
|
f"[green]✓[/] Você já está na versão mais recente ([cyan]{__version__}[/])"
|
|
47
122
|
)
|
|
48
123
|
return False
|
|
49
124
|
|
|
50
125
|
installer = detect_installer()
|
|
126
|
+
|
|
127
|
+
# Obtém versão antes do upgrade para comparação
|
|
128
|
+
version_before = get_installed_version(installer) or __version__
|
|
129
|
+
|
|
51
130
|
console.print(
|
|
52
|
-
f"[yellow]→[/] Atualizando de {
|
|
131
|
+
f"[yellow]→[/] Atualizando de {version_before} "
|
|
53
132
|
f"para {update_info.latest_version}..."
|
|
54
133
|
)
|
|
55
134
|
|
|
@@ -67,21 +146,37 @@ def run_upgrade(console: Console | None = None) -> bool:
|
|
|
67
146
|
check=False,
|
|
68
147
|
)
|
|
69
148
|
|
|
149
|
+
# Sempre limpa o cache após tentativa de upgrade
|
|
150
|
+
clear_cache()
|
|
151
|
+
|
|
70
152
|
if result.returncode == 0:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
153
|
+
# Verifica se a versão realmente mudou
|
|
154
|
+
version_after = get_installed_version(installer)
|
|
155
|
+
|
|
156
|
+
if version_after and version_after != version_before:
|
|
157
|
+
console.print(
|
|
158
|
+
f"[green]✓[/] Atualizado de {version_before} para {version_after}"
|
|
159
|
+
)
|
|
160
|
+
return True
|
|
161
|
+
else:
|
|
162
|
+
# Comando executou mas versão não mudou
|
|
163
|
+
console.print(
|
|
164
|
+
f"[green]✓[/] Você já está na versão mais recente "
|
|
165
|
+
f"([cyan]{version_after or version_before}[/])"
|
|
166
|
+
)
|
|
167
|
+
return False
|
|
75
168
|
else:
|
|
76
169
|
console.print(f"[red]✗[/] Falha ao atualizar: {result.stderr.strip()}")
|
|
77
170
|
console.print(f"[dim]Tente manualmente: {' '.join(cmd)}[/]")
|
|
78
171
|
return False
|
|
79
172
|
|
|
80
173
|
except FileNotFoundError:
|
|
174
|
+
clear_cache()
|
|
81
175
|
console.print(f"[red]✗[/] Comando '{cmd[0]}' não encontrado")
|
|
82
176
|
if installer == "pipx":
|
|
83
177
|
console.print("[dim]Tente: pip install --upgrade airev[/]")
|
|
84
178
|
return False
|
|
85
179
|
except Exception as e:
|
|
180
|
+
clear_cache()
|
|
86
181
|
console.print(f"[red]✗[/] Erro inesperado: {e}")
|
|
87
182
|
return False
|
|
@@ -110,6 +110,24 @@ def _write_cache(latest_version: str) -> None:
|
|
|
110
110
|
pass
|
|
111
111
|
|
|
112
112
|
|
|
113
|
+
def clear_cache() -> bool:
|
|
114
|
+
"""Remove o arquivo de cache de verificação de versão.
|
|
115
|
+
|
|
116
|
+
Deve ser chamada após upgrade para garantir que a próxima
|
|
117
|
+
verificação consulte o PyPI novamente.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
True se o cache foi removido ou não existia, False se falhou
|
|
121
|
+
"""
|
|
122
|
+
try:
|
|
123
|
+
if CACHE_FILE.exists():
|
|
124
|
+
CACHE_FILE.unlink()
|
|
125
|
+
return True
|
|
126
|
+
except OSError:
|
|
127
|
+
# Falha ao remover cache - ignora silenciosamente
|
|
128
|
+
return False
|
|
129
|
+
|
|
130
|
+
|
|
113
131
|
def get_latest_version(timeout: float = DEFAULT_TIMEOUT) -> str | None:
|
|
114
132
|
"""Consulta PyPI para obter a versão mais recente.
|
|
115
133
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|