Planeta PythonBrasil

November 19, 2019

Vinta Software

PyGotham 2019: Talking Python in NY!

We are arriving in New York! Part of our team is on their way to PyGotham 2019, the biggest event of the Python community in New York. The experience last year was amazing, so we decided to come back. We are also sponsoring it this year, so if you are going to the event make sure to stop by our booth, we are bringing lots of cool swags and some Br

19 de November de 2019 às 17:00

DjangoCon US 2019: Python & Django in San Diego!

We are back to San Diego!! Our team will be joining DjangoCon US's conference, one of the biggest Django events in the world. For this year, we'll be giving two talks: Pull Requests: Merging good practices into your project and Building effective Django queries with expressions Here is the slide from the talk we gave during the conference: Pull Re

19 de November de 2019 às 17:00

November 11, 2019

Thiago Avelino

Diferença entre amadores e profissionais

Porque algumas pessoas parecem ser extremamente bem sucedidas e fazer muito, enquanto a grande maioria de nós luta para pisar na água? A resposta é complicada e provavelmente composta por diversas respostas. O aspecto principal é a forma de pensar e planejamento. Mas qual é a diferença? Na verdade, há diversas diferenças: Amadores param quando chega a seu objetivo, profissionais entendem que a realização inicial é apenas o começo; Amadores têm um objetivo, profissionais têm um processo; Amadores pensam que são bons em tudo, profissionais entendem seus círculos de competência; Amadores ver feedback e concelho como criticas, profissionais sabem que têm pontos fracos e procuram críticas construtivas; Amadores valorizam o desempenho isolado, pense sobre o receptor que pega a bola uma vez em um lance difícil.

11 de November de 2019 às 16:00

November 08, 2019

Thiago Avelino

Chegar ao estado de Flow, para alcançar metas

Compreendendo a Psicologia do Flow Você já se sentiu completamente imerso em uma atividade? Se sim, você pode ter experimentado um estado mental que os psicólogos chama de flow, mas o que é isso? Vamos fazer uma analogia para tentar explicar: imagine que você está fazendo uma corrida Sua atenção está focada nos movimentos do seu corpo, na força dos seus músculos, sua respiração e sensação da rua aos seus pés.

08 de November de 2019 às 21:00

October 01, 2019

PythonClub

Criando dicts a partir de outros dicts

Neste tutorial, será abordado o processo de criação de um dict ou dicionário, a partir de um ou mais dicts em Python.

Como já é de costume da linguagem, isso pode ser feito de várias maneiras diferentes.

Abordagem inicial

Pra começar, vamos supor que temos os seguintes dicionários:

dict_1 = {
    'a': 1,
    'b': 2,
}

dict_2 = {
    'b': 3,
    'c': 4,
}

Como exemplo, vamos criar um novo dicionário chamado new_dict com os valores de dict_1 e dict_2 logo acima. Uma abordagem bem conhecida é utilizar o método update.

new_dict = {}

new_dcit.update(dict_1)
new_dcit.update(dict_2)

Assim, temos que new_dict será:

>> print(new_dict)
{
    'a': 1,
    'b': 3,
    'c': 4,
}

Este método funciona bem, porém temos de chamar o método update para cada dict que desejamos mesclar em new_dict. Não seria interessante se fosse possível passar todos os dicts necessários já na inicialização de new_dict?

Novidades do Python 3

O Python 3 introduziu uma maneira bem interessante de se fazer isso, utilizando os operadores **.

new_dict = {
    **dict_1,
    **dict_2,
}

Assim, de maneira semelhante ao exemplo anterior, temos que new_dict será :

>> print(new_dict['a'])
1
>> print(new_dict['b'])
3
>> print(new_dict['c'])
4

Cópia real de dicts

Ao utilizamos o procedimento de inicialização acima, devemos tomar conseiderar alguns fatores. Apenas os valores do primeiro nível serão realmente duplicados no novo dicionário. Como exemplo, vamos alterar uma chave presente em ambos os dicts e verificar se as mesmas possuem o mesmo valor:

>> dict_1['a'] = 10
>> new_dict['a'] = 11
>> print(dict_1['a'])
10
>> print(new_dict['a'])
11

Porém isso muda quando um dos valores de dict_1 for uma list, outro dict ou algum objeto complexo. Por exemplo:

dict_3 = {
    'a': 1,
    'b': 2,
    'c': {
        'd': 5,
    }
}

e agora, vamos criar um novo dict a partir desse:

new_dict = {
    **dict_3,
}

Como no exemplo anterior, podemos imaginar que foi realizado uma cópia de todos os elementos de dict_3, porém isso não é totalmente verdade. O que realmente aconteceu é que foi feita uma cópia superficial dos valores de dict_3, ou seja, apenas os valores de primeiro nível foram duplicados. Observe o que acontece quando alteramos o valor do dict presente na chave c.

>> new_dict['c']['d'] = 11
>> print(new_dict['c']['d'])
11
>> print(dict_3['c']['d'])
11 
# valor anterior era 5

No caso da chave c, ela contem uma referência para outra estrutura de dados (um dict, no caso). Quando alteramos algum valor de dict_3['c'], isso reflete em todos os dict que foram inicializados com dict_3. Em outras palavras, deve-se ter cuidado ao inicializar um dict a partir de outros dicts quando os mesmos possuírem valores complexos, como list, dict ou outros objetos (os atributos deste objeto não serão duplicados).

De modo a contornar este inconveniente, podemos utilizar o método deepcopy da lib nativa copy. Agora, ao inicializarmos new_dict:

import copy

dict_3 = {
    'a': 1,
    'b': 2,
    'c': {
        'd': 5,
    }
}

new_dict = copy.deepcopy(dict_3)

O método deepcopy realiza uma cópia recursiva de cada elemento de dict_3, resolvendo nosso problema. Veja mais um exemplo:

>> new_dict['c']['d'] = 11
>> print(new_dict['c']['d'])
11
>> print(dict_3['c']['d'])
5 
# valor não foi alterado

Conclusão

Este artigo tenta demonstrar de maneira simples a criação de dicts, utilizando os diversos recursos que a linguagem oferece bem como os prós e contras de cada abordagem.

Referências

Para mais detalhes e outros exemplos, deem uma olhada neste post do forum da Python Brasil aqui.

É isso pessoal. Obrigado por ler!

por Michell Stuttgart em 01 de October de 2019 às 16:00

September 23, 2019

Vinta Software

DjangoCon US 2019: Python & Django in San Diego!

We are back to San Diego!! Our team will be joining DjangoCon US's conference, one of the biggest Django events in the world. For this year, we'll be giving two talks: Pull Requests: Merging good practices into your project and Building effective Django queries with expressions. Here are the slides from the talks we gave during the conference: Pu

23 de September de 2019 às 20:00

September 16, 2019

Filipe Saraiva

Grupo de Estudos do Laboratório Amazônico de Estudos Sociotécnicos – UFPA

Eu e o prof. Leonardo Cruz da Faculdade de Ciências Sociais estamos juntos trabalhando no desenvolvimento do Laboratório Amazônico de Estudos Sociotécnicos da UFPA.

Nossa proposta é realizar leituras e debates críticos sobre o tema da sociologia da tecnologia, produzir pesquisas teóricas e empíricas na região amazônica sobre as relações entre tecnologia e sociedade, e trabalhar com tecnologias livres em comunidades próximas a Belém.

No momento estamos com um grupo de estudos montado com cronograma de textos e filmes para trabalharmos e debatermos criticamente. Esse grupo será o embrião para a orientação de alunos de graduação e pós em temas como impacto da inteligência artificial, computação e guerra, cibernética, vigilantismo, capitalismo de plataforma, fake news, pirataria, software livre, e outros.

Aos interessados, nosso cronograma de estudos está disponível nesse link.

E para quem usa Telegram, pode acessar o grupo de discussão aqui.

Quaisquer dúvidas, só entrar em contato!

por Filipe Saraiva em 16 de September de 2019 às 13:24

September 10, 2019

Humberto Rocha

Desbravando o pygame 5 - Movimento e Colisão

O movimento é uma característica que está presente na maioria dos jogos. Ao saltar entre plataformas, atirar contra a horda de inimigos, pilotar uma nave espacial e correr pelas estradas estamos exercendo movimento, interagindo com o ambiente do jogo, aplicando ações e causando reações. Neste capítulo iremos conhecer os conceitos básicos de movimentação de objetos na tela e sua interação com outros elementos através da detecção de colisão. Movimento Se você vem acompanhando esta série de postagens, teve um breve exemplo de movimentação na postagem sobre game loop, onde uma bola que se movimentava quicando pela tela foi implementada.

10 de September de 2019 às 03:00

August 28, 2019

Humberto Rocha

Publicando meu primeiro Jogo

Jogos sempre me conectam com tecnologia desde o início. Eu e meu pai montamos nosso primeiro computador (um Pentium 286) e a primeira coisa que eu me lembro de fazer, foi jogar os jogos de DOS como Prince of Persia e Lunar Lander. Eu aprendi vários comandos de CLI só para poder jogar os meus jogos favoritos. A paixão por jogar e fazer jogos sempre me acompanhou como um hobby.

28 de August de 2019 às 03:00

August 19, 2019

Vinta Software

PyBay 2019: Talking about Python in SF

We are back to San Francisco! Our team will be joining PyBay's conference, one of the biggest Python events in the Bay Area. For this year, we'll be giving the talk: Building effective Django queries with expressions. PyBay has been a fantastic place to meet new people, connect with new ideas, and integrate this thriving community. Here is the sl

19 de August de 2019 às 21:59

[pt-BR] PythonBrasil[14] talks

Slides from talks given during the PythonBrasil[14] event will be posted here. This post and the slides are written in Brazilian Portuguese. Como Programar seu Processo de Software Palestrante: Robertson Novelino Link dos Slides: Como Programar seu Processo de Software Todos usamos um método para programar, uma forma que nós gostamos de fazer as

19 de August de 2019 às 21:59

Understanding Time Series Forecasting with Python

Vinta is a software studio whose focus is to produce high quality software and give clients great consulting advices to make their businesses grow. However, even though our main focus is web development, we also do our share of machine learning over here. This article is the first of a few designed to show everything (or almost everything) you need

19 de August de 2019 às 21:59

Dealing with resource-consuming tasks on Celery

In this post, we will talk about how you can optimize your Celery tasks and avoid certain kind of problems related to resource-consuming tasks. If you are new to Celery or want to know more about it before reading this, you might wanna check first this post with an overview about Celery and this one with some more advanced tips and tricks. When w

19 de August de 2019 às 21:59

Celery in the wild: tips and tricks to run async tasks in the real world

This post is aimed at people with some experience writing async taks, if you are starting on Celery you might want to read this other post I wrote before starting on this one. The thing about async tasks is that the hard part is not how to run them [although it can be fairly complicated to understand the architecture and set up things when you

19 de August de 2019 às 21:59

[pt-BR] PythonBrasil[13] Talks

Vinhemos para a Python Brasil novamente. Dessa vez aprovamos 6 palestras. Indo desde Python para uso científico até técnicas para salvar grandes projetos.

19 de August de 2019 às 21:59

Vinta's Talks Around the Globe: DjangoConUS, PyBay2017 and DjangoConAU

Slides from talks given during the DjangoConUS, PyBay2017 and DjangoConAU events will be posted here

19 de August de 2019 às 21:59

Advanced Django querying: sorting events by date

Imagine the situation where our application has events (scheduled tasks, appointments, python conferences across the world) happening in different moments of time. Almost anything with a date attached to it. We want to display them in a simple list to the user. Given we are in February 2017 (the date this post was written), what would be the best w

19 de August de 2019 às 21:59

Contributing to Django Framework is easier than you think

For those who are starting to code and wish to make open source, sometimes it is hard to start. The idea of contributing with that fancy and wonderful lib that you love can sound a little bit scary. Lucky for us many of those libs have room for whoever is willing to start. They also give us the support that we need. Pretty sweet, right? Do you know

19 de August de 2019 às 21:59

Don't forget the stamps: testing email content in Django

When developing a web app how often do you check the emails you send are all working properly? Not as often as your web pages, right? That's ok, don't feel guilty, emails are hard to test and they are often someone's else responsibility to write and take care. This doesn't mean we should give up on them. There are some things we can do to prevent e

19 de August de 2019 às 21:59

How I test my DRF serializers

In this blog post, I will show the whats and whys on testing Django REST Framework serializers. First, some context. Here is the model setup we are going to use for this example: from django.db import models class Bike(models.Model): COLOR_OPTIONS = (('yellow', 'Yellow'), ('red', 'Red'), ('black', 'B

19 de August de 2019 às 21:59

Python API clients with Tapioca

In this post I'll present to you Tapioca, a Python library to create powerful API clients with very few lines of code. If you don't want to read through the reasons why I've built it, you may just jump straight to the Tapioca Wrapper section. Why do we need a better way to build API clients Integrating with external services is painful. Here at Vin

19 de August de 2019 às 21:59

Happython 2019!

Happy PyHolidays and Happy New Year! We are approaching the end of the year 2018! And as it turns out this was an incredible year for Python! Even though Guido stepped out of his role as BDFL (this alone is worth a couple of blogposts so this one will not extend the discussion), there are a lot of happy recollections from this year. In 2017 StackO

19 de August de 2019 às 21:59

PyGotham 2018 Talks

Critical Incidents: a guide for developers Presenter: Lais Varejão Slides: http://bit.ly/critical-incidents-guide Pluggable Libs Through Design Patterns Presenter: Filipe Ximenes Video: https://www.youtube.com/watch?v=PfgEU3W0kyU Slides: http://bit.ly/pluggable-libs Examples: https://github.com/filipeximenes/talk-design-patterns 1 + 1 = 1 or Re

19 de August de 2019 às 21:59

Taming Irreversibility with Feature Flags (in Python)

Feature Flags are a very simple technique to make features of your application quickly toggleable. The way it works is, everytime we change some behavior in our software, a logical branch is created and this new behavior is only accessible if some specific configuration variable is set or, in certain cases, if the application context respects some

19 de August de 2019 às 21:59

Django REST Framework Read & Write Serializers

Django REST Framework (DRF) is a terrific tool for creating very flexible REST APIs. It has a lot of built-in features like pagination, search, filters, throttling, and many other things developers usually don't like to worry about. And it also lets you easily customize everything so you can make your API work the way you want. There are many gen

19 de August de 2019 às 21:59

Celery: an overview of the architecture and how it works

Asynchronous task queues are tools to allow pieces of a software program to run in a separate machine/process. It is often used in web architectures as way to delegate long lasting tasks while quickly answering requests. The delegated task can trigger an action such as sending an email to the user or simply update data internally in the system whe

19 de August de 2019 às 21:59

Multitenancy: juggling customer data in Django

Suppose you want to build a new SaaS (Software as a Service) application. Suppose your application will store sensitive data from your customers. What is the best way to guarantee the isolation of the data and make sure information from one client does not leak to the other? The answer to that is: it depends. It depends on the number of customers y

19 de August de 2019 às 21:59

PyCon US 2017: the biggest Python Event in the World

Pycon 2017 happened in Oregon, Portland! If you wanted to discuss anything about Python, that was the place to be. It was the biggest Python event of the world, it lasted from May 17th to May 25th. I got to see talks from some important names on it, like Lisa Guo and Katy Huff, both of them are using Python to make great things! Lisa is using on In

19 de August de 2019 às 21:59

[pt-BR] Python Nordeste 2017 Talks

Slides from talks given during the Python Nordeste 2017 event will be posted here. This post and the slides are written in Brazilian Portuguese. 5 meses de Python: o que aprendi Palestrante: @rsarai Link dos slides: 5 meses de Python: o que aprendi Trabalhar como desenvolvedor de software pode ser um pouco frustrante, as vezes por estar preso a

19 de August de 2019 às 21:59

[Talk] All Things Python meetup in Sunnyvale

I'll be talking at the All Things Python meetup! It will happen on June 6 in Sunnyvale, California. I'll be talking about good practices designing async tasks and some advanced Celery features.This will be a first version of the talk I'm preparing for DjangoCon US in August. For signing up or more information, this is the link to the event. Looki

19 de August de 2019 às 21:59

Metaprogramming and Django - Using Decorators

While programming is about, in some way, doing code to transform data, metaprogramming can be seen as the task of doing code to change code. This category is often used to help programmers to enhance the readability and maintainability of the code, help with separation of concerns and respect one of the most important principles of software develop

19 de August de 2019 às 21:59

Vinta's Review of PythonBrasil[12]

PythonBrasil[12] happened in Florianópolis - SC and lasted for 6 days. We saw some amazing Keynotes from some awesome speakers, such as @SagnewShreds, @hannelita, @NaomiCeder, @freakboy3742, @seocam we got to have a lot of community time getting to know new people from all around Brazil and still got to present 4 talks(Hooray!!). On the following

19 de August de 2019 às 21:59

[pt-BR] PythonBrasil[12] Talks

Slides from talks given during the PythonBrasil[12] event will be posted here. This post and the slides are in written in Brazilian Portuguese. O que é esse tal de REST? Palestrante: @xima Link dos slides: O que é esse tal de REST? REST é a bola vez quando falamos sobre API. As maioria dos serviços que encontramos na web fornece interfaces dest

19 de August de 2019 às 21:59

Database concurrency in Django the right way

When developing applications which have real-time requirements or other specific needs for running asynchronous tasks outside the web application, it is common to adopt a task queue such as Celery. This allows, for example, for the server to handle a request, start an asynchronous task responsible of doing some heavyweight processing, and return an answer while the task is still running. Here, we are considering a similar scenario: a request is made, and the server has to do some processing on the request. Ideally, we want to separate the high time-demanding parts from the view processing flow, so we run those parts in a separate task. Now, let's suppose we have to do some database operations both in the view and the task when the request happens. If not done carefully, those operations can be a source for issues that can be hard to track.

19 de August de 2019 às 21:59

August 08, 2019

Humberto Rocha

Libs Fantásticas: pipx

Estou começando esta série para dar dicas sobre bibliotecas que podem ser muito úteis no seu dia a dia, e também para apresentar bibliotecas interessantes nas quais que você deveria ficar de olho. Uma das habilidades de um bom Programador é ter a ferramenta certa para realizar seu trabalho, e nada mais apropriado que começar esta série com uma ferramenta que instala outras ferramentas! Quantas vezes você já teve que instalar algum programa Python em uma virtualenv que você acabou de criar?

08 de August de 2019 às 03:00

July 12, 2019

Humberto Rocha

TLDR: Gerando Secret Key para o Django

Levante a mão quem nunca versionou a SECRET_KEY do Django no início de um projeto e precisou gerar uma nova na hora de subir pra produção. Este TLDR é um lembrete rápido de como você pode regerar uma secret key localmente, sem recorrer a sites na internet para gera-la para você. Como o Django gera a secret key no início de um projeto, já existe esta função implementada em seu código e você pode acessá-la desta forma:

12 de July de 2019 às 00:00

July 07, 2019

Thiago Avelino

Trocando forma de pensar (mudando mindset) de empresário para 'empregado'

Se ainda não me conhece empreendi desde 2011 até junho/2019 (durante esse tempo comentei algumas vezes que nunca mais iria empreender) e resolvi voltar para o mercado de trabalho e não é por motivos que quebrei financeiramente, indo na contramão do hype de startups. Acredito que surgiu diversas perguntas em sua cabeça ao ler o texto acima, acredite que na minha cabeça foram longos meses (quase 1 ano) refletindo sobre o assunto, colocando no papel os prós e contras, imaginando como seria, como me portaria em algumas situações até que por fim resolvi experimentar um ambiente novo, “desconhecido” e acredito que seja desafiador (pelo menos para mim).

07 de July de 2019 às 00:00

June 25, 2019

PythonClub

Tutorial Django 2.2

Este tutorial é baseado no Intro to Django que fica na parte de baixo da página start do Django project.

Até a data deste post o Django está na versão 2.2.2, e requer Python 3.

O que você precisa?

Python 3.6 ou superior, pip e virtualenv.

Considere que você tenha instalado Python 3.6 ou superior, pip e virtualenv.

Criando o ambiente

Crie uma pasta com o nome django2-pythonclub

$ mkdir django2-pythonclub
$ cd django2-pythonclub

A partir de agora vamos considerar esta como a nossa pasta principal.

Considerando que você está usando Python 3, digite

python3 -m venv .venv

Lembre-se de colocar esta pasta no seu .gitignore, caso esteja usando.

echo .venv >> .gitignore

Depois ative o ambiente digitando

source .venv/bin/activate

Lembre-se, sempre quando você for mexer no projeto, tenha certeza de ter ativado o virtualenv, executando o comando source .venv/bin/activate. Você deve repetir esse comando toda a vez que você abrir um novo terminal.

Instalando Django 2.2.2

Basta digitar

pip install django==2.2.2

Dica: se você digitar pip freeze você verá a versão dos programas instalados.

É recomendável que você atualize a versão do pip

pip install -U pip

Se der erro então faça:

python -m pip install --upgrade pip

Instalando mais dependências

Eu gosto de usar o django-extensions e o django-widget-tweaks, então digite

pip install django-extensions django-widget-tweaks python-decouple

Importante: você precisa criar um arquivo requirements.txt para instalações futuras do projeto em outro lugar.

pip freeze > requirements.txt

Este é o resultado do meu até o dia deste post:

(.venv):$ cat requirements.txt 

django-extensions==2.1.6
django-widget-tweaks==1.4.3
python-decouple==3.1
pytz==2018.9
six==1.12.0

Escondendo a SECRET_KEY e trabalhando com variáveis de ambiente

É muito importante que você não deixe sua SECRET_KEY exposta. Então remova-o imediatamente do seu settings.py ANTES mesmo do primeiro commit. Espero que você esteja usando Git.

Vamos usar o python-decouple escrito por Henrique Bastos para gerenciar nossas variáveis de ambiente. Repare que já instalamos ele logo acima.

Em seguida você vai precisar criar um arquivo .env, para isso rode o comando a seguir, ele vai criar uma pasta contrib e dentro dele colocar um arquivo env_gen.py

if [ ! -d contrib ]; then mkdir contrib; fi; git clone https://gist.github.com/22626de522f5c045bc63acdb8fe67b24.git contrib/
rm -rf contrib/.git/  # remova a pasta .git que está dentro de contrib.

Em seguida rode

python contrib/env_gen.py

que ele vai criar o arquivo .env.

Supondo que você está versionando seu código com Git, é importante que você escreva isso dentro do seu arquivo .gitignore, faça direto pelo terminal

echo .env >> .gitignore
echo .venv >> .gitignore
echo '*.sqlite3' >> .gitignore

Pronto, agora você pode dar o primeiro commit.

Criando o projeto e a App

Para criar o projeto digite

$ django-admin startproject myproject .

repare no ponto no final do comando, isto permite que o arquivo manage.py fique nesta mesma pasta django2-pythonclub .

Agora vamos criar a app bands, mas vamos deixar esta app dentro da pasta myproject. Então entre na pasta

$ cd myproject

e digite

$ python ../manage.py startapp bands

A intenção é que os arquivos tenham a seguinte hierarquia nas pastas:

.
├── manage.py
├── myproject
│   ├── bands
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── models.py
│   │   ├── tests.py
│   │   └── views.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── requirements.txt

Agora permaneça sempre na pasta django2-pythonclub

cd ..

e digite

$ python manage.py migrate

para criar a primeira migração (isto cria o banco de dados SQLite), e depois rode a aplicação com

$ python manage.py runserver

e veja que a aplicação já está funcionando. Veja o endereço da url aqui

Django version 2.2.2, using settings 'myproject.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Editando settings.py

Em INSTALLED_APPS acrescente as linhas abaixo.

INSTALLED_APPS = (
    ...
    'widget_tweaks',
    'django_extensions',
    'myproject.bands',
)

E mude também o idioma.

LANGUAGE_CODE = 'pt-br'

E caso você queira o mesmo horário de Brasília-BR

TIME_ZONE = 'America/Sao_Paulo'

Já que falamos do python-decouple, precisamos de mais alguns ajustes

from decouple import config, Csv

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = config('SECRET_KEY')

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = config('DEBUG', default=False, cast=bool)

ALLOWED_HOSTS = config('ALLOWED_HOSTS', default=[], cast=Csv())

Veja que é importante manter sua SECRET_KEY bem guardada (em outro lugar).

Então crie um arquivo .env e guarde sua SECRET_KEY dentro dele, exemplo:

SECRET_KEY=your_secret_key
DEBUG=True
ALLOWED_HOSTS=127.0.0.1,.localhost

Editando models.py

from django.db import models
from django.urls import reverse_lazy


class Band(models.Model):

    """A model of a rock band."""
    name = models.CharField(max_length=200)
    can_rock = models.BooleanField(default=True)

    class Meta:
        ordering = ('name',)
        verbose_name = 'band'
        verbose_name_plural = 'bands'

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        # retorna a url no formato /bands/1/
        return reverse_lazy('band_detail', kwargs={'pk': self.pk})

    def get_members_count(self):
        # count members by band
        # conta os membros por banda
        return self.band.count()


class Member(models.Model):

    """A model of a rock band member."""
    name = models.CharField("Member's name", max_length=200)
    instrument = models.CharField(choices=(
        ('g', "Guitar"),
        ('b', "Bass"),
        ('d', "Drums"),
        ('v', "Vocal"),
        ('p', "Piano"),
    ),
        max_length=1
    )

    band = models.ForeignKey("Band", related_name='band', on_delete=models.CASCADE)

    class Meta:
        ordering = ('name',)
        verbose_name = 'member'
        verbose_name_plural = 'members'

    def __str__(self):
        return self.name

Tem algumas coisas que eu não estou explicando aqui para o tutorial ficar curto, mas uma coisa importante é que, como nós editamos o models.py vamos precisar criar um arquivo de migração do novo modelo. Para isso digite

python manage.py makemigrations
python manage.py migrate

O primeiro comando cria o arquivo de migração e o segundo o executa, criando as tabelas no banco de dados.

Editando urls.py

from django.urls import include, path
from myproject.bands import views as v
from django.contrib import admin

app_name = 'bands'

urlpatterns = [
    path('', v.home, name='home'),
    # path('bands/', v.band_list, name='bands'),
    # path('bands/<int:pk>/', v.band_detail, name='band_detail'),
    # path('bandform/', v.BandCreate.as_view(), name='band_form'),
    # path('memberform/', v.MemberCreate.as_view(), name='member_form'),
    # path('contact/', v.band_contact, name='contact'),
    # path('protected/', v.protected_view, name='protected'),
    # path('accounts/login/', v.message),
    path('admin/', admin.site.urls),
]

Obs: deixei as demais urls comentada porque precisa da função em views.py para que cada url funcione. Descomente cada url somente depois que você tiver definido a função em classe em views.py a seguir.

Editando views.py

from django.shortcuts import render
from django.http import HttpResponse
from django.contrib.auth.decorators import login_required
from django.views.generic import CreateView
from django.urls import reverse_lazy
from .models import Band, Member
# from .forms import BandContactForm, BandForm, MemberForm

Obs: Deixei a última linha comentada porque ainda não chegamos em forms.

A função a seguir retorna um HttpResponse, ou seja, uma mensagem simples no navegador.

def home(request):
    return HttpResponse('Welcome to the site!')

A próxima função (use uma ou outra) renderiza um template, uma página html no navegador.

def home(request):
    return render(request, 'home.html')

A função band_list retorna todas as bandas.

Para fazer a busca por nome de banda usamos o comando search = request.GET.get('search_box'), onde search_box é o nome do campo no template band_list.html.

E os nomes são retornados a partir do comando bands = bands.filter(name__icontains=search). Onde icontains procura um texto que contém a palavra, ou seja, você pode digitar o nome incompleto (ignora maiúsculo ou minúsculo).

def band_list(request):
    """ A view of all bands. """
    bands = Band.objects.all()
    search = request.GET.get('search_box')
    if search:
        bands = bands.filter(name__icontains=search)
    return render(request, 'bands/band_list.html', {'bands': bands})

Em urls.py pode descomentar a linha a seguir:

path('bands/', v.band_list, name='bands'),

A função band_contact mostra como tratar um formulário na view. Esta função requer BandContactForm, explicado em forms.py.

def band_contact(request):
    """ A example of form """
    if request.method == 'POST':
        form = BandContactForm(request.POST)
    else:
        form = BandContactForm()
    return render(request, 'bands/band_contact.html', {'form': form})

Em urls.py pode descomentar a linha a seguir:

path('contact/', v.band_contact, name='contact'),

A função band_detail retorna todos os membros de cada banda, usando o pk da banda junto com o comando filter em members.

def band_detail(request, pk):
    """ A view of all members by bands. """
    band = Band.objects.get(pk=pk)
    members = Member.objects.all().filter(band=band)
    context = {'members': members, 'band': band}
    return render(request, 'bands/band_detail.html', context)

Em urls.py pode descomentar a linha a seguir:

path('bands/<int:pk>/', v.band_detail, name='band_detail'),

BandCreate e MemberCreate usam o Class Based View para tratar formulário de uma forma mais simplificada usando a classe CreateView. O reverse_lazy serve para tratar a url de retorno de página.

As classes a seguir requerem BandForm e MemberForm, explicado em forms.py.

class BandCreate(CreateView):
    model = Band
    form_class = BandForm
    template_name = 'bands/band_form.html'
    success_url = reverse_lazy('bands')


class MemberCreate(CreateView):
    model = Member
    form_class = MemberForm
    template_name = 'bands/member_form.html'
    success_url = reverse_lazy('bands')

Em urls.py pode descomentar a linha a seguir:

path('bandform/', v.BandCreate.as_view(), name='band_form'),
path('memberform/', v.MemberCreate.as_view(), name='member_form'),

A próxima função requer que você entre numa página somente quando estiver logado.

[@login_required](https://docs.djangoproject.com/en/2.2/topics/auth/default/#the-login-required-decorator) é um decorator.

login_url='/accounts/login/' é página de erro, ou seja, quando o usuário não conseguiu logar.

E render(request, 'bands/protected.html',... é página de sucesso.

@login_required(login_url='/accounts/login/')
def protected_view(request):
    """ A view that can only be accessed by logged-in users """
    return render(request, 'bands/protected.html', {'current_user': request.user})

HttpResponse retorna uma mensagem simples no navegador sem a necessidade de um template.

def message(request):
    """ Message if is not authenticated. Simple view! """
    return HttpResponse('Access denied!')

Em urls.py pode descomentar a linha a seguir:

path('protected/', v.protected_view, name='protected'),
path('accounts/login/', v.message),

Comandos básicos do manage.py

Para criar novas migrações com base nas alterações feitas nos seus modelos

$ python manage.py makemigrations bands

Obs: talvez dê erro porque está faltando coisas de forms.py, explicado mais abaixo.

Para aplicar as migrações

$ python manage.py migrate

Para criar um usuário e senha para o admin

$ python manage.py createsuperuser

Para rodar a aplicação localmente

$ python manage.py runserver

Após criar um super usuário você pode entrar em localhost:8000/admin

Obs: Se você entrar agora em localhost:8000 vai faltar o template home.html. Explicado mais abaixo.

shell_plus

É o interpretador interativo do python rodando via terminal direto na aplicação do django.

Com o comando a seguir abrimos o shell do Django.

$ python manage.py shell

Mas se você está usando o django-extensions (mostrei como configurá-lo no settings.py), então basta digitar

$ python manage.py shell_plus

Veja a seguir como inserir dados direto pelo shell.

>>> from myproject.bands.models import Band, Member
>>> # Com django-extensions não precisa fazer o import
>>> # criando o objeto e salvando
>>> band = Band.objects.create(name='Metallica')
>>> band.name
>>> band.can_rock
>>> band.id
>>> # criando uma instancia da banda a partir do id
>>> b = Band.objects.get(id=band.id)
>>> # criando uma instancia do Membro e associando o id da banda a ela
>>> m = Member(name='James Hetfield', instrument='b', band=b)
>>> m.name
>>> # retornando o instrumento
>>> m.instrument
>>> m.get_instrument_display()
>>> m.band
>>> # salvando
>>> m.save()
>>> # listando todas as bandas
>>> Band.objects.all()
>>> # listando todos os membros
>>> Member.objects.all()
>>> # criando mais uma banda
>>> band = Band.objects.create(name='The Beatles')
>>> band = Band.objects.get(name='The Beatles')
>>> band.id
>>> b = Band.objects.get(id=band.id)
>>> # criando mais um membro
>>> m = Member(name='John Lennon', instrument='v', band=b)
>>> m.save()
>>> # listando tudo novamente
>>> Band.objects.all()
>>> Member.objects.all()
>>> exit()

Criando os templates

Você pode criar os templates com os comandos a seguir...

$ mkdir -p myproject/bands/templates/bands
$ touch myproject/bands/templates/{menu,base,home}.html
$ touch myproject/bands/templates/bands/{band_list,band_detail,band_form,band_contact,member_form,protected}.html

... ou pegar os templates já prontos direto do Github.

mkdir -p myproject/bands/templates/bands
wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/myproject/bands/templates/base.html -P myproject/bands/templates/
wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/myproject/bands/templates/home.html -P myproject/bands/templates/
wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/myproject/bands/templates/menu.html -P myproject/bands/templates/
wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/myproject/bands/templates/bands/band_contact.html -P myproject/bands/templates/bands/
wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/myproject/bands/templates/bands/band_detail.html -P myproject/bands/templates/bands/
wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/myproject/bands/templates/bands/band_form.html -P myproject/bands/templates/bands/
wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/myproject/bands/templates/bands/band_list.html -P myproject/bands/templates/bands/
wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/myproject/bands/templates/bands/member_form.html -P myproject/bands/templates/bands/
wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/myproject/bands/templates/bands/protected.html -P myproject/bands/templates/bands/

forms.py

$ touch myproject/bands/forms.py

Edite o forms.py.

from django import forms
from .models import Band, Member


class BandContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    message = forms.CharField(widget=forms.Textarea)
    sender = forms.EmailField()
    cc_myself = forms.BooleanField(required=False)


class BandForm(forms.ModelForm):

    class Meta:
        model = Band
        fields = '__all__'


class MemberForm(forms.ModelForm):

    class Meta:
        model = Member
        fields = '__all__'

Lembra que eu deixei o código comentado em views.py?

Descomente ele por favor

from .forms import BandContactForm, BandForm, MemberForm

admin.py

Criamos uma customização para o admin onde em members aparece um filtro por bandas.

from django.contrib import admin
from .models import Band, Member


class MemberAdmin(admin.ModelAdmin):
    """Customize the look of the auto-generated admin for the Member model."""
    list_display = ('name', 'instrument')
    list_filter = ('band',)


admin.site.register(Band)  # Use the default options
admin.site.register(Member, MemberAdmin)  # Use the customized options

Carregando dados de um CSV

Vamos baixar alguns arquivos para criar os dados no banco a partir de um CSV.

wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/create_data.py
mkdir fix
wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/fix/bands.csv -P fix/
wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/fix/members.csv -P fix/

Estando na pasta principal, rode o comando

python create_data.py

que ele vai carregar alguns dados pra você.

Veja o código de create_data.py.

Veja o código completo em https://github.com/rg3915/django2-pythonclub

git clone https://github.com/rg3915/django2-pythonclub.git

por Regis da Silva em 25 de June de 2019 às 01:00

April 15, 2019

Thiago Avelino

Formando desenvolvedores de alta performance

Estou a mais de 1 ano treinando para meu primeiro triathlon (IRONMAN 70.3) e nos últimos 7 meses treinando com time de alta performance que faz triathlon profissionalmente a muitos anos. O ano de 2018 foi um ano de muito aprendizado em uma área que nunca imaginei que entraria, para contextualizar segue o conteúdo abaixo: 1. Pivotei minha carreira profissional para área de #esporte 2. Estou escrevendo o meu primeiro #livro, minha saída de 180kg a treinar para meu primeiro #ironman (#Triathlon)

15 de April de 2019 às 00:00

April 12, 2019

Bruno Cezar Rocha

from dynaconf import settings

Often when starting a new Python project we need to spend some time thinking about how to manage the settings, decide on which module the configuration manager will be written, decide which name to give to this module, create a class or function to store the configuration keys, create the conditions for multiple environments and still need to worry about where these keys will be stored and in which file format?

No more! now you have Dynaconf!

Spend your precious time developing your application, run pip install dynaconf and let Dynaconf take care of your settings.

Quick start.

from dynaconf import settings

And that's it!

That is the only line of code you need, no complicated boilerplate, no hadouken-ifs, no need to maintain config classes.

You must be wondering - "What magic is this? Where does the setting values come from?"

Well, there is no magic, and the values can come from wherever you want, by default and following the recommendations of the 12 factor apps Dynaconf has preference for environment variables.

# optionally you can save it in .env file
export DYNACONF_DEBUG=true
export DYNACONF_NAME=Bruno
# app.py
from dynaconf import settings
if settings.DEBUG is True:
    print(settings.NAME)
$ python3 app.py
Bruno

And the environment variables for Dynaconf are typed using the toml format sotrue has been evaluated to boolean True and this makes it possible to export lists, dictionaries, floats, booleans, and so on.

Read more about envvars

More than environment variables

Well, that's cool, but your project will not have settings coming from just the environment variables, I'm sure you want to have a settings file where you can set default values.

Dynaconf can read multiple file formats, out of the box it supports .py, .toml, .ini and .json. If PyYAML is installed then it will also support .yaml and you don't have to take care of finding and opening the files. The preferred format is .toml because it is currently the best configuration format, widely addopted, and you can use whatever file format you want.

# settings.toml
[default]
name = "Bruno"

[development]
debug = true

[production]
debug = false
# app.py
from dynaconf import settings
if settings.DEBUG is True:
    print(settings.NAME)
$ python3 app.py
Bruno

And as you can see now using settings. file we can have separate [environments] by default dynaconf will always work on [development] which means only [default] and [development] variables will be loaded. At any time you can do export ENV_FOR_DYNACONF=production and then it starts using the values from [production] environment.

If you don't want to have that separation by environment, you can simply put everything under [default] section.

Read more about environments and settings file

Some values are secrets

A good practice is to not store your secrets like passwords and tokens directly on settings files, because you can make a mistake and commit that to a public git repository, so there are some alternatives to store secrets

Environment Variables

Not recommended

There are some people who disagrees and it is really a point of security failure. However, if you are sure that your machine is protected, you can leave the secrets in the variables, at your own risk, Dynaconf can read it normally.

Secret files

This is a simple level of security for keeping secrets, and it is specially useful to keep development secrets. That token you use to access the development API etc.

It is very simple, together with your normal settings.toml you put a new file called .secrets.toml and store your sensitive data there. Dynaconf will read it after the read of the settings.toml

Wait.. how does it solve my security problem?

Well it does not (yet) but it make your life easier in 2 ways.

  1. Put .secrets.* in your ~/.gitignore so you will never commit the mistake of sending that data to a public git repository.
  2. Dynaconf can output debug information when DEBUG_LEVEL_FOR_DYNACON=DEBUG is exported, all loaded values are printed but if the values comes from a .secrets.* file, then only the key is printed and the value is masked. It is useful to use on public CI.
  3. You can setup a step on your Ansible deployment playbook that will safely copy or generate the secrets file to store there on your production environment.

You can also tell Dynaconf to load that file from somewhere else export SECRETS_FOR_DYNACONF=/path/to/secrets/location/.secrets.yaml (very useful for CI like Jenkins)

Vault Project from Hashicorp

Recommended!

Now we are really talking about true security

Using Vault is the better way to protect your secrets dynaconf has built-in support:

export VAULT_ENABLED_FOR_DYNACONF=true
export VAULT_URL_FOR_DYNACONF=https://..../
export OTHER_VAULT_CONFIGS

And then if have for example the TOKEN stores on your vault server you can simply do:

from dynaconf import settings
perform_your_authentication(settings.TOKEN)

Vault has lots of features like leases and sealed vaults.

Read More

Are you using Django or Flask?

Dynaconf provides extensions for those 2 frameworks, with 2 lines of code you enable it and then your framework will start reading settings from Dynaconf.

Django

# settings.py
import dynaconf  # noqa
settings = dynaconf.DjangoDynaconf(__name__, **options)

Now you if you do export DJANGO_FOO=BAR you can access inside your app via django.conf.settings.FOO

read more

Flask

# app.py
from dynaconf import FlaskDynaconf
FlaskDynaconf(app, **options)

Now you if you do export FLASK_FOO=BAR you can access inside your app via app.config['FOO']

read more

What if you are using a different settings file format? a different framework and a different external storage?

You can extend Dynaconf adding new loaders!

Dynaconf already provides loaders for:

  • .py
  • .json
  • .yaml
  • .toml
  • .ini
  • Redis Server
  • Vault Server
  • .env files
  • Environment variables

But if this is not a fit for your project you can still create your own loader

Conclusion

Dynaconf is the only thing you need to manage your settings!

  • Well tested
  • Trusted by companies like Red Hat, Seek, Catho and others
  • Well tested both on Linux and Windows environment
  • Strict separation of settings from code (following 12-factor applications Guide).
  • Define comprehensive default values.
  • Store parameters in multiple file formats (.toml, .json, .yaml, .ini and .py).
  • Sensitive secrets like tokens and passwords can be stored in safe places like .secrets file or vault server.
  • Parameters can optionally be stored in external services like Redis server.
  • Simple feature flag system.
  • Layered [environment] system.
  • Environment variables can be used to override parameters.
  • Support for .env files to automate the export of environment variables.
  • Correct data types (even for environment variables).
  • Have only one canonical settings module to rule all your instances.
  • Drop in extension for Flask app.config object.
  • Drop in extension for Django conf.settings object.
  • Powerful $ dynaconf CLI to help you manage your settings via console.
  • Customizable Validation System to ensure correct config parameters.
  • Allow the change of dynamic parameters on the fly without the need to redeploy your application.

Read the docs

Settings are simple but Dynaconf provides even more features like Feature Flags, Settings Context Managers, Plugin Settings etc..

Documentation: http://dynaconf.readthedocs.io/

Dynaconf is waiting for your feedback and Contribution

:)

from dynaconf import settings
settings.THANKS_FOR_READING

por Bruno Rocha em 12 de April de 2019 às 14:38

March 20, 2019

Osvaldo Santana Neto

How to create a variable in Python

Hello there, in this post we are going to learning about creating a variable in Python. The process is very simple like creating a variable in other languages but if you are new to programming don’t worry I’ll explain each step in details. What is Python variable: A Python variable is used to store some information/value that we can use in our program. It can be anything; a number, string, function, or a variable itself. Well, this is how a Python variable look like: website = "Pythonologia" Let me explain... Read More

por Deepak Jangra em 20 de March de 2019 às 03:14

March 10, 2019

Osvaldo Santana Neto

How to install LEMP stack on Digital Ocean

Hello and welcome everybody. I’m Deepak and today we are going to looking at How to install LEMP stack on Digital Ocean. Before installing LEMP stack on Digital Ocean you must have an Digital Ocean account. For creating the Digital Ocean account. Visit this link and sign up there by using this link you will get $100 free credit for 2 months that means you can use a live hosting for free for 2 months. Disclaimer: The link mentioned above is an affiliate link. It will help Pythonologia to continue... Read More

por Deepak Jangra em 10 de March de 2019 às 22:59

January 10, 2019

Rodrigo Delduca

Empreendendo sem dinheiro

Criei uma espécie de desafio mental, esse desafio consiste em resolver problemas já enfrentados ou de outras origens de forma criativa, em pouco tempo e se possível evolvendo pouco ou nenhum custo!

E o desafio da semana foi criar um daqueles projetos de “media indoor”.

Então pensei: “já sei vou usar grpc, s3 rsync, elastic transcoder, fastly, frontend do admin em react e é claro kubernetes!”

Já no cliente, que é responsável por tocar os vídeos…: “vou escrever em Qt, criar a interface em QML, usar boost.asio para o meu downloader e criar uma distribuição de Linux embarcado usando o yocto !“.

“The best code is no code at all.”

Painel administrativo

As pessoas, e desse ramo principalmente, estão acostumadas a usar planilhas para as mais variadas tarefas, então por que não usar uma planilha como “admin”?

Google Sheets

Envio, armazenamento, transcodificação e distribuição de vídeos

Ao invés de desenvolver um complexo sistema de gerenciamento de arquivos de vídeo, com transcodificação usando as ferramentas que citei acima, usando lambda e outras coisas, vamos usar o YouTube.

Quê?

É isso mesmo, no nosso protótipo vamos usar o YouTube, pois não tem nenhum custo e já faz a conversão e distribuição do vídeo nos mais variados formatos e tamanhos.

Atenção: De acordo com os termos de uso do YouTube não é permitido reproduzir o conteúdo da plataforma fora do player do youtube, o que estou demonstrando é apenas para fins educacionais.

O nosso work é playá

Nada mais do que um pequeno script em bash será necessário para executar as tarefas de baixar a playlist, os vídeos, a remoção de vídeos não mais usados entre outras coisas.

Já o player propriamente dito é o omxplayer, que é capaz de decodificar vídeos usando aceleração por hardware; omxplayer foi escrito especialmente para a GPU do Raspberry Pi e faz uso da API OpenMAX, é extremamente eficiente.

O trecho abaixo é de um apps script que transforma a primeira coluna da planilha num array de objetos e serializa a reposta num JSON.

function doGet(request) {
  var app = SpreadsheetApp;
  var worksheet = app.getActiveSpreadsheet();
  var sheet = worksheet.getSheetByName(request.parameters.sheet);
  if (sheet) {
    var range = sheet.getDataRange();
    var values = range.getValues();
    var headers = values.shift();
    var playlist = values.map(function (el) { return { url: el[0] }; });
    return ContentService.createTextOutput(JSON.stringify({ playlist: playlist }))
      .setMimeType(ContentService.MimeType.JSON);
  }
}

É possível publicar o script acima num endereço público e de acesso anônimo, de modo que seja possível baixar o JSON até mesmo pelo cURL, e é com essa reposta que iremos usar para saber quais arquivos baixar e gerar a playlist:

$ curl -sL "https://script.google.com/macros/s/${...}/exec?sheet=Sheet1" | jq
{
  "result": [
    {
      "url": "https://www.youtube.com/watch?v=..."
    },
    ...
  ]
}

Com uma simples entrada no cron é possível criar um agendamento para baixar a playlist de tempos em tempos:

*/30 * * * * user curl -sL "https://script.google.com/macros/s/${...}/exec?sheet=Sheet1" > playlists/1.json

A função download usa a ferramenta jq para gerar uma lista de urls a serem baixadas pelo youtube-dl que por sua vez executa um pequeno script (--exec) para adicionar o arquivo recém baixado para a playlist, tomando cuidado para não duplicar:

download() {
  cat playlists/*.json | jq '.[].url' \
    | xargs youtube-dl --exec "grep -sqxF '{}' $playlist || echo '{}' >> $playlist"
}

Alguns parâmetros do youtube-dl foram omitidos pois foram movidos para o arquivo de configuração global.

Com o entr é possível monitorar se algum arquivo foi modificado ou mesmo adicionado novos arquivos no diretório; se isso acontecer, a função download será chamada:

watch() {
  while :; do
    ls -d playlists/*.json | entr -d "$0" download
  done
}

De tempos em tempos é necessário remover os arquivos antigos e downloads incompletos; a função recycle remove todos os arquivos do tipo vídeo modificados pela última vez há mais de 7 dias e que não estão sendo usados:

A razão de ser alguns dias depois e não imediatamente é de ser maleável caso tenha sido algum equívoco.

recycle() {
  declare -a args=(
    -mtime +7
    -type f
  )

  while read -r uri; do
    args+=(-not -name "$uri")
  done <<< "$(cat $playlist)"

  find "$PWD" "${args[@]}" -exec bash -c "file -b --mime-type {} | grep -q ^video/" \; -delete
}

Todas essas funções podem ser chamadas inúmeras vezes sem efeitos indesejados.

Tocar a playlist é a parte mais fácil:

play() {
  setterm -cursor off

  export DISPLAY=":0.0"

  while :; do
    while read -r uri; do
      omxplayer --refresh --no-osd --no-keys "$uri"
      xrefresh -display :0
    done <<< "$(cat $playlist)"
  done
}

Graças ao omxplayer o consumo de CPU fica bem baixo, mesmo em 1080@60fps, algo em torno de ~0.5% num Raspberry 3.

O próximo passo é contabilizar algumas estatísticas, como o número de vezes que um vídeo foi tocado, se teve alguma interrupção por falta de energia ou por problemas técnicos, etc.

Para isso uma boa pedida é o papertrail, com essa ferramenta é possível centralizar todos os logs da máquina, exportar para o BigQuery e executar as consultas na mesma planilha que ficam os vídeos.

Ops… Acho que minha febre por cloud computing voltou :-)

Criei uma espécie de desafio mental, esse desafio consiste em resolver problemas já enfrentados ou de outras origens de forma criativa, em pouco tempo e se possível evolvendo pouco ou nenhum custo!

por Rodrigo Delduca (rodrigodelduca@gmail.com) em 10 de January de 2019 às 00:00

January 05, 2019

Gabbleblotchits

Scientific Rust #rust2019

The Rust community requested feedback last year for where the language should go in 2018, and now they are running it again for 2019. Last year I was too new in Rust to organize a blog post, but after an year using it I feel more comfortable writing this!

(Check my previous post about replacing the C++ core in sourmash with Rust for more details on how I spend my year in Rust).

What counts as "scientific Rust"?

Anything that involves doing science using computers counts as scientific programming. It includes from embedded software running on satellites to climate models running in supercomputers, from shell scripts running tools in a pipeline to data analysis using notebooks.

It also makes the discussion harder, because it's too general! But it is very important to keep in mind, because scientists are not your regular user: they are highly qualified in their field of expertise, and they are also pushing the boundaries of what we know (and this might need flexibility in their tools).

In this post I will be focusing more in two areas: array computing (what most people consider 'scientific programming' to be) and "data structures".

Array computing

This one is booming in the last couple of years due to industry interest in data sciences and deep learning (where they will talk about tensors instead of arrays), and has its roots in models running in supercomputers (a field where Fortran is still king!). Data tends to be quite regular (representable with matrices) and amenable to parallel processing.

A good example is the SciPy stack in Python, built on top of NumPy and SciPy. The adoption of the SciPy stack (both in academia and industry) is staggering, and many alternative implementations try to provide a NumPy-like API to try to capture its mindshare.

This is the compute-intensive side science (be it CPU or GPU/TPU), and also the kind of data that pushed CPU evolution and is still very important in defining policy in scientific computing funding (see countries competing for the largest supercomputers and measuring performance in floating point operations per second).

Data structures for efficient data representation

For data that is not so regular the situation is a bit different. I'll use bioinformatics as an example: the data we get out of nucleotide sequencers is usually represented by long strings (of ACGT), and algorithms will do a lot of string processing (be it building string-overlap graphs for assembly, or searching for substrings in large collections). This is only one example: there are many analyses that will work with other types of data, and most of them don't have a universal data representation as in the array computing case.

This is the memory-intensive science, and it's hard to measure performance in floating point operations because... most of the time you're not even using floating point numbers. It also suffers from limited data locality (which is almost a prerequisite for compute-intensive performance).

High performance core, interactive API

There is something common in both cases: while performance-intensive code is implemented in C/C++/Fortran, users usually interact with the API from other languages (especially Python or R) because it's faster to iterate and explore the data, and many of the tools already available in these languages are very helpful for these tasks (think Jupyter/pandas or RStudio/tidyverse). These languages are used to define the computation, but it is a lower-level core library that drives it (NumPy or Tensorflow follow this idea, for example).

How to make Rust better for science?

The biggest barrier to learning Rust is the ownership model, and while we can agree it is an important feature it is also quite daunting for newcomers, especially if they don't have previous programming experience and exposure to what bugs are being prevented. I don't see it being the first language we teach to scientists any time soon, because the majority of scientists are not system programmers, and have very different expectations for a programming language. That doesn't mean that they can't benefit from Rust!

Rust is already great for building the performance-intensive parts, and thanks to Cargo it is also a better alternative for sharing this code around, since they tend to get 'stuck' inside Python or R packages. And the 'easy' approach of vendoring C/C++ instead of having packages make it hard to keep track of changes and doesn't encourage reusable code.

And, of course, if this code is Rust instead of C/C++ it also means that Rust users can use them directly, without depending on the other languages. Seems like a good way to bootstrap a scientific community in Rust =]

What I would like to see in 2019?

An attribute proc-macro like #[wasm_bindgen] but for FFI

While FFI is an integral part of Rust goals (interoperability with C/C++), I have serious envy of the structure and tooling developed for WebAssembly! (Even more now that it works in stable too)

We already have #[no_mangle] and pub extern "C", but they are quite low-level. I would love to see something closer to what wasm-bindgen does, and define some traits (like IntoWasmAbi) to make it easier to pass more complex data types through the FFI.

I know it's not that simple, and there are different design restrictions than WebAssembly to take into account... The point here is not having the perfect solution for all use cases, but something that serves as an entry point and helps to deal with the complexity while you're still figuring out all the quirks and traps of FFI. You can still fallback and have more control using the lower-level options when the need rises.

More -sys and Rust-like crates for interoperability with the larger ecosystems

There are new projects bringing more interoperability to dataframes and tensors. While this ship has already sailed and they are implemented in C/C++, it would be great to be a first-class citizen, and not reinvent the wheel. (Note: the arrow project already have pretty good Rust support!)

In my own corner (bioinformatics), the Rust-bio community is doing a great job of wrapping useful libraries in C/C++ and exposing them to Rust (and also a shout-out to 10X Genomics for doing this work for other tools while also contributing to Rust-bio!).

More (bioinformatics) tools using Rust!

We already have great examples like finch and yacrd, since Rust is great for single binary distribution of programs. And with bioinformatics focusing so much in independent tools chained together in workflows, I think we can start convincing people to try it out =]

A place to find other scientists?

Another idea is to draw inspiration from rOpenSci and have a Rust equivalent, where people can get feedback about their projects and how to better integrate it with other crates. This is quite close to the working group idea, but I think it would serve more as a gateway to other groups, more focused on developing entry-level docs and bringing more scientists to the community.

Final words

In the end, I feel like this post ended up turning into my 'wishful TODO list' for 2019, but I would love to find more people sharing these goals (or willing to take any of this and just run with it, I do have a PhD to finish! =P)

Comments?

por luizirber em 05 de January de 2019 às 19:00

Filipe Saraiva

LaKademy 2018

Em outubro de 2018, Florianópolis foi sede da sexta edição do LaKademy, o sprint latinoamericano do KDE. Esse momento é uma oportunidade para termos em um mesmo lugar vários desenvolvedores do KDE – tanto veteranos quanto novatos – de diferentes projetos para melhorarem os respectivos softwares em que trabalham e também planejar as ações de promoção da comunidade para o subcontinente.

Na parte técnica, eu trabalhei com Cantor, Sprat, e nos sites do KDE Brasil e LaKademy.

Para o Cantor, eu pesquisei algumas novas maneiras de implementar os backends, em especial quanto a utilização de websockets. Essa é uma ideia antiga que tenta encontrar uma abordagem a ser recomendada para implementação desses backends de forma que possam ser utilizados para qualquer linguagem de programação e funcionem em qualquer plataforma. Entretanto, como nas tentativas anteriores, ainda tenho dúvidas se essa é uma maneira interessante e se os objetivos podem ser atingidos por ela. Enfim, é algo que precisa de mais pesquisa.

Sprat é um editor de texto direcionado para a escrita de artigos científicos. O software implementa a metodologia Amadeus para escrita de artigos, e é mais como uma coleção de sentenças comuns que podem ser utilizadas in seções específicas do artigo. Sprat é meu projeto-pet, e espero lançar esse ano além de transformá-lo em um projeto do KDE.

O site do KDE Brasil uma uma antiga versão do Drupal. Eu e Fred pesquisamos alguns plugins para importar o conteúdo desse site para o WordPress, e atualmente estamos estudando como realizar essa tarefa.

Por último, portei o site do LaKademy para Jekyll. Isso é algo que ainda precisa de algum trabalho, e espero lançá-lo o quanto antes.

Na parte social, discutimos algumas atividades para o KDE nesse ano, como voltar a participar do FISL e Latinoware, tentar comparecer a outros eventos na América Latina (DebConf e Cubaconf, estamos olhando pra vocês), organizar o “Café com Qt” (nosso evento distribuído sobre Qt e KDE), feedbacks sobre o gerenciamento do nosso grupo do KDE Brasil no Telegram, nossos novos materiais promocionais para serem produzidos e distribuídos nos eventos daqui, e mais.

Ainda nesse aspecto, também ajudei os novatos no trabalho de revisão de código do KDE e tirando dúvidas sobre Qt.

LaKademy é uma grande oportunidade para encontrar outros desenvolvedores do KDE e trabalharmos juntos para aumentar nossa comunidade. Nos últimos anos, o KDE assumiu um papel de importância na comunidade brasileira, e estamos planejando expandi-la para diferentes países. Esperamos organizar o próximo LaKademy em algum outro país fora do Brasil, e trabalharemos forte para expandir a comunidade no subcontinente.

Foto em grupo do LaKademy 2018

Nos vemos no LaKademy 2019!

por Filipe Saraiva em 05 de January de 2019 às 17:43

January 02, 2019

Blog do PauloHRPinheiro

Feature toggles com django-waffle

Feature toggles: ativando e desativando comportamentos em um sistema sem alterar o código, usando django-waffle.

02 de January de 2019 às 00:00

December 27, 2018

Rodrigo Delduca

Blobs, blurbs, bubbles…

TL;DR Usar o SQLite ao invés do sistema de arquivos para armazenar em forma de blob os assets do jogo pode ser uma ótima ideia.

Dia desses estava lendo SQLite As An Application File Format o que me fez lembrar de quando eu lia muito a respeito de desenvolvimento de jogos, até cheguei a desenvolver um framework chamado Wintermoon, no meu framework eu usei o PhysicsFS foi quando descobri o MPQ e fiquei encantado.

Mo’PaQ

O MPQ é (ou era) amplamente utilizado em praticamente todos os jogos da Blizzard, desde o Diablo (1997) até o StarCraft 2 (2010). Inclusive o StarCraft 2 recebe atualizações até hoje, e quase que mensalmente desde seu lançamento! Digo isto para dar um contexto de onde quero chegar.

O MPQ leva o nome de seu criador, e surgiu devido há alguns requerimentos da época, como segurança, acesso rápido, compressão, expansibilidade e multi-linguagem.

Atualmente alguns requerimentos mencionados não fazem muito sentido, porém estamos falando de uma época onde o principal sistema de arquivos onde esses títulos rodavam era o FAT32.

PhysicsFS

Sempre gostei da ideia de empacotar os assets do jogo num único arquivo comprimido. O PhysicsFS permite “montar” diretórios e arquivos comprimidos como se fossem um único diretório, com todos os arquivos estruturados dentro dos seus respectivos diretórios; algo semelhante ao que o UnionFS, OverlayFS e similares fazem.

Outra vantagem é a segurança, pois o processo fica restrito à aquele(s) diretório(s) previamente especificado(s).

Usar o physfs com a SDL é bem simples, veja como é o processo de montar um arquivo comprimido e carregar uma imagem:

int main(int argc, char *argv[]) {
  PHYSFS_init(argv[0]);

  SDL_Init(SDL_INIT_VIDEO);

  // monta o arquivo `assets.7z` como se fosse um diretório.
  PHYSFS_mount("assets.7z", "/", 0);

  SDL_Window * window = SDL_CreateWindow(
    NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI);

  SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

  // carrega o arquivo `texture001.tga` que está dentro de `assets.7z`.
  SDL_RWops * rwops = PHYSFSRWOPS_openRead("texture001.tga");

  // carrega a textura.
  SDL_Surface * surface = IMG_Load_RW(rwops, 1);
  SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, surface);
  SDL_FreeSurface(surface);

  SDL_bool running = SDL_TRUE;
  while(running) {
    SDL_Event event;
    while (SDL_PollEvent(&event)) {
      if (event.type == SDL_QUIT) {
        running = SDL_FALSE;
      }
    }

    // desenha a textura na janela.
    SDL_RenderCopy(renderer, texture, NULL, NULL);
    SDL_RenderPresent(renderer);
    SDL_Delay(1000 / 60);
  }

  SDL_DestroyWindow(window);
  SDL_Quit();
  return 0;
}

Legal né?

Little Bobby Tables

O SQLite é provavelmente um dos componentes de software mais utilizados no mundo, está presente em todo o lugar; se estiver lendo esse texto num Android deve ter pelo menos umas 3 cópias dele na suas mãos! SQLite é como um fopen(3) com esteroides.

Lendo o texto que menciono no inicio do texto, penso “E se eu usar SQLite no lugar do PhysicsFS?”

DBA wanna be…

Embora o SQLite possua uma forma prática de ser fazer o que farei a seguir, o SQLite Archive Files, irei apresentar o passo a passo.

Primeiro vamos criar uma tabela com dois campos, um deles para indentificação e o outro com o conteúdo binario em si.

O SQLite (e a grande maioria dos bancos de dados) não suportam armazenar dados binários, para isso existe um tipo de dados especial chamado BLOB (Binary Large OBject).

sqlite3 assets.db "CREATE TABLE IF NOT EXISTS assets (key TEXT PRIMARY KEY, blob BLOB);"

E é isso. O campo key é uma chave primaria e portanto tem um índice próprio, como sei?

$ sqlite3 assets.db
SQLite version 3.24.0 2018-06-04 14:10:15
Enter ".help" for usage hints.
sqlite> .schema assets
CREATE TABLE assets (key TEXT PRIMARY KEY, blob BLOB);
sqlite> .indexes assets
sqlite_autoindex_assets_1

O próximo passo é inserir o arquivo da textura texture001.tga que será usada:

sqlite3 assets.db "INSERT INTO assets(key, blob) VALUES ('texture001', readfile('texture001.tga'));"

O SQLite tem uma função readfile que carrega o arquivo diretamente.

É possível verificar o tamanho do blob com a função length:

$ sqlite3 assets.db
SQLite version 3.24.0 2018-06-04 14:10:15
Enter ".help" for usage hints.
sqlite> select key, length(blob) from assets;
texture001|3686418

Que é exatamente o mesmo do arquivo original:

$ stat -f%z texture001.tga
3686418

Adaptando o exemplo acima para a API em C do SQLite temos:

sqlite3 * db;
// abre o arquivo do banco de dados do sqlite.
sqlite3_open("assets.db", &db);
// ...

// preparamos a query.
const char * sql = "SELECT blob FROM assets WHERE key = ?";
sqlite3_stmt * stmt;
sqlite3_prepare_v2(db, sql, -1, &stmt, 0);

// "atrela" o valor `texture001` no primeiro parâmetro do sql, o `?`.
sqlite3_bind_text(stmt, 1, "texture001", -1, SQLITE_STATIC);

// executa a query "SELECT blob FROM assets WHERE key = 'texture001'".
sqlite3_step(stmt);

// criamos um `SDL_RWops` com os bytes do blob.
int bytes = sqlite3_column_bytes(stmt, 0);
const void * buffer = sqlite3_column_blob(stmt, 0);
SDL_RWops * rwops = SDL_RWFromConstMem(buffer, (sizeof(unsigned char) * bytes));

// finaliza (responsável por liberar a memória retornada por sqlite3_column_blob e outros recursos.)
sqlite3_reset(stmt);

// (como anteriormente) carrega a textura.
SDL_Surface * surface = IMG_Load_RW(rwops, 1);
SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_FreeSurface(surface);

Benchmarks, é disso que o povo gosta!

Usando a função SDL_GetPerformanceFrequency para mensurar o trecho responsável apenas por carregar a textura obtive os seguintes resultados:

$ file texture001.tga
texture001.tga: Targa image data - RGB 1280 x 960 x 24
$ ls -lh texture001.tga | awk '{print $5}'
3.5M
PhysicsFS (gzip compressed)
for i in {1..10}; do ./physfs; done
42.060247
40.972251
38.589466
40.684438
43.327696
38.578994
...
SQLite
for i in {1..10}; do ./sqlite; done
27.433850
30.553595
27.706754
27.282197
27.561867
27.853982
...
IMG_Load("texture001.tga") (A.K.A. diretamente)
for i in {1..10}; do ./a.out; done
22.792655
23.667172
22.286974
23.551452
22.094010
23.657177
...

Acredito que se utilizado compressão no SQLite o uso de disco seria reduzido e como consequência resultados ainda melhores.

Patches everywhere!

metalhead with lots of patches

Uma das principais características do software é que ele não funciona e precisa constantemente ser remendado, e nos jogos não é diferente.

O MPQ tem um mecanismo de patches, como na época a maioria dos jogos eram distribuídas em mídias somente leitura, como o CD-ROM, era preciso uma outra abordagem, já que não era possível reescrever o .mpq original, portanto era criado uma espécie de corrente, então após o jogo carregar, as alterações eram aplicadas em cima, na mesma sequencia de que foram publicadas.

A ideia por trás de usar o SQLite no lugar do PhysicsFS é de aproveitar algumas características de um banco de dados, que é de… criar, atualizar, modificar e deletar de forma atômica!

O arquivo de update do jogo poderia ser um conjunto de instruções SQL.

Vamos desconsiderar o binário do jogo por hora, e vamos supor que uma nova textura foi adicionada no banco de dados do desenvolvedor, e por algum motivo desconhecido ele é preguiçoso e usou a ferramenta sqldiff para gerar o patch e não schema migration.

sqlite3 assets.db "INSERT INTO assets(key, blob) VALUES ('texture002', readfile('texture002.jpg'));"

Estou usando texturas como exemplo pois geralmente é o tipo de arquivo que ocupa mais espaço em disco dos jogos. O exemplo vale para qualquer tipo de arquivo… seja textos, scripts, shaders, etc.

$ sqldiff old.db assets.db > patch01.sql
$ # checando o conteúdo da atualização.
$ head -c 100 up.sql
INSERT INTO assets(rowid,"key", blob) VALUES(2,'texture002',x'ffd8ffe000104a46494600010100000100010%
$ ls -lh patch01.sql | awk '{print $5}'
663K
$ tar -cvzf patch01.tgz patch01.sql
$ ls -lh patch01.tgz | awk '{print $5}'
363K

Como se trata de um arquivo .jpeg representado em hexadecimal dentro de um .sql os ganhos com compressão são pequenos.

Agora basta a nossa ferramenta responsável por atualizar o jogo aplicar os patches na mesma sequencia que foram gerados.

Essa é uma forma bem simples e descomplicada de atualizar o jogo e é algo bem resolvido no mundo dos banco de dados há décadas.

É possível criar updates ainda menores, o Google Chrome tem um projeto chamado courgette que usa a ferramenta bsdiff combinada com um outro algoritmo descrito no link, podemos usar o bsdiff para gerar o patch do asset a ser atualizado e no cliente usar o bspatch para aplicar a modificação.

Além de todas essas vantagens, o uso do SQLite ainda possibilita o data-driven programming.

Winterphobos

Pretendo utilizar o SQLite como descrito num novo projeto chamado Winterphobos, um motor de jogos minimalista, e uma das premissas é ser totalmente “scriptável” em lua com entity–component–system .

vault boy

TL;DR Usar o SQLite ao invés do sistema de arquivos para armazenar em forma de blob os assets do jogo pode ser uma ótima ideia.

por Rodrigo Delduca (rodrigodelduca@gmail.com) em 27 de December de 2018 às 00:00

November 29, 2018

PythonClub

Algoritmos de Ordenação

Fala pessoal, tudo bom?

Nos vídeos abaixo, vamos aprender como implementar alguns dos algoritmos de ordenação usando Python.

Bubble Sort

Como o algoritmo funciona: Como implementar o algoritmo usando Python: https://www.youtube.com/watch?v=Doy64STkwlI.

Como implementar o algoritmo usando Python: https://www.youtube.com/watch?v=B0DFF0fE4rk.

Código do algoritmo

def sort(array):

    for final in range(len(array), 0, -1):
        exchanging = False

        for current in range(0, final - 1):
            if array[current] > array[current + 1]:
                array[current + 1], array[current] = array[current], array[current + 1]
                exchanging = True

        if not exchanging:
            break

Selection Sort

Como o algoritmo funciona: Como implementar o algoritmo usando Python: https://www.youtube.com/watch?v=vHxtP9BC-AA.

Como implementar o algoritmo usando Python: https://www.youtube.com/watch?v=0ORfCwwhF_I.

Código do algoritmo

def sort(array):
    for index in range(0, len(array)):
        min_index = index

        for right in range(index + 1, len(array)):
            if array[right] < array[min_index]:
                min_index = right

        array[index], array[min_index] = array[min_index], array[index]

Insertion Sort

Como o algoritmo funciona: Como implementar o algoritmo usando Python: https://www.youtube.com/watch?v=O_E-Lj5HuRU.

Como implementar o algoritmo usando Python: https://www.youtube.com/watch?v=Sy_Z1pqMgko.

Código do algoritmo

def sort(array):
    for p in range(0, len(array)):
        current_element = array[p]

        while p > 0 and array[p - 1] > current_element:
            array[p] = array[p - 1]
            p -= 1

        array[p] = current_element

Merge Sort

Como o algoritmo funciona: Como implementar o algoritmo usando Python: https://www.youtube.com/watch?v=Lnww0ibU0XM.

Como implementar o algoritmo usando Python - Parte I: https://www.youtube.com/watch?v=cXJHETlYyVk.

Código do algoritmo

def sort(array):
    sort_half(array, 0, len(array) - 1)


def sort_half(array, start, end):
    if start >= end:
        return

    middle = (start + end) // 2

    sort_half(array, start, middle)
    sort_half(array, middle + 1, end)

    merge(array, start, end)


def merge(array, start, end):
    array[start: end + 1] = sorted(array[start: end + 1])

por Lucas Magnum em 29 de November de 2018 às 15:10

November 22, 2018

Blog do PauloHRPinheiro

Teste de carga e desempenho

Testando a capacidade e desempenho de uma API com o framework Locust, em Python

22 de November de 2018 às 00:00

October 21, 2018

Thiago Avelino

A arte de reescrever software

Lidar com software legado hoje em dia é mais comum do que podemos imaginar, costumo dizer que muitos softwares nascem legado, como assim? Para mim software que não tem teste automatizado é legado, não tem como garantir funcionamento de absolutamente nada dentro dele e muitos comportamentos (recursos ou bugs) só irá aparecer com usuários usando constantemente. Após alinhamento do que é software legado é comum a empresa (principalmente as com cultura de startup) e desenvolvedores ter que trocar peças do software em pleno o voo, não temos como pousar o avião para fazer manutenção e depois decolar novamente quando a empresa está com clientes usando o software em produção.

21 de October de 2018 às 00:00

October 06, 2018

PythonClub

Trabalhando com operadores ternários

Quando estamos escrevendo um código qualquer, possivelmente a expressão que mais utilizamos é o if. Para qualquer tarefas que buscamos automatizar ou problemas que buscamos resolver, sempre acabamos caindo em lógicas como "Se isso acontecer, então faça aquilo, senão faça aquele outro...".

Quando estamos falando de ações a serem executadas, pessoalmente gosto da forma com que o código fica organizado em python quando usamos este tipo de condições, por exemplo:

if vencer_o_thanos:
    restaurar_a_paz()

else:
    foo()

Graças a indentação e ao espaçamento, vemos onde onde começa e/ou termina o bloco executado caso a varável vencer_o_thanos seja True. Quanto mais if's você aninhar, mais bonito seu código fica e em momento algum o mesmo se torna mais confuso (ao menos, não deveria se tornar). Entretanto, sempre fico extremamente incomodado quando tenho de escrever um bloco apenas marcar uma variável, como por exemplo:

if vencer_o_thanos:
    paz = True

else:
    paz = False

Por isso, para trabalhar com variáveis que possuem um valor condicional, gosto sempre de trabalhar com expressões condicionais, ou como costumam ser chamadas, operadores ternários.

Operadores ternários são todos os operadores que podem receber três operandos. Como as expressões condicionais costumam ser os operadores ternários mais populares nas linguagens em que aparecem, acabamos por associar estes nomes e considerar que são a mesma coisa. Cuidado ao tirar este tipo de conclusão, mesmo que toda vogal esteja no alfabeto, o alfabeto não é composto apenas por vogais.

A estrutura de uma expressão condicional é algo bem simples, veja só:

paz = True if vencer_o_thanos else False
tipo_de_x = "Par" if x % 2 == 0 else "impar"

Resumidamente, teremos um valor seguido de uma condição e por fim seu valor caso a condição seja falsa. Pessoalmente acredito que apesar de um pouco diferente, essa forma de escrita para casos como o exemplificado acima é muito mais clara, mais explicita.

Se você fizer uma tradução literal das booleanas utilizadas no primeiro exemplo, lerá algo como paz é verdadeira caso vencer_o_thanos, caso contrário é Falsa. já o segundo exemplo fica mais claro ainda, pois lemos algo como tipo_de_x é par caso o resto da divisão de x por 2 seja 0, se não, tipo_de_x é impar..

Interpretar código dessa forma pode ser estranho para um programador. Interpretar uma abertura de chave ou uma indentação já é algo mas natural. Todavia, para aqueles que estão começando, o raciocínio ocorre de forma muito mais parecida com a descrita acima. Espero que tenham gostado do texto e que esse conhecimento lhes seja útil.

por Vitor Hugo de Oliveira Vargas em 06 de October de 2018 às 12:21

October 01, 2018

Bruno Cezar Rocha

Hacktoberfest 2018

Hacktoberfest 2018

Hacktoberfest is an amazing campaign by Digital Ocean and Github, you contribute with at least 5 open source Pull Requests and then you get a T-shirt and some stickers.

Maintainers are encouraged to label and organize the issues to be worked on.

Register at: https://hacktoberfest.digitalocean.com/

I will list here some of my Projects and the issues I am expecting to get some contributions.

Dynaconf

Dynaconf is a library for settings management in any kind of Python project.

Skills needed: CI, Python, decorators, Python Module Initialization, Data Structures and Python data Model

Issues: https://github.com/rochacbruno/dynaconf/issues

Highlights:

Flasgger

Flasgger is the project powering the http://httpbin.org website, it allows you to document your Flask API and serves Swagger UI.

Skills needed: API REST, Flask, OPenAPISpec, Decorators, Python data model.

Issues: https://github.com/rochacbruno/flasgger/issues
HIghlights:

Flask Google Maps

Easy way to add maps to Flask views.

Skills needed: Flask, Google APIs

Issues: https://github.com/rochacbruno/Flask-GoogleMaps

Flask Simple Login

Easy way to protect your Flask views with login.

Skills needed: Python, Flask, environment variables, templating, CSS, HTML, Bootstrap.

Issues: https://github.com/rochacbruno/flask_simplelogin/issues

Highlights:

Quokka CMS

Quokka is a Content Management Framework, which is in process of rewriting, the idea is having a core written in Flask, use Pelican themes and allow generation of static websites.

Skills needed: Flask, Python, Templating, MongoDB

Issues: https://github.com/rochacbruno/quokka

All the issues are good, as it is a re-writing from scratch project.

Py2rs

This is a Guide for Pythonistas who are learning Rust language

Issues: https://github.com/rochacbruno/py2rs/issues

The project really needs more examples to be written and also more comparison and fixes. Any kind of contributions are welcome.

Talkshow

This is a call 4 papers system (used as didatic example only)

Skills needed: Flask, Templating, mongoDB

Issues: https://github.com/rochacbruno/talkshow/issues

por Bruno Rocha em 01 de October de 2018 às 18:20

September 25, 2018

Thiago Avelino

Keeping open source projects - awesome-go

Beginning of any project (especially when we are talking about open source) is extremely entertaining for developer, over the years the fun passes and it is the responsibility to keep your “son” following the path of it. How did the starting awesome-go? All projects I started are out of necessity, the awesome-go was no different. After knowing the awesome-python and seeing other “awesomes” projects I searched for the awesome-go and did not get results.

25 de September de 2018 às 00:00

September 24, 2018

Gabbleblotchits

What open science is about

Today I got a pleasant surprise: Olga Botvinnik posted on Twitter about a poster she is presenting at the Beyond the Cell Atlas conference and she name-dropped a bunch of people that helped her. The cool thing? They are all open source developers, and Olga interacted thru GitHub to ask for features, report bugs and even submit pull requests.

That's what open science is about: collaboration, good practices, and in the end coming up with something that is larger than each individual piece. Now sourmash is better, bamnostic is better, reflow is better. I would like to see this becoming more and more common =]

Comments?

por luizirber em 24 de September de 2018 às 20:00

September 22, 2018

Filipe Saraiva

Akademy 2018

Procure seu colaborador favorito do KDE na Foto em grupo oficial do Akademy 2018

Estive em Viena para participar do Akademy 2018, o encontro anual do KDE. Este foi o meu quarto Akademy, sendo antecedido por Berlin’2012 (na verdade, Desktop Summit ), Brno’2014, e Berlin’2016 (junto com a QtCon). Interessante, vou ao Akademy a cada 2 anos – pretendo melhorar isso já no próximo. 🙂

Após uma viagem muito longa, pude finalmente encontrar “cabeças de engrenagem” de todas as partes do mundo, incluindo o próprio Brasil. Vi velhos e novos amigos trabalhando juntos para melhorar a experiência de utilizar um computador com software livre, cada qual contribuindo com pequenas (e alguns, realmente gigantes) partes para tornar isso realidade. Sempre que encontro esse pessoal me sinto reenergizado para seguir com esse trabalho.

Das palestras, gostei muito da feita por Volker sobre o KDE Itinerary, uma nova aplicação para gerenciar passbooks relacionados com viagens. Penso que um software para gerenciar todos os tipos de arquivos passbook (como entradas para shows, cinemas, e mais) como este seria uma interessante adição para a família de softwares do KDE, e um passo anterior à ideia perseguida pelo KDE Itinerary. De qualquer forma, estou na expectativa por novidades deste software.

A palestra sobre criação de transições utilizando o Kdenlive me fez pensar em quão interessante seria um plugin para executar scripts bash (ou python, talvez) de forma a automatizar vários passos realizados por editores nesse software. Inclusive, talves utilizando a KDE Store para compartilhar esses scripts… enfim, muitas ideias.

Conheci Camilo durante o evento. A palestra dele sobre o vvave me deu esperanças por uma nova e interessante aplicação de player multimídia, como uma vez tivemos no passado (saudades Amarok).

A última palestra que chamou minha atenção foi de Nate sobre algumas ideias para melhorar nosso ecossistema. Nate está fazendo um trabalho fabuloso sobre usabilidade, “polindo” nossos software de diversas formas. Recomendo o blog dele para quem quiser ficar acompanhar também. Apesar de eu concordar em geral com boa parte das ideias – por exemplo, é urgente a necessidade de melhorarmos nossa suíte de aplicações pessoais -, eu tive alguns desacordos em outras, em especial a ideia de que os desenvolvedores do KDE se dediquem a contribuir também para o LibreOffice. LibreOffice tem um código fonte completamente diferente, que utiliza tecnologias e práticas nada relacionadas com o que vemos no KDE, e há várias (e para muitos de nós, desconhecidas) influências das diferentes organizações que gerem a The Document Foundation, entidade responsável por desenvolver o LibreOffice. E por fim, nós ainda temos a suíte de escritório Calligra – a idea me soou como “vamos acabar com o Calligra”. De qualquer forma, isso foi apenas um desacordo com uma das sugestões, nada demais.

Após as seções de palestras o Akademy teve batantes sessões de BoF, que são mini-reuniões direcionadas sobre tópicos específicos. Pude participar de algumas, como a sobre o KDE e Qt (é sempre bom manter os olhos sobre esse tópico), KDE Phabricator (Phabricator é um conjunto muito bom de ferramentas para gerenciamento de projetos/repositórios/e afins, mas sofre por conta dos competidores (Gitlab) serem muito mais conhecidos e também por não ter das melhores usabilidades), e MyCroft (gosto da ideia de integração entre o MyCroft e o Plasma, especialmente para casos de uso especĩficos como auxiliar pessoas com deficiência – estou pensando nisso já há alguns meses).

Este ano, Aracele, Sandro e eu realizamos um BoF chamado “KDE in Americas”. A ideia foi apresentar algumas das nossas conquistas para o KDE na América Latina e discutir com o pessoal das demais américas sobre um evento “continental”, trazendo de volta o antigo CampKDE em uma nova edição junto com o LaKademy (o nome secreto é LaKamp :D). Esta ideia ainda precisa de alguma maturação para seguir em frente, mas estamos trabalhando.

Este ano eu tentei realizar o BoF sobre KDE na ciência e Cantor, mas infelizmente eu não tive o feedback necessário sobre potenciais participantes. Vamos ver se no futuro poderemos ter alguns deles acontecendo.

Akademy é um evento fantástico onde você encontra colaboradores do KDE de diferentes frentes e culturas, pode discutir com eles, pegar opiniões sobre projetos atuais e mesmo iniciar novos. Gostaria de agradecer ao KDE e.V. pelo patrocínio que me permitiu ir ao evento e espero ver todos vocês e mais alguns no próximo ano (vou tentar inserir um distúrbio naquela distribuição da minha sequência bianual de participações) no Akademy ou, em algumas semanas, no LaKademy!

Brasileiros no Akademy 2018: KDHelio, Caio, Sandro, Filipe (eu), Tomaz (abaixo), Eliakin, Aracele, e Lays

por Filipe Saraiva em 22 de September de 2018 às 21:13

September 13, 2018

Gabbleblotchits

New crate: nthash

A quick announcement: I wrote a Rust implementation of ntHash and published it in crates.io. It implements an Iterator to take advantage of the rolling properties of ntHash which make it so useful in bioinformatics (where we work a lot with sliding windows over sequences).

It's a pretty small crate, and probably was a better project to learn Rust than doing a sourmash implementation because it doesn't involve gnarly FFI issues. I also put some docs, benchmarks using criterion, and even an oracle property-based test with quickcheck.

More info in the docs, and if you want an optimization versioning bug discussion be sure to check the ntHash bug? repo, which has a (slow) Python implementation and a pretty nice analysis notebook.

Comments?

por luizirber em 13 de September de 2018 às 20:00

August 27, 2018

Gabbleblotchits

Oxidizing sourmash: WebAssembly

sourmash calculates MinHash signatures for genomic datasets, meaning we are reducing the data (via subsampling) to a small representative subset (a signature) capable of answering one question: how similar is this dataset to another one? The key here is that a dataset with 10-100 GB will be reduced to something in the megabytes range, and two approaches for doing that are:

  • The user install our software in their computer. This is not so bad anymore (yay bioconda!), but still requires knowledge about command line interfaces and how to install all this stuff. The user data never leaves their computer, and they can share the signatures later if they want to.
  • Provide a web service to calculate signatures. In this case no software need to be installed, but it's up to someone (me?) to maintain a server running with an API and frontend to interact with the users. On top of requiring more maintenance, another drawback is that the user need to send me the data, which is very inefficient network-wise and lead to questions about what I can do with their raw data (and I'm not into surveillance capitalism, TYVM).

But... what if there is a third way?

What if we could keep the frontend code from the web service (very user-friendly) but do all the calculations client-side (and avoid the network bottleneck)? The main hurdle here is that our software is implemented in Python (and C++), which are not supported in browsers. My first solution was to write the core features of sourmash in JavaScript, but that quickly started hitting annoying things like JavaScript not supporting 64-bit integers. There is also the issue of having another codebase to maintain and keep in sync with the original sourmash, which would be a relevant burden for us. I gave a lab meeting about this approach, using a drag-and-drop UI as proof of concept. It did work but it was finicky (dealing with the 64-bit integer hashes is not fun). The good thing is that at least I had a working UI for further testing1

In "Oxidizing sourmash: Python and FFI" I described my road to learn Rust, but something that I omitted was that around the same time the WebAssembly support in Rust started to look better and better and was a huge influence in my decision to learn Rust. Reimplementing the sourmash C++ extension in Rust and use the same codebase in the browser sounded very attractive, and now that it was working I started looking into how to use the WebAssembly target in Rust.

WebAssembly?

From the official site,

WebAssembly (abbreviated Wasm) is a binary
instruction format for a stack-based
virtual machine. Wasm is designed as a
portable target for compilation of high-level
languages like C/C++/Rust, enabling deployment
on the web for client and server applications.

You can write WebAssembly by hand, but the goal is to have it as lower level target for other languages. For me the obvious benefit is being able to use something that is not JavaScript in the browser, even though the goal is not to replace JS completely but complement it in a big pain point: performance. This also frees JavaScript from being the target language for other toolchains, allowing it to grow into other important areas (like language ergonomics).

Rust is not the only language targeting WebAssembly: Go 1.11 includes experimental support for WebAssembly, and there are even projects bringing the scientific Python to the web using WebAssembly.

But does it work?

With the Rust implementation in place and with all tests working on sourmash, I added the finishing touches using wasm-bindgen and built an NPM package using wasm-pack: sourmash is a Rust codebase compiled to WebAssembly and ready to use in JavaScript projects.

(Many thanks to Madicken Munk, who also presented during SciPy about how they used Rust and WebAssembly to do interactive visualization in Jupyter and helped with a good example on how to do this properly =] )

Since I already had the working UI from the previous PoC, I refactored the code to use the new WebAssembly module and voilà! It works!2. 3 But that was the demo from a year ago with updated code and I got a bit better with frontend development since then, so here is the new demo:

sourmash + Wasm

Drag & drop a FASTA or FASTQ file here to calculate the sourmash signature.

For the source code for this demo, check the sourmash-wasm directory.

Next steps

The proof of concept works, but it is pretty useless right now. I'm thinking about building it as a Web Component and making it really easy to add to any webpage4.

Another interesting feature would be supporting more input formats (the GMOD project implemented a lot of those!), but more features are probably better after something simple but functional is released =P

Next time!

Where we will go next? Maybe explore some decentralized web technologies like IPFS and dat, hmm? =]

Comments?

Updates

  • 2018-08-30: Added a demo in the blog post.

Footnotes

  1. even if horrible, I need to get some design classes =P

  2. the first version of this demo only worked in Chrome because they implemented the BigInt proposal, which is not in the official language yet. The funny thing is that BigInt would have made the JS implementation of sourmash viable, and I probably wouldn't have written the Rust implementation =P. Turns out that I didn't need the BigInt support if I didn't expose any 64-bit integers to JS, and that is what I'm doing now.

  3. Along the way I ended up writing a new FASTQ parser... because it wouldn't be bioinformatics if it didn't otherwise, right? =P

  4. or maybe a React component? I really would like to have something that works independent of framework, but not sure what is the best option in this case...

por luizirber em 27 de August de 2018 às 18:30

August 23, 2018

Gabbleblotchits

Oxidizing sourmash: Python and FFI

I think the first time I heard about Rust was because Frank Mcsherry chose it to write a timely dataflow implementation. Since then it started showing more and more in my news sources, leading to Armin Ronacher publishing a post in the Sentry blog last November about writing Python extensions in Rust.

Last December I decided to give it a run: I spent some time porting the C++ bits of sourmash to Rust. The main advantage here is that it's a problem I know well, so I know what the code is supposed to do and can focus on figuring out syntax and the mental model for the language. I started digging into the symbolic codebase and understanding what they did, and tried to mirror or improve it for my use cases.

(About the post title: The process of converting a codebase to Rust is referred as "Oxidation" in the Rust community, following the codename Mozilla chose for the process of integrating Rust components into the Firefox codebase. 1 Many of these components were tested and derived in Servo, an experimental browser engine written in Rust, and are being integrated into Gecko, the current browser engine (mostly written in C++).)

Why Rust?

There are other programming languages more focused on scientific software that could be used instead, like Julia2. Many programming languages start from a specific niche (like R and statistics, or Maple and mathematics) and grow into larger languages over time. While Rust goal is not to be a scientific language, its focus on being a general purpose language allows a phenomenon similar to what happened with Python, where people from many areas pushed the language in different directions (system scripting, web development, numerical programming...) allowing developers to combine all these things in their systems.

But by far my interest in Rust is for the many best practices it brings to the default experience: integrated package management (with Cargo), documentation (with rustdoc), testing and benchmarking. It's understandable that older languages like C/C++ need more effort to support some of these features (like modules and an unified build system), since they are designed by standard and need to keep backward compatibility with codebases that already exist. Nonetheless, the lack of features increase the effort needed to have good software engineering practices, since you need to choose a solution that might not be compatible with other similar but slightly different options, leading to fragmentation and increasing the impedance to use these features.

Another big reason is that Rust doesn't aim to completely replace what already exists, but complement and extend it. Two very good talks about how to do this, one by Ashley Williams, another by E. Dunham.

Converting from a C++ extension to Rust

The current implementation of the core data structures in sourmash is in a C++ extension wrapped with Cython. My main goals for converting the code are:

  • support additional languages and platforms. sourmash is available as a Python package and CLI, but we have R users in the lab that would benefit from having an R package, and ideally we wouldn't need to rewrite the software every time we want to support a new language.

  • reducing the number of wheel packages necessary (one for each OS/platform).

  • in the long run, use the Rust memory management concepts (lifetimes, borrowing) to increase parallelism in the code.

Many of these goals are attainable with our current C++ codebase, and "rewrite in a new language" is rarely the best way to solve a problem. But the reduced burden in maintenance due to better tooling, on top of features that would require careful planning to execute (increasing the parallelism without data races) while maintaining compatibility with the current codebase are promising enough to justify this experiment.

Cython provides a nice gradual path to migrate code from Python to C++, since it is a superset of the Python syntax. It also provides low overhead for many C++ features, especially the STL containers, with makes it easier to map C++ features to the Python equivalent. For research software this also lead to faster exploration of solutions before having to commit to lower level code, but without a good process it might also lead to code never crossing into the C++ layer and being stuck in the Cython layer. This doesn't make any difference for a Python user, but it becomes harder from users from other languages to benefit from this code (since your language would need some kind of support to calling Python code, which is not as readily available as calling C code).

Depending on the requirements, a downside is that Cython is tied to the CPython API, so generating the extension requires a development environment set up with the appropriate headers and compiler. This also makes the extension specific to a Python version: while this is not a problem for source distributions, generating wheels lead to one wheel for each OS and Python version supported.

The new implementation

This is the overall architecture of the Rust implementation: It is pretty close to what symbolic does, so let's walk through it.

The Rust code

If you take a look at my Rust code, you will see it is very... C++. A lot of the code is very similar to the original implementation, which is both a curse and a blessing: I'm pretty sure that are more idiomatic and performant ways of doing things, but most of the time I could lean on my current mental model for C++ to translate code. The biggest exception was the merge function, were I was doing something on the C++ implementation that the borrow checker didn't like. Eventually I found it was because it couldn't keep track of the lifetime correctly and putting braces around it fixed the problem, which was both an epiphany and a WTF moment. Here is an example that triggers the problem, and the solution.

"Fighting the borrow checker" seems to be a common theme while learning Rust, but the compiler really tries to help you to understand what is happening and (most times) how to fix it. A lot of people grow to hate the borrow checker, but I see it more as a 'eat your vegetables' situation: you might not like it at first, but it's better in the long run. Even though I don't have a big codebase in Rust yet, it keeps you from doing things that will come back to bite you hard later.

Generating C headers for Rust code: cbindgen

With the Rust library working, the next step was taking the Rust code and generate C headers describing the functions and structs we expose with the #[no_mangle] attribute in Rust (these are defined in the ffi.rs module in sourmash-rust). This attribute tells the Rust compiler to generate names that are compatible with the C ABI, and so can be called from other languages that implement FFI mechanisms. FFI (the foreign function interface) is quite low-level, and pretty much defines things that C can represent: integers, floats, pointers and structs. It doesn't support higher level concepts like objects or generics, so in a sense it looks like a feature funnel. This might sound bad, but ends up being something that other languages can understand without needing too much extra functionality in their runtimes, which means that most languages have support to calling code through an FFI.

Writing the C header by hand is possible, but is very error prone. A better solution is to use cbindgen, a program that takes Rust code and generate a C header file automatically. cbindgen is developed primarily to generate the C headers for webrender, the GPU-based renderer for servo, so it's pretty likely that if it can handle a complex codebase it will work just fine for the majority of projects.

Interfacing with Python: CFFI and Milksnake

Once we have the C headers, we can use the FFI to call Rust code in Python. Python has a FFI module in the standard library: ctypes, but the Pypy developers also created CFFI, which has more features.

The C headers generated by cbindgen can be interpreted by CFFI to generate a low-level Python interface for the code. This is the equivalent of declaring the functions/methods and structs/classes in a pxd file (in the Cython world): while the code is now usable in Python, it is not well adapted to the features and idioms available in the language.

Milksnake is the package developed by Sentry that takes care of running cargo for the Rust compilation and generating the CFFI boilerplate, making it easy to load the low-level CFFI bindings in Python. With this low-level binding available we can now write something more Pythonic (the pyx file in Cython), and I ended up just renaming the _minhash.pyx file back to minhash.py and doing one-line fixes to replace the Cython-style code with the equivalent CFFI calls.

All of these changes should be transparent to the Python code, and to guarantee that I made sure that all the current tests that we have (both for the Python module and the command line interface) are still working after the changes. It also led to finding some quirks in the implementation, and even improvements in the current C++ code (because we were moving a lot of data from C++ to Python).

Where I see this going

It seems it worked as an experiment, and I presented a poster at GCCBOSC 2018 and SciPy 2018 that was met with excitement by many people. Knowing that it is possible, I want to reiterate some points why Rust is pretty exciting for bioinformatics and science in general.

Bioinformatics as libraries (and command line tools too!)

Bioinformatics is an umbrella term for many different methods, depending on what analysis you want to do with your data (or model). In this sense, it's distinct from other scientific areas where it is possible to rely on a common set of libraries (numpy in linear algebra, for example), since a library supporting many disjoint methods tend to grow too big and hard to maintain.

The environment also tends to be very diverse, with different languages being used to implement the software. Because it is hard to interoperate, the methods tend to be implemented in command line programs that are stitched together in pipelines, a workflow describing how to connect the input and output of many different tools to generate results. Because the basic unit is a command-line tool, pipelines tend to rely on standard operating system abstractions like files and pipes to make the tools communicate with each other. But since tools might have input requirements distinct from what the previous tool provides, many times it is necessary to do format conversion or other adaptations to make the pipeline work.

Using tools as blackboxes, controllable through specific parameters at the command-line level, make exploratory analysis and algorithm reuse harder: if something needs to be investigated the user needs to resort to perturbations of the parameters or the input data, without access to the more feature-rich and meaningful abstraction happening inside the tool.

Even if many languages are used for writing the software, most of the time there is some part written in C or C++ for performance reasons, and these tend to be the core data structures of the computational method. Because it is not easy to package your C/C++ code in a way that other people can readily use it, most of this code is reinvented over and over again, or is copy and pasted into codebases and start diverging over time. Rust helps solve this problem with the integrated package management, and due to the FFI it can also be reused inside other programs written in other languages.

sourmash is not going to be Rust-only and abandon Python, and it would be crazy to do so when it has so many great exploratory tools for scientific discovery. But now we can also use our method in other languages and environment, instead of having our code stuck in one language.

Don't rewrite it all!

I could have gone all the way and rewrite sourmash in Rust3, but it would be incredibly disruptive for the current sourmash users and it would take way longer to pull off. Because Rust is so focused in supporting existing code, you can do a slow transition and reuse what you already have while moving into more and more Rust code. A great example is this one-day effort by Rob Patro to bring CQF (a C codebase) into Rust, using bindgen (a generator of C bindings for Rust). Check the Twitter thread for more =]

Good scientific citizens

There is another MinHash implementation already written in Rust, finch. Early in my experiment I got an email from them asking if I wanted to work together, but since I wanted to learn the language I kept doing my thing. (They were totally cool with this, by the way). But the fun thing is that Rust has a pair of traits called From and Into that you can implement for your type, and so I did that and now we can have interoperable implementations. This synergy allows finch to use sourmash methods, and vice versa.

Maybe this sounds like a small thing, but I think it is really exciting. We can stop having incompatible but very similar methods, and instead all benefit from each other advances in a way that is supported by the language.

Next time!

Turns out Rust supports WebAssembly as a target, so... what if we run sourmash in the browser? That's what I'm covering in the next blog post, so stay tuned =]

Comments?


Footnotes

  1. The creator of the language is known to keep making up different explanations for the name of the language, but in this case "oxidation" refers to the chemical process that creates rust, and rust is the closest thing to metal (metal being the hardware). There are many terrible puns in the Rust community.

  2. Even more now that it hit 1.0, it is a really nice language

  3. and risk being kicked out of the lab =P

por luizirber em 23 de August de 2018 às 20:00