From d59e97e0bf3601e23c5294973c8938a3b2b04e6d Mon Sep 17 00:00:00 2001 From: Otavio72 Date: Mon, 10 Nov 2025 15:08:29 -0300 Subject: [PATCH 1/4] Atualiza script para Windows e README --- README.md | 27 ++++++++++++++++++++ setup_windows.ps1 | 65 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 setup_windows.ps1 diff --git a/README.md b/README.md index a24fffa..3bd218a 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,33 @@ desenvolvimento de aplicações para o business Brasileiro. pip install brutils ``` +## Instalação para Usuários Windows 🪟 + +Atualmente, o **Brazilian Utils** não possui suporte nativo completo para Windows. Para simplificar a instalação e execução do projeto, criamos um **script PowerShell (`setup_windows.ps1`)** que cuida de toda a configuração necessária. + +### Requisitos + +Antes de rodar o script, o usuário precisa ter: + +- **Sistema Operacional:** Windows 11 +- **Python 3.9 ou superior** + - Pode ser a versão instalada via Microsoft Store ou a versão tradicional baixada do site oficial +- **Poetry:** será instalado automaticamente pelo script, caso ainda não esteja presente + +> Não é necessário instalar Makefile, Chocolatey ou usar WSL. O script faz toda a detecção, instalação e configuração automaticamente. + +### Passos para Instalação e Configuração + +1. Clone o repositório: + ```bash + git clone + cd brazilian-utils + ``` +2. Execute o script PowerShell: +```powershell + .\setup_windows.ps1 +``` + # Utilização Para usar um de nossos utilitários, basta importar a função necessária, como no exemplo abaixo: diff --git a/setup_windows.ps1 b/setup_windows.ps1 new file mode 100644 index 0000000..d6a4932 --- /dev/null +++ b/setup_windows.ps1 @@ -0,0 +1,65 @@ +Write-Host "Verificando Python disponível..." -ForegroundColor Cyan + +# 1️⃣ - Verifica Python (Microsoft Store ou instalação normal) +$pythonPaths = @( + "$env:LOCALAPPDATA\Microsoft\WindowsApps\python3.11.exe", + "$env:LOCALAPPDATA\Programs\Python\Python311\python.exe", + "$env:ProgramFiles\Python311\python.exe", + "$env:ProgramFiles(x86)\Python311\python.exe" +) + +$pythonPath = $pythonPaths | Where-Object { Test-Path $_ } | Select-Object -First 1 + +if (-not $pythonPath) { + Write-Host " Nenhum Python encontrado. Instale o Python 3.11+ e tente novamente." -ForegroundColor Red + exit 1 +} + +Write-Host " Python encontrado em $pythonPath" -ForegroundColor Green + + +# 2️⃣ - Verifica se o Poetry já está instalado +$possiblePoetryPaths = @( + "$env:APPDATA\Python\Scripts\poetry.exe", + "$env:APPDATA\Roaming\Python\Scripts\poetry.exe", + "$env:LOCALAPPDATA\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\Roaming\pypoetry\venv\Scripts\poetry.exe", + "$env:LOCALAPPDATA\pypoetry\venv\Scripts\poetry.exe" +) + +$poetryPath = $possiblePoetryPaths | Where-Object { Test-Path $_ } | Select-Object -First 1 + +# 3️⃣ - Instala o Poetry se não encontrado +if (-not $poetryPath) { + Write-Host "⚙️ Poetry não encontrado. Instalando..." -ForegroundColor Yellow + try { + (Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | & $pythonPath - + Start-Sleep -Seconds 5 + + # tenta localizar após instalação + $poetryPath = $possiblePoetryPaths | Where-Object { Test-Path $_ } | Select-Object -First 1 + + if ($poetryPath) { + Write-Host " Poetry instalado com sucesso em $poetryPath" -ForegroundColor Green + } else { + Write-Host " Erro: instalação do Poetry parece ter falhado." -ForegroundColor Red + exit 1 + } + } catch { + Write-Host " Erro durante a instalação do Poetry: $_" -ForegroundColor Red + exit 1 + } +} else { + Write-Host " Poetry já está instalado em $poetryPath" -ForegroundColor Green +} + +# 4️⃣ - Adiciona ao PATH temporariamente +$env:PATH += ";" + (Split-Path $poetryPath) + +# 5️⃣ - Instala dependências e roda projeto +Write-Host " Instalando dependências do projeto..." -ForegroundColor Cyan +& $poetryPath install + +Write-Host " Rodando o projeto..." -ForegroundColor Cyan +& $poetryPath run python main.py + +Write-Host " Projeto finalizado!" -ForegroundColor Green From 84eaeae5721ce0610d38f85504096a802b625003 Mon Sep 17 00:00:00 2001 From: Otavio72 Date: Mon, 10 Nov 2025 16:14:15 -0300 Subject: [PATCH 2/4] Add Windows setup script and update README/CHANGELOG --- CHANGELOG.md | 2 +- README_EN.md | 29 +++++++++++++++++++++++++++ setup_windows.ps1 | 51 ++++++++++++++++++++++++----------------------- 3 files changed, 56 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a6d24f..83c5480 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added - +- Script PowerShell `setup_windows.ps1` que instala automaticamente o Poetry e configura as dependências no Windows. [#639](https://github.com/brazilian-utils/python/issues/639) - Utilitário `convert_name_to_uf` - Utilitário `is_valid_legal_nature` [#641](https://github.com/brazilian-utils/python/issues/641) - Utilitário `get_legal_nature_description` [#641](https://github.com/brazilian-utils/python/issues/641) diff --git a/README_EN.md b/README_EN.md index aa784da..85cf123 100644 --- a/README_EN.md +++ b/README_EN.md @@ -29,6 +29,35 @@ the development of applications for the Brazilian business. pip install brutils ``` +## Installation for Windows Users 🪟 + +Currently, **Brazilian Utils** does not have full native support for Windows. +To simplify the setup and execution of the project, we created a **PowerShell script (`setup_windows.ps1`)** that handles all the required configuration automatically. + +### Requirements + +Before running the script, make sure you have: + +- **Operating System:** Windows 11 +- **Python 3.9 or higher** + - You can use either the version installed via Microsoft Store or the standard one downloaded from the official website +- **Poetry:** it will be automatically installed by the script if not already present + +> There’s no need to install Makefile, Chocolatey, or use WSL. +> The script automatically detects your environment, installs the required dependencies, and sets up everything for you. + +### Installation and Setup Steps + +1. Clone the repository: + ```bash + git clone + cd brazilian-utils + ``` +2. Run the PowerShell script: +```powershell + .\setup_windows.ps1 +``` + # Usage To use one of our utilities you just need to import the required function as in the example below: diff --git a/setup_windows.ps1 b/setup_windows.ps1 index d6a4932..98ff215 100644 --- a/setup_windows.ps1 +++ b/setup_windows.ps1 @@ -1,36 +1,40 @@ -Write-Host "Verificando Python disponível..." -ForegroundColor Cyan +Write-Host "Verificando Python disponivel..." -ForegroundColor Cyan -# 1️⃣ - Verifica Python (Microsoft Store ou instalação normal) -$pythonPaths = @( - "$env:LOCALAPPDATA\Microsoft\WindowsApps\python3.11.exe", - "$env:LOCALAPPDATA\Programs\Python\Python311\python.exe", - "$env:ProgramFiles\Python311\python.exe", - "$env:ProgramFiles(x86)\Python311\python.exe" -) +# - Procura todos os executáveis python no PATH +$pythonPaths = Get-Command python* -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source + +# - Filtra versões >= 3.9 +$pythonPaths = $pythonPaths | ForEach-Object { + $versionOutput = & $_ --version 2>&1 + if ($versionOutput -match "Python (\d+)\.(\d+)\.(\d+)") { + $major = [int]$matches[1] + $minor = [int]$matches[2] + if ($major -eq 3 -and $minor -ge 9) { $_ } + } +} -$pythonPath = $pythonPaths | Where-Object { Test-Path $_ } | Select-Object -First 1 +# Pega a versão mais alta disponível +$pythonPath = $pythonPaths | Sort-Object -Descending | Select-Object -First 1 if (-not $pythonPath) { - Write-Host " Nenhum Python encontrado. Instale o Python 3.11+ e tente novamente." -ForegroundColor Red + Write-Host " Nenhum Python 3.9+ encontrado. Instale o Python e tente novamente." -ForegroundColor Red exit 1 } Write-Host " Python encontrado em $pythonPath" -ForegroundColor Green - -# 2️⃣ - Verifica se o Poetry já está instalado +# - Verifica se o Poetry já está instalado $possiblePoetryPaths = @( "$env:APPDATA\Python\Scripts\poetry.exe", "$env:APPDATA\Roaming\Python\Scripts\poetry.exe", - "$env:LOCALAPPDATA\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\Roaming\pypoetry\venv\Scripts\poetry.exe", "$env:LOCALAPPDATA\pypoetry\venv\Scripts\poetry.exe" ) $poetryPath = $possiblePoetryPaths | Where-Object { Test-Path $_ } | Select-Object -First 1 -# 3️⃣ - Instala o Poetry se não encontrado +# - Instala o Poetry se não encontrado if (-not $poetryPath) { - Write-Host "⚙️ Poetry não encontrado. Instalando..." -ForegroundColor Yellow + Write-Host " Poetry nao encontrado. Instalando..." -ForegroundColor Yellow try { (Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | & $pythonPath - Start-Sleep -Seconds 5 @@ -41,25 +45,22 @@ if (-not $poetryPath) { if ($poetryPath) { Write-Host " Poetry instalado com sucesso em $poetryPath" -ForegroundColor Green } else { - Write-Host " Erro: instalação do Poetry parece ter falhado." -ForegroundColor Red + Write-Host " Erro: instalacao do Poetry parece ter falhado." -ForegroundColor Red exit 1 } } catch { - Write-Host " Erro durante a instalação do Poetry: $_" -ForegroundColor Red + Write-Host " Erro durante a instalacao do Poetry: $_" -ForegroundColor Red exit 1 } } else { - Write-Host " Poetry já está instalado em $poetryPath" -ForegroundColor Green + Write-Host " Poetry ja esta instalado em $poetryPath" -ForegroundColor Green } -# 4️⃣ - Adiciona ao PATH temporariamente +# - Adiciona ao PATH temporariamente $env:PATH += ";" + (Split-Path $poetryPath) -# 5️⃣ - Instala dependências e roda projeto -Write-Host " Instalando dependências do projeto..." -ForegroundColor Cyan +# - Instala dependências e roda projeto +Write-Host " Instalando dependencias do projeto..." -ForegroundColor Cyan & $poetryPath install -Write-Host " Rodando o projeto..." -ForegroundColor Cyan -& $poetryPath run python main.py - -Write-Host " Projeto finalizado!" -ForegroundColor Green +Write-Host " instalacao finalizada!" -ForegroundColor Green From c7568a6313f4bcf6d916374013bc84f7d40ecaca Mon Sep 17 00:00:00 2001 From: Otavio72 Date: Thu, 13 Nov 2025 13:38:56 -0300 Subject: [PATCH 3/4] adicionado o arquivo boleto.py e funcoes baseadas no cpf.py criadas display e format --- brutils/boleto.py | 205 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 brutils/boleto.py diff --git a/brutils/boleto.py b/brutils/boleto.py new file mode 100644 index 0000000..386dbae --- /dev/null +++ b/brutils/boleto.py @@ -0,0 +1,205 @@ +from random import randint + +# FORMATTING +############ + + +def sieve(dirty: str) -> str: + """ + Removes specific symbols from a CPF (Brazilian Individual Taxpayer Number) + string. + + This function takes a CPF string as input and removes all occurrences of + the '.', '-' characters from it. + + Args: + cpf (str): The CPF string containing symbols to be removed. + + Returns: + str: A new string with the specified symbols removed. + + Example: + >>> sieve("123.456.789-01") + '12345678901' + >>> sieve("987-654-321.01") + '98765432101' + + .. note:: + This method should not be used in new code and is only provided for + backward compatibility. + """ + + return "".join(filter(lambda char: char not in ".-", dirty)) + + +def remove_symbols(dirty: str) -> str: + """ + Alias for the `sieve` function. Better naming. + + Args: + cpf (str): The CPF string containing symbols to be removed. + + Returns: + str: A new string with the specified symbols removed. + """ + + return sieve(dirty) + + +def display(boleto: str) -> str: + boleto = remove_symbols(boleto) + + if not boleto.isdigit() or len(boleto) != 47 or len(set(boleto)) == 1: + return None + + return "{}.{} {}.{} {}.{} {} {}".format(boleto[:5], boleto[5:10], boleto[10:15], boleto[15:21], boleto[21:26], boleto[26:32], boleto[32:33], boleto[33:]) + + +def format_boleto(boleto: str) -> str: + + if not is_valid(boleto): + return None + + return "{}.{} {}.{} {}.{} {} {}".format(boleto[:5], boleto[5:10], boleto[10:15], boleto[15:21], boleto[21:26], boleto[26:32], boleto[32:33], boleto[33:]) + + + +# OPERATIONS +############ + + +def validate(boleto: str) -> bool: + """ + Validate the checksum digits of a CPF. + + This function checks whether the verifying checksum digits of the given CPF + match its base number. The input should be a digit string of the proper + length. + + Args: + cpf (str): A numbers-only CPF string. + + Returns: + bool: True if the checksum digits are valid, False otherwise. + + Example: + >>> validate("82178537464") + True + >>> validate("55550207753") + True + + .. note:: + This method should not be used in new code and is only provided for + backward compatibility. + """ + + if not cpf.isdigit() or len(cpf) != 11 or len(set(cpf)) == 1: + return False + + return all(_hashdigit(cpf, i + 10) == int(v) for i, v in enumerate(cpf[9:])) + + +def is_valid(cpf: str) -> bool: + """ + Returns whether or not the verifying checksum digits of the given `˜CPF` + match its base number. + + This function does not verify the existence of the CPF; it only + validates the format of the string. + + Args: + cpf (str): The CPF to be validated, a 11-digit string + + Returns: + bool: True if the checksum digits match the base number, + False otherwise. + + Example: + >>> is_valid("82178537464") + True + >>> is_valid("55550207753") + True + """ + + return isinstance(cpf, str) and validate(cpf) + + +def generate() -> str: + """ + Generate a random valid CPF digit string. + + This function generates a random valid CPF string. + + Returns: + str: A random valid CPF string. + + Example: + >>> generate() + "10895948109" + >>> generate() + "52837606502" + """ + + base = str(randint(1, 999999998)).zfill(9) + + return base + _checksum(base) + + +def _hashdigit(cpf: str, position: int) -> int: + """ + Compute the given position checksum digit for a CPF. + + This function computes the specified position checksum digit for the CPF + input. + The input needs to contain all elements previous to the position, or the + computation will yield the wrong result. + + Args: + cpf (str): A CPF string. + position (int): The position to calculate the checksum digit for. + + Returns: + int: The calculated checksum digit. + + Example: + >>> _hashdigit("52599927765", 11) + 5 + >>> _hashdigit("52599927765", 10) + 6 + """ + + val = ( + sum( + int(digit) * weight + for digit, weight in zip(cpf, range(position, 1, -1)) + ) + % 11 + ) + + return 0 if val < 2 else 11 - val + + +def _checksum(basenum: str) -> str: + """ + Compute the checksum digits for a given CPF base number. + + This function calculates the checksum digits for a given CPF base number. + The base number should be a digit string of adequate length. + + Args: + basenum (str): A digit string of adequate length. + + Returns: + str: The calculated checksum digits. + + Example: + >>> _checksum("335451269") + '51' + >>> _checksum("382916331") + '26' + """ + + verifying_digits = str(_hashdigit(basenum, 10)) + verifying_digits += str(_hashdigit(basenum + verifying_digits, 11)) + + return verifying_digits From 06d0c8d3d08982f68b3a863632f8570a142e05bc Mon Sep 17 00:00:00 2001 From: Otavio72 Date: Fri, 14 Nov 2025 09:36:40 -0300 Subject: [PATCH 4/4] Remove boleto implementation from PR --- brutils/boleto.py | 205 ---------------------------------------------- 1 file changed, 205 deletions(-) delete mode 100644 brutils/boleto.py diff --git a/brutils/boleto.py b/brutils/boleto.py deleted file mode 100644 index 386dbae..0000000 --- a/brutils/boleto.py +++ /dev/null @@ -1,205 +0,0 @@ -from random import randint - -# FORMATTING -############ - - -def sieve(dirty: str) -> str: - """ - Removes specific symbols from a CPF (Brazilian Individual Taxpayer Number) - string. - - This function takes a CPF string as input and removes all occurrences of - the '.', '-' characters from it. - - Args: - cpf (str): The CPF string containing symbols to be removed. - - Returns: - str: A new string with the specified symbols removed. - - Example: - >>> sieve("123.456.789-01") - '12345678901' - >>> sieve("987-654-321.01") - '98765432101' - - .. note:: - This method should not be used in new code and is only provided for - backward compatibility. - """ - - return "".join(filter(lambda char: char not in ".-", dirty)) - - -def remove_symbols(dirty: str) -> str: - """ - Alias for the `sieve` function. Better naming. - - Args: - cpf (str): The CPF string containing symbols to be removed. - - Returns: - str: A new string with the specified symbols removed. - """ - - return sieve(dirty) - - -def display(boleto: str) -> str: - boleto = remove_symbols(boleto) - - if not boleto.isdigit() or len(boleto) != 47 or len(set(boleto)) == 1: - return None - - return "{}.{} {}.{} {}.{} {} {}".format(boleto[:5], boleto[5:10], boleto[10:15], boleto[15:21], boleto[21:26], boleto[26:32], boleto[32:33], boleto[33:]) - - -def format_boleto(boleto: str) -> str: - - if not is_valid(boleto): - return None - - return "{}.{} {}.{} {}.{} {} {}".format(boleto[:5], boleto[5:10], boleto[10:15], boleto[15:21], boleto[21:26], boleto[26:32], boleto[32:33], boleto[33:]) - - - -# OPERATIONS -############ - - -def validate(boleto: str) -> bool: - """ - Validate the checksum digits of a CPF. - - This function checks whether the verifying checksum digits of the given CPF - match its base number. The input should be a digit string of the proper - length. - - Args: - cpf (str): A numbers-only CPF string. - - Returns: - bool: True if the checksum digits are valid, False otherwise. - - Example: - >>> validate("82178537464") - True - >>> validate("55550207753") - True - - .. note:: - This method should not be used in new code and is only provided for - backward compatibility. - """ - - if not cpf.isdigit() or len(cpf) != 11 or len(set(cpf)) == 1: - return False - - return all(_hashdigit(cpf, i + 10) == int(v) for i, v in enumerate(cpf[9:])) - - -def is_valid(cpf: str) -> bool: - """ - Returns whether or not the verifying checksum digits of the given `˜CPF` - match its base number. - - This function does not verify the existence of the CPF; it only - validates the format of the string. - - Args: - cpf (str): The CPF to be validated, a 11-digit string - - Returns: - bool: True if the checksum digits match the base number, - False otherwise. - - Example: - >>> is_valid("82178537464") - True - >>> is_valid("55550207753") - True - """ - - return isinstance(cpf, str) and validate(cpf) - - -def generate() -> str: - """ - Generate a random valid CPF digit string. - - This function generates a random valid CPF string. - - Returns: - str: A random valid CPF string. - - Example: - >>> generate() - "10895948109" - >>> generate() - "52837606502" - """ - - base = str(randint(1, 999999998)).zfill(9) - - return base + _checksum(base) - - -def _hashdigit(cpf: str, position: int) -> int: - """ - Compute the given position checksum digit for a CPF. - - This function computes the specified position checksum digit for the CPF - input. - The input needs to contain all elements previous to the position, or the - computation will yield the wrong result. - - Args: - cpf (str): A CPF string. - position (int): The position to calculate the checksum digit for. - - Returns: - int: The calculated checksum digit. - - Example: - >>> _hashdigit("52599927765", 11) - 5 - >>> _hashdigit("52599927765", 10) - 6 - """ - - val = ( - sum( - int(digit) * weight - for digit, weight in zip(cpf, range(position, 1, -1)) - ) - % 11 - ) - - return 0 if val < 2 else 11 - val - - -def _checksum(basenum: str) -> str: - """ - Compute the checksum digits for a given CPF base number. - - This function calculates the checksum digits for a given CPF base number. - The base number should be a digit string of adequate length. - - Args: - basenum (str): A digit string of adequate length. - - Returns: - str: The calculated checksum digits. - - Example: - >>> _checksum("335451269") - '51' - >>> _checksum("382916331") - '26' - """ - - verifying_digits = str(_hashdigit(basenum, 10)) - verifying_digits += str(_hashdigit(basenum + verifying_digits, 11)) - - return verifying_digits