Skip to content

Commit 288737e

Browse files
chrisemkeKrisque
authored andcommitted
The last PR before tag v0.1 (#3)
There are still a lot of work to do in this features I started start tests, I don't have much experience with pytest, so many things are far from being the best way to do them; start plugins, you still need to create a factory/builder to build the list of plugin tasks. I added a plugin (cep_aberto) for testing; docstrings everywhere see CHANGELOG.md for more info Reviewed-on: https://codeberg.org/Krisque/jacobson/pulls/3 Co-authored-by: Christian G. Semke <[email protected]> Co-committed-by: Christian G. Semke <[email protected]>
1 parent 256ce41 commit 288737e

33 files changed

+2234
-777
lines changed

.pre-commit-config.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,15 @@ repos:
4444
--no-space,
4545
]
4646
- repo: https://github.com/astral-sh/ruff-pre-commit
47-
rev: v0.3.7
47+
rev: v0.4.3
4848
hooks:
4949
- id: ruff
5050
name: Run Ruff Linter & Formater
5151
args: [--fix, --exit-non-zero-on-fix]
5252
- id: ruff-format
5353
name: Run Ruff Formater
5454
- repo: https://github.com/pre-commit/mirrors-mypy
55-
rev: v1.9.0
55+
rev: v1.10.0
5656
hooks:
5757
- id: mypy
5858
name: Run Mypy (Static type checker)
@@ -66,7 +66,7 @@ repos:
6666
- id: poetry-export
6767
args: [-f, requirements.txt, -o, requirements.txt]
6868
- repo: https://github.com/commitizen-tools/commitizen
69-
rev: v3.22.0
69+
rev: v3.25.0
7070
hooks:
7171
- id: commitizen
7272
- id: commitizen-branch

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
3838

3939
### Refactor
4040

41+
- **api**: add docstrings and drop coordinates for now
42+
- **plugins**: start base for plugins and cep_aberto service
43+
- **settings**: move all .env settings to utils directory
4144
- **pydantic**: move pydantic models to sqlmodel models
4245
- **edgedb-jacobson**: remove edgedb and legacy jacobson
4346
- **graphql-query**: add pydantic and strawberry types to query

README.md

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,28 @@ else async call to all plugins that are configured, return and insert on databas
3232
call to tell the api to update some register from plugins that are configured
3333
```
3434

35-
# TODO
35+
# TODO (Needed for v0.1)
3636
- [x] git hooks (pre-commit)
3737
- [x] SqlModel
38-
- [ ] Api's support plugin-like (cepaberto, brazilapi...)
39-
- [ ] Tests (pytest)
38+
- [-] Api's support plugin-like (viacep, brazilapi...) cep aberto was added for test, need to think in a better structure for plugins and tasks
39+
- [-] Tests, need to fix a lot of tests, need to study other ways to test
40+
- [ ] Integration Tests
41+
- [ ] Custom exceptions
42+
- [ ] Add log support (see loguru)
4043
- [ ] Docs (mkdocs)
41-
- [ ] fix podman pod for all devs (see jacobson-dev.yaml)
4244
- [ ] Alembic migrations
4345

46+
## TODO (nice to have)
47+
- [ ] move from docker-compose to a podman pod
48+
- [ ] study mypyc viability
4449

4550
# DEV
4651
The idea is to just run this command and podman will run the entire dev environment
4752
```bash
4853
podman compose up -d --build
4954
```
55+
56+
You can access the api at localhost port 8000 /graphql
57+
```
58+
http://127.0.0.1:8000/graphql
59+
```

api/address/inputs.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
along with this program. If not, see <https://www.gnu.org/licenses/>.
1717
"""
1818

19-
from strawberry import auto, input
19+
from strawberry import auto
2020
from strawberry.experimental.pydantic import input as pydantic_input
2121

2222
from database.models.brazil import Address, AddressBase, City, State
@@ -27,23 +27,23 @@ class StateInput:
2727
acronym: auto
2828
# Needed until strawberry support auto | None type
2929
# https://github.com/strawberry-graphql/strawberry/issues/3435
30-
name: str | None
30+
name: str | None = None
3131

3232

3333
@pydantic_input(model=City)
3434
class CityInput:
3535
ibge: auto
3636
# Needed until strawberry support auto | None type
3737
# https://github.com/strawberry-graphql/strawberry/issues/3435
38-
name: str | None
38+
name: str | None = None
3939
ddd: auto
4040

4141

42-
@input
43-
class CoordinatesInput:
44-
latitude: float
45-
longitude: float
46-
altitude: float | None = None
42+
# @input
43+
# class CoordinatesInput:
44+
# latitude: float
45+
# longitude: float
46+
# altitude: float | None = None
4747

4848

4949
@pydantic_input(model=AddressBase)

api/address/types.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
along with this program. If not, see <https://www.gnu.org/licenses/>.
1717
"""
1818

19-
from strawberry import auto, type
19+
from strawberry import auto
2020
from strawberry.experimental.pydantic import type as pydantic_type
2121

2222
from database.models.brazil import Address, City, State
@@ -35,11 +35,11 @@ class CityType:
3535
ddd: auto
3636

3737

38-
@type(name='Coordinates')
39-
class CoordinatesType:
40-
latitude: float
41-
longitude: float
42-
altitude: float
38+
# @type(name='Coordinates')
39+
# class CoordinatesType:
40+
# latitude: float
41+
# longitude: float
42+
# altitude: float
4343

4444

4545
@pydantic_type(name='Address', model=Address)
@@ -49,4 +49,4 @@ class AddressType:
4949
state: StateType
5050
neighborhood: auto
5151
complement: auto
52-
coordinates: CoordinatesType | None = None
52+
# coordinates: CoordinatesType | None = None

api/app.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@
2525
app.include_router(graphql_app, prefix='/graphql')
2626

2727

28-
@app.on_event("startup")
28+
@app.on_event('startup')
2929
async def on_startup() -> None:
30+
"""
31+
Create database.
32+
33+
Todo:
34+
----
35+
- Move from events to lifespan
36+
see https://fastapi.tiangolo.com/advanced/events/
37+
38+
"""
3039
await init_db()

api/resolvers.py

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,38 @@
2121
from api.address.inputs import AddressFilterInput, AddressInsertInput
2222
from database import functions
2323
from database.models.brazil import Address
24+
from plugins.plugins_controller import get_zipcode_from_plugins
2425

2526

2627
async def get_address(
2728
filter: AddressFilterInput,
2829
page_size: PositiveInt,
2930
page_number: PositiveInt,
30-
) -> list[Address | None]:
31+
) -> list[Address]:
32+
"""
33+
Get all addresses from database or all plugins.
34+
35+
Parameters
36+
----------
37+
filter : AddressFilterInput
38+
Strawberry input dataclass, everything can be None
39+
(based on sqlmodel model)
40+
page_size : PositiveInt
41+
How many elements in each page
42+
page_number : PositiveInt
43+
Number of the page
44+
45+
Returns
46+
-------
47+
list[Address]
48+
All addresses (db model) based on filter or empty list
49+
50+
"""
3151
result = await functions.get_address_by_dc_join_state_join_city(
3252
filter, page_size, page_number
3353
)
34-
if not result:
35-
try:
36-
...
37-
# result = async get from plugins
38-
except Exception:
39-
...
40-
# there is no address found
41-
else:
42-
...
43-
# async insert on database
54+
if not result and filter.zipcode:
55+
result = await get_zipcode_from_plugins(filter.zipcode)
4456
return result
4557

4658

api/schema.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,27 @@ async def all_address(
3333
filter: AddressFilterInput,
3434
page_size: PositiveInt = 10,
3535
page_number: PositiveInt = 1,
36-
) -> list[AddressType | None]:
36+
) -> list[AddressType]:
37+
"""
38+
Query all addresses from database or all plugins.
39+
40+
Parameters
41+
----------
42+
filter : AddressFilterInput
43+
Strawberry input dataclass, everything can be None
44+
(based on sqlmodel model)
45+
page_size : PositiveInt, optional
46+
How many elements in each page, by default 10
47+
page_number : PositiveInt, optional
48+
Number of the page, by default 1
49+
50+
Returns
51+
-------
52+
list[AddressType]
53+
All addresses (db model converted to strawberry dataclass)
54+
based on filter or empty list
55+
56+
"""
3757
return list(
3858
map(
3959
AddressType.from_pydantic,
@@ -49,6 +69,6 @@ async def create_address(self, address: AddressInsertInput) -> AddressType:
4969
return AddressType.from_pydantic(await insert_address(address))
5070

5171

52-
schema = Schema(query=Query, mutation=Mutation) # , mutation=Mutation)
72+
schema = Schema(query=Query, mutation=Mutation)
5373

5474
graphql_app = GraphQLRouter[object, object](schema)

database/__init__.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"""
2+
Jacobson is a self hosted zipcode API
3+
Copyright (C) 2023-2024 Christian G. Semke.
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU Affero General Public License as
7+
published by the Free Software Foundation, either version 3 of the
8+
License, or (at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU Affero General Public License for more details.
14+
15+
You should have received a copy of the GNU Affero General Public License
16+
along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
"""

database/engine.py

Lines changed: 3 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -16,59 +16,21 @@
1616
along with this program. If not, see <https://www.gnu.org/licenses/>.
1717
"""
1818

19-
from urllib.parse import quote_plus
20-
21-
from pydantic import (
22-
BaseModel,
23-
MySQLDsn,
24-
PositiveInt,
25-
computed_field,
26-
)
27-
from pydantic_settings import BaseSettings
2819
from sqlalchemy.ext.asyncio import create_async_engine
2920
from sqlmodel import SQLModel
3021

31-
32-
class UrlValidate(BaseModel):
33-
url: MySQLDsn
34-
35-
36-
class Database(BaseSettings):
37-
DATABASE_USER: str
38-
DATABASE_PASSWORD: str
39-
DATABASE_HOST: str
40-
DATABASE_PORT: PositiveInt
41-
DATABASE_NAME: str
42-
43-
@computed_field # type: ignore[misc]
44-
@property
45-
def DATABASE_URL(self) -> str:
46-
url = (
47-
'mysql+asyncmy://'
48-
f'{self.DATABASE_USER}:{quote_plus(self.DATABASE_PASSWORD)}@'
49-
f'{self.DATABASE_HOST}:{self.DATABASE_PORT}/{self.DATABASE_NAME}'
50-
)
51-
52-
return str(UrlValidate(url=url).url)
53-
54-
class Config:
55-
"""A config class to make model immutable."""
56-
57-
env_file = '.env'
58-
frozen = True
59-
60-
61-
database = Database()
22+
from utils.settings import settings
6223

6324
engine = create_async_engine(
64-
database.DATABASE_URL,
25+
settings.DATABASE_URL,
6526
echo=True,
6627
future=True,
6728
pool_size=20,
6829
max_overflow=20,
6930
pool_recycle=3600,
7031
)
7132

33+
7234
async def init_db() -> None:
7335
async with engine.begin() as session:
7436
await session.run_sync(SQLModel.metadata.create_all)

0 commit comments

Comments
 (0)