Finaliza ajustes para iniciar Repositorio Git do SDK de Integração do Notion separado do meu projeto original
--- - Cria singleton de `client` com func `configure` para inicializar e `get_instance` para buscar instância do client; - Ajusta clients para buscar headers vindo do pai `client` e fixa versão legacy no client de databases; - Adiciona inicialização de `client` no init do projeto com api_token e api_version informados pelo usuário; - Altera `NotionConfig` para inserir `database_id` no lugar de `database_name`; - Altera sistema para receber `database_id` no lugar de `database_name`; - Altera tipo de `properties` em `schemas.responses.pages.Page` de `Union[Dict[str, Any]], TDB` para `Union[Any, TDB]` para resolver reclamações de type hint; - Adiciona param `generic_response` no init de `client` e nos clients e databases e pages para pular uso de mapping ao usar `.generic`; - Adiciona param `raw_response` para pular parser e mappings e retornar resposta original da api; - Finaliza `types` com subpastas para importações mas com init mãe vazio para evitar dependência circular e permitir uso de `notion.types.` pelo usuário; - Remove importações do projeto original não relacionadas com o SDK; - Adiciona param `timezone` na func `start_date` em `orm.common.SetProperty` que antes vinha do env, para posteriormente puxar da init da integração; - Monta `LICENSE`, `README.md` e `pyproject.toml` base simples para commit inicial do projeto permitindo build de pacote; ---
This commit is contained in:
Executable
+10
@@ -0,0 +1,10 @@
|
|||||||
|
# Python Cache Files
|
||||||
|
**/__pycache__/
|
||||||
|
# Python Virtual Environment
|
||||||
|
.venv
|
||||||
|
# Environment Settings
|
||||||
|
.env
|
||||||
|
# VSCode Settings
|
||||||
|
.vscode
|
||||||
|
# Temp Folder
|
||||||
|
.temp/
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# MIT License
|
||||||
|
|
||||||
|
Copyright 2026 Eduardo Riguetto (kralot / riguettodev)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Notion SDK
|
||||||
|
|
||||||
|
**SDK para Integração com Notion API** com base forte em *pydantic*, *asyncio*, e programação orientada a objetos.
|
||||||
|
|
||||||
|
Pensado para o uso como *ORMs*. Permitindo personalização total do usuário ao configurar suas Databases do Notion, com recursos como mapeamentos, transformadores, validadores, calculos e mais.
|
||||||
Executable
+52
@@ -0,0 +1,52 @@
|
|||||||
|
from typing import Type, TypeVar, Generic, Union, Literal
|
||||||
|
from .auth import headers as _headers
|
||||||
|
from .schemas.orm.database.DatabasesContainer import DatabasesContainer as _DatabasesContainer
|
||||||
|
from .orm.repositories import _Repositories
|
||||||
|
from .client import Client as _Client
|
||||||
|
|
||||||
|
TContainer = TypeVar('TContainer', bound = _DatabasesContainer)
|
||||||
|
|
||||||
|
class Notion(Generic[TContainer]):
|
||||||
|
|
||||||
|
"Classe principal para configurar a integração Notion."
|
||||||
|
|
||||||
|
orm: '_ORM[TContainer]'
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
api_token : str,
|
||||||
|
api_version : Union[Literal["legacy", "data_sources"], str] = "data_sources",
|
||||||
|
orm_container : Type[TContainer] = _DatabasesContainer,
|
||||||
|
timezone : str = "Etc/UTC"
|
||||||
|
):
|
||||||
|
|
||||||
|
"""
|
||||||
|
### Integration Params
|
||||||
|
- **api_token** = Bearer Token de Integração com a API Notion.
|
||||||
|
- **api_version** = Seleção entre versão `legacy` com Databases e versão mais nova com `data_sources`, permitindo inserir versão personalizada. Valor padrão: `legacy` *(2022-06-28)*.
|
||||||
|
- **orm_container** = Databases Container com configuração de ORM personalizada com classe base de tipo `types.DatabasesContainer`
|
||||||
|
"""
|
||||||
|
|
||||||
|
headers = _headers(
|
||||||
|
api_token = api_token,
|
||||||
|
api_version = api_version
|
||||||
|
)
|
||||||
|
_Client.configure(headers)
|
||||||
|
self.client = _Client.get_instance()
|
||||||
|
|
||||||
|
self.orm = _ORM(databases_container = orm_container)
|
||||||
|
|
||||||
|
self.DatabasesContainer = _DatabasesContainer
|
||||||
|
|
||||||
|
class _ORM(Generic[TContainer]):
|
||||||
|
|
||||||
|
"Namespace ORM com tipo propagado"
|
||||||
|
|
||||||
|
repo: _Repositories[TContainer]
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
databases_container : Type[TContainer]
|
||||||
|
):
|
||||||
|
self.repo = _Repositories()
|
||||||
|
self.repo.databases.container = databases_container()
|
||||||
|
|
||||||
|
__all__ = ["Notion"]
|
||||||
Executable
+22
@@ -0,0 +1,22 @@
|
|||||||
|
from typing import Literal, Union
|
||||||
|
|
||||||
|
def headers(
|
||||||
|
api_token : str,
|
||||||
|
api_version : Union[Literal["legacy", "data_sources"], str] = "data_sources"
|
||||||
|
):
|
||||||
|
|
||||||
|
match api_version:
|
||||||
|
case "legacy":
|
||||||
|
version = "2022-06-28"
|
||||||
|
case "data_sources":
|
||||||
|
version = "2025-09-03"
|
||||||
|
case _:
|
||||||
|
version = api_version
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"Authorization" : f"Bearer {api_token}",
|
||||||
|
"Content-Type" : "application/json",
|
||||||
|
"Notion-Version" : version
|
||||||
|
}
|
||||||
|
|
||||||
|
return headers
|
||||||
Executable
+75
@@ -0,0 +1,75 @@
|
|||||||
|
from typing import Dict, Optional
|
||||||
|
from .blocks import Blocks
|
||||||
|
from .pages import Pages
|
||||||
|
from .databases import Databases
|
||||||
|
|
||||||
|
class Client:
|
||||||
|
|
||||||
|
"Client singleton da API Notion"
|
||||||
|
|
||||||
|
_headers : Optional[Dict[str, str]] = None
|
||||||
|
_instance : Optional['Client'] = None
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._blocks = None
|
||||||
|
self._pages = None
|
||||||
|
self._databases = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def configure(cls, headers : Dict[str, str]):
|
||||||
|
|
||||||
|
"Configura o client com headers"
|
||||||
|
|
||||||
|
cls._headers = headers
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_instance(cls) -> 'Client':
|
||||||
|
|
||||||
|
"Retorna a instância configurada"
|
||||||
|
|
||||||
|
if cls._instance is None:
|
||||||
|
|
||||||
|
cls._instance = Client()
|
||||||
|
|
||||||
|
return cls._instance
|
||||||
|
|
||||||
|
@property
|
||||||
|
def blocks(self) -> Blocks:
|
||||||
|
|
||||||
|
if self._blocks is None:
|
||||||
|
|
||||||
|
if Client._headers is None:
|
||||||
|
raise RuntimeError("Client não configurado. Instancie NotionIntegration primeiro.")
|
||||||
|
|
||||||
|
self._blocks = Blocks(Client._headers)
|
||||||
|
|
||||||
|
return self._blocks
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pages(self) -> Pages:
|
||||||
|
|
||||||
|
if self._pages is None:
|
||||||
|
|
||||||
|
if Client._headers is None:
|
||||||
|
raise RuntimeError("Client não configurado. Instancie NotionIntegration primeiro.")
|
||||||
|
|
||||||
|
self._pages = Pages(Client._headers)
|
||||||
|
|
||||||
|
return self._pages
|
||||||
|
|
||||||
|
@property
|
||||||
|
def databases(self) -> Databases:
|
||||||
|
|
||||||
|
if self._databases is None:
|
||||||
|
|
||||||
|
if Client._headers is None:
|
||||||
|
raise RuntimeError("Client não configurado. Instancie NotionIntegration primeiro.")
|
||||||
|
|
||||||
|
self._databases = Databases(Client._headers)
|
||||||
|
|
||||||
|
return self._databases
|
||||||
|
|
||||||
|
def get_client() -> Client:
|
||||||
|
return Client.get_instance()
|
||||||
|
|
||||||
|
__all__ = ["Client", "get_client"]
|
||||||
Executable
+24
@@ -0,0 +1,24 @@
|
|||||||
|
import httpx
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
|
class Blocks:
|
||||||
|
|
||||||
|
"Reference: https://developers.notion.com/reference/retrieve-a-block"
|
||||||
|
|
||||||
|
def __init__(self, headers : Dict[str, str]):
|
||||||
|
self._headers = headers
|
||||||
|
|
||||||
|
async def get_children(self, page_id : str):
|
||||||
|
|
||||||
|
"Busca pelos blocos de uma página"
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(timeout=httpx.Timeout(30.0)) as client:
|
||||||
|
|
||||||
|
response = await client.get(
|
||||||
|
f'https://api.notion.com/v1/blocks/{page_id}/children',
|
||||||
|
headers = self._headers
|
||||||
|
)
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
__all__ = ["Blocks"]
|
||||||
Executable
+64
@@ -0,0 +1,64 @@
|
|||||||
|
import httpx
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
|
class Databases:
|
||||||
|
|
||||||
|
def __init__(self, headers : Dict[str, str]):
|
||||||
|
self._headers = {**headers, "Notion-Version": "2022-06-28"}
|
||||||
|
|
||||||
|
async def get(self, database_id):
|
||||||
|
|
||||||
|
"Buscar informações de um Banco de Dados"
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(timeout=httpx.Timeout(30.0)) as client:
|
||||||
|
|
||||||
|
response = await client.get(
|
||||||
|
f'https://api.notion.com/v1/databases/{database_id}',
|
||||||
|
headers = self._headers
|
||||||
|
)
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
async def query(self, database_id, json_data = {}):
|
||||||
|
|
||||||
|
"Buscar as Páginas de um Banco de Dados"
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(timeout=httpx.Timeout(30.0)) as client:
|
||||||
|
|
||||||
|
response = await client.post(
|
||||||
|
f'https://api.notion.com/v1/databases/{database_id}/query',
|
||||||
|
headers = self._headers,
|
||||||
|
json = json_data
|
||||||
|
)
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
async def query_propriety(self, database_id, propriety_type, json_data = {}):
|
||||||
|
|
||||||
|
"Buscar as Páginas de um Banco de Dados filtrando por uma Propriedade"
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(timeout=httpx.Timeout(30.0)) as client:
|
||||||
|
|
||||||
|
response = await client.post(
|
||||||
|
f'https://api.notion.com/v1/databases/{database_id}/query?filter_properties={propriety_type}',
|
||||||
|
headers = self._headers,
|
||||||
|
json = json_data
|
||||||
|
)
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
async def update(self, database_id, json_data):
|
||||||
|
|
||||||
|
"Atualiza as informações sobre um Banco de Dados"
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(timeout=httpx.Timeout(30.0)) as client:
|
||||||
|
|
||||||
|
response = await client.patch(
|
||||||
|
f'https://api.notion.com/v1/databases/{database_id}',
|
||||||
|
headers = self._headers,
|
||||||
|
json = json_data
|
||||||
|
)
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
__all__ = ["Databases"]
|
||||||
Executable
+73
@@ -0,0 +1,73 @@
|
|||||||
|
import httpx
|
||||||
|
from typing import Dict, Any
|
||||||
|
|
||||||
|
class Pages:
|
||||||
|
|
||||||
|
def __init__(self, headers : Dict[str, str]):
|
||||||
|
self._headers = headers
|
||||||
|
|
||||||
|
async def get(self,
|
||||||
|
page_id : str
|
||||||
|
):
|
||||||
|
|
||||||
|
"Buscar informações de uma Página"
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(timeout=httpx.Timeout(30.0)) as client:
|
||||||
|
|
||||||
|
response = await client.get(
|
||||||
|
f'https://api.notion.com/v1/pages/{page_id}',
|
||||||
|
headers = self._headers
|
||||||
|
)
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
async def get_property(self,
|
||||||
|
page_id : str,
|
||||||
|
property_name : str
|
||||||
|
):
|
||||||
|
|
||||||
|
"Buscar por informações de uma Propriedade em uma Página"
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(timeout=httpx.Timeout(30.0)) as client:
|
||||||
|
|
||||||
|
response = await client.get(
|
||||||
|
f'https://api.notion.com/v1/pages/{page_id}/properties/{property_name}',
|
||||||
|
headers = self._headers
|
||||||
|
)
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
async def update_properties(self,
|
||||||
|
page_id : str,
|
||||||
|
json_data : Dict[str, Any]
|
||||||
|
):
|
||||||
|
|
||||||
|
"Atualiza as Propriedades de uma Página"
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(timeout=httpx.Timeout(30.0)) as client:
|
||||||
|
|
||||||
|
response = await client.patch(
|
||||||
|
f'https://api.notion.com/v1/pages/{page_id}',
|
||||||
|
headers = self._headers,
|
||||||
|
json=json_data
|
||||||
|
)
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
async def create(self,
|
||||||
|
json_data : Dict[str, Any]
|
||||||
|
):
|
||||||
|
|
||||||
|
"Criar uma nova Página"
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(timeout=httpx.Timeout(30.0)) as client:
|
||||||
|
|
||||||
|
response = await client.post(
|
||||||
|
f'https://api.notion.com/v1/pages',
|
||||||
|
headers = self._headers,
|
||||||
|
json = json_data
|
||||||
|
)
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
__all__ = ["Pages"]
|
||||||
Executable
+15
@@ -0,0 +1,15 @@
|
|||||||
|
from .common import Common as _common
|
||||||
|
from .parsers import Parser as _parser
|
||||||
|
from .mapping import Mapping as _mapping
|
||||||
|
from .repositories import repo as _repositories
|
||||||
|
|
||||||
|
class _NotionOrm:
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.common = _common
|
||||||
|
self.parser = _parser
|
||||||
|
self.mapping = _mapping
|
||||||
|
self.repo = _repositories
|
||||||
|
|
||||||
|
NotionOrm = _NotionOrm()
|
||||||
|
__all__ = ["NotionOrm"]
|
||||||
Executable
+106
@@ -0,0 +1,106 @@
|
|||||||
|
from typing import Any, Optional
|
||||||
|
from pydantic import validate_call
|
||||||
|
from ..extrators.Properties import PropertyExtractor
|
||||||
|
|
||||||
|
class _PageProperty(PropertyExtractor):
|
||||||
|
|
||||||
|
"Getter específico para propriedades individuais do Notion. Permite buscar uma propriedade específica por nome e tipo."
|
||||||
|
|
||||||
|
def _get_properties_dict(self, response: dict) -> dict:
|
||||||
|
"Extrai o dicionário de properties do response"
|
||||||
|
nt_dict = response.get('properties')
|
||||||
|
if nt_dict is None:
|
||||||
|
nt_dict = response.get('result')
|
||||||
|
if nt_dict is None:
|
||||||
|
raise KeyError("Response inserido é inválido")
|
||||||
|
return nt_dict
|
||||||
|
|
||||||
|
def _get_property_data(self, response: dict, name: str, expected_type: str) -> dict:
|
||||||
|
|
||||||
|
"""
|
||||||
|
Busca e valida uma propriedade específica.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
response: Response completo do Notion
|
||||||
|
name: Nome da propriedade
|
||||||
|
expected_type: Tipo esperado da propriedade
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dados da propriedade
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
KeyError: Se propriedade não existe
|
||||||
|
ValueError: Se tipo não corresponde
|
||||||
|
"""
|
||||||
|
|
||||||
|
properties = self._get_properties_dict(response)
|
||||||
|
|
||||||
|
prop = properties.get(name)
|
||||||
|
if not prop:
|
||||||
|
raise KeyError(f"Propriedade '{name}' não foi encontrada")
|
||||||
|
|
||||||
|
actual_type = prop.get('type')
|
||||||
|
if actual_type != expected_type:
|
||||||
|
raise ValueError(
|
||||||
|
f"Propriedade '{name}' não é do tipo '{expected_type}' "
|
||||||
|
f"(tipo atual: '{actual_type}')"
|
||||||
|
)
|
||||||
|
|
||||||
|
return prop
|
||||||
|
|
||||||
|
# ==================== CLASSES INTERNAS ====================
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def id(self, response: dict) -> str:
|
||||||
|
prop = response.get('id')
|
||||||
|
if not prop:
|
||||||
|
raise KeyError("ID da página não foi encontrada")
|
||||||
|
return prop
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def title(self, response: dict, name: str) -> Optional[str]:
|
||||||
|
prop = self._get_property_data(response, name, "title")
|
||||||
|
return self._title(prop)
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def text(self, response: dict, name: str) -> Optional[dict]:
|
||||||
|
prop = self._get_property_data(response, name, "rich_text")
|
||||||
|
return self._rich_text(prop)
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def number(self, response: dict, name: str) -> Optional[float]:
|
||||||
|
prop = self._get_property_data(response, name, "number")
|
||||||
|
return self._number(prop)
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def select(self, response: dict, name: str) -> Optional[dict]:
|
||||||
|
prop = self._get_property_data(response, name, "select")
|
||||||
|
return self._select(prop)
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def checkbox(self, response: dict, name: str) -> bool:
|
||||||
|
prop = self._get_property_data(response, name, "checkbox")
|
||||||
|
return self._checkbox(prop)
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def date(self, response: dict, name: str) -> Optional[dict]:
|
||||||
|
prop = self._get_property_data(response, name, "date")
|
||||||
|
return self._date(prop)
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def relation(self, response: dict, name: str) -> Optional[list]:
|
||||||
|
prop = self._get_property_data(response, name, "relation")
|
||||||
|
return self._relation(prop)
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def rollup(self, response: dict, name: str) -> Any:
|
||||||
|
prop = self._get_property_data(response, name, "rollup")
|
||||||
|
return self._rollup(prop)
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def formula(self, response: dict, name: str) -> Any:
|
||||||
|
prop = self._get_property_data(response, name, "formula")
|
||||||
|
return self._formula(prop)
|
||||||
|
|
||||||
|
PageProperty = _PageProperty()
|
||||||
|
__all__ = ['_PageProperty']
|
||||||
Executable
+9
@@ -0,0 +1,9 @@
|
|||||||
|
from .PageProperty import PageProperty as _PageProperty
|
||||||
|
|
||||||
|
class _Acessors:
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.PageProperty = _PageProperty
|
||||||
|
|
||||||
|
Acessors = _Acessors
|
||||||
|
__all__ = ["Acessors"]
|
||||||
Executable
+12
@@ -0,0 +1,12 @@
|
|||||||
|
import json
|
||||||
|
from ..QueryFilter import QueryFilter
|
||||||
|
|
||||||
|
filter1 = QueryFilter.and_(
|
||||||
|
QueryFilter.title("Name", "contains", "Teste"),
|
||||||
|
QueryFilter.or_(
|
||||||
|
QueryFilter.number("Value", "greater_than", 10),
|
||||||
|
QueryFilter.number("Value", "less_than", 5)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
print(json.dumps({"filter":filter1.to_dict()}))
|
||||||
Executable
+12
@@ -0,0 +1,12 @@
|
|||||||
|
import json
|
||||||
|
from ..QuerySort import QuerySort
|
||||||
|
|
||||||
|
sort1 = QuerySort.ascending("Teste")
|
||||||
|
|
||||||
|
print(json.dumps({"sorts":sort1.to_dict()}))
|
||||||
|
|
||||||
|
sort2 = QuerySort.and_(
|
||||||
|
QuerySort.ascending("Teste")
|
||||||
|
)
|
||||||
|
|
||||||
|
print(json.dumps({"sorts":sort2.to_dict()}))
|
||||||
Executable
+541
@@ -0,0 +1,541 @@
|
|||||||
|
from typing import Any, Dict, Literal, Union
|
||||||
|
from datetime import datetime, date
|
||||||
|
|
||||||
|
class _NotionFilter:
|
||||||
|
|
||||||
|
"Classe base para filtros do Notion"
|
||||||
|
|
||||||
|
def to_dict(self) -> Dict[str, Any]:
|
||||||
|
"Converte o filtro para o formato JSON do Notion"
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def and_(self, *filters: '_NotionFilter') -> '_NotionFilter':
|
||||||
|
"Combina este filtro com outros usando AND"
|
||||||
|
return _AndFilter(self, *filters)
|
||||||
|
|
||||||
|
def or_(self, *filters: '_NotionFilter') -> '_NotionFilter':
|
||||||
|
"Combina este filtro com outros usando OR"
|
||||||
|
return _OrFilter(self, *filters)
|
||||||
|
|
||||||
|
class _PropertyFilter(_NotionFilter):
|
||||||
|
|
||||||
|
"Filtro para uma propriedade específica"
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
property_name: str,
|
||||||
|
property_type: str,
|
||||||
|
condition: str,
|
||||||
|
value: Any
|
||||||
|
):
|
||||||
|
self.property_name = property_name
|
||||||
|
self.property_type = property_type
|
||||||
|
self.condition = condition
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def to_dict(self) -> Dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"property": self.property_name,
|
||||||
|
self.property_type: {
|
||||||
|
self.condition: self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AndFilter(_NotionFilter):
|
||||||
|
|
||||||
|
"Combina múltiplos filtros com AND"
|
||||||
|
|
||||||
|
def __init__(self, *filters: _NotionFilter):
|
||||||
|
self.filters = list(filters)
|
||||||
|
|
||||||
|
def to_dict(self) -> Dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"and": [filter_obj.to_dict() for filter_obj in self.filters]
|
||||||
|
}
|
||||||
|
|
||||||
|
class _OrFilter(_NotionFilter):
|
||||||
|
|
||||||
|
"Combina múltiplos filtros com OR"
|
||||||
|
|
||||||
|
def __init__(self, *filters: _NotionFilter):
|
||||||
|
self.filters = list(filters)
|
||||||
|
|
||||||
|
def to_dict(self) -> Dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"or": [filter_obj.to_dict() for filter_obj in self.filters]
|
||||||
|
}
|
||||||
|
|
||||||
|
class QueryFilter:
|
||||||
|
|
||||||
|
"Builder principal para criar filtros"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def and_(*filters: _NotionFilter) -> _AndFilter:
|
||||||
|
"Combina filtros com AND"
|
||||||
|
return _AndFilter(*filters)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def or_(*filters: _NotionFilter) -> _OrFilter:
|
||||||
|
"Combina filtros com OR"
|
||||||
|
return _OrFilter(*filters)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def created_time(
|
||||||
|
property_name: str,
|
||||||
|
condition: Literal[
|
||||||
|
"equals",
|
||||||
|
"before",
|
||||||
|
"after",
|
||||||
|
"on_or_before",
|
||||||
|
"on_or_after",
|
||||||
|
"is_empty",
|
||||||
|
"is_not_empty"
|
||||||
|
],
|
||||||
|
value: Union[date, Literal[True]]
|
||||||
|
):
|
||||||
|
if isinstance(value, date):
|
||||||
|
property_value = value.strftime("%Y-%m-%d")
|
||||||
|
else:
|
||||||
|
property_value = value
|
||||||
|
return _PropertyFilter(
|
||||||
|
property_name = property_name,
|
||||||
|
property_type = "created_time",
|
||||||
|
condition = condition,
|
||||||
|
value = property_value
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def last_edited_time(
|
||||||
|
property_name: str,
|
||||||
|
condition: Literal[
|
||||||
|
"equals",
|
||||||
|
"before",
|
||||||
|
"after",
|
||||||
|
"on_or_before",
|
||||||
|
"on_or_after",
|
||||||
|
"is_empty",
|
||||||
|
"is_not_empty"
|
||||||
|
],
|
||||||
|
value: Union[date, Literal[True]]
|
||||||
|
):
|
||||||
|
if isinstance(value, date):
|
||||||
|
property_value = value.strftime("%Y-%m-%d")
|
||||||
|
else:
|
||||||
|
property_value = value
|
||||||
|
return _PropertyFilter(
|
||||||
|
property_name = property_name,
|
||||||
|
property_type = "last_edited_time",
|
||||||
|
condition = condition,
|
||||||
|
value = property_value
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def title(
|
||||||
|
property_name: str,
|
||||||
|
condition: Literal[
|
||||||
|
"equals",
|
||||||
|
"does_not_equal",
|
||||||
|
"contains",
|
||||||
|
"does_not_contain",
|
||||||
|
"starts_with",
|
||||||
|
"ends_with",
|
||||||
|
"is_empty",
|
||||||
|
"is_not_empty"
|
||||||
|
],
|
||||||
|
value: str
|
||||||
|
):
|
||||||
|
property_value = value
|
||||||
|
return _PropertyFilter(
|
||||||
|
property_name = property_name,
|
||||||
|
property_type = "title",
|
||||||
|
condition = condition,
|
||||||
|
value = property_value
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def rich_text(
|
||||||
|
property_name: str,
|
||||||
|
condition: Literal[
|
||||||
|
"equals",
|
||||||
|
"does_not_equal",
|
||||||
|
"contains",
|
||||||
|
"does_not_contain",
|
||||||
|
"starts_with",
|
||||||
|
"ends_with",
|
||||||
|
"is_empty",
|
||||||
|
"is_not_empty"
|
||||||
|
],
|
||||||
|
value: str
|
||||||
|
):
|
||||||
|
property_value = value
|
||||||
|
return _PropertyFilter(
|
||||||
|
property_name = property_name,
|
||||||
|
property_type = "rich_text",
|
||||||
|
condition = condition,
|
||||||
|
value = property_value
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def number(
|
||||||
|
property_name: str,
|
||||||
|
condition: Literal[
|
||||||
|
"equals",
|
||||||
|
"does_not_equal",
|
||||||
|
"greater_than",
|
||||||
|
"less_than",
|
||||||
|
"greater_than_or_equal_to",
|
||||||
|
"less_than_or_equal_to",
|
||||||
|
"is_empty",
|
||||||
|
"is_not_empty"
|
||||||
|
],
|
||||||
|
value: Union[float, Literal[True]]
|
||||||
|
):
|
||||||
|
property_value = value
|
||||||
|
return _PropertyFilter(
|
||||||
|
property_name = property_name,
|
||||||
|
property_type = "number",
|
||||||
|
condition = condition,
|
||||||
|
value = property_value
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def checkbox(
|
||||||
|
property_name: str,
|
||||||
|
condition: Literal[
|
||||||
|
"equals",
|
||||||
|
"does_not_equal"
|
||||||
|
],
|
||||||
|
value: Literal[True]
|
||||||
|
):
|
||||||
|
property_value = value
|
||||||
|
return _PropertyFilter(
|
||||||
|
property_name = property_name,
|
||||||
|
property_type = "checkbox",
|
||||||
|
condition = condition,
|
||||||
|
value = property_value
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def select(
|
||||||
|
property_name: str,
|
||||||
|
condition: Literal[
|
||||||
|
"equals",
|
||||||
|
"does_not_equal",
|
||||||
|
"is_empty",
|
||||||
|
"is_not_empty"
|
||||||
|
],
|
||||||
|
value: Union[str, Literal[True]]
|
||||||
|
):
|
||||||
|
property_value = value
|
||||||
|
return _PropertyFilter(
|
||||||
|
property_name = property_name,
|
||||||
|
property_type = "select",
|
||||||
|
condition = condition,
|
||||||
|
value = property_value
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def multi_select(
|
||||||
|
property_name: str,
|
||||||
|
condition: Literal[
|
||||||
|
"contains",
|
||||||
|
"does_not_contain",
|
||||||
|
"equals",
|
||||||
|
"does_not_equal",
|
||||||
|
"is_empty",
|
||||||
|
"is_not_empty"
|
||||||
|
],
|
||||||
|
value: Union[str, Literal[True]]
|
||||||
|
):
|
||||||
|
property_value = value
|
||||||
|
return _PropertyFilter(
|
||||||
|
property_name = property_name,
|
||||||
|
property_type = "multi_select",
|
||||||
|
condition = condition,
|
||||||
|
value = property_value
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def status(
|
||||||
|
property_name: str,
|
||||||
|
condition: Literal[
|
||||||
|
"equals",
|
||||||
|
"does_not_equal",
|
||||||
|
"is_empty",
|
||||||
|
"is_not_empty"
|
||||||
|
],
|
||||||
|
value: Union[str, Literal[True]]
|
||||||
|
):
|
||||||
|
property_value = value
|
||||||
|
return _PropertyFilter(
|
||||||
|
property_name = property_name,
|
||||||
|
property_type = "status",
|
||||||
|
condition = condition,
|
||||||
|
value = property_value
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def dates(
|
||||||
|
property_name: str,
|
||||||
|
condition: Literal[
|
||||||
|
"equals",
|
||||||
|
"does_not_equal",
|
||||||
|
"after",
|
||||||
|
"on_or_before",
|
||||||
|
"on_or_after",
|
||||||
|
"is_empty",
|
||||||
|
"is_not_empty"
|
||||||
|
],
|
||||||
|
value: Union[date, datetime, Literal[True]]
|
||||||
|
):
|
||||||
|
if isinstance(value, date):
|
||||||
|
property_value = value.strftime("%Y-%m-%d")
|
||||||
|
elif isinstance(value, datetime):
|
||||||
|
property_value = value.strftime("%Y-%m-%dT%H:%M:%S")
|
||||||
|
else:
|
||||||
|
property_value = value
|
||||||
|
return _PropertyFilter(
|
||||||
|
property_name = property_name,
|
||||||
|
property_type = "date",
|
||||||
|
condition = condition,
|
||||||
|
value = property_value
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def people(
|
||||||
|
property_name: str,
|
||||||
|
condition: Literal[
|
||||||
|
"contains",
|
||||||
|
"does_not_contain",
|
||||||
|
"is_empty",
|
||||||
|
"is_not_empty"
|
||||||
|
],
|
||||||
|
value: Union[str, Literal[True]]
|
||||||
|
):
|
||||||
|
property_value = value
|
||||||
|
return _PropertyFilter(
|
||||||
|
property_name = property_name,
|
||||||
|
property_type = "people",
|
||||||
|
condition = condition,
|
||||||
|
value = property_value
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def files(
|
||||||
|
property_name: str,
|
||||||
|
condition: Literal[
|
||||||
|
"is_empty",
|
||||||
|
"is_not_empty"
|
||||||
|
],
|
||||||
|
value: Literal[True]
|
||||||
|
):
|
||||||
|
property_value = value
|
||||||
|
return _PropertyFilter(
|
||||||
|
property_name = property_name,
|
||||||
|
property_type = "files",
|
||||||
|
condition = condition,
|
||||||
|
value = property_value
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def url(
|
||||||
|
property_name: str,
|
||||||
|
condition: Literal[
|
||||||
|
"equals",
|
||||||
|
"does_not_equal",
|
||||||
|
"contains",
|
||||||
|
"does_not_contain",
|
||||||
|
"starts_with",
|
||||||
|
"ends_with",
|
||||||
|
"is_empty",
|
||||||
|
"is_not_empty"
|
||||||
|
],
|
||||||
|
value: Union[str, Literal[True]]
|
||||||
|
):
|
||||||
|
property_value = value
|
||||||
|
return _PropertyFilter(
|
||||||
|
property_name = property_name,
|
||||||
|
property_type = "url",
|
||||||
|
condition = condition,
|
||||||
|
value = property_value
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def email(
|
||||||
|
property_name: str,
|
||||||
|
condition: Literal[
|
||||||
|
"equals",
|
||||||
|
"does_not_equal",
|
||||||
|
"contains",
|
||||||
|
"does_not_contain",
|
||||||
|
"starts_with",
|
||||||
|
"ends_with",
|
||||||
|
"is_empty",
|
||||||
|
"is_not_empty"
|
||||||
|
],
|
||||||
|
value: Union[str, Literal[True]]
|
||||||
|
):
|
||||||
|
property_value = value
|
||||||
|
return _PropertyFilter(
|
||||||
|
property_name = property_name,
|
||||||
|
property_type = "email",
|
||||||
|
condition = condition,
|
||||||
|
value = property_value
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def phone_number(
|
||||||
|
property_name: str,
|
||||||
|
condition: Literal[
|
||||||
|
"equals",
|
||||||
|
"does_not_equal",
|
||||||
|
"contains",
|
||||||
|
"does_not_contain",
|
||||||
|
"starts_with",
|
||||||
|
"ends_with",
|
||||||
|
"is_empty",
|
||||||
|
"is_not_empty"
|
||||||
|
],
|
||||||
|
value: Union[str, Literal[True]]
|
||||||
|
):
|
||||||
|
property_value = value
|
||||||
|
return _PropertyFilter(
|
||||||
|
property_name = property_name,
|
||||||
|
property_type = "phone_number",
|
||||||
|
condition = condition,
|
||||||
|
value = property_value
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def relation(
|
||||||
|
property_name: str,
|
||||||
|
condition: Literal[
|
||||||
|
"contains",
|
||||||
|
"does_not_contain",
|
||||||
|
"is_empty",
|
||||||
|
"is_not_empty"
|
||||||
|
],
|
||||||
|
value: Union[str, Literal[True]]
|
||||||
|
):
|
||||||
|
property_value = value
|
||||||
|
return _PropertyFilter(
|
||||||
|
property_name = property_name,
|
||||||
|
property_type = "relation",
|
||||||
|
condition = condition,
|
||||||
|
value = property_value
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def created_by(
|
||||||
|
property_name: str,
|
||||||
|
condition: Literal[
|
||||||
|
"contains",
|
||||||
|
"does_not_contain",
|
||||||
|
"is_empty",
|
||||||
|
"is_not_empty"
|
||||||
|
],
|
||||||
|
value: Union[str, Literal[True]]
|
||||||
|
):
|
||||||
|
property_value = value
|
||||||
|
return _PropertyFilter(
|
||||||
|
property_name = property_name,
|
||||||
|
property_type = "created_by",
|
||||||
|
condition = condition,
|
||||||
|
value = property_value
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def last_edited_by(
|
||||||
|
property_name: str,
|
||||||
|
condition: Literal[
|
||||||
|
"contains",
|
||||||
|
"does_not_contain",
|
||||||
|
"is_empty",
|
||||||
|
"is_not_empty"
|
||||||
|
],
|
||||||
|
value: Union[str, Literal[True]]
|
||||||
|
):
|
||||||
|
property_value = value
|
||||||
|
return _PropertyFilter(
|
||||||
|
property_name = property_name,
|
||||||
|
property_type = "last_edited_by",
|
||||||
|
condition = condition,
|
||||||
|
value = property_value
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def formula(
|
||||||
|
property_name: str,
|
||||||
|
formula_type: Literal["string", "checkbox", "number", "date"],
|
||||||
|
condition: Literal[
|
||||||
|
"equals",
|
||||||
|
"does_not_equal",
|
||||||
|
"contains",
|
||||||
|
"does_not_contain",
|
||||||
|
"starts_with",
|
||||||
|
"ends_with",
|
||||||
|
"is_empty",
|
||||||
|
"is_not_empty",
|
||||||
|
"greater_than",
|
||||||
|
"less_than",
|
||||||
|
"greater_than_or_equal_to",
|
||||||
|
"less_than_or_equal_to",
|
||||||
|
"before",
|
||||||
|
"after",
|
||||||
|
"on_or_before",
|
||||||
|
"on_or_after"
|
||||||
|
],
|
||||||
|
value: Union[str, bool, float, date, datetime, Literal[True]]
|
||||||
|
) -> _PropertyFilter:
|
||||||
|
if isinstance(value, date):
|
||||||
|
property_value = value.strftime("%Y-%m-%d")
|
||||||
|
elif isinstance(value, datetime):
|
||||||
|
property_value = value.strftime("%Y-%m-%dT%H:%M:%S")
|
||||||
|
else:
|
||||||
|
property_value = value
|
||||||
|
return _PropertyFilter(
|
||||||
|
property_name = property_name,
|
||||||
|
property_type = f"formula.{formula_type}",
|
||||||
|
condition = condition,
|
||||||
|
value = property_value
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def unique_id(
|
||||||
|
property_name: str,
|
||||||
|
condition: Literal[
|
||||||
|
"equals",
|
||||||
|
"does_not_equal",
|
||||||
|
"greater_than",
|
||||||
|
"less_than",
|
||||||
|
"greater_than_or_equal_to",
|
||||||
|
"less_than_or_equal_to",
|
||||||
|
"is_empty",
|
||||||
|
"is_not_empty"
|
||||||
|
],
|
||||||
|
value: Union[float, Literal[True]]
|
||||||
|
):
|
||||||
|
property_value = value
|
||||||
|
return _PropertyFilter(
|
||||||
|
property_name = property_name,
|
||||||
|
property_type = "unique_id",
|
||||||
|
condition = condition,
|
||||||
|
value = property_value
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def verification(
|
||||||
|
property_name: str,
|
||||||
|
condition: Literal[
|
||||||
|
"status"
|
||||||
|
],
|
||||||
|
value: Literal["verified", "expired", "none", ""]
|
||||||
|
):
|
||||||
|
property_value = value
|
||||||
|
return _PropertyFilter(
|
||||||
|
property_name = property_name,
|
||||||
|
property_type = "verification",
|
||||||
|
condition = condition,
|
||||||
|
value = property_value
|
||||||
|
)
|
||||||
|
|
||||||
|
__all__ = ["QueryFilter"]
|
||||||
Executable
+72
@@ -0,0 +1,72 @@
|
|||||||
|
from typing import Any, Dict, Literal, List
|
||||||
|
|
||||||
|
class _NotionSort:
|
||||||
|
|
||||||
|
"Classe base para classificação do Notion"
|
||||||
|
|
||||||
|
def _sort_to_dict(self) -> Dict[str, Any]:
|
||||||
|
"Converte uma classificação para o formato JSON do Notion"
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def to_dict(self) -> List[Dict[str, Any]]:
|
||||||
|
"Converte uma ou multiplas classificações para o formato JSON do Notion"
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
class _PropertySort(_NotionSort):
|
||||||
|
|
||||||
|
"Classificação para uma propriedade específica"
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
property_name: str,
|
||||||
|
direction: Literal["ascending", "descending"]
|
||||||
|
):
|
||||||
|
self.property_name = property_name
|
||||||
|
self.direction = direction
|
||||||
|
|
||||||
|
def _sort_to_dict(self) -> Dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"property": self.property_name,
|
||||||
|
"direction": self.direction
|
||||||
|
}
|
||||||
|
|
||||||
|
def to_dict(self) -> List[Dict[str, Any]]:
|
||||||
|
return [self._sort_to_dict()]
|
||||||
|
|
||||||
|
class _MultiSort(_NotionSort):
|
||||||
|
|
||||||
|
"Combina múltiplas classificações com vírgula"
|
||||||
|
|
||||||
|
def __init__(self, *sorts: _NotionSort):
|
||||||
|
self.sorts = sorts
|
||||||
|
|
||||||
|
def to_dict(self) -> List[Dict[str, Any]]:
|
||||||
|
return [sort_obj._sort_to_dict() for sort_obj in self.sorts]
|
||||||
|
|
||||||
|
class QuerySort:
|
||||||
|
|
||||||
|
"Builder principal para criar filtros"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def and_(*sorts: _NotionSort) -> _MultiSort:
|
||||||
|
"Combina classificações com vírgula"
|
||||||
|
return _MultiSort(*sorts)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def ascending(
|
||||||
|
property_name: str
|
||||||
|
):
|
||||||
|
return _PropertySort(
|
||||||
|
property_name = property_name,
|
||||||
|
direction = "ascending"
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def descending(
|
||||||
|
property_name: str
|
||||||
|
):
|
||||||
|
return _PropertySort(
|
||||||
|
property_name = property_name,
|
||||||
|
direction = "descending"
|
||||||
|
)
|
||||||
|
|
||||||
|
__all__ = ["QuerySort"]
|
||||||
Executable
+231
@@ -0,0 +1,231 @@
|
|||||||
|
from typing import Dict, Any, Union, Optional, Literal, List, TYPE_CHECKING
|
||||||
|
from datetime import datetime, date
|
||||||
|
from pydantic import validate_call
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from ..repositories.pages.CreatePage import CreatePage
|
||||||
|
from ..repositories.databases.CreateDatabasePage import CreateDatabasePage
|
||||||
|
|
||||||
|
class SetProperty:
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
CreatePageClass : Union['CreatePage', 'CreateDatabasePage'],
|
||||||
|
properties : Dict[str, Any]
|
||||||
|
) -> None:
|
||||||
|
self._CreatePage = CreatePageClass
|
||||||
|
self._properties = properties
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def number(self,
|
||||||
|
name : str,
|
||||||
|
value : Optional[float]
|
||||||
|
):
|
||||||
|
if value is None:
|
||||||
|
return self._CreatePage
|
||||||
|
self._properties[name] = {
|
||||||
|
"number": value
|
||||||
|
}
|
||||||
|
return self._CreatePage
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def checkbox(self,
|
||||||
|
name : str,
|
||||||
|
value : Optional[bool]
|
||||||
|
):
|
||||||
|
if value is None:
|
||||||
|
return self._CreatePage
|
||||||
|
self._properties[name] = {
|
||||||
|
"checkbox": value
|
||||||
|
}
|
||||||
|
return self._CreatePage
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def start_date(self,
|
||||||
|
name : str,
|
||||||
|
value : Optional[Union[date, datetime]],
|
||||||
|
timezone : str = "Etc/UTC"
|
||||||
|
):
|
||||||
|
if value is None:
|
||||||
|
return self._CreatePage
|
||||||
|
if type(value) == date:
|
||||||
|
self._properties[name] = {
|
||||||
|
"date": {
|
||||||
|
"start": value.strftime("%Y-%m-%d")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elif type(value) == datetime:
|
||||||
|
self._properties[name] = {
|
||||||
|
"date": {
|
||||||
|
"start": value.strftime("%Y-%m-%dT%H:%M:%S"),
|
||||||
|
"time_zone": timezone
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self._CreatePage
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def end_date(self,
|
||||||
|
name : str,
|
||||||
|
value : Optional[Union[date, datetime]]
|
||||||
|
):
|
||||||
|
if value is None:
|
||||||
|
return self._CreatePage
|
||||||
|
if not self._properties.get(name):
|
||||||
|
raise KeyError("start_date is missing")
|
||||||
|
date_value = None
|
||||||
|
if type(value) == date:
|
||||||
|
date_value = value.strftime("%Y-%m-%d")
|
||||||
|
elif type(value) == datetime:
|
||||||
|
date_value = value.strftime("%Y-%m-%dT%H:%M:%S")
|
||||||
|
self._properties[name]["date"]["end"] = date_value
|
||||||
|
return self._CreatePage
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def relation(self,
|
||||||
|
name : str,
|
||||||
|
value : Optional[str]
|
||||||
|
):
|
||||||
|
if value is None:
|
||||||
|
return self._CreatePage
|
||||||
|
self._properties[name] = {
|
||||||
|
"relation": [
|
||||||
|
{
|
||||||
|
"id": str(value)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
return self._CreatePage
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def text(self,
|
||||||
|
name : str,
|
||||||
|
value : Optional[str]
|
||||||
|
):
|
||||||
|
if value is None:
|
||||||
|
return self._CreatePage
|
||||||
|
self._properties[name] = {
|
||||||
|
"rich_text" : [
|
||||||
|
{
|
||||||
|
"type":"text",
|
||||||
|
"text":{
|
||||||
|
"content": value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
return self._CreatePage
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def rich_text(self,
|
||||||
|
name : str,
|
||||||
|
value : Optional[Union[Dict[str, Any], List[Dict[str, Any]]]]
|
||||||
|
):
|
||||||
|
if value is None:
|
||||||
|
return self._CreatePage
|
||||||
|
value = [value] if isinstance(value, dict) else value
|
||||||
|
self._properties[name] = {
|
||||||
|
"rich_text" : value
|
||||||
|
}
|
||||||
|
return self._CreatePage
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def select(self,
|
||||||
|
name : str,
|
||||||
|
value : Optional[str],
|
||||||
|
color : Optional[Literal[
|
||||||
|
"default",
|
||||||
|
"gray",
|
||||||
|
"brown",
|
||||||
|
"orange",
|
||||||
|
"yellow",
|
||||||
|
"green",
|
||||||
|
"blue",
|
||||||
|
"purple",
|
||||||
|
"pink",
|
||||||
|
"red"
|
||||||
|
]] = None
|
||||||
|
):
|
||||||
|
if value is None:
|
||||||
|
return self._CreatePage
|
||||||
|
if color:
|
||||||
|
self._properties[name] = {
|
||||||
|
"select" : {
|
||||||
|
"name" : value,
|
||||||
|
"color" : color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self._CreatePage
|
||||||
|
self._properties[name] = {
|
||||||
|
"select" : {
|
||||||
|
"name" : value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self._CreatePage
|
||||||
|
|
||||||
|
# @validate_call
|
||||||
|
# def multi_select(self, name : str, value : str):
|
||||||
|
|
||||||
|
# @validate_call
|
||||||
|
# def status(self, name : str, value : str):
|
||||||
|
|
||||||
|
# @validate_call
|
||||||
|
# def media(self, name : str, value : str):
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def url(self,
|
||||||
|
name : str,
|
||||||
|
value : Optional[str]
|
||||||
|
):
|
||||||
|
if value is None:
|
||||||
|
return self._CreatePage
|
||||||
|
self._properties[name] = {
|
||||||
|
"url" : value
|
||||||
|
}
|
||||||
|
return self._CreatePage
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def email(self,
|
||||||
|
name : str,
|
||||||
|
value : Optional[str]
|
||||||
|
):
|
||||||
|
if value is None:
|
||||||
|
return self._CreatePage
|
||||||
|
if "@" not in value:
|
||||||
|
raise ValueError("Invalid email")
|
||||||
|
self._properties[name] = {
|
||||||
|
"email": str(value)
|
||||||
|
}
|
||||||
|
return self._CreatePage
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def phone(self,
|
||||||
|
name : str,
|
||||||
|
value : Optional[str]
|
||||||
|
):
|
||||||
|
if value is None:
|
||||||
|
return self._CreatePage
|
||||||
|
self._properties[name] = {
|
||||||
|
"phone_number": str(value)
|
||||||
|
}
|
||||||
|
return self._CreatePage
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def person(self,
|
||||||
|
name : str,
|
||||||
|
value : Optional[str]
|
||||||
|
):
|
||||||
|
if value is None:
|
||||||
|
return self._CreatePage
|
||||||
|
self._properties[name] = {
|
||||||
|
"people": [
|
||||||
|
{
|
||||||
|
"object": "user",
|
||||||
|
"id": str(value)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
return self._CreatePage
|
||||||
|
|
||||||
|
# @validate_call
|
||||||
|
# def place(self, name : str, value : str):
|
||||||
|
|
||||||
|
__all__ = ["SetProperty"]
|
||||||
Executable
+13
@@ -0,0 +1,13 @@
|
|||||||
|
from .QueryFilter import QueryFilter as _QueryFilter
|
||||||
|
from .QuerySort import QuerySort as _QuerySort
|
||||||
|
from .SetProperty import SetProperty as _SetProperty
|
||||||
|
|
||||||
|
class _Common:
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.QueryFilter = _QueryFilter
|
||||||
|
self.QuerySort = _QuerySort
|
||||||
|
self.SetProperty = _SetProperty
|
||||||
|
|
||||||
|
Common = _Common()
|
||||||
|
__all__ = ["Common"]
|
||||||
Executable
+146
@@ -0,0 +1,146 @@
|
|||||||
|
from typing import Optional, Any
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
class PropertyExtractor:
|
||||||
|
|
||||||
|
"Classe base com métodos de extração de propriedades do Notion"
|
||||||
|
|
||||||
|
def extract(self, prop_data: dict) -> Any:
|
||||||
|
|
||||||
|
"""
|
||||||
|
Extrai o valor de uma propriedade baseado no seu tipo.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prop_data: Dicionário com dados da propriedade do Notion
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Valor extraído da propriedade ou None
|
||||||
|
"""
|
||||||
|
|
||||||
|
tipo = prop_data.get("type")
|
||||||
|
if not tipo:
|
||||||
|
return None
|
||||||
|
|
||||||
|
extractors = {
|
||||||
|
"title" : self._title,
|
||||||
|
"rich_text" : self._rich_text,
|
||||||
|
"number" : self._number,
|
||||||
|
"checkbox" : self._checkbox,
|
||||||
|
"url" : self._url,
|
||||||
|
"select" : self._select,
|
||||||
|
"multi_select" : self._multi_select,
|
||||||
|
"date" : self._date,
|
||||||
|
"relation" : self._relation,
|
||||||
|
"rollup" : self._rollup,
|
||||||
|
"formula" : self._formula,
|
||||||
|
}
|
||||||
|
|
||||||
|
extractor = extractors.get(tipo)
|
||||||
|
if extractor:
|
||||||
|
return extractor(prop_data)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _title(self, prop_data: dict) -> Optional[str]:
|
||||||
|
"Extrai conteúdo de propriedade tipo `title`"
|
||||||
|
title = prop_data.get("title")
|
||||||
|
if title is None:
|
||||||
|
return None
|
||||||
|
if isinstance(title, list) and len(title) == 1:
|
||||||
|
return title[0]['text'].get('content')
|
||||||
|
if isinstance(title, dict):
|
||||||
|
return title['text'].get('content')
|
||||||
|
content_list = [item['plain_text'] for item in title]
|
||||||
|
return "".join(content_list)
|
||||||
|
|
||||||
|
def _rich_text(self, prop_data: dict) -> Optional[dict]:
|
||||||
|
"Extrai conteúdo de propriedade tipo 'rich_text'"
|
||||||
|
prop_list = prop_data.get('rich_text')
|
||||||
|
if prop_list is None:
|
||||||
|
return None
|
||||||
|
content_list = [item['plain_text'] for item in prop_list]
|
||||||
|
return {"text": "".join(content_list), "detailed": prop_list}
|
||||||
|
|
||||||
|
def _number(self, prop_data: dict) -> Optional[float]:
|
||||||
|
"Extrai conteúdo de propriedade tipo 'number'"
|
||||||
|
return prop_data.get("number")
|
||||||
|
|
||||||
|
def _checkbox(self, prop_data: dict) -> bool:
|
||||||
|
"Extrai conteúdo de propriedade tipo 'checkbox'"
|
||||||
|
return prop_data.get("checkbox") == True
|
||||||
|
|
||||||
|
def _url(self, prop_data: dict) -> Optional[str]:
|
||||||
|
"Extrai conteúdo de propriedade tipo 'url'"
|
||||||
|
return prop_data.get("url")
|
||||||
|
|
||||||
|
def _select(self, prop_data: dict) -> Optional[dict]:
|
||||||
|
"Extrai conteúdo de propriedade tipo 'select'"
|
||||||
|
select = prop_data.get("select")
|
||||||
|
if not select:
|
||||||
|
return None
|
||||||
|
return {"name": select.get("name"), "color": select.get("color")}
|
||||||
|
|
||||||
|
def _multi_select(self, prop_data: dict) -> Optional[list[dict]]:
|
||||||
|
"Extrai conteúdo de propriedade tipo 'multi_select'"
|
||||||
|
multi_select = prop_data.get("multi_select")
|
||||||
|
if not multi_select:
|
||||||
|
return None
|
||||||
|
selects = []
|
||||||
|
for select in multi_select:
|
||||||
|
selects.append(
|
||||||
|
{"name": select.get("name"), "color": select.get("color")}
|
||||||
|
)
|
||||||
|
return selects
|
||||||
|
|
||||||
|
def _date(self, prop_data: dict) -> Optional[dict]:
|
||||||
|
"Extrai conteúdo de propriedade tipo 'date'"
|
||||||
|
date = prop_data.get("date")
|
||||||
|
if not date:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def parse_date(date_str):
|
||||||
|
if not date_str:
|
||||||
|
return None
|
||||||
|
for fmt in ["%Y-%m-%dT%H:%M:%S.%fZ", "%Y-%m-%dT%H:%M:%S", "%Y-%m-%d"]:
|
||||||
|
try:
|
||||||
|
return datetime.strptime(date_str, fmt)
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
return None
|
||||||
|
|
||||||
|
start = parse_date(date.get("start"))
|
||||||
|
end = parse_date(date.get("end"))
|
||||||
|
return {"start": start, "end": end}
|
||||||
|
|
||||||
|
def _relation(self, prop_data: dict) -> Optional[list]:
|
||||||
|
"Extrai conteúdo de propriedade tipo 'relation'"
|
||||||
|
relations = prop_data.get("relation", [])
|
||||||
|
if not relations:
|
||||||
|
return None
|
||||||
|
return [relation["id"] for relation in relations]
|
||||||
|
|
||||||
|
def _rollup(self, prop_data: dict) -> Any:
|
||||||
|
"Extrai conteúdo de propriedade tipo 'rollup'"
|
||||||
|
rollup = prop_data.get("rollup", {})
|
||||||
|
rollup_type = rollup.get("type")
|
||||||
|
|
||||||
|
if rollup_type == "number":
|
||||||
|
return rollup.get("number")
|
||||||
|
elif rollup_type == "array":
|
||||||
|
return rollup.get("array", [])
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _formula(self, prop_data: dict) -> Any:
|
||||||
|
"Extrai conteúdo de propriedade tipo 'formula'"
|
||||||
|
formula = prop_data.get("formula", {})
|
||||||
|
formula_type = formula.get("type")
|
||||||
|
|
||||||
|
if formula_type == "number":
|
||||||
|
return formula.get("number")
|
||||||
|
elif formula_type == "string":
|
||||||
|
return formula.get("string")
|
||||||
|
elif formula_type == "boolean":
|
||||||
|
return formula.get("boolean")
|
||||||
|
return None
|
||||||
|
|
||||||
|
__all__ = ["PropertyExtractor"]
|
||||||
Executable
+8
@@ -0,0 +1,8 @@
|
|||||||
|
from .Properties import PropertyExtractor as _PropertyExtractor
|
||||||
|
|
||||||
|
class Extrator:
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.props = _PropertyExtractor
|
||||||
|
|
||||||
|
__all__ = ["Extrator"]
|
||||||
Executable
+12
@@ -0,0 +1,12 @@
|
|||||||
|
from .database import NotionDatabase as _NotionDatabase
|
||||||
|
from .registry import DatabaseRegistry as _DatabaseRegistry
|
||||||
|
|
||||||
|
class _Mapping:
|
||||||
|
|
||||||
|
NotionDatabase = _NotionDatabase
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.registry = _DatabaseRegistry
|
||||||
|
|
||||||
|
Mapping = _Mapping()
|
||||||
|
__all__ = ["Mapping"]
|
||||||
Executable
+198
@@ -0,0 +1,198 @@
|
|||||||
|
from typing import Dict, Any, Optional, Callable, ClassVar, TypeVar, Type
|
||||||
|
from pydantic import BaseModel, field_validator
|
||||||
|
|
||||||
|
T = TypeVar('T', bound='NotionDatabase')
|
||||||
|
|
||||||
|
class NotionConfigMeta:
|
||||||
|
|
||||||
|
"Metadados de configuração da database do Notion"
|
||||||
|
|
||||||
|
def __init__(self, config_class):
|
||||||
|
|
||||||
|
self.database_id : Optional[str] = getattr(config_class, 'database_id', None)
|
||||||
|
self.mappings : Dict[str, Any] = getattr(config_class, 'mappings', {})
|
||||||
|
self.validators : Dict[str, Callable] = getattr(config_class, 'validators', {})
|
||||||
|
self.computed : Dict[str, Callable] = getattr(config_class, 'computed', {})
|
||||||
|
|
||||||
|
transformers_config: Dict[str, Callable] = getattr(config_class, 'transformers', {})
|
||||||
|
|
||||||
|
# Processa mappings para separar nome e transformer
|
||||||
|
self.field_mappings : Dict[str, str] = {}
|
||||||
|
self.transformers : Dict[str, Callable] = {}
|
||||||
|
|
||||||
|
for field_name, mapping in self.mappings.items():
|
||||||
|
|
||||||
|
if isinstance(mapping, str):
|
||||||
|
|
||||||
|
# Mapping simples: "field": "Notion Name"
|
||||||
|
self.field_mappings[field_name] = mapping
|
||||||
|
|
||||||
|
elif isinstance(mapping, tuple) and len(mapping) == 2:
|
||||||
|
|
||||||
|
# Mapping com transformer: "field": ("Notion Name", lambda x: ...)
|
||||||
|
self.field_mappings[field_name] = mapping[0]
|
||||||
|
self.transformers[field_name] = mapping[1]
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
raise ValueError(
|
||||||
|
f"Mapping inválido para '{field_name}'. "
|
||||||
|
f"Use: 'Notion Name' ou ('Notion Name', transformer_func)"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.transformers.update(transformers_config)
|
||||||
|
|
||||||
|
class NotionDatabaseMeta(type(BaseModel)):
|
||||||
|
|
||||||
|
"Metaclass que processa a classe e injeta funcionalidades do Notion"
|
||||||
|
|
||||||
|
_notion_config: NotionConfigMeta
|
||||||
|
|
||||||
|
def __new__(mcs, name, bases, namespace, **kwargs):
|
||||||
|
|
||||||
|
# Cria a classe Pydantic
|
||||||
|
cls = super().__new__(mcs, name, bases, namespace, **kwargs)
|
||||||
|
|
||||||
|
# Se tem NotionConfig, processa
|
||||||
|
if hasattr(cls, 'NotionConfig'):
|
||||||
|
|
||||||
|
config = NotionConfigMeta(cls.NotionConfig)
|
||||||
|
|
||||||
|
# Injeta o config processado
|
||||||
|
cls._notion_config = config # type: ignore
|
||||||
|
|
||||||
|
if not config.database_id:
|
||||||
|
raise AttributeError("Database ID is missing")
|
||||||
|
|
||||||
|
# Injeta validators customizados do NotionConfig
|
||||||
|
if config.validators:
|
||||||
|
|
||||||
|
for field_name, validator_func in config.validators.items():
|
||||||
|
|
||||||
|
# Cria um validator Pydantic dinâmico
|
||||||
|
validator_name = f'validate_{field_name}_notion'
|
||||||
|
|
||||||
|
def make_validator(func):
|
||||||
|
def validator(cls, v):
|
||||||
|
return func(v)
|
||||||
|
return field_validator(field_name)(validator)
|
||||||
|
|
||||||
|
setattr(cls, validator_name, make_validator(validator_func))
|
||||||
|
|
||||||
|
return cls
|
||||||
|
|
||||||
|
class NotionDatabase(BaseModel, metaclass = NotionDatabaseMeta):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Classe base para schemas de databases do Notion.
|
||||||
|
|
||||||
|
Uso:
|
||||||
|
----
|
||||||
|
class AccountsDB(NotionDatabase):
|
||||||
|
name: str
|
||||||
|
credit: float
|
||||||
|
type: List[str]
|
||||||
|
|
||||||
|
class NotionConfig:
|
||||||
|
mappings = {
|
||||||
|
"name": "Name",
|
||||||
|
"credit": "Credit",
|
||||||
|
"type": ("Type", lambda x: [s["name"] for s in x] if x else [])
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
_notion_config: ClassVar[NotionConfigMeta]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_notion_page(
|
||||||
|
cls : Type[T],
|
||||||
|
page_properties : Dict[str, Any],
|
||||||
|
page_parser : Optional[Callable] = None
|
||||||
|
) -> Optional[T]:
|
||||||
|
|
||||||
|
"""
|
||||||
|
Cria uma instância do schema a partir de propriedades parseadas do Notion.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
page_properties: Dict com propriedades já parseadas pelo PropertyExtractor
|
||||||
|
page_parser: Função de parsing (se as propriedades ainda não foram parseadas)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Instância do schema ou None se parsing falhar
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not hasattr(cls, '_notion_config'):
|
||||||
|
raise AttributeError(
|
||||||
|
f"{cls.__name__} não tem NotionConfig definido. "
|
||||||
|
f"Adicione uma subclasse NotionConfig com os mappings."
|
||||||
|
)
|
||||||
|
|
||||||
|
config: NotionConfigMeta = cls._notion_config
|
||||||
|
|
||||||
|
# Se recebeu a página raw, faz o parsing
|
||||||
|
if page_parser and 'properties' in page_properties:
|
||||||
|
page_properties = page_parser(page_properties)
|
||||||
|
|
||||||
|
if not page_properties:
|
||||||
|
return None
|
||||||
|
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
# Processa campos mapeados
|
||||||
|
for field_name, notion_name in config.field_mappings.items():
|
||||||
|
|
||||||
|
raw_value = page_properties.get(notion_name)
|
||||||
|
|
||||||
|
# Aplica transformer se existir
|
||||||
|
if field_name in config.transformers:
|
||||||
|
value = config.transformers[field_name](raw_value)
|
||||||
|
else:
|
||||||
|
value = raw_value
|
||||||
|
|
||||||
|
result[field_name] = value
|
||||||
|
|
||||||
|
# Cria instância temporária para computed fields
|
||||||
|
instance = cls(**result)
|
||||||
|
|
||||||
|
# Processa computed fields
|
||||||
|
for field_name, compute_func in config.computed.items():
|
||||||
|
|
||||||
|
computed_value = compute_func(instance)
|
||||||
|
result[field_name] = computed_value
|
||||||
|
|
||||||
|
# Retorna instância final com computed fields
|
||||||
|
return cls(**result)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_database_id(cls) -> str:
|
||||||
|
|
||||||
|
"Retorna o nome da database no Notion"
|
||||||
|
|
||||||
|
if hasattr(cls, '_notion_config'):
|
||||||
|
return cls._notion_config.database_id or cls.__name__
|
||||||
|
|
||||||
|
return cls.__name__
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_notion_field_name(cls,
|
||||||
|
python_field : str
|
||||||
|
) -> Optional[str]:
|
||||||
|
|
||||||
|
"Retorna o nome do campo no Notion a partir do nome Python"
|
||||||
|
|
||||||
|
if hasattr(cls, '_notion_config'):
|
||||||
|
return cls._notion_config.field_mappings.get(python_field)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_all_mappings(cls) -> Dict[str, str]:
|
||||||
|
|
||||||
|
"Retorna todos os mappings field_python -> field_notion"
|
||||||
|
|
||||||
|
if hasattr(cls, '_notion_config'):
|
||||||
|
return cls._notion_config.field_mappings.copy()
|
||||||
|
|
||||||
|
return {}
|
||||||
|
|
||||||
|
__all__ = ["NotionDatabase"]
|
||||||
Executable
+92
@@ -0,0 +1,92 @@
|
|||||||
|
from typing import Dict, Any, Optional, Callable, Type
|
||||||
|
from .database import NotionDatabase as _NotionDatabase
|
||||||
|
|
||||||
|
class DatabaseRegistry:
|
||||||
|
|
||||||
|
"""
|
||||||
|
Registry global de databases do Notion.
|
||||||
|
Permite acessar schemas e criar parsers dinamicamente.
|
||||||
|
"""
|
||||||
|
|
||||||
|
_databases: Dict[str, Type[_NotionDatabase]] = {}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def register(cls,
|
||||||
|
database_class : Type[_NotionDatabase]
|
||||||
|
) -> None:
|
||||||
|
|
||||||
|
"Registra uma database no registry"
|
||||||
|
|
||||||
|
db_name = database_class.get_database_id()
|
||||||
|
cls._databases[db_name] = database_class
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get(cls,
|
||||||
|
database_id : str
|
||||||
|
) -> Optional[Type[_NotionDatabase]]:
|
||||||
|
|
||||||
|
"Retorna a classe de schema de uma database"
|
||||||
|
|
||||||
|
return cls._databases.get(database_id)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_parser(cls,
|
||||||
|
database_id : str,
|
||||||
|
page_parser : Callable
|
||||||
|
) -> Callable:
|
||||||
|
|
||||||
|
"""
|
||||||
|
Retorna uma função parser para a database.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
database_id: ID da Database
|
||||||
|
page_parser: Função que parseia páginas (ex: PageProperties.parse)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Função parser ou None se database não encontrada
|
||||||
|
"""
|
||||||
|
|
||||||
|
db_class = cls.get(database_id)
|
||||||
|
if not db_class:
|
||||||
|
raise ValueError(f"Database de ID '{database_id}' não está registrada")
|
||||||
|
|
||||||
|
def parser(page : Dict[str, Any]) -> Optional[_NotionDatabase]:
|
||||||
|
return db_class.from_notion_page(page, page_parser)
|
||||||
|
|
||||||
|
return parser
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def list_databases(cls) -> list[str]:
|
||||||
|
|
||||||
|
"Lista todas as databases registradas"
|
||||||
|
|
||||||
|
return list(cls._databases.keys())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def auto_register(cls,
|
||||||
|
*database_classes : Type[_NotionDatabase]
|
||||||
|
) -> None:
|
||||||
|
|
||||||
|
"Registra múltiplas databases de uma vez"
|
||||||
|
|
||||||
|
for db_class in database_classes:
|
||||||
|
cls.register(db_class)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generate_literal_type(cls) -> str:
|
||||||
|
|
||||||
|
"Gera o código do Literal com todas as databases registradas"
|
||||||
|
|
||||||
|
db_names = list(cls._databases.keys())
|
||||||
|
literal_str = ", ".join([f'"{name}"' for name in db_names])
|
||||||
|
|
||||||
|
return f"Literal[{literal_str}]"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_database_class_by_id(cls,
|
||||||
|
db_id : str
|
||||||
|
) -> Optional[Type[_NotionDatabase]]:
|
||||||
|
|
||||||
|
"Retorna a classe schema baseado no nome da database"
|
||||||
|
|
||||||
|
return cls._databases.get(db_id)
|
||||||
Executable
+36
@@ -0,0 +1,36 @@
|
|||||||
|
from typing import Optional, Dict, Any
|
||||||
|
from urllib.parse import unquote
|
||||||
|
from ..extrators.Properties import PropertyExtractor as _PropertyExtractor
|
||||||
|
|
||||||
|
class _PageProperties(_PropertyExtractor):
|
||||||
|
|
||||||
|
"Parser completo de página do Notion. Retorna todas as propriedades parseadas de uma vez."
|
||||||
|
|
||||||
|
def parse(self, page: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
||||||
|
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
if page.get("object") == "property_item":
|
||||||
|
|
||||||
|
value = self.extract(page)
|
||||||
|
|
||||||
|
if value is not None:
|
||||||
|
result[unquote(page["id"])] = value
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
properties = page.get("properties")
|
||||||
|
|
||||||
|
if not properties:
|
||||||
|
return None
|
||||||
|
|
||||||
|
for prop_name, prop_data in properties.items():
|
||||||
|
value = self.extract(prop_data)
|
||||||
|
|
||||||
|
if value is not None:
|
||||||
|
result[prop_name] = value
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
PageProperties = _PageProperties()
|
||||||
|
__all__ = ["PageProperties"]
|
||||||
Executable
+9
@@ -0,0 +1,9 @@
|
|||||||
|
from .PageProperties import PageProperties as _PageProperties
|
||||||
|
|
||||||
|
class _Parser:
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.page_props = _PageProperties.parse
|
||||||
|
|
||||||
|
Parser = _Parser()
|
||||||
|
__all__ = ["Parser"]
|
||||||
Executable
+26
@@ -0,0 +1,26 @@
|
|||||||
|
from typing import TypeVar, Generic, TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from ...schemas.orm.database.DatabasesContainer import DatabasesContainer as _DatabasesContainer
|
||||||
|
|
||||||
|
TContainer = TypeVar('TContainer', bound = '_DatabasesContainer')
|
||||||
|
|
||||||
|
class DatabasesRepo(Generic[TContainer]):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.container: TContainer
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def generic(database_id : str):
|
||||||
|
from .databases import Database
|
||||||
|
return Database.generic(database_id)
|
||||||
|
|
||||||
|
class _Repositories(Generic[TContainer]):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
from .pages import _Pages
|
||||||
|
self.pages = _Pages()
|
||||||
|
self.databases: DatabasesRepo[TContainer] = DatabasesRepo()
|
||||||
|
|
||||||
|
repo: _Repositories = _Repositories()
|
||||||
|
__all__ = ["repo", "_Repositories"]
|
||||||
+93
@@ -0,0 +1,93 @@
|
|||||||
|
from typing import Optional, Literal, Generic, TypeVar
|
||||||
|
from pydantic import validate_call
|
||||||
|
from ....schemas.responses import Schemas as _schm
|
||||||
|
from ...mapping.database import NotionDatabase as _NotionDatabase
|
||||||
|
from ...mapping import Mapping as _map
|
||||||
|
from ...parsers import Parser as _parser
|
||||||
|
from ...common.SetProperty import SetProperty as _setProperty
|
||||||
|
from ..pages.CreatePage import CreatePage as _CreatePage
|
||||||
|
|
||||||
|
TDB = TypeVar('TDB', bound = _NotionDatabase)
|
||||||
|
|
||||||
|
class CreateDatabasePage(Generic[TDB]):
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
database_id : str,
|
||||||
|
generic_response : bool = False
|
||||||
|
) -> None:
|
||||||
|
self._database_id = database_id
|
||||||
|
self._generic_response = generic_response
|
||||||
|
self._instance = _CreatePage().set_parent(
|
||||||
|
type = "database_id",
|
||||||
|
parent_id = self._database_id
|
||||||
|
)
|
||||||
|
self.set_property = _setProperty(self, self._instance.data["properties"])
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def set_template(self,
|
||||||
|
type : Literal["default", "template_id"],
|
||||||
|
template_id : Optional[str] = None
|
||||||
|
):
|
||||||
|
self._instance.set_template(
|
||||||
|
type = type,
|
||||||
|
template_id = template_id
|
||||||
|
)
|
||||||
|
return self
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def set_title(self,
|
||||||
|
prop_name : Optional[str],
|
||||||
|
prop_value : Optional[str]
|
||||||
|
):
|
||||||
|
self._instance.set_title(
|
||||||
|
prop_name = prop_name,
|
||||||
|
prop_value = prop_value
|
||||||
|
)
|
||||||
|
return self
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def set_icon(self,
|
||||||
|
type : Literal["external"],
|
||||||
|
content : Optional[str] = None
|
||||||
|
):
|
||||||
|
self._instance.set_icon(
|
||||||
|
type = type,
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
return self
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
async def call(self,
|
||||||
|
map_properties : bool = True,
|
||||||
|
raw_response : bool = False
|
||||||
|
) -> _schm.pages.Page[TDB]:
|
||||||
|
|
||||||
|
page = await self._instance.call(
|
||||||
|
parse_properties = False
|
||||||
|
)
|
||||||
|
|
||||||
|
if not raw_response:
|
||||||
|
|
||||||
|
if map_properties:
|
||||||
|
|
||||||
|
parser = None
|
||||||
|
if not self._generic_response:
|
||||||
|
# Tenta pegar parser do registry
|
||||||
|
parser = _map.registry.get_parser(
|
||||||
|
database_id = self._database_id,
|
||||||
|
page_parser = _parser.page_props
|
||||||
|
)
|
||||||
|
|
||||||
|
# Fallback: se database não registrada, usa parser genérico
|
||||||
|
if not parser:
|
||||||
|
parser = _parser.page_props
|
||||||
|
|
||||||
|
page = page.model_dump()
|
||||||
|
mapped_properties = parser(page = page)
|
||||||
|
page["properties"] = mapped_properties
|
||||||
|
|
||||||
|
page = _schm.pages.Page(**page)
|
||||||
|
|
||||||
|
return page
|
||||||
|
|
||||||
|
__all__ = ["CreateDatabasePage"]
|
||||||
+101
@@ -0,0 +1,101 @@
|
|||||||
|
from typing import Optional, Generic, TypeVar
|
||||||
|
from pydantic import validate_call
|
||||||
|
from ....client import get_client as _get_client
|
||||||
|
from ....schemas.responses import Schemas as _schm
|
||||||
|
from ...mapping.database import NotionDatabase as _NotionDatabase
|
||||||
|
from ...mapping import Mapping as _map
|
||||||
|
from ...common.QueryFilter import QueryFilter as _Filter, _NotionFilter
|
||||||
|
from ...common.QuerySort import QuerySort as _Sort, _NotionSort
|
||||||
|
from ...parsers import Parser as _parser
|
||||||
|
|
||||||
|
TDB = TypeVar('TDB', bound = _NotionDatabase)
|
||||||
|
|
||||||
|
class SearchPage(Generic[TDB]):
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
database_id : str,
|
||||||
|
generic_response : bool = False
|
||||||
|
) -> None:
|
||||||
|
self._database_id = database_id
|
||||||
|
self._generic_response = generic_response
|
||||||
|
self.query_limit : int = 100
|
||||||
|
self.filter = _Filter
|
||||||
|
self._filter_obj : Optional[_NotionFilter] = None
|
||||||
|
self.sort = _Sort
|
||||||
|
self._sort_obj : Optional[_NotionSort] = None
|
||||||
|
|
||||||
|
def set_limit(self,
|
||||||
|
page_limit : int
|
||||||
|
):
|
||||||
|
"Define o limite de páginas a serem retornadas na requisição"
|
||||||
|
self.query_limit = page_limit
|
||||||
|
return self
|
||||||
|
|
||||||
|
def set_sort(self,
|
||||||
|
sort_obj : _NotionSort
|
||||||
|
):
|
||||||
|
"Define a classificação a ser usada na query"
|
||||||
|
self._sort_obj = sort_obj
|
||||||
|
return self
|
||||||
|
|
||||||
|
def set_filter(self,
|
||||||
|
filter_obj : _NotionFilter
|
||||||
|
):
|
||||||
|
"Define o filtro a ser usado na query"
|
||||||
|
self._filter_obj = filter_obj
|
||||||
|
return self
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
async def call(self,
|
||||||
|
map_properties : bool = True,
|
||||||
|
raw_response : bool = False
|
||||||
|
) -> _schm.databases.Query[TDB]:
|
||||||
|
|
||||||
|
payload = {}
|
||||||
|
if self.query_limit:
|
||||||
|
payload["page_size"] = self.query_limit
|
||||||
|
if self._sort_obj:
|
||||||
|
payload["sorts"] = self._sort_obj.to_dict()
|
||||||
|
if self._filter_obj:
|
||||||
|
payload["filter"] = self._filter_obj.to_dict()
|
||||||
|
|
||||||
|
client = _get_client()
|
||||||
|
|
||||||
|
query = await client.databases.query(
|
||||||
|
database_id = self._database_id,
|
||||||
|
json_data = payload
|
||||||
|
)
|
||||||
|
|
||||||
|
if query['object'] == 'error':
|
||||||
|
error = _schm.errors.Error(**query)
|
||||||
|
raise KeyError(error.__dict__)
|
||||||
|
|
||||||
|
pages = []
|
||||||
|
results = query["results"]
|
||||||
|
|
||||||
|
if not raw_response:
|
||||||
|
|
||||||
|
if map_properties:
|
||||||
|
|
||||||
|
parser = None
|
||||||
|
if not self._generic_response:
|
||||||
|
# Tenta pegar parser do registry
|
||||||
|
parser = _map.registry.get_parser(
|
||||||
|
database_id = self._database_id,
|
||||||
|
page_parser = _parser.page_props
|
||||||
|
)
|
||||||
|
|
||||||
|
# Fallback: se database não registrada, usa parser genérico
|
||||||
|
if not parser:
|
||||||
|
parser = _parser.page_props
|
||||||
|
|
||||||
|
for page in results:
|
||||||
|
page_properties = parser(page)
|
||||||
|
page["properties"] = page_properties if page_properties else None
|
||||||
|
pages.append(page)
|
||||||
|
|
||||||
|
results = pages
|
||||||
|
|
||||||
|
return _schm.databases.Query(**query)
|
||||||
|
|
||||||
|
__all__ = ["SearchPage"]
|
||||||
+94
@@ -0,0 +1,94 @@
|
|||||||
|
from typing import Optional, Literal, List
|
||||||
|
from ....client import get_client as _get_client
|
||||||
|
from ....schemas.orm.database import Schemas as _schm
|
||||||
|
from ....schemas.responses import Schemas as _schmResponses
|
||||||
|
from ...common.QueryFilter import QueryFilter as _Filter, _NotionFilter
|
||||||
|
from ...parsers import Parser as _parser
|
||||||
|
|
||||||
|
class SearchPageProperty:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# CUIDADO AO UTILIZAR!!
|
||||||
|
### [Bug Conhecido](https://community.latenode.com/t/notion-api-relation-property-showing-empty-array-despite-ui-showing-connected-pages/25780) na API do Notion impede retornos confiáveis em propriedades paginadas
|
||||||
|
Ultimo teste : 2026-01-10
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, database_id : str) -> None:
|
||||||
|
self._database_id = database_id
|
||||||
|
self.filter = _Filter
|
||||||
|
self._filter_obj : Optional[_NotionFilter] = None
|
||||||
|
self._property_type = None
|
||||||
|
|
||||||
|
def set_filter(self,
|
||||||
|
property_type : Literal[
|
||||||
|
"unique_id",
|
||||||
|
"icon",
|
||||||
|
"title",
|
||||||
|
"number",
|
||||||
|
"checkbox",
|
||||||
|
"start_date",
|
||||||
|
"end_date",
|
||||||
|
#"relation",
|
||||||
|
"text",
|
||||||
|
"rich_text",
|
||||||
|
"select",
|
||||||
|
"multi_select",
|
||||||
|
"status",
|
||||||
|
"media",
|
||||||
|
"url",
|
||||||
|
"email",
|
||||||
|
"phone",
|
||||||
|
"person",
|
||||||
|
"place"
|
||||||
|
],
|
||||||
|
filter_obj : _NotionFilter
|
||||||
|
):
|
||||||
|
"Define o filtro a ser usado na query"
|
||||||
|
self._property_type = property_type
|
||||||
|
self._filter_obj = filter_obj
|
||||||
|
return self
|
||||||
|
|
||||||
|
async def call(self,
|
||||||
|
raw_response : bool = False
|
||||||
|
) -> List[_schm.SearchPageProperty]:
|
||||||
|
|
||||||
|
if not self._property_type:
|
||||||
|
raise TypeError("Filter is not fully defined")
|
||||||
|
|
||||||
|
payload = {}
|
||||||
|
if self._filter_obj:
|
||||||
|
payload["filter"] = self._filter_obj.to_dict()
|
||||||
|
|
||||||
|
client = _get_client()
|
||||||
|
|
||||||
|
query = await client.databases.query_propriety(
|
||||||
|
database_id = self._database_id,
|
||||||
|
propriety_type = self._property_type,
|
||||||
|
json_data = payload
|
||||||
|
)
|
||||||
|
|
||||||
|
if query['object'] == 'error':
|
||||||
|
error = _schmResponses.errors.Error(**query)
|
||||||
|
raise KeyError(error.__dict__)
|
||||||
|
|
||||||
|
results = query["results"]
|
||||||
|
|
||||||
|
pages = []
|
||||||
|
for page in results:
|
||||||
|
if raw_response:
|
||||||
|
page["properties"] = _parser.page_props(page = page)
|
||||||
|
pages.append(page)
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for page in pages:
|
||||||
|
prop_value = page["properties"]
|
||||||
|
if prop_value:
|
||||||
|
prop_value = list(prop_value.values())[0]
|
||||||
|
result.append(
|
||||||
|
_schm.SearchPageProperty(
|
||||||
|
page_id = page["id"],
|
||||||
|
prop_value = prop_value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
+57
@@ -0,0 +1,57 @@
|
|||||||
|
from typing import Generic, TypeVar
|
||||||
|
from ...mapping.database import NotionDatabase as _NotionDatabase
|
||||||
|
from ..pages import _Pages as _Pages
|
||||||
|
from .CreateDatabasePage import CreateDatabasePage as _CreateDatabasePage
|
||||||
|
from .SearchPage import SearchPage as _SearchPage
|
||||||
|
from .SearchPageProperty import SearchPageProperty as _SearchPageProperty
|
||||||
|
|
||||||
|
TDB = TypeVar('TDB', bound = _NotionDatabase)
|
||||||
|
|
||||||
|
class Database(Generic[TDB]):
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
database_id : str,
|
||||||
|
generic_response : bool = False
|
||||||
|
) -> None:
|
||||||
|
|
||||||
|
self._database_id = database_id
|
||||||
|
self._generic_response = generic_response
|
||||||
|
|
||||||
|
@property
|
||||||
|
def CreateDatabasePage(self) -> _CreateDatabasePage[TDB]:
|
||||||
|
return _CreateDatabasePage(
|
||||||
|
database_id = self._database_id,
|
||||||
|
generic_response = self._generic_response
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def SearchPage(self) -> _SearchPage[TDB]:
|
||||||
|
return _SearchPage(
|
||||||
|
database_id = self._database_id,
|
||||||
|
generic_response = self._generic_response
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def SearchPageProperty(self) -> _SearchPageProperty:
|
||||||
|
return _SearchPageProperty(
|
||||||
|
database_id = self._database_id
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def page(self) -> _Pages[TDB]:
|
||||||
|
return _Pages(
|
||||||
|
database_id = self._database_id,
|
||||||
|
generic_response = self._generic_response
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def generic(database_id : str) -> 'Database[_NotionDatabase]':
|
||||||
|
|
||||||
|
"Acessa database sem schema definido"
|
||||||
|
|
||||||
|
return Database(
|
||||||
|
database_id = database_id,
|
||||||
|
generic_response = True
|
||||||
|
)
|
||||||
|
|
||||||
|
__all__ = ["Database"]
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# async def main():
|
||||||
|
# instance = NotionOrm.repo.pages()
|
||||||
|
# create = await instance.CreatePage()\
|
||||||
|
# .set_parent("page_id", "2a564c9be67881a185c1c5d9133b9b1c")\
|
||||||
|
# .set_title("Name", "Teste abc")\
|
||||||
|
# .set_children("heading_1", "Teste")\
|
||||||
|
# .call()
|
||||||
|
# return create
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
import sys, os, asyncio
|
||||||
|
sys.path.append(
|
||||||
|
os.path.abspath(
|
||||||
|
os.path.join(
|
||||||
|
os.path.dirname(__file__), '..', '..', '..', '..', '..', '..', '..'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
from src.utils.pprint import pprint
|
||||||
|
from src.integrations.notion.orm.repositories.pages.GetPage import GetPage
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
instance = GetPage()
|
||||||
|
search = await instance\
|
||||||
|
.set_database(name="accounts")\
|
||||||
|
.set_pageid("0db2806f-b365-4327-919d-afbd1943f2ad")\
|
||||||
|
.select("Name")
|
||||||
|
#.call(True)
|
||||||
|
return search
|
||||||
|
|
||||||
|
test = await main()
|
||||||
|
pprint(test)
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import sys, os, asyncio
|
||||||
|
sys.path.append(
|
||||||
|
os.path.abspath(
|
||||||
|
os.path.join(
|
||||||
|
os.path.dirname(__file__), '..', '..', '..', '..', '..', '..', '..'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
from src.utils.pprint import pprint
|
||||||
|
from src.integrations.notion.orm.repositories.pages.GetPageProperty import GetPageProperty
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
instance = GetPageProperty()
|
||||||
|
search = await instance\
|
||||||
|
.set_pageid("0db2806f-b365-4327-919d-afbd1943f2ad")\
|
||||||
|
.set_propname("Movements")\
|
||||||
|
.call()
|
||||||
|
return search
|
||||||
|
|
||||||
|
test = await main()
|
||||||
|
pprint(test)
|
||||||
Executable
+176
@@ -0,0 +1,176 @@
|
|||||||
|
from typing import Literal, Any, Optional
|
||||||
|
from pydantic import validate_call
|
||||||
|
from ....schemas.responses.pages.Page import Page as _schmPage
|
||||||
|
from ....schemas.responses.errors.Error import Error as _schmError
|
||||||
|
from ....client import get_client as _get_client
|
||||||
|
from ...common.SetProperty import SetProperty as _setProperty
|
||||||
|
from ...parsers import Parser as _parser
|
||||||
|
|
||||||
|
class CreatePage:
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.data : dict[str, Any] = {
|
||||||
|
"properties": {}
|
||||||
|
}
|
||||||
|
self.set_property = _setProperty(self, self.data["properties"])
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def set_parent(self,
|
||||||
|
type : Literal["page_id", "database_id"],
|
||||||
|
parent_id : str
|
||||||
|
):
|
||||||
|
|
||||||
|
self.data["parent"] = {
|
||||||
|
type : parent_id
|
||||||
|
}
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def set_template(self,
|
||||||
|
type : Literal["default", "template_id"],
|
||||||
|
template_id : Optional[str] = None
|
||||||
|
):
|
||||||
|
|
||||||
|
if type == "template_id":
|
||||||
|
if template_id is None:
|
||||||
|
raise TypeError("Template Type was set to 'template_id' but no ID was provided")
|
||||||
|
self.data["template"] = {
|
||||||
|
"type": type,
|
||||||
|
"template_id": template_id
|
||||||
|
}
|
||||||
|
return self
|
||||||
|
|
||||||
|
self.data["template"] = {
|
||||||
|
"type": type
|
||||||
|
}
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def set_title(self,
|
||||||
|
prop_name : Optional[str],
|
||||||
|
prop_value : Optional[str]
|
||||||
|
):
|
||||||
|
|
||||||
|
if prop_value is None:
|
||||||
|
return self
|
||||||
|
|
||||||
|
if self.data["parent"].get("page_id"):
|
||||||
|
|
||||||
|
self.data["properties"] = {
|
||||||
|
"title": [
|
||||||
|
{
|
||||||
|
"text": {
|
||||||
|
"content": prop_value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
self.data["properties"][prop_name] = {
|
||||||
|
"title": [
|
||||||
|
{
|
||||||
|
"text": {
|
||||||
|
"content": prop_value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def set_icon(self,
|
||||||
|
type: Literal["external"],
|
||||||
|
content: Optional[str]
|
||||||
|
):
|
||||||
|
|
||||||
|
if content is None:
|
||||||
|
return self
|
||||||
|
|
||||||
|
match type:
|
||||||
|
|
||||||
|
case "external":
|
||||||
|
self.data["icon"] = {
|
||||||
|
"external": {
|
||||||
|
"url": str(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def set_children(self,
|
||||||
|
type: Literal["heading_1", "paragraph"],
|
||||||
|
content: Any
|
||||||
|
):
|
||||||
|
|
||||||
|
if self.data.get("children") is None:
|
||||||
|
self.data["children"] = []
|
||||||
|
|
||||||
|
match type:
|
||||||
|
|
||||||
|
case "heading_1":
|
||||||
|
self.data["children"].append(
|
||||||
|
{
|
||||||
|
"object": "block",
|
||||||
|
"type": "heading_1",
|
||||||
|
"heading_1": {
|
||||||
|
"rich_text": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": {
|
||||||
|
"content": content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
case "paragraph":
|
||||||
|
self.data["children"].append(
|
||||||
|
{
|
||||||
|
"object": "block",
|
||||||
|
"type": "paragraph",
|
||||||
|
"paragraph": {
|
||||||
|
"rich_text": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": {
|
||||||
|
"content": content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
async def call(self,
|
||||||
|
parse_properties : bool = True
|
||||||
|
) -> _schmPage:
|
||||||
|
|
||||||
|
client = _get_client()
|
||||||
|
|
||||||
|
create = await client.pages.create(
|
||||||
|
json_data = self.data
|
||||||
|
)
|
||||||
|
|
||||||
|
if create['object'] == 'error':
|
||||||
|
error = _schmError(**create)
|
||||||
|
raise KeyError(error.__dict__)
|
||||||
|
|
||||||
|
if parse_properties:
|
||||||
|
|
||||||
|
properties = _parser.page_props(page = create)
|
||||||
|
|
||||||
|
create["properties"] = properties
|
||||||
|
|
||||||
|
return _schmPage(**create)
|
||||||
|
|
||||||
|
__all__ = ["CreatePage"]
|
||||||
Executable
+92
@@ -0,0 +1,92 @@
|
|||||||
|
from typing import Dict, Any, Optional, TypeVar, Generic
|
||||||
|
from ....schemas.responses.pages.Page import Page as _schmPage
|
||||||
|
from ....schemas.responses.errors.Error import Error as _schmError
|
||||||
|
from ....client import get_client as _get_client
|
||||||
|
from ...mapping.database import NotionDatabase as _NotionDatabase
|
||||||
|
from ...mapping import Mapping as _map
|
||||||
|
from ...parsers import Parser as _parser
|
||||||
|
|
||||||
|
TDB = TypeVar('TDB', bound =_NotionDatabase)
|
||||||
|
|
||||||
|
class GetPage(Generic[TDB]):
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
database_id : Optional[str] = None,
|
||||||
|
generic_response : bool = False
|
||||||
|
) -> None:
|
||||||
|
self._database_id : Optional[str] = database_id
|
||||||
|
self._generic_response = generic_response
|
||||||
|
self._pageid : str
|
||||||
|
|
||||||
|
def set_pageid(self,
|
||||||
|
id : str
|
||||||
|
) -> 'GetPage[TDB]':
|
||||||
|
self._pageid = id
|
||||||
|
return self
|
||||||
|
|
||||||
|
def set_database(self,
|
||||||
|
id : str
|
||||||
|
) -> 'GetPage[TDB]':
|
||||||
|
self._database_id = id
|
||||||
|
return self
|
||||||
|
|
||||||
|
async def select(self,
|
||||||
|
property : str
|
||||||
|
) -> Optional[Any]:
|
||||||
|
|
||||||
|
client = _get_client()
|
||||||
|
|
||||||
|
page : Dict[str, Any] = await client.pages.get(
|
||||||
|
page_id = self._pageid
|
||||||
|
)
|
||||||
|
|
||||||
|
if page['object'] == 'error':
|
||||||
|
error = _schmError(**page)
|
||||||
|
raise KeyError(error.__dict__)
|
||||||
|
|
||||||
|
page["properties"] = _parser.page_props(page = page)
|
||||||
|
if page["properties"] is None:
|
||||||
|
return None
|
||||||
|
allprops = page["properties"]
|
||||||
|
|
||||||
|
return allprops[property]
|
||||||
|
|
||||||
|
async def call(self,
|
||||||
|
map_properties : bool = True,
|
||||||
|
raw_response : bool = False
|
||||||
|
) -> _schmPage[TDB]:
|
||||||
|
|
||||||
|
client = _get_client()
|
||||||
|
|
||||||
|
page : Dict[str, Any] = await client.pages.get(
|
||||||
|
page_id = self._pageid
|
||||||
|
)
|
||||||
|
|
||||||
|
if page['object'] == 'error':
|
||||||
|
error = _schmError(**page)
|
||||||
|
raise KeyError(error.__dict__)
|
||||||
|
|
||||||
|
if not raw_response:
|
||||||
|
|
||||||
|
if map_properties and self._database_id:
|
||||||
|
|
||||||
|
parser = None
|
||||||
|
if not self._generic_response:
|
||||||
|
# Tenta pegar parser do registry
|
||||||
|
parser = _map.registry.get_parser(
|
||||||
|
database_id = self._database_id,
|
||||||
|
page_parser = _parser.page_props
|
||||||
|
)
|
||||||
|
|
||||||
|
# Fallback: se database não registrada, usa parser genérico
|
||||||
|
if not parser:
|
||||||
|
parser = _parser.page_props
|
||||||
|
|
||||||
|
mapped_properties = parser(page = page)
|
||||||
|
page["properties"] = mapped_properties
|
||||||
|
|
||||||
|
elif map_properties:
|
||||||
|
|
||||||
|
page["properties"] = _parser.page_props(page = page)
|
||||||
|
|
||||||
|
return _schmPage(**page)
|
||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
from pydantic import validate_call
|
||||||
|
from typing import Dict, Any, Optional
|
||||||
|
from ....schemas.responses.errors.Error import Error as _schmError
|
||||||
|
from ....client import get_client as _get_client
|
||||||
|
from ...parsers.PageProperties import PageProperties as _PageProperties
|
||||||
|
|
||||||
|
class GetPageProperty:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# CUIDADO AO UTILIZAR!!
|
||||||
|
### [Bug Conhecido](https://community.latenode.com/t/notion-api-relation-property-showing-empty-array-despite-ui-showing-connected-pages/25780) na API do Notion impede retornos confiáveis em propriedades paginadas
|
||||||
|
Ultimo teste : 2026-01-10
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self._pageid : str
|
||||||
|
self._propname : str
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def set_pageid(self,
|
||||||
|
id : str
|
||||||
|
):
|
||||||
|
self._pageid = id
|
||||||
|
return self
|
||||||
|
|
||||||
|
@validate_call
|
||||||
|
def set_propname(self,
|
||||||
|
name : str
|
||||||
|
):
|
||||||
|
self._propname = name
|
||||||
|
return self
|
||||||
|
|
||||||
|
async def call(self,
|
||||||
|
raw_response : bool = False
|
||||||
|
) -> Optional[Dict[str, Any]]:
|
||||||
|
|
||||||
|
client = _get_client()
|
||||||
|
|
||||||
|
getprop = await client.pages.get_property(
|
||||||
|
page_id = self._pageid,
|
||||||
|
property_name = self._propname
|
||||||
|
)
|
||||||
|
|
||||||
|
if getprop['object'] == 'error':
|
||||||
|
error = _schmError(**getprop)
|
||||||
|
raise KeyError(error.__dict__)
|
||||||
|
|
||||||
|
prop_data = getprop.get("results")
|
||||||
|
if getprop.get("object") == "property_item":
|
||||||
|
prop_data = [getprop]
|
||||||
|
if not prop_data:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not raw_response:
|
||||||
|
|
||||||
|
result = _PageProperties.parse(
|
||||||
|
page = prop_data[0]
|
||||||
|
)
|
||||||
|
|
||||||
|
result = prop_data[0]
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
Executable
+30
@@ -0,0 +1,30 @@
|
|||||||
|
from typing import Optional, Generic, TypeVar
|
||||||
|
from ...mapping.database import NotionDatabase as _NotionDatabase
|
||||||
|
from .CreatePage import CreatePage as _CreatePage
|
||||||
|
from .GetPage import GetPage as _GetPage
|
||||||
|
from .GetPageProperty import GetPageProperty as _GetPageProperty
|
||||||
|
|
||||||
|
TDB = TypeVar('TDB', bound = _NotionDatabase)
|
||||||
|
|
||||||
|
class _Pages(Generic[TDB]):
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
database_id : Optional[str] = None,
|
||||||
|
generic_response : bool = False
|
||||||
|
) -> None:
|
||||||
|
|
||||||
|
self._database_id = database_id
|
||||||
|
self._generic_response = generic_response
|
||||||
|
|
||||||
|
self.CreatePage = _CreatePage
|
||||||
|
self.GetPageProperty = _GetPageProperty
|
||||||
|
|
||||||
|
@property
|
||||||
|
def GetPage(self) -> _GetPage:
|
||||||
|
return _GetPage(
|
||||||
|
database_id = self._database_id,
|
||||||
|
generic_response = self._generic_response
|
||||||
|
)
|
||||||
|
|
||||||
|
Pages = _Pages()
|
||||||
|
__all__ = ["Pages", "_Pages"]
|
||||||
Executable
+9
@@ -0,0 +1,9 @@
|
|||||||
|
from .responses import Schemas as _responses
|
||||||
|
from .orm import Schemas as _orm
|
||||||
|
|
||||||
|
class Schemas:
|
||||||
|
|
||||||
|
responses = _responses
|
||||||
|
orm = _orm
|
||||||
|
|
||||||
|
__all__ = ["Schemas"]
|
||||||
Executable
+13
@@ -0,0 +1,13 @@
|
|||||||
|
from pydantic import BaseModel, ConfigDict
|
||||||
|
from datetime import datetime, date
|
||||||
|
|
||||||
|
class BaseModelSdk(BaseModel):
|
||||||
|
|
||||||
|
"Pydantic BaseModel com configuraçoes Padronizadas para o SDK"
|
||||||
|
|
||||||
|
model_config = ConfigDict(
|
||||||
|
json_encoders = {
|
||||||
|
datetime: lambda v: v.strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
|
date: lambda v: v.strftime("%Y-%m-%d")
|
||||||
|
}
|
||||||
|
)
|
||||||
Executable
+7
@@ -0,0 +1,7 @@
|
|||||||
|
from .database import Schemas as _database
|
||||||
|
|
||||||
|
class Schemas:
|
||||||
|
|
||||||
|
database = _database
|
||||||
|
|
||||||
|
__all__ = ["Schemas"]
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
class DatabasesContainer:
|
||||||
|
|
||||||
|
pass
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
from ....schemas.dto import BaseModelSdk
|
||||||
|
from pydantic import ConfigDict
|
||||||
|
from typing import Any, Optional
|
||||||
|
|
||||||
|
class SearchPageProperty(BaseModelSdk):
|
||||||
|
model_config = ConfigDict(title="Notion_Orm_Database_SearchPageProperty")
|
||||||
|
page_id : str
|
||||||
|
prop_value : Optional[Any] = None
|
||||||
Executable
+9
@@ -0,0 +1,9 @@
|
|||||||
|
from .DatabasesContainer import DatabasesContainer as _DatabasesContainer
|
||||||
|
from .SearchPageProperty import SearchPageProperty as _SearchPageProperty
|
||||||
|
|
||||||
|
class Schemas:
|
||||||
|
|
||||||
|
DatabasesContainer = _DatabasesContainer
|
||||||
|
SearchPageProperty = _SearchPageProperty
|
||||||
|
|
||||||
|
__all__ = ["Schemas"]
|
||||||
Executable
+9
@@ -0,0 +1,9 @@
|
|||||||
|
from ....schemas.dto import BaseModelSdk
|
||||||
|
from pydantic import ConfigDict
|
||||||
|
from typing import Dict, Any, List, Optional
|
||||||
|
from ...responses.pages.properties.RichText import RichText as _RichText
|
||||||
|
|
||||||
|
class RichText(BaseModelSdk):
|
||||||
|
model_config = ConfigDict(title="Notion_Orm_Common_RichText")
|
||||||
|
text: Optional[str]
|
||||||
|
detailed: List[_RichText]
|
||||||
Executable
+7
@@ -0,0 +1,7 @@
|
|||||||
|
from .RichText import RichText as _RichText
|
||||||
|
|
||||||
|
class Schemas:
|
||||||
|
|
||||||
|
RichText = _RichText
|
||||||
|
|
||||||
|
__all__ = ["Schemas"]
|
||||||
Executable
+13
@@ -0,0 +1,13 @@
|
|||||||
|
from .databases import Schemas as _databases
|
||||||
|
from .pages import Schemas as _pages
|
||||||
|
from .users import Schemas as _users
|
||||||
|
from .errors import Schemas as _errors
|
||||||
|
|
||||||
|
class Schemas:
|
||||||
|
|
||||||
|
databases = _databases
|
||||||
|
pages = _pages
|
||||||
|
users = _users
|
||||||
|
errors = _errors
|
||||||
|
|
||||||
|
__all__ = ["Schemas"]
|
||||||
Executable
+15
@@ -0,0 +1,15 @@
|
|||||||
|
from ....schemas.dto import BaseModelSdk
|
||||||
|
from pydantic import ConfigDict
|
||||||
|
from typing import Optional, List, TypeVar, Generic
|
||||||
|
from ....orm.mapping.database import NotionDatabase as _NotionDatabase
|
||||||
|
from ..pages.Page import Page as _Page
|
||||||
|
|
||||||
|
TDB = TypeVar('TDB', bound = _NotionDatabase)
|
||||||
|
|
||||||
|
class Query(BaseModelSdk, Generic[TDB]):
|
||||||
|
model_config = ConfigDict(title="Notion_Responses_Databases_Query")
|
||||||
|
results: List[_Page[TDB]]
|
||||||
|
next_cursor: Optional[str] = None
|
||||||
|
has_more: bool = False
|
||||||
|
type: str = "page_or_database"
|
||||||
|
page_or_database: dict = {}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
from .Query import Query as _Query
|
||||||
|
|
||||||
|
class Schemas:
|
||||||
|
|
||||||
|
Query = _Query
|
||||||
|
|
||||||
|
__all__ = ["Schemas"]
|
||||||
Executable
+8
@@ -0,0 +1,8 @@
|
|||||||
|
from ....schemas.dto import BaseModelSdk
|
||||||
|
from pydantic import ConfigDict
|
||||||
|
|
||||||
|
class Error(BaseModelSdk):
|
||||||
|
model_config = ConfigDict(title="Notion_Responses_Errors_Error")
|
||||||
|
status: int
|
||||||
|
code: str
|
||||||
|
message: str
|
||||||
Executable
+7
@@ -0,0 +1,7 @@
|
|||||||
|
from .Error import Error as _Error
|
||||||
|
|
||||||
|
class Schemas:
|
||||||
|
|
||||||
|
Error = _Error
|
||||||
|
|
||||||
|
__all__ = ["Schemas"]
|
||||||
Executable
+24
@@ -0,0 +1,24 @@
|
|||||||
|
from ....schemas.dto import BaseModelSdk
|
||||||
|
from pydantic import ConfigDict
|
||||||
|
from typing import Optional, Any, Dict, Generic, TypeVar, Union
|
||||||
|
from datetime import datetime
|
||||||
|
from ....orm.mapping.database import NotionDatabase as _NotionDatabase
|
||||||
|
from ..users.User import User as _User
|
||||||
|
from .Parent import Parent as _Parent
|
||||||
|
|
||||||
|
TDB = TypeVar('TDB', bound = _NotionDatabase)
|
||||||
|
|
||||||
|
class Page(BaseModelSdk, Generic[TDB]):
|
||||||
|
model_config = ConfigDict(title="Notion_Responses_Pages_Page")
|
||||||
|
id: str
|
||||||
|
created_time: datetime
|
||||||
|
last_edited_time: datetime
|
||||||
|
created_by: _User
|
||||||
|
last_edited_by: _User
|
||||||
|
cover: Optional[Dict[str, Any]]
|
||||||
|
icon: Optional[Dict[str, Any]]
|
||||||
|
parent: _Parent
|
||||||
|
archived: bool
|
||||||
|
properties: Union[Any, TDB]
|
||||||
|
url: str
|
||||||
|
public_url: Optional[str]
|
||||||
Executable
+9
@@ -0,0 +1,9 @@
|
|||||||
|
from ....schemas.dto import BaseModelSdk
|
||||||
|
from pydantic import ConfigDict
|
||||||
|
from typing import Optional, Literal
|
||||||
|
|
||||||
|
class Parent(BaseModelSdk):
|
||||||
|
model_config = ConfigDict(title="Notion_Responses_Pages_Parent")
|
||||||
|
type: Literal ["page_id", "data_source_id", "database_id"]
|
||||||
|
data_source_id: Optional[str] = None
|
||||||
|
database_id: Optional[str] = None
|
||||||
Executable
+9
@@ -0,0 +1,9 @@
|
|||||||
|
from .Page import Page as _Page
|
||||||
|
from .Parent import Parent as _Parent
|
||||||
|
|
||||||
|
class Schemas:
|
||||||
|
|
||||||
|
Page = _Page
|
||||||
|
Parent = _Parent
|
||||||
|
|
||||||
|
__all__ = ["Schemas"]
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
from .....schemas.dto import BaseModelSdk
|
||||||
|
from pydantic import ConfigDict
|
||||||
|
from typing import Dict, Any, Optional
|
||||||
|
|
||||||
|
class RichText(BaseModelSdk):
|
||||||
|
model_config = ConfigDict(title="Notion_Responses_Pages_Properties_RichText")
|
||||||
|
type: str
|
||||||
|
text: 'Text'
|
||||||
|
annotations: 'Annotations'
|
||||||
|
plain_text: Optional[str]
|
||||||
|
href: Optional[str]
|
||||||
|
|
||||||
|
class Text(BaseModelSdk):
|
||||||
|
content: Optional[str]
|
||||||
|
link: Optional[str]
|
||||||
|
|
||||||
|
class Annotations(BaseModelSdk):
|
||||||
|
bold: bool
|
||||||
|
italic: bool
|
||||||
|
strikethrough: bool
|
||||||
|
underline: bool
|
||||||
|
code: bool
|
||||||
|
color: str
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
from .RichText import RichText as _RichText
|
||||||
|
|
||||||
|
class Schemas:
|
||||||
|
|
||||||
|
RichText = _RichText
|
||||||
|
|
||||||
|
__all__ = ["Schemas"]
|
||||||
Executable
+11
@@ -0,0 +1,11 @@
|
|||||||
|
from ....schemas.dto import BaseModelSdk
|
||||||
|
from pydantic import ConfigDict
|
||||||
|
from .type.Bot import Bot as _Bot
|
||||||
|
|
||||||
|
class Bot(BaseModelSdk):
|
||||||
|
model_config = ConfigDict(title="Notion_Responses_Users_Bot")
|
||||||
|
id: str
|
||||||
|
type: str = "bot"
|
||||||
|
bot: _Bot
|
||||||
|
name: str
|
||||||
|
avatar_url: str
|
||||||
Executable
+11
@@ -0,0 +1,11 @@
|
|||||||
|
from ....schemas.dto import BaseModelSdk
|
||||||
|
from pydantic import ConfigDict
|
||||||
|
from .type.Person import Person as _Person
|
||||||
|
|
||||||
|
class Person(BaseModelSdk):
|
||||||
|
model_config = ConfigDict(title="Notion_Responses_Users_Person")
|
||||||
|
id: str
|
||||||
|
type: str = "person"
|
||||||
|
person: _Person
|
||||||
|
name: str
|
||||||
|
avatar_url: str
|
||||||
Executable
+6
@@ -0,0 +1,6 @@
|
|||||||
|
from ....schemas.dto import BaseModelSdk
|
||||||
|
from pydantic import ConfigDict
|
||||||
|
|
||||||
|
class User(BaseModelSdk):
|
||||||
|
model_config = ConfigDict(title="Notion_Responses_Users_User")
|
||||||
|
id: str
|
||||||
Executable
+13
@@ -0,0 +1,13 @@
|
|||||||
|
from .type import Schemas as _type
|
||||||
|
from .User import User as _User
|
||||||
|
from .Person import Person as _Person
|
||||||
|
from .Bot import Bot as _Bot
|
||||||
|
|
||||||
|
class Schemas:
|
||||||
|
|
||||||
|
type = _type
|
||||||
|
User = _User
|
||||||
|
Person = _Person
|
||||||
|
Bot = _Bot
|
||||||
|
|
||||||
|
__all__ = ["Schemas"]
|
||||||
Executable
+6
@@ -0,0 +1,6 @@
|
|||||||
|
from .....schemas.dto import BaseModelSdk
|
||||||
|
from pydantic import ConfigDict
|
||||||
|
|
||||||
|
class Bot(BaseModelSdk):
|
||||||
|
model_config = ConfigDict(title="Notion_Responses_Users_Type_Bot")
|
||||||
|
...
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
from .....schemas.dto import BaseModelSdk
|
||||||
|
from pydantic import ConfigDict
|
||||||
|
|
||||||
|
class Person(BaseModelSdk):
|
||||||
|
model_config = ConfigDict(title="Notion_Responses_Users_Type_Person")
|
||||||
|
email: str
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
from .Person import Person as _Person
|
||||||
|
from .Bot import Bot as _Bot
|
||||||
|
|
||||||
|
class Schemas:
|
||||||
|
|
||||||
|
Person = _Person
|
||||||
|
Bot = _Bot
|
||||||
|
|
||||||
|
__all__ = ["Schemas"]
|
||||||
Executable
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
from ...orm.mapping.database import NotionDatabase
|
||||||
|
from ...orm.mapping.registry import DatabaseRegistry
|
||||||
|
from ...schemas.orm.database.DatabasesContainer import DatabasesContainer
|
||||||
Executable
+1
@@ -0,0 +1 @@
|
|||||||
|
from ....schemas.orm.properties.RichText import RichText
|
||||||
Executable
Executable
+1
@@ -0,0 +1 @@
|
|||||||
|
from ....schemas.responses.databases.Query import Query
|
||||||
Executable
+1
@@ -0,0 +1 @@
|
|||||||
|
from ....schemas.responses.errors.Error import Error
|
||||||
Executable
+2
@@ -0,0 +1,2 @@
|
|||||||
|
from ....schemas.responses.pages.Page import Page
|
||||||
|
from ....schemas.responses.pages.Parent import Parent
|
||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
from ....schemas.responses.users.Bot import Bot
|
||||||
|
from ....schemas.responses.users.Person import Person
|
||||||
|
from ....schemas.responses.users.User import User
|
||||||
Executable
+21
@@ -0,0 +1,21 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=61.0"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "sdk-notion"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Async Python SDK for the Notion API"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.9"
|
||||||
|
license = { text = "MIT" }
|
||||||
|
authors = [
|
||||||
|
{ name = "Eduardo Riguetto" }
|
||||||
|
]
|
||||||
|
dependencies = [
|
||||||
|
"httpx>=0.25,<1.0",
|
||||||
|
"pydantic>=2.5,<3.0"
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.urls]
|
||||||
|
Homepage = "https://github.com/riguettodev/sdk-notion"
|
||||||
Reference in New Issue
Block a user