-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Murillo Bianconi
committed
Oct 16, 2024
1 parent
f70e7ca
commit 790107d
Showing
9 changed files
with
488 additions
and
157 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
name: Publish Python Package | ||
|
||
on: | ||
push: | ||
tags: | ||
- 'v*.*.*' | ||
|
||
jobs: | ||
publish: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- name: Install uv | ||
uses: astral-sh/setup-uv@v3 | ||
|
||
- name: "Set up Python" | ||
uses: actions/setup-python@v5 | ||
with: | ||
python-version-file: ".python-version" | ||
|
||
- name: "Build" | ||
run: uv build | ||
|
||
- name: Publish to PyPI | ||
run: uv publish | ||
env: | ||
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,162 +1,10 @@ | ||
# Byte-compiled / optimized / DLL files | ||
# Python-generated files | ||
__pycache__/ | ||
*.py[cod] | ||
*$py.class | ||
|
||
# C extensions | ||
*.so | ||
|
||
# Distribution / packaging | ||
.Python | ||
*.py[oc] | ||
build/ | ||
develop-eggs/ | ||
dist/ | ||
downloads/ | ||
eggs/ | ||
.eggs/ | ||
lib/ | ||
lib64/ | ||
parts/ | ||
sdist/ | ||
var/ | ||
wheels/ | ||
share/python-wheels/ | ||
*.egg-info/ | ||
.installed.cfg | ||
*.egg | ||
MANIFEST | ||
|
||
# PyInstaller | ||
# Usually these files are written by a python script from a template | ||
# before PyInstaller builds the exe, so as to inject date/other infos into it. | ||
*.manifest | ||
*.spec | ||
|
||
# Installer logs | ||
pip-log.txt | ||
pip-delete-this-directory.txt | ||
|
||
# Unit test / coverage reports | ||
htmlcov/ | ||
.tox/ | ||
.nox/ | ||
.coverage | ||
.coverage.* | ||
.cache | ||
nosetests.xml | ||
coverage.xml | ||
*.cover | ||
*.py,cover | ||
.hypothesis/ | ||
.pytest_cache/ | ||
cover/ | ||
|
||
# Translations | ||
*.mo | ||
*.pot | ||
|
||
# Django stuff: | ||
*.log | ||
local_settings.py | ||
db.sqlite3 | ||
db.sqlite3-journal | ||
|
||
# Flask stuff: | ||
instance/ | ||
.webassets-cache | ||
|
||
# Scrapy stuff: | ||
.scrapy | ||
|
||
# Sphinx documentation | ||
docs/_build/ | ||
|
||
# PyBuilder | ||
.pybuilder/ | ||
target/ | ||
|
||
# Jupyter Notebook | ||
.ipynb_checkpoints | ||
|
||
# IPython | ||
profile_default/ | ||
ipython_config.py | ||
|
||
# pyenv | ||
# For a library or package, you might want to ignore these files since the code is | ||
# intended to run in multiple environments; otherwise, check them in: | ||
# .python-version | ||
*.egg-info | ||
|
||
# pipenv | ||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. | ||
# However, in case of collaboration, if having platform-specific dependencies or dependencies | ||
# having no cross-platform support, pipenv may install dependencies that don't work, or not | ||
# install all needed dependencies. | ||
#Pipfile.lock | ||
|
||
# poetry | ||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. | ||
# This is especially recommended for binary packages to ensure reproducibility, and is more | ||
# commonly ignored for libraries. | ||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control | ||
#poetry.lock | ||
|
||
# pdm | ||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. | ||
#pdm.lock | ||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it | ||
# in version control. | ||
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control | ||
.pdm.toml | ||
.pdm-python | ||
.pdm-build/ | ||
|
||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm | ||
__pypackages__/ | ||
|
||
# Celery stuff | ||
celerybeat-schedule | ||
celerybeat.pid | ||
|
||
# SageMath parsed files | ||
*.sage.py | ||
|
||
# Environments | ||
.env | ||
# Virtual environments | ||
.venv | ||
env/ | ||
venv/ | ||
ENV/ | ||
env.bak/ | ||
venv.bak/ | ||
|
||
# Spyder project settings | ||
.spyderproject | ||
.spyproject | ||
|
||
# Rope project settings | ||
.ropeproject | ||
|
||
# mkdocs documentation | ||
/site | ||
|
||
# mypy | ||
.mypy_cache/ | ||
.dmypy.json | ||
dmypy.json | ||
|
||
# Pyre type checker | ||
.pyre/ | ||
|
||
# pytype static type analyzer | ||
.pytype/ | ||
|
||
# Cython debug symbols | ||
cython_debug/ | ||
|
||
# PyCharm | ||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can | ||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore | ||
# and can be added to the global gitignore or merged into this file. For a more nuclear | ||
# option (not recommended) you can uncomment the following to ignore the entire idea folder. | ||
#.idea/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
3.11 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,54 @@ | ||
# omie-py | ||
# Documentação do Integrador Omie | ||
|
||
## Dependencias | ||
A única dependencia necessária é a biblioteca [zeep](https://docs.python-zeep.org/en/master/index.html), que é usada para criar os clientes SOAP. | ||
|
||
## Autenticação | ||
|
||
Para autenticar na API do Omie, você precisa fornecer uma `app_key` e um (`app_secret`). Esse dados são obtidos no site da [omie](https://developer.omie.com.br/). | ||
|
||
```python | ||
import os | ||
|
||
from omie_py.client import OmieClient | ||
|
||
key = os.getenv('OMIE_APP_KEY') | ||
secret = os.getenv('OMIE_APP_SECRET') | ||
client = OmieClient(key, secret) | ||
``` | ||
|
||
## Usar métodos das API | ||
|
||
A Omie disponibiliza várias APIs e o cliente recebe uma chamada e verifica em qual API o método está disponível e executa a chamada. O mesmo vale para os tipos disponibilizados na API. | ||
|
||
Para verificar os métodos e tipos disponiveis o [site da API](https://developer.omie.com.br/service-list/) deve ser usado. | ||
|
||
Os tipos oferecem validação de campos e tipos. | ||
|
||
Exemplo para listar departamentos. | ||
|
||
```python | ||
departamento_listar_request = client.get_type('departamento_listar_request') | ||
|
||
response_pages = client.execute_call("ListarDepartamentos", departamento_listar_request(**{ | ||
"pagina": 1, | ||
"registros_por_pagina": 20, | ||
}), True) | ||
|
||
for response in response_pages: | ||
print(response) | ||
``` | ||
|
||
### Métodos principais do cliente | ||
|
||
- `execute_call(method_name: str, params: dict, is_paginated: bool = False)`: Executa uma chamada à API. | ||
- `get_type(type_name)`: Obtém um tipo específico para ser usado nas requisições. | ||
|
||
### Classe PaginatedResponse | ||
|
||
Quando o `is_paginated` é passado como `True` para o método execute_call, o retorno é um `Iterable` que faz as chamadas subsequentes para o método. | ||
|
||
### Rate limit | ||
A API atualmente limite a 4 req/s e o projeto não gerencia isso. | ||
|
||
[Mais informações](https://ajuda.omie.com.br/pt-BR/articles/8112984-limites-de-consumo-da-api-do-omie). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
[project] | ||
name = "omie-py" | ||
version = "0.1.0" | ||
description = "Add your description here" | ||
authors = [ | ||
{ name = "Murillo Bianconi", email = "[email protected]" } | ||
] | ||
requires-python = ">=3.11" | ||
dependencies = [ | ||
"zeep>=4.3.1", | ||
] | ||
|
||
[build-system] | ||
requires = ["hatchling"] | ||
build-backend = "hatchling.build" | ||
|
||
[tool.uv] | ||
dev-dependencies = [ | ||
"ruff>=0.6.9", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
def hello() -> str: | ||
return "Hello from omie-py!" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import zeep.exceptions | ||
from zeep import Client, xsd | ||
|
||
|
||
class OmieClient: | ||
_WDSLS = [ | ||
"https://app.omie.com.br/api/v1/financas/contapagar/?WSDL", | ||
"https://app.omie.com.br/api/v1/financas/contareceber/?WSDL", | ||
"https://app.omie.com.br/api/v1/geral/anexo/?WSDL", | ||
"https://app.omie.com.br/api/v1/geral/clientes/?WSDL", | ||
"https://app.omie.com.br/api/v1/geral/categorias/?WSDL", | ||
"https://app.omie.com.br/api/v1/geral/departamentos/?WSDL", | ||
] | ||
|
||
def __init__(self, app_key, app_secret) -> None: | ||
self._app_key = app_key | ||
self._app_secret = app_secret | ||
self._clients = [] | ||
|
||
auth_header = xsd.Element( | ||
"auth", | ||
xsd.ComplexType( | ||
[ | ||
xsd.Element("app_key", xsd.String()), | ||
xsd.Element("app_secret", xsd.String()), | ||
] | ||
), | ||
) | ||
|
||
auth_value = auth_header(app_key=self._app_key, app_secret=self._app_secret) | ||
|
||
for wdsl in self._WDSLS: | ||
client = Client(wdsl) | ||
client.set_default_soapheaders([auth_value]) | ||
self._clients.append(client) | ||
|
||
def execute_call(self, method_name: str, params: dict, is_paginated: bool = False): | ||
for client in self._clients: | ||
method = getattr(client.service, method_name, None) | ||
if method: | ||
response = method(params) | ||
if ( | ||
is_paginated | ||
and "total_de_paginas" in response | ||
or "nTotPaginas" in response | ||
): | ||
return PaginatedResponse(method, params, response) | ||
return response | ||
|
||
raise ValueError( | ||
f"Método '{method_name}' não encontrado em nenhum endpoint registrado." | ||
) | ||
|
||
def get_type(self, type_name): | ||
for client in self._clients: | ||
try: | ||
return client.get_type("ns0:" + type_name) | ||
except zeep.exceptions.LookupError: | ||
continue | ||
raise ValueError( | ||
f"Tipo '{type_name}' não encontrado em nenhum endpoint registrado." | ||
) | ||
|
||
|
||
class PaginatedResponse: | ||
def __init__(self, method, params: dict, response: dict) -> None: | ||
self.page_number = getattr( | ||
response, "pagina", getattr(response, "nPagina", None) | ||
) | ||
self.page_total = getattr( | ||
response, "total_de_paginas", getattr(response, "nTotPaginas", None) | ||
) | ||
self.params = params | ||
self._method = method | ||
self._current_response = response | ||
self._first_return = False | ||
|
||
def __iter__(self): | ||
return self | ||
|
||
def __next__(self): | ||
if not self._first_return: | ||
self._first_return = True | ||
return self._current_response | ||
|
||
self.page_number += 1 | ||
|
||
if self.page_number > self.page_total: | ||
raise StopIteration() | ||
|
||
if "pagina" in self.params: | ||
self.params["pagina"] = self.page_number | ||
if "nPagina" in self.params: | ||
self.params["nPagina"] = self.page_number | ||
|
||
self._current_response = self._method(self.params) | ||
|
||
return self._current_response |
Empty file.
Oops, something went wrong.