Programando em Python no PyCharm
O PyCharm cria automaticamente um virtual environment para o seu projeto (venv).
ATENÇÃO! DEIXE O PIP NA VERSÃO 9.0.3! NÃO ATUALIZE!
File -> Settings -> Project : Nome do seu projeto -> Project Interpreter -> Clique no + verde à direita da janela
O PyCharm no Windows pode baixar os pacotes em suas últimas versões.
É preciso instalar o pacote virtualenv
[code language="batch"] pip install virtualenv [/code]
[code] C:\Users\Tito\PycharmProjects\NetworkMonitor\venv\Scripts\activate.bat easy_install -U pip easy_install -U setuptools [/code]
Para atualizar no windows é preciso entrar no VENV e fazer
[code] easy_install -U pip [/code]
Distribuindo seu código
https://packaging.python.org/tutorials/packaging-projects/
Usando o PEX (Exe de Python)
Discussão no Redit https://www.reddit.com/r/Python/comments/5rey4a/distributing_a_virtualenv_and_all_dependencies_as/
Pipenv https://pipenv.readthedocs.io/en/latest/
Como dar nome aos pacotes, classes, etc? Convenção de nomes no Python.
Nome do pacote: caixabaixa (de preferência sem underscore) Nome dos arquivos: caixa_baixa Nome das classes: NomeDaClasse
Modelo de estrutura de projeto
[code] /meu_programa /meu_programa __init__.py setup.py LICENSE README.md [/code]
Exemplo de setup.py
[code language="python"]
import setuptools
with open("README.md", "r") as fh: long_description = fh.read()
setuptools.setup( name="meu_programa", version="0.0.1", author="Johnny Wow", author_email="[email protected]", description="Software para fazer algo", long_description=long_description, long_description_content_type="text/markdown", url="https://github.com/pypa/sampleproject", packages=setuptools.find_packages(), classifiers=[ "Programming Language :: Python :: 3", "Operating System :: OS Independent", ], ) [/code]
Declarando tipos em Python (Python 3.6 a diante)
A partir do Python 3.6 é possível declarar tipos no Python. O compilador em si não realiza verificações, mas as IDEs podem usar isso para facilitar os trabalhos. Aqui vai um tutorial.
Modelo de main em Python
[code language="python"] def main(): print("Hello World!")
if __name__ == "__main__": main() [/code]
Listen/Notify com PostgreSQL no Python
Enviando uma notificação no PostgreSQL
[code language="sql"] --O esqueleto da notificação é NOTIFY nome_do_canal, mensagem (também chamado de payload) NOTIFY canal_usuario, 'oi, você recebeu uma notificação do canal_usuário.'; --Também da pra enviar notificações assim: SELECT pg_notify('canal_usuario','oi, você recebeu uma notificação do canal_usuário.'); [/code]
Recebendo uma notificação no Python 3.6 com psycopg2
[code language="python"]
import select import psycopg2 import psycopg2.extensions import logging from threading import Thread from threading import RLock from values_monitor.config import DatabaseConfig import values_monitor.monitor_state
class PostgreSQLConnection:
def __init__(self, database_config: DatabaseConfig, ): self.database_config = database_config self.logger = logging.getLogger('PostgreSQLConnection') self.logger.debug(database_config.database) self.logger.debug(database_config.host) self.conn = None self.readLock: RLock self.writeLock: RLock
def connect(self): try: self.conn = psycopg2.connect( host=self.database_config.host, port=self.database_config.port, dbname=self.database_config.database, user=self.database_config.user, password=self.database_config.password ) self.conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT) except psycopg2.Error as e: self.logger.error("Error while creating database connection.") self.logger.error(e)
def get_version(self): with self.conn.cursor() as cur: cur.execute("SELECT version();") result = cur.fetchall() self.logger.debug(result)
def __listen(self, channel: str, operation): seconds_step = 120 with self.conn.cursor() as cur: cur.execute("LISTEN "+channel+";") self.logger.info("Listening for notifications in channel {}.".format(channel)) seconds_passed = 0 while True: if select.select([self.conn], [], [], seconds_step) == ([], [], []): seconds_passed += seconds_step self.logger.debug("{} seconds passed without a notification at channel {}." .format(seconds_passed, channel)) else: self.conn.poll() seconds_passed = 0 while self.conn.notifies: notify = self.conn.notifies.pop(0) self.logger.info("Notify received! Content is:") self.logger.info(notify) operation(notify)
def listen_as_thread(self, channel: str, operation): thread = Thread(target=self.__listen, args=(channel, operation), name='pg_listen_'+channel) thread.start()
[/code]
Referências
PostgreSQL Wiki Presentation https://wiki.postgresql.org/images/7/77/Psycopg-2010-stuttgart.pdf
Documentação oficial psycopg2 http://initd.org/psycopg/docs/advanced.html
Exemplo de Listen/Notify no Python com psycopg2 https://gist.github.com/dtheodor/126fc329960a714f1945
Exemplo de Listen/Notify no Python com psycopg2 https://github.com/nickdmoore/pg_channels/blob/master/pg_channels/__init__.py
Threads em Python
A biblioteca mais moderna para lidar com threads em python é a threading.
O python é bem flexível para criar threads.
Mas no Python temos um detalhe, as threads não são capazes de usar todos os cores do processador. Para processamentos pesados, utilizar o numpy ou o multiprocessing.
Tutorial curto e bom http://alissonmachado.com.br/python-threads/
Tutorial completo https://www.tutorialspoint.com/python/python_multithreading.htm
Tutorial mais longo https://cadernodelaboratorio.com.br/2017/12/18/threads-em-python-3/
Documentação oficial do threading https://docs.python.org/3.4/library/threading.html
Python RESTful Web Server + Flask + Requests
https://www.bogotobogo.com/python/python-REST-API-Http-Requests-for-Humans-with-Flask.php
Colocando o Flask em Produção com Waitress
O Flask vêm com um web server integrado, mas ele não é recomendado para ambientes de produção. Uma das recomendações é usar o waitress.
http://gr33ndata.blogspot.com/2012/01/waitress-flask.html
Algumas opções de outros servidores em python https://quintagroup.com/cms/python/web-server http://flask.pocoo.org/docs/1.0/deploying/
Programação funcional em Python
https://docs.python.org/3/howto/functional.html
Agendador de tarefas avançado no Python
Imagine que de tempos em tempos você queria que seu programa chame uma função.
Se você só precisa a função seja chamada de x em x tempos (tipo 30 em 30 segundos, 1 em 1 hora, 3 em 3 dias...), você pode usar o threading.Timer, biblioteca padrão do Python.
Mas se você quer agendar algo de forma mais avançada? Tipo agendar uma tarefa em determinados dias da semana? Abaixo mostro algumas soluções
Biblioteca APScheduler
É a biblioteca mais avançada, implementa scheduling baseado em date, interval e cron. Confira a documentação oficial.
[code language="python"] from apscheduler.schedulers.background import BackgroundScheduler from apscheduler.triggers.date import DateTrigger from apscheduler.triggers.cron import CronTrigger from apscheduler.triggers.interval import IntervalTrigger
interval_trigger = IntervalTrigger(seconds=5) scheduler.add_job(print, trigger=interval_trigger, args=['Hello, this was printed by an interval based job.'])
date_trigger = DateTrigger(run_date='2018-11-19 21:15:00', timezone='UTC') scheduler.add_job(print, trigger=date_trigger, args=['Hello, this was printed by a date based job.'])
cron_trigger = CronTrigger(year=2018, month=11, second=20, start_date='2018-10-01', end_date='2018-11-19 19:41:00', timezone='America/Sao_Paulo') scheduler.add_job(print, cron_trigger, args=['Hello, this was printed by a cron based job.'])
# But you can also add jobs after the schedule has started.
scheduler.start() [/code]
O APScheduler usa os seguintes conceitos:
- scheduler
- executor
- job store
No código fonte existem as seguintes classes:
base
É a classe abstrata que todas as outras classes de job store implementam
memory
Banco em memória, não implementa persistência
mongodb
Persiste no MongoDB
redis
Persiste no Redis
rethinkdb
Persiste no Redis
sqlalchemy
Persiste em qualquer banco suportado pelo SQLAlchemy
zookeper
Persiste no Zookeper
- trigger
Atenção, se você for rodar muitos schedules, é preciso aumentar o número de ThreadPoolExecutors e ProcessPoolExecutors.
Criando um histórico dos
Banco de dados em memória e persistente no Python com PyDbLite
É um banco de dados bem simples, que utiliza dicionários como base e permite indexação dos campos via hash.