Skip to content

Commit

Permalink
v1.1.0a1 (#10)
Browse files Browse the repository at this point in the history
Pydantic based app settings
Inject arguments to endpoints based on type annotations (FastAPI-like)
Inject logger or other components using the same mechanics
  • Loading branch information
uthunderbird authored Oct 28, 2022
1 parent b9d2a85 commit 041dc93
Show file tree
Hide file tree
Showing 50 changed files with 2,660 additions and 810 deletions.
11 changes: 9 additions & 2 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
UPCOMING
pass
TODO
Policies declaration via app config (https://www.rabbitmq.com/parameters.html)
Run separate service/consumer as worker
Add ABC to prevent circular import hell

v 1.1.0a1
Pydantic based app settings
Inject arguments to endpoints based on type annotations (FastAPI-like)
Inject logger or other components

v 1.0.11
Make it possible to just register endpoints, without running loop (method `Mela.setup()`)
Expand Down
66 changes: 66 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# COLORS
GREEN := $(shell tput -Txterm setaf 2)
WHITE := $(shell tput -Txterm setaf 7)
YELLOW := $(shell tput -Txterm setaf 3)
RESET := $(shell tput -Txterm sgr0)

.DEFAULT_GOAL := help
.PHONY: help setup run lint type flake8 mypy test testcov run clean

VENV=.venv
PYTHON=$(VENV)/bin/python3

## Initialize venv and install dependencies
setup: $(VENV)/bin/activate
$(VENV)/bin/activate:
python3 -m venv $(VENV)
$(PYTHON) -m pip install pipenv==2022.9.8
$(PYTHON) -m pipenv sync -d

## Analyze project source code for slylistic errors
lint: setup
$(PYTHON) -m flake8 mela tests

## Analyze project source code for typing errors
type: setup
$(PYTHON) -m mypy mela tests

## Run flake8
flake8: setup
$(PYTHON) -m flake8 mela tests

## Run mypy
mypy: setup
$(PYTHON) -m mypy mela tests

## Run project tests
test: setup
$(PYTHON) -m pytest

## Run project tests and open HTML coverage report
testcov: setup
$(PYTHON) -m pytest --cov-report=html
xdg-open htmlcov/index.html

## Clean up project environment
clean:
rm -rf $(VENV) *.egg-info .eggs .coverage htmlcov .pytest_cache
find . -type f -name '*.pyc' -delete

## Show help
help:
@echo ''
@echo 'Usage:'
@echo ' ${YELLOW}make${RESET} ${GREEN}<target>${RESET}'
@echo ''
@echo 'Targets:'
@awk '/^[a-zA-Z\-\_0-9]+:/ { \
helpMessage = match(lastLine, /^## (.*)/); \
if (helpMessage) { \
helpCommand = $$1; sub(/:$$/, "", helpCommand); \
helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \
printf " ${YELLOW}%-$(TARGET_MAX_CHAR_NUM)15s${RESET} ${GREEN}%s${RESET}\n", helpCommand, helpMessage; \
} \
} \
{ lastLine = $$0 }' $(MAKEFILE_LIST)
@echo ''
31 changes: 31 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
aio-pika = "==8.2.1"
envyaml = "==1.10.211231"
pydantic = "==1.10.2"

[dev-packages]
flake8 = "==5.0.4"
flake8-broken-line = "==0.5.0"
flake8-commas = "==2.1.0"
flake8-comprehensions = "==3.10.0"
flake8-eradicate = "==1.3.0"
flake8-isort = "==4.2.0"
flake8-print = "==5.0.0"
pep8-naming = "==0.13.2"
flake8-bandit = "==4.1.1"
flake8-use-fstring = "==1.4"
bandit = "==1.7.4"
mypy = "==0.971"
pytest = "==7.1.3"
pytest-cov = "==3.0.0"
pytest-mock = "==3.8.2"
pytest-asyncio = "==0.19.0"
pytest-clarity = "==1.0.1"

[requires]
python_version = "3.10"
734 changes: 734 additions & 0 deletions Pipfile.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0.11
1.1.0a1
5 changes: 2 additions & 3 deletions examples/bridge_between_two_rabbits/app.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
from mela import Mela

app = Mela(__name__)
app.read_config_yaml('application.yml')


@app.service("input", "output")
def serve(body, message):
@app.service("bridge")
async def serve(body, message):
return body


Expand Down
46 changes: 20 additions & 26 deletions examples/bridge_between_two_rabbits/application.yml
Original file line number Diff line number Diff line change
@@ -1,30 +1,24 @@
connections:
input_connection:
host: ${RABBIT_INPUT_HOST}
port: 5672
username: rabbitmq-bridge
password: rabbitmq-bridge
connTimeout: 1000
heartbeat: 360
host: $RABBIT_INPUT_HOST
port: ${RABBIT_INPUT_PORT|5672}
username: ${RABBIT_INPUT_USERNAME|rabbitmq-bridge}
password: ${RABBIT_INPUT_PASSWORD|rabbitmq-bridge}
output_connection:
host: ${RABBIT_OUTPUT_HOST}
port: 5672
username: rabbitmq-bridge
password: rabbitmq-bridge
connTimeout: 1000
heartbeat: 360
host: $RABBIT_OUTPUT_HOST
port: ${RABBIT_OUTPUT_PORT|5672}
username: ${RABBIT_OUTPUT_USERNAME|rabbitmq-bridge}
password: ${RABBIT_OUTPUT_PASSWORD|rabbitmq-bridge}

consumers:
input:
connection: input_connection
prefetch_count: 100
routing_key: general-sentiment-q
exchange: general-sentiment-x
queue: general-sentiment-temp-q
decode: json

producers:
output:
connection: output_connection
routing_key: general-sentiment-q
exchange: general-sentiment-x
services:
bridge:
consumer:
connection: input_connection
prefetch_count: ${RABBIT_INPUT_PREFETCH_COUNT|1}
routing_key: ${RABBIT_INPUT_ROUTING_KEY}
exchange: ${RABBIT_INPUT_EXCHANGE}
queue: ${RABBIT_INPUT_QUEUE}
producer:
connection: output_connection
routing_key: ${RABBIT_OUTPUT_ROUTING_KEY}
exchange: ${RABBIT_OUTPUT_EXCHANGE}
18 changes: 7 additions & 11 deletions examples/dead_letter_exchange/app.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
from mela import Mela
from mela.components.exceptions import NackMessageError

app = Mela(__name__)
app.read_config_yaml('application.yml')

i = 0


@app.service("printer")
@app.service("service_with_dlx")
async def printer(body, message):
global i
i += 1
if i % 2 == 0:
raise NotImplementedError("Method is not implemented")
return i
# for obj in body:
# if i % 2 == 0:
# yield obj
# else:
# yield obj, {'routing_key': "test_queue2"}
# raise ConnectionError("something went wrong")
# i += 1
print(body, "NO")
raise NackMessageError("Method is not implemented", requeue=False)
else:
print(body, "YES")
return body


if __name__ == '__main__':
Expand Down
2 changes: 1 addition & 1 deletion examples/dead_letter_exchange/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ connections:
password: admin

services:
printer:
service_with_dlx:
consumer:
exchange: dlx-test-x
routing_key: dlx-test-k
Expand Down
11 changes: 0 additions & 11 deletions examples/error_handler/app.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,11 @@
from mela import Mela

app = Mela(__name__)
app.read_config_yaml('application.yml')


@app.service("splitter")
async def printer(body, message):
i = 0
i += 1
raise NotImplementedError("Method is not implemented")
return i
# for obj in body:
# if i % 2 == 0:
# yield obj
# else:
# yield obj, {'routing_key': "test_queue2"}
# raise ConnectionError("something went wrong")
# i += 1


if __name__ == '__main__':
Expand Down
4 changes: 1 addition & 3 deletions examples/exchange_type_topic/app.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
from aio_pika import IncomingMessage
from mela import Mela

app = Mela(__name__)
app.read_config_yaml('application.yml')


@app.service("printer")
def printer(body, message: IncomingMessage):
def printer(body, message):
print(body)
print(message.routing_key)
return body
Expand Down
30 changes: 13 additions & 17 deletions examples/extra_publishing_service/app.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,23 @@
from pydantic import BaseModel, Field
from mela import Mela
from mela.components import Publisher
from mela.settings import Settings

app = Mela(__name__)
app.read_config_yaml('application.yml')

logging_publisher = app.publisher()
class Document(BaseModel):
id_: int = Field(alias='id')


app = Mela(__name__)
app.settings = Settings()

SPLITTER_SERVICE_NAME = "splitter"
log_publisher: Publisher = app.publisher_instance('log')


@app.service(SPLITTER_SERVICE_NAME)
async def logger(body, message):
default_routing_key = app.services['splitter'].config['publisher']['routing_key']
i = 0
for obj in body:
if i % 2 == 0:
routing_key = default_routing_key
else:
routing_key = "test_queue2"
yield obj, {'routing_key': routing_key}
# Anyway, we should publish message into logging exchange
await logging_publisher.publish(obj, routing_key='.'.join([SPLITTER_SERVICE_NAME, routing_key]))
i += 1
@app.service('extra_publishing')
async def logger(body: Document):
await log_publisher.publish(body)
return body


if __name__ == '__main__':
Expand Down
4 changes: 2 additions & 2 deletions examples/extra_publishing_service/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ connections:
password: admin

services:
splitter:
extra_publishing:
consumer:
exchange: general-sentiment-x
routing_key: general-sentiment-q
Expand All @@ -16,7 +16,7 @@ services:
routing_key: test_queue

publishers:
default:
log:
exchange: log-x
exchange_type: topic
routing_key: splitter.test_queue
32 changes: 20 additions & 12 deletions examples/rpc/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from mela import Mela

app = Mela(__name__)
app.read_config_yaml('application.yml')


fetcher = app.rpc_client("fetcher")
Expand All @@ -14,26 +13,35 @@
async def main():
# RPC calls over RabbitMQ never were simpler!
res = await fetcher.call({'asdf': 5, 'lol': [3, 8, ["haha", "wow"]]})
print(res)
# res

# we can even gather call results!
g = await asyncio.gather(fetcher.call(url1), fetcher.call(url2))
print(g)

create_bot_result = await bot_manager.call(
{'bot_id': 1, 'bot_username': "LalkaPalka", 'bot_password': "supersecret"},
headers={'method': 'create_bot'}
# g

create_bot_result = await bot_manager.call({
'bot_id': 1,
'bot_username': "LalkaPalka",
'bot_password': "supersecret",
},
headers={'method': 'create_bot'},
)
print(f"create_bot result: {create_bot_result}")
# create_bot result {create_bot_result}

get_bot_result = await bot_manager.call({'bot_id': 1}, headers={'method': 'get_bot'})
print(f"get_bot_result: {get_bot_result}")
# get_bot_result {get_bot_result}

unknown_method_result = await bot_manager.call({'bot_id': 4}, headers={'method': 'getBot'})
print(f"unknown method result: {unknown_method_result}")
# unknown method result: {unknown_method_result}


if __name__ == '__main__':
url1 = 'https://tengrinews.kz/kazakhstan_news/vorvalis-dom-izbili-almatinka-rasskazala-zaderjanii-supruga-459127/'
url2 = 'https://www.inform.kz/ru/skol-ko-lichnyh-podsobnyh-hozyaystv-naschityvaetsya-v-kazahstane_a3896073'
url1 = (
'https://tengrinews.kz/kazakhstan_news/vorvalis-dom-izbili-'
'almatinka-rasskazala-zaderjanii-supruga-459127/'
)
url2 = (
'https://www.inform.kz/ru/skol-ko-lichnyh-podsobnyh-'
'hozyaystv-naschityvaetsya-v-kazahstane_a3896073'
)
app.run(main())
3 changes: 1 addition & 2 deletions examples/rpc/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from mela import Mela

app = Mela(__name__)
app.configure_from_yaml('application.yml')


async def fetch(url):
Expand All @@ -13,7 +12,7 @@ async def fetch(url):
return url


@app.rpc_server("fetcher")
@app.rpc_service("fetcher")
async def fetcher(link, message):
return await fetch(link)

Expand Down
Loading

0 comments on commit 041dc93

Please sign in to comment.