{"id":1016,"date":"2020-07-21T17:22:57","date_gmt":"2020-07-21T20:22:57","guid":{"rendered":"https:\/\/micheladrianomedeiros.com.br\/blog\/?p=1016"},"modified":"2020-07-21T17:22:59","modified_gmt":"2020-07-21T20:22:59","slug":"devops-com-python-4","status":"publish","type":"post","link":"https:\/\/micheladrianomedeiros.com.br\/blog\/devops-com-python-4\/","title":{"rendered":"DevOps com Python #4"},"content":{"rendered":"\n<h4 class=\"wp-block-heading\">Setup e Wheels<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">O termo &#8220;third party&#8221; (com um &#8220;pacote de terceiros&#8221;) referencia-se a algu\u00e9m que tenha como principal fun\u00e7\u00e3o desenvolvedor do core do Python (&#8220;primeiro grupo&#8221;) ou o desenvolvedor local (&#8220;segundo grupo&#8221;).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instalamos pacotes do &#8220;primeiro grupo&#8221; na instala\u00e7\u00e3o do Python. Usamos o pip e virtualenv para instalar &#8220;pacotes de terceiros&#8221;. Agora vamos para o segundo grupo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Vamos ver novas adi\u00e7\u00f5es, como pyproject.toml e flit. Contudo, \u00e9 importante entender a maneira cl\u00e1ssica de fazer as coisas. Por um lado, demora um tempo para aplicar as novas pr\u00e1ticas recomendadas. Por outro lado,  h\u00e1 pr\u00e1ticas que s\u00e3o baseadas na setup.py, e isso continuar\u00e1 por muito tempo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">O arquivo descrito no setup.py, no c\u00f3digo, na nossa &#8220;distribui\u00e7\u00e3o&#8221;. Veja que &#8220;distribui\u00e7\u00e3o&#8221; \u00e9 diferente do &#8220;pacote&#8221;. Um pacote \u00e9 um diret\u00f3rio com (geralmente) __init__.py o qual o Python pode importar.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Uma distribui\u00e7\u00e3o pode conter v\u00e1rios pacotes ou at\u00e9 mesmo nenhum! Contudo, \u00e9 uma boa ideia manter a rela\u00e7\u00e3o 1-1-1: um distribui\u00e7\u00e3o, um pacote, com o mesmo nome.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Geralmente, setup.py ir\u00e1 come\u00e7ar importando setuptools ou distutils. Enquanto distutils j\u00e1 vem com a ferramenta, setuptools n\u00e3o \u00e9. Contudo, ele quase sempre \u00e9 instalado primeiro no ambiente virtual, devido a sua grande popularidade.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Distutils n\u00e3o \u00e9 recomendado: por n\u00e3o ter uma atualiza\u00e7\u00e3o a muito tempo. Veja que setup.py n\u00e3o pode significativamente, explicitamente, declarar que precisamos do setuptools nem explicitar a necessidade de uma vers\u00e3o espec\u00edfica.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">O m\u00ednimo setup.py ir\u00e1 funcionar assim:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \" >import setuptools\nsetuptools.setup(\npackages=setuptools.find_packages(),\n)<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">A documenta\u00e7\u00e3o oficial chama muitos outros campos &#8220;necess\u00e1rios&#8221; por alguma raz\u00e3o, o pacote pode ser constru\u00eddo mesmo que o pacote esteja faltando. Para alguns, os pacotes ficar\u00e1 com um nomes horr\u00edveis, tais como UNKNOWN.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Muito desses campos, claro, s\u00e3o bons para ter. Mas essa estrutura do setup.py n\u00e3o \u00e9 suficiente para criar uma distribui\u00e7\u00e3o local de pacotes do Python no diret\u00f3rio.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Admito que quase sempre, ter\u00e1 outros campos para adicionar. \u00c9 definitivamente o caso que h\u00e1 outros campos que voc\u00ea precisar\u00e1 adicionar nesse pacote, eles ser\u00e3o carregados em um pacote indexado, mesmo se for um indexado privado.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u00c9 uma boa ideia adicionar pelo menos o &#8220;nome&#8221; do campo. Isso te dar\u00e1 um nome para a distribui\u00e7\u00e3o. \u00c9 quase sempre um boa ideia nome\u00e1-lo depois do pacote top-level da distribui\u00e7\u00e3o.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Uma t\u00edpica hierarquia de c\u00f3digo, seria parecido com essa:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \" >setup.py\nimport setuptools\nsetuptools.setup(\nname='my_special_package',\npackages=setuptools.find_packages(),\n)\nmy_special_package\/\n__init__.py\nanother_module.py\ntests\/\ntest_another_module.py<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Outro campo que \u00e9 uma boa ideia ter \u00e9 a vers\u00e3o. Versionar um software \u00e9 sempre dif\u00edcil. Mesmo sendo um n\u00famero cont\u00ednuo, \u00e9 uma boa maneira de responder: &#8220;O que est\u00e1 rodando, uma vers\u00e3o nova ou velha?&#8221;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">H\u00e1 algumas ferramentas que podem ajudar com o controle da vers\u00e3o, especialmente assumindo que queremos disponibilizar para o Python em execu\u00e7\u00e3o. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Especialmente se fizer com o Calendar Versioning, que automatiza algumas coisas que s\u00e3o chatas. bumpversion \u00e9 uma ferramenta \u00fatil, especialmente quando escolhemos uma vers\u00e3o sem\u00e2ntica.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Finalmente, o versioneer tem uma f\u00e1cil integra\u00e7\u00e3o com o sistema de controle de vers\u00e3o git, ent\u00e3o uma tag \u00e9 tudo o que precisa ser feito para uma nova vers\u00e3o.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Outro campo popular no setup.py, o qual n\u00e3o \u00e9 marcado como &#8220;necess\u00e1rio&#8221; na documenta\u00e7\u00e3o, mas est\u00e1 presente em quase todos os pacotes, \u00e9 o install_requires.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Isso \u00e9 como marcamos outras distribui\u00e7\u00f5es que nosso c\u00f3digo utiliza. \u00c9 uma boa pr\u00e1tica colocar &#8220;loose&#8221; depend\u00eancias no setup.py. Isso contrasta com depend\u00eancias exatas, o qual espec\u00edfica uma vers\u00e3o espec\u00edfica.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Uma depend\u00eancia loose \u00e9 algo assim: Twisted >=17.5 &#8211; especificando a m\u00ednima vers\u00e3o, mas n\u00e3o a m\u00e1xima. Depend\u00eancias exatas \u00e9 algo assim: Twisted==18.1, \u00e9 uma m\u00e1 ideia fazer isso no setup.py. S\u00f3 se for em um caso especial.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Por fim, \u00e9 uma boa id\u00e9ia fornecer aos find_packages uma lista de permiss\u00f5es, para evitar arquivos esp\u00farios. Por exemplo,<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">setuptools.find_packages(include=[&#8220;my_package\u2217&#8221;])<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Tendo o setup.py e algum c\u00f3digo Python, podemos criar uma distribui\u00e7\u00e3o. H\u00e1 v\u00e1rios formatos de distribui\u00e7\u00e3o, veremos o wheel. Se meu-diretorio \u00e9 o que tem o setup.py, execute pip wheel meu-diretorio, isso produzir\u00e1 um wheel, como tamb\u00e9m os wheels de todas as depend\u00eancias. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Por padr\u00e3o coloca-se o wheels no diret\u00f3rio que se encontra, mas geralmente n\u00e3o \u00e9 o que queremos. Utilizando &#8211;wheels-dir&lt;diret\u00f3rio-de-sa\u00edda> voc\u00ea pode colocar o wheel e qualquer depend\u00eancia na pasta que voc\u00ea deseja.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">H\u00e1 muitas coisas que n\u00f3s podemos fazer com o wheels, mas o importante \u00e9 que podemos fazer \u00e9 pip install &lt;arquivo wheel>. Podemos tamb\u00e9m fazer assim: pip install &lt;arquivo wheel> &#8211;wheel-dir &lt;diret\u00f3rio de sa\u00edda>, ent\u00e3o o pip usar\u00e1 o wheels no diret\u00f3rio e n\u00e3o sair\u00e1 do PyPI. Isso \u00e9 \u00fatil para reproduzir instala\u00e7\u00f5es, ou fornecer no modo air-gapped. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Fonte: DevOps in Python: Infrastructure as Python<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Setup e Wheels O termo &#8220;third party&#8221; (com um &#8220;pacote de terceiros&#8221;) referencia-se a algu\u00e9m que tenha como principal fun\u00e7\u00e3o desenvolvedor do core do Python (&#8220;primeiro grupo&#8221;) ou o desenvolvedor local (&#8220;segundo grupo&#8221;). Instalamos pacotes do &#8220;primeiro grupo&#8221; na instala\u00e7\u00e3o do Python. Usamos o pip e virtualenv para instalar &#8220;pacotes de terceiros&#8221;. Agora vamos para [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":171,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[42],"tags":[],"class_list":["post-1016","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops"],"_links":{"self":[{"href":"https:\/\/micheladrianomedeiros.com.br\/blog\/wp-json\/wp\/v2\/posts\/1016","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/micheladrianomedeiros.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/micheladrianomedeiros.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/micheladrianomedeiros.com.br\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/micheladrianomedeiros.com.br\/blog\/wp-json\/wp\/v2\/comments?post=1016"}],"version-history":[{"count":4,"href":"https:\/\/micheladrianomedeiros.com.br\/blog\/wp-json\/wp\/v2\/posts\/1016\/revisions"}],"predecessor-version":[{"id":1020,"href":"https:\/\/micheladrianomedeiros.com.br\/blog\/wp-json\/wp\/v2\/posts\/1016\/revisions\/1020"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/micheladrianomedeiros.com.br\/blog\/wp-json\/wp\/v2\/media\/171"}],"wp:attachment":[{"href":"https:\/\/micheladrianomedeiros.com.br\/blog\/wp-json\/wp\/v2\/media?parent=1016"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/micheladrianomedeiros.com.br\/blog\/wp-json\/wp\/v2\/categories?post=1016"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/micheladrianomedeiros.com.br\/blog\/wp-json\/wp\/v2\/tags?post=1016"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}