{"id":24996,"date":"2023-10-17T05:00:00","date_gmt":"2023-10-17T03:00:00","guid":{"rendered":"https:\/\/sii.pl\/blog\/?p=24996"},"modified":"2023-10-11T14:29:22","modified_gmt":"2023-10-11T12:29:22","slug":"statyczna-analiza-kodu-w-pythonie","status":"publish","type":"post","link":"https:\/\/sii.pl\/blog\/statyczna-analiza-kodu-w-pythonie\/","title":{"rendered":"Statyczna analiza kodu w Pythonie"},"content":{"rendered":"\n<p>Wsp\u00f3\u0142cze\u015bnie profesjonalne zespo\u0142y programist\u00f3w przyk\u0142adaj\u0105 ogromn\u0105 wag\u0119 do jako\u015bci wytwarzanego oprogramowania, jak r\u00f3wnie\u017c optymalizacji czasu potrzebnego do jego sprawdzenia. Wysoki standard kodu bezpo\u015brednio koreluje z bezpiecze\u0144stwem, stabilno\u015bci\u0105 i niezawodno\u015bci\u0105 produkt\u00f3w. Aby zachowa\u0107 t\u0119 jako\u015b\u0107, wiele zespo\u0142\u00f3w stosuje techniki, takie jak manualne przegl\u0105danie kodu (ang. code review), testowanie automatyczne i r\u0119czne.<\/p>\n\n\n\n<p>Chocia\u017c przegl\u0105d kodu i testy automatyczne s\u0105 wa\u017cne dla tworzenia kodu wysokiej jako\u015bci, nie odkryj\u0105 one wszystkich problem\u00f3w w oprogramowaniu. Poniewa\u017c recenzenci kodu i autorzy test\u00f3w automatycznych to ludzie, b\u0142\u0119dy i luki w zabezpieczeniach cz\u0119sto przedostaj\u0105 si\u0119 do \u015brodowiska produkcyjnego. Analiza kodu \u017ar\u00f3d\u0142owego mo\u017ce zapobiec po\u0142owie problem\u00f3w, kt\u00f3re cz\u0119sto prze\u015blizguj\u0105 si\u0119 przez p\u0119kni\u0119cia w produkcji.<\/p>\n\n\n\n<p><strong>Zamiast gasi\u0107 po\u017cary<\/strong> spowodowane z\u0142ym kodem, lepszym podej\u015bciem by\u0142oby w\u0142\u0105czenie zapewniania jako\u015bci i egzekwowanie standard\u00f3w kodowania na wczesnym etapie cyklu \u017cycia oprogramowania za pomoc\u0105 statycznej analizy kodu.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Czym jest statyczna analiza kodu?<\/strong><\/h2>\n\n\n\n<p>Statyczna analiza kodu to proces, kt\u00f3ry bez uruchamiania analizuje struktur\u0119 kodu \u017ar\u00f3d\u0142owego lub kodu skompilowanego. S\u0142u\u017cy do wykrywania potencjalnych luk w zabezpieczeniach, ale r\u00f3wnie\u017c uwsp\u00f3lnia i poprawia jako\u015b\u0107 poprzez por\u00f3wnanie z og\u00f3lnie przyj\u0119tymi standardami.<\/p>\n\n\n\n<p>Ka\u017cdy j\u0119zyk programowania ma sw\u00f3j indywidualny zestaw regu\u0142\/sugestii\/wytycznych dotycz\u0105cych jako\u015bci kodu. W Pythonie jest to dokument <a href=\"https:\/\/peps.python.org\/pep-0008\/\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >Python Enhancement Proposals<\/a> (w skr\u00f3cie PEP).<\/p>\n\n\n\n<p>Szczeg\u00f3\u0142owo\u015b\u0107 PEP potrafi przyt\u0142acza\u0107, ale te\u017c nie ma potrzeby zapami\u0119tania wszystkich wytycznych. Wsp\u00f3\u0142czesne IDE (na przyk\u0142ad Pycharm, VS Code) potrafi\u0105 analizowa\u0107 kod \u201ew locie\u201d.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img decoding=\"async\" width=\"514\" height=\"137\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/10\/pycharm_lint.png\" alt=\"kod\" class=\"wp-image-24997\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/10\/pycharm_lint.png 514w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/10\/pycharm_lint-300x80.png 300w\" sizes=\"(max-width: 514px) 100vw, 514px\" \/><\/figure>\n\n\n\n<p>Niestety, nadal nie jest to rozwi\u0105zanie idealne. Nie wszyscy programi\u015bci korzystaj\u0105 z tego samego IDE, a pomi\u0119dzy poszczeg\u00f3lnymi programami potrafi\u0105 pojawia\u0107 si\u0119 r\u00f3\u017cnice w interpretacji PEP. Aby <strong>ujednolici\u0107 spos\u00f3b analizy<\/strong>, warto zastosowa\u0107 dedykowane narz\u0119dzia, kt\u00f3re jednocze\u015bnie s\u0105 proste w automatyzacji CI (ang. <a href=\"https:\/\/sii.pl\/blog\/continuous-integration-i-continuous-delivery-dobre-praktyki\/?category=development-na-miekko&amp;tag=continuous-delivery,continuous-integration,devops,dobre-praktyki,testing\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\">continous integration<\/a>). Takimi narz\u0119dziami s\u0105:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Pylint,<\/strong><\/li>\n\n\n\n<li><strong>Black,<\/strong><\/li>\n\n\n\n<li><strong>Isort<\/strong>,<\/li>\n<\/ul>\n\n\n\n<p>potocznie nazywanymi \u201elinterami\u201d.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Pylint<\/strong><\/h2>\n\n\n\n<p><a href=\"https:\/\/pylint.readthedocs.io\/en\/stable\/\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >Pylint<\/a> jest jednym z najbardziej rozbudowanych i zaawansowanych linter\u00f3w. Jednocze\u015bnie pr\u00f3g wej\u015bcia i pocz\u0105tkowa konfiguracja s\u0105 bardzo proste i intuicyjne.<\/p>\n\n\n\n<p>Bardzo wa\u017cne pytanie brzmi: <strong>co wyr\u00f3\u017cnia Pylint<\/strong> od reszty program\u00f3w do statycznej analizy kodu?<\/p>\n\n\n\n<p>Pylint nie ufa typowaniu zapisanemu w kodzie, zawsze sprawdza typ w ka\u017cdym w\u0119\u017ale z osobna. Niestety, powoduje to znaczne wyd\u0142u\u017cenie czasu skanowania. Dodatkowo posiada mechanizm plugin\u00f3w (na przyk\u0142ad od sprawdzania pisowni nazw, docstring\u00f3w itp.).<\/p>\n\n\n\n<p>Aby go zainstalowa\u0107, nale\u017cy wykona\u0107 w terminalu komend\u0119:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\npip install pylint\n<\/pre><\/div>\n\n\n<p>Istnieje r\u00f3wnie\u017c mo\u017cliwo\u015b\u0107 sprawdzania gramatyki. Wymaga to instalacji dodatkowych plugin\u00f3w:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\npip install pylint&#x5B;spelling]\n<\/pre><\/div>\n\n\n<p>Dzia\u0142anie Pylint zaprezentowa\u0107 mo\u017cna na przyk\u0142adzie pliku <em>simplecaesar.py. <\/em>Jego zawarto\u015b\u0107:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n#!\/usr\/bin\/env python3\n\nimport string\n\nshift = 3\nchoice = input(&quot;would you like to encode or decode?&quot;)\nword = input(&quot;Please enter text&quot;)\nletters = string.ascii_letters + string.punctuation + string.digits\nencoded = &quot;&quot;\nif choice == &quot;encode&quot;:\n    for letter in word:\n        if letter == &quot; &quot;:\n            encoded = encoded + &quot; &quot;\n        else:\n            x = letters.index(letter) + shift\n            encoded = encoded + letters&#x5B;x]\nif choice == &quot;decode&quot;:\n    for letter in word:\n        if letter == &quot; &quot;:\n            encoded = encoded + &quot; &quot;\n        else:\n            x = letters.index(letter) - shift\n            encoded = encoded + letters&#x5B;x]\n\nprint(encoded)\n<\/pre><\/div>\n\n\n<p>Przy u\u017cyciu najprostszej dost\u0119pnej komendy:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\npylint simplecaesar.py\n<\/pre><\/div>\n\n\n<p>Wynikiem b\u0119dzie \u201esprawozdanie\u201d z jako\u015bci kodu:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n************* Module simplecaesar\nsimplecaesar.py:1:0: C0114: Missing module docstring (missing-module-docstring)\nsimplecaesar.py:5:0: C0103: Constant name &quot;shift&quot; doesn&#039;t conform to UPPER_CASE naming style (invalid-name)\nsimplecaesar.py:8:0: C0103: Constant name &quot;letters&quot; doesn&#039;t conform to UPPER_CASE naming style (invalid-name)\nsimplecaesar.py:9:0: C0103: Constant name &quot;encoded&quot; doesn&#039;t conform to UPPER_CASE naming style (invalid-name)\nsimplecaesar.py:13:12: C0103: Constant name &quot;encoded&quot; doesn&#039;t conform to UPPER_CASE naming style (invalid-name)\nsimplecaesar.py:15:12: C0103: Constant name &quot;x&quot; doesn&#039;t conform to UPPER_CASE naming style (invalid-name)\nsimplecaesar.py:16:12: C0103: Constant name &quot;encoded&quot; doesn&#039;t conform to UPPER_CASE naming style (invalid-name)\nsimplecaesar.py:20:12: C0103: Constant name &quot;encoded&quot; doesn&#039;t conform to UPPER_CASE naming style (invalid-name)\nsimplecaesar.py:22:12: C0103: Constant name &quot;x&quot; doesn&#039;t conform to UPPER_CASE naming style (invalid-name)\nsimplecaesar.py:23:12: C0103: Constant name &quot;encoded&quot; doesn&#039;t conform to UPPER_CASE naming style (invalid-name)\n\n-----------------------------------\nYour code has been rated at 4.74\/10\n<\/pre><\/div>\n\n\n<p>Rozbijmy na czynniki powy\u017cszy raport na podstawie pierwszego znalezionego problemu:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n&quot;simplecaesar.py:1:0: C0114: Missing module docstring (missing-module-docstring)&quot;\n<\/pre><\/div>\n\n\n<p>Oznacza to, \u017ce w linii pierwszej, w kolumnie zerowej (sama g\u00f3ra pliku) naruszana jest konwencja <em>C0114<\/em>. Istotna jest r\u00f3wnie\u017c czytelna nazwa: <em>missing-module-docstring. <\/em>Je\u017celi chcemy uzyska\u0107 dodatkow\u0105 informacj\u0119 na temat konkretnego b\u0142\u0119du, niepotrzebne jest przeszukiwanie internetu. Wystarczy komenda:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\npylint --help-msg=missing-module-docstring\n<\/pre><\/div>\n\n\n<p>kt\u00f3ra zwr\u00f3ci wynik:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n:missing-module-docstring (C0114): *Missing module docstring*\n  Used when a module has no docstring.Empty modules do not require a docstring.\n  This message belongs to the basic checker.\n<\/pre><\/div>\n\n\n<p>Dzi\u0119ki temu zdob\u0119dziemy wiedz\u0119, co nale\u017cy poprawi\u0107.<\/p>\n\n\n\n<p>Wracaj\u0105c do raportu wygenerowanego przez Pylint. Na dole mo\u017cna zauwa\u017cy\u0107:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nYour code has been rated at 4.74\/10\n<\/pre><\/div>\n\n\n<p>Jest to globalna punktacja, a maksymalna warto\u015b\u0107 to 10. Ka\u017cdy kod powinien by\u0107 oceniany na w\u0142a\u015bnie tak\u0105 liczb\u0119 punkt\u00f3w. Z ka\u017cdym poprawionym b\u0142\u0119dem punktacja wzrasta.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Pylint w praktyce<\/strong><\/h3>\n\n\n\n<p>Dobrze, w takim razie spr\u00f3bujmy naprawi\u0107 pierwszy problem z brakuj\u0105cym docstringiem na pocz\u0105tku pliku pythonowego. Obecnie plik <em>simplecaesar.py <\/em>zosta\u0142 zaktualizowany w ten spos\u00f3b na samej g\u00f3rze:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n#!\/usr\/bin\/env python3\n\n&quot;&quot;&quot;This script prompts a user to enter a message to encode or decode\nusing a classic Caesar shift substitution (3 letter shift)&quot;&quot;&quot;\n\nimport string\n<\/pre><\/div>\n\n\n<p>Gdy ponownie wygenerujemy raport, otrzymamy zmniejszon\u0105 liczb\u0119 b\u0142\u0119d\u00f3w i podniesion\u0105 punktacj\u0119:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n************* Module simplecaesar\nsimplecaesar.py:8:0: C0103: Constant name &quot;shift&quot; doesn&#039;t conform to UPPER_CASE naming style (invalid-name)\nsimplecaesar.py:11:0: C0103: Constant name &quot;letters&quot; doesn&#039;t conform to UPPER_CASE naming style (invalid-name)\nsimplecaesar.py:12:0: C0103: Constant name &quot;encoded&quot; doesn&#039;t conform to UPPER_CASE naming style (invalid-name)\nsimplecaesar.py:16:12: C0103: Constant name &quot;encoded&quot; doesn&#039;t conform to UPPER_CASE naming style (invalid-name)\nsimplecaesar.py:18:12: C0103: Constant name &quot;x&quot; doesn&#039;t conform to UPPER_CASE naming style (invalid-name)\nsimplecaesar.py:19:12: C0103: Constant name &quot;encoded&quot; doesn&#039;t conform to UPPER_CASE naming style (invalid-name)\nsimplecaesar.py:23:12: C0103: Constant name &quot;encoded&quot; doesn&#039;t conform to UPPER_CASE naming style (invalid-name)\nsimplecaesar.py:25:12: C0103: Constant name &quot;x&quot; doesn&#039;t conform to UPPER_CASE naming style (invalid-name)\nsimplecaesar.py:26:12: C0103: Constant name &quot;encoded&quot; doesn&#039;t conform to UPPER_CASE naming style (invalid-name)\n\n------------------------------------------------------------------\nYour code has been rated at 5.26\/10 (previous run: 4.74\/10, +0.53)\n<\/pre><\/div>\n\n\n<p>W ostatniej linii dowiedzieli\u015bmy si\u0119, \u017ce punktacja wzros\u0142a, co jest zgodne z planem. Pozosta\u0142 tylko b\u0142\u0105d<em> invalid-name (C0103). <\/em>Istniej\u0105 do\u015b\u0107 dobrze zdefiniowane konwencje dotycz\u0105ce nazewnictwa takich rzeczy, jak zmienne instancji, funkcje, klasy itp. Konwencje skupiaj\u0105 si\u0119 na u\u017cyciu WIELKICH i ma\u0142ych liter, a tak\u017ce znak\u00f3w oddzielaj\u0105cych wiele s\u0142\u00f3w w nazwie. Nadaje si\u0119 to dobrze do sprawdzania za pomoc\u0105 wyra\u017cenia regularnego, dlatego powinno pasowa\u0107 do <em>(([A-Z_][A-Z1-9_]*)|(__.*__))$.<\/em><\/p>\n\n\n\n<p>W tym przypadku Pylint m\u00f3wi nam, \u017ce te zmienne wydaj\u0105 si\u0119 by\u0107 sta\u0142ymi i wszystkie powinny by\u0107 pisane WIELKIMI LITERAMI. Mo\u017cna tworzy\u0107 w\u0142asne, wewn\u0119trzne konwencje nazewnictwa, ale na potrzeby tego samouczka chcemy trzyma\u0107 si\u0119 standardu <em>PEP 8<\/em>. W tym przypadku zadeklarowane przez nas zmienne powinny by\u0107 zgodne z konwencj\u0105 ma\u0142ych liter. Odpowiednia regu\u0142a wygl\u0105da\u0142aby mniej wi\u0119cej tak: \u201epowinno pasowa\u0107 do [a-z_][a-z0-9_]{2,30}$\u201d. Zwr\u00f3\u0107 uwag\u0119 na ma\u0142e litery w wyra\u017ceniu regularnym (a-z kontra A-Z).<\/p>\n\n\n\n<p>Je\u017celi wygenerujemy raport przy u\u017cyciu tej komendy (z now\u0105 regu\u0142\u0105 nazewnictwa):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\npylint simplecaesar.py --const-rgx=&#039;&#x5B;a-z\\_]&#x5B;a-z0-9\\_]{2,30}$&#039;\n<\/pre><\/div>\n\n\n<p>To otrzymamy zaktualizowane sprawozdanie:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n************* Module simplecaesar\nsimplecaesar.py:18:12: C0103: Constant name &quot;x&quot; doesn&#039;t conform to &#039;&#x5B;a-z\\\\_]&#x5B;a-z0-9\\\\_]{2,30}$&#039; pattern (invalid-name)\nsimplecaesar.py:25:12: C0103: Constant name &quot;x&quot; doesn&#039;t conform to &#039;&#x5B;a-z\\\\_]&#x5B;a-z0-9\\\\_]{2,30}$&#039; pattern (invalid-name)\n\n------------------------------------------------------------------\nYour code has been rated at 8.95\/10 (previous run: 5.26\/10, +3.68)\n<\/pre><\/div>\n\n\n<p>Ci\u0105g\u0142e okre\u015blanie tego wyra\u017cenia regularnego w wierszu polece\u0144 by\u0142oby naprawd\u0119 uci\u0105\u017cliwe, szczeg\u00f3lnie je\u015bli u\u017cywamy wielu innych opcji. Do tego w\u0142a\u015bnie s\u0142u\u017cy <strong>plik konfiguracyjny<\/strong>. Mo\u017cna zorganizowa\u0107 Pylint tak, aby przechowywa\u0142 opcje, by nie trzeba by\u0142o deklarowa\u0107 ich w wierszu polece\u0144.<\/p>\n\n\n\n<p>Korzystanie z pliku konfiguracyjnego to dobry spos\u00f3b na sformalizowanie regu\u0142 i szybkie udost\u0119pnienie ich innym. Wywo\u0142anie <em>pylint &#8211;generate-toml-config<\/em> spowoduje utworzenie przyk\u0142adowej sekcji <em>.toml<\/em> ze wszystkimi opcjami ustawionymi i wyja\u015bnionymi w komentarzach. Mo\u017cna to nast\u0119pnie doda\u0107 do pliku <em>pyproject.toml<\/em> lub dowolnego innego pliku <em>.toml<\/em> wskazanego opcj\u0105 <em>&#8211;rcfile<\/em>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Black<\/strong><\/h2>\n\n\n\n<p><a href=\"https:\/\/black.readthedocs.io\/en\/stable\/index.html\" rel=\"nofollow\" >Black<\/a> stanowi zupe\u0142nie inn\u0105 koncepcj\u0119 linter\u00f3w. W por\u00f3wnaniu do Pylinta <strong>nie tylko wskazuje b\u0142\u0119dy, ale r\u00f3wnie\u017c potrafi je poprawia\u0107<\/strong>. Nale\u017cy jednak pami\u0119ta\u0107, \u017ce jego mo\u017cliwo\u015bci s\u0105 du\u017co mniejsze ni\u017c Pylinta (nie pokrywa tak wielu konwencji). Kolejn\u0105 kwesti\u0105 wart\u0105 przemy\u015blenia jest styl, jaki wprowadza Black. Dla cz\u0119\u015bci os\u00f3b potrafi by\u0107 nieczytelny, co oczywi\u015bcie nie jest niczym z\u0142ym.<\/p>\n\n\n\n<p>Wprowadzenie konkretnego stylu kodu dla ca\u0142ego projektu oznacza wi\u0119ksz\u0105 powtarzalno\u015b\u0107 kodu, co w perspektywie czasu przek\u0142ada si\u0119 na jego czytelno\u015b\u0107. Formatowanie wykonywane przez Black mo\u017cna do\u0142\u0105czy\u0107 do automatyzacji proces\u00f3w, np. pre-commit, b\u0105d\u017a przy budowaniu kodu \u017ar\u00f3d\u0142owego. W ten spos\u00f3b mamy pewno\u015b\u0107, \u017ce ca\u0142y kod cechuje si\u0119 podobnym stylem.<\/p>\n\n\n\n<p>Black mo\u017cna zainstalowa\u0107 standardow\u0105 komend\u0105 pip:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\npip install black\n<\/pre><\/div>\n\n\n<p>Przyk\u0142adowy kod:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\npip install black\n\n# 1.15\n\nx = {  &#039;a&#039;:37,&#039;b&#039;:42,\n\n&#039;c&#039;:927}\n\nclass Foo  (     object  ):\n  def f    (self   ):\n    return       37*-2\n  def g(self, x,y=42):\n      return y\n\ndef very_important_function(template: str,*variables,file: os.PathLike,debug:bool=False,):\n    &quot;&quot;&quot;Applies `variables` to the `template` and writes to `file`.&quot;&quot;&quot;\n    with open(file, &quot;w&quot;) as f:\n     ...\n<\/pre><\/div>\n\n\n<p>Po sformatowaniu przez Black komend\u0105:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nblack {source_file_or_directory}...\n<\/pre><\/div>\n\n\n<p>Otrzymamy uporz\u0105dkowany skrypt:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nx = {&quot;a&quot;: 37, &quot;b&quot;: 42, &quot;c&quot;: 927}\n\n\nclass Foo(object):\n    def f(self):\n        return 37 * -2\n\n    def g(self, x, y=42):\n        return y\n\n\ndef very_important_function(\n    template: str,\n    *variables,\n    file: os.PathLike,\n    debug: bool = False,\n):\n    &quot;&quot;&quot;Applies `variables` to the `template` and writes to `file`.&quot;&quot;&quot;\n    with open(file, &quot;w&quot;) as f:\n        ...\n<\/pre><\/div>\n\n\n<p>Black mo\u017ce r\u00f3wnie\u017c generowa\u0107 raport, bez jakichkolwiek zmian w kodzie. Do tego mo\u017cna doda\u0107 na ko\u0144cu komendy uruchomieniowej parametr <em>\u2013check. <\/em>W ten spos\u00f3b otrzymamy kr\u00f3tki wynik:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n$ black test.py --check\nwould reformat test.py\nOh no! \ud83d\udca5 \ud83d\udc94 \ud83d\udca5\n1 file would be reformatted.\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\"><strong>Podsumowanie<\/strong><\/h2>\n\n\n\n<p>Na rynku dost\u0119pnych jest wiele narz\u0119dzi do statycznej analizy kodu. Optymalizacja czasu i zwi\u0119kszona jako\u015b\u0107 kodu zdecydowanie zach\u0119caj\u0105 do wdro\u017cenia tych rozwi\u0105za\u0144 nie tylko w obszarze profesjonalnym, ale r\u00f3wnie\u017c w prywatnym kodzie \u017ar\u00f3d\u0142owym.<\/p>\n\n\n\n<p>Przedstawione w tym artykule programy s\u0105 tylko jednymi z wielu dost\u0119pnych na rynku rozwi\u0105za\u0144. Warto r\u00f3wnie\u017c wspomnie\u0107 o kilku innych rozwi\u0105zaniach takich jak:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Flake8,<\/li>\n\n\n\n<li>Ruff,<\/li>\n\n\n\n<li>Isort.<\/li>\n<\/ul>\n\n\n\n<p>Dzia\u0142aj\u0105 na bardzo podobnej zasadzie, z r\u00f3\u017cn\u0105 list\u0105 zaimplementowanych regu\u0142.<\/p>\n\n\n\n<p>Niezale\u017cnie od tego, kt\u00f3re narz\u0119dzie wybierzesz, zdecydowanie podniesie jako\u015b\u0107 dostarczanego kodu w bardzo kr\u00f3tkim czasie.<\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;24996&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;3&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;11&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;5\\\/5 ( votes: 3)&quot;,&quot;size&quot;:&quot;18&quot;,&quot;title&quot;:&quot;Statyczna analiza kodu w Pythonie&quot;,&quot;width&quot;:&quot;139.5&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} ( {votes}: {count})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 139.5px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 14.4px;\">\n            5\/5 ( votes: 3)    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>Wsp\u00f3\u0142cze\u015bnie profesjonalne zespo\u0142y programist\u00f3w przyk\u0142adaj\u0105 ogromn\u0105 wag\u0119 do jako\u015bci wytwarzanego oprogramowania, jak r\u00f3wnie\u017c optymalizacji czasu potrzebnego do jego sprawdzenia. Wysoki &hellip; <a class=\"continued-btn\" href=\"https:\/\/sii.pl\/blog\/statyczna-analiza-kodu-w-pythonie\/\">Continued<\/a><\/p>\n","protected":false},"author":543,"featured_media":25008,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_editorskit_title_hidden":false,"_editorskit_reading_time":0,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","inline_featured_image":false,"footnotes":""},"categories":[1314],"tags":[1819,1818,1546,584],"class_list":["post-24996","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development-na-twardo","tag-black","tag-pylint","tag-przeglad-narzedzi","tag-python"],"acf":[],"aioseo_notices":[],"republish_history":[],"featured_media_url":"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2023\/10\/Statyczna-analiza-kodu-w-Pythonie.jpg","category_names":["Development na twardo"],"_links":{"self":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/24996"}],"collection":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/users\/543"}],"replies":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/comments?post=24996"}],"version-history":[{"count":3,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/24996\/revisions"}],"predecessor-version":[{"id":25007,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/24996\/revisions\/25007"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media\/25008"}],"wp:attachment":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media?parent=24996"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/categories?post=24996"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/tags?post=24996"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}