{"id":38479,"date":"2019-10-31T22:23:56","date_gmt":"2019-10-31T19:23:56","guid":{"rendered":"https:\/\/prohoster.info\/blog\/put-k-proverke-tipov-4-millionov-strok-python-koda-chast-2\/"},"modified":"2019-10-31T22:23:56","modified_gmt":"2019-10-31T19:23:56","slug":"put-k-proverke-tipov-4-millionov-strok-python-koda-chast-2","status":"publish","type":"post","link":"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/put-k-proverke-tipov-4-millionov-strok-python-koda-chast-2","title":{"rendered":"Tee 4 miljoni rea Python-koodi t\u00fc\u00fcpide kontrollimiseni. 2. osa","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>T\u00e4na avaldame teise osa materjali t\u00f5lkest, kuidas Dropboxis korraldati t\u00fc\u00fcbi kontrollimist mitme miljoni rea Python koodi kohta.<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/468235\/\"><img decoding=\"async\" alt=\"Tee 4 miljoni rea Python-koodi t\u00fc\u00fcpide kontrollimiseni. 2. osa\" src=\"\/wp-content\/uploads\/2019\/09\/3f8f396d724153a0374a3fadca190d55.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><\/p>\n<p>\u2192 <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/468233\/\">Loe esimest osa<\/a><\/noindex><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Ametlik t\u00fc\u00fcbi tugi (PEP 484)<\/h2>\n<p>\n2014. aasta Hack Weeki ajal tegime Dropboxis esimesi t\u00f5siseid katsetusi mypyga. Hack Week on \u00fcritus, mida korraldab Dropbox n\u00e4dal aega, mil t\u00f6\u00f6tajad saavad t\u00f6\u00f6tada millegi kallal, mis neid huvitab! Paljud Dropboxi tuntud tehnoloogiaprojektid algasid just sellistel \u00fcritustel. Selle eksperimendi tulemusena j\u00f5udsime j\u00e4reldusele, et mypy n\u00e4eb v\u00e4lja lubav, kuigi see projekt polnud veel laiemaks kasutamiseks valmis.<\/p>\n<p>Sel ajal valitses \u00f5hus idee Pythonit\u00fc\u00fcpide vihjete standardiseerimisest. Nagu ma varem mainisin, alates Python 3.0 oli v\u00f5imalik kasutada funktsioonide t\u00fc\u00fcbi annotateeringuid, kuid need olid lihtsalt suvalised v\u00e4ljendid, ilma kindla s\u00fcntaksita ja semantikata. Programmeerimise k\u00e4igus ignoreeriti neid annotateeringuid enamasti t\u00e4ielikult. P\u00e4rast Hack Weeki alustasime semantika standardiseerimise kallal t\u00f6\u00f6tamist. See t\u00f6\u00f6 viis PEP 484. <noindex><a rel=\"nofollow\" href=\"https:\/\/www.python.org\/dev\/peps\/pep-0484\/\">PEP 484<\/a><\/noindex> (selle dokumendi kallal t\u00f6\u00f6tasid koos Guido van Rossum, \u0141ukasz Langa ja mina).<\/p>\n<p>Meie motiive v\u00f5is vaadata kahest k\u00fcljest. Esiteks lootsime, et kogu Python'i \u00f6kos\u00fcsteem v\u00f5iks omaks v\u00f5tta \u00fchtse l\u00e4henemise t\u00fc\u00fcbi vihjete kasutamisele (type hints \u2014 termin, mida Pythonis kasutatakse t\u00fc\u00fcbi annotateeringute analoogina). See oleks, arvestades v\u00f5imalikke riske, parem kui paljude \u00fcksteisega \u00fchilduvate l\u00e4henemiste kasutamine. Teiseks soovisime avatud arutelu t\u00fc\u00fcbi annotateerimise mehhanismide \u00fcle koos paljude Python'i kogukonna esindajatega. Osaliselt oli see soov tingitud hirmust, et me ei sooviks paista nagu \u201ek\u00e4tkijad\u201d keele p\u00f5hialuste ideede suhtes laiemas Python'i programmeerijate ringis. See on d\u00fcnaamiliselt t\u00fc\u00fcbitud keel, tuntud \u201epartide t\u00fc\u00fcbi\u201d t\u00f5ttu. Alguses v\u00f5ib kogukonnas olla m\u00f5ned kahtlused staatilise t\u00fc\u00fcbistamise idee suhtes. Kuid selline hoiak n\u00f5rgenes l\u00f5puks \u2014 p\u00e4rast seda, kui sai selgeks, et staatilist t\u00fc\u00fcbistamist ei kavatseta muuta kohustuslikuks (ja p\u00e4rast seda, kui inimesed m\u00f5istsid, et see on t\u00f5eliselt kasulik).<\/p>\n<p>L\u00f5puks vastu v\u00f5etud t\u00fc\u00fcbi soovituste s\u00fcntaks sarnanes v\u00e4ga sellele, mida tol ajal toetas mypy. PEP 484 dokument ilmus koos Python 3.5-ga 2015. aastal. Python ei olnud enam ainult d\u00fcnaamilise t\u00fcpiseerimisega keel. Mulle meeldib m\u00f5elda sellele s\u00fcndmusele kui olulisele verstapostile Python\u2019i ajaloos.<\/p>\n<h2>Migratsiooni algus<\/h2>\n<p>\n2015. aasta l\u00f5puks loodi Dropboxis mypy arendamiseks kolme inimesega meeskond. Sellesse kuulusid Guido van Rossum, Greg Price ja David Fisher. Sellest hetkest alates hakkas olukord kiiresti arenema. Esimene takistus mypy kasvu teel oli j\u00f5udlus. Nagu ma eelnevalt mainisin, m\u00f5tlesin projekti varases arengus mypy realiseerimise C keelde \u00fcmber t\u00f5lkida, kuid see idee t\u00f5mmati hetkel k\u00f5rvale. Me olime takerdunud olukorda, kus s\u00fcsteemi k\u00e4itamiseks kasutati CPython\u2019i t\u00f5lgendajat, millel ei olnud piisavat kiirusetootlikkust mypy-sarnaste t\u00f6\u00f6riistade jaoks. (PyPy projekt, alternatiivne Python\u2019i realiseerimine JIT-kompilatsiooniga, ei aidanud ka meid.)<\/p>\n<p>\u00d5nneks aitasid meid m\u00f5ned algoritmilised t\u00e4iustused. Esimene v\u00f5imas \u201ekiirendaja\u201d oli inkrementaalse kontrollimise realiseerimine. Selle t\u00e4iustuse idee oli lihtne: kui k\u00f5iki s\u00f5ltuvusi moodulist alates mypy eelmisest k\u00e4ivitamisest ei ole muudetud, saame s\u00f5ltuvustega t\u00f6\u00f6tamisel kasutada eelmisest sessioonist vahem\u00e4llu salvestatud andmeid. Meil oli vaja vaid kontrollida t\u00fc\u00fcpide muutunud failides ja nendes failides, mis s\u00f5ltusid neist. Mypy l\u00e4ks isegi veidi kaugemale: kui mooduli v\u00e4line liides ei muutunud, arvas mypy, et teisi mooduleid, mis seda moodulit impordivad, ei pea uuesti kontrollima.<\/p>\n<p>Inkrementaalne kontroll aitas meid v\u00e4ga palju olemasoleva koodi suure mahtude annotatsioonide tegemisel. Asi on selles, et see protsess h\u00f5lmab tavaliselt mitmeid iteratiivseid mypy k\u00e4ivitusi, kuna annotatsioonid lisatakse j\u00e4rk-j\u00e4rgult koodi ja paranevad j\u00e4rk-j\u00e4rgult. Esimene mypy k\u00e4ivitus oli endiselt v\u00e4ga aeglane, kuna seda t\u00e4ites tuli kontrollida palju s\u00f5ltuvusi. Seet\u00f5ttu, olukorra parandamiseks, rakendasime kaugkasutuse vahehoidmismehhanismi. Kui mypy tuvastab, et kohalik vahem\u00e4lu on t\u00f5en\u00e4oliselt aegunud, laadib ta kogu koodibaasi jaoks p\u00e4evakohase vahem\u00e4lu v\u00e4ljav\u00f5tte tsentraliseeritud registrist. Seej\u00e4rel viib ta l\u00e4bi inkrementaalse kontrolli, kasutades seda v\u00e4ljav\u00f5tet. See t\u00f5i meid veel \u00fche suure sammu v\u00f5rra l\u00e4hemale mypy tootlikkuse suurendamisele.<\/p>\n<p>See oli kiire ja loomuliku t\u00fc\u00fcbi kontrollimise s\u00fcsteemi juurutamise periood Dropboxis. Aasta l\u00f5puks 2016 oli meil juba umbes 420 000 rida Python-koodi, millel olid t\u00fc\u00fcbiannotatsioonid. Paljud kasutajad suhtusid t\u00fc\u00fcbikontrolli entusiasmiga. Dropboxis kasutas mypy j\u00e4rk-j\u00e4rgult \u00fcha rohkem arendustiime.<\/p>\n<p>K\u00f5ik tundus siis h\u00e4sti, kuid meil oli veel palju teha. Alustasime kasutajate regulaarsete siseuuringute l\u00e4biviimist, et tuvastada projekti probleemsed kohad ja m\u00f5ista, millised k\u00fcsimused tuleb esimesena lahendada (see praktika on ettev\u00f5ttes kasutusel ka t\u00e4nap\u00e4eval). Kaks \u00fclesannet, mis olid selged, osutusid k\u00f5ige olulisemaks. Esiteks, koodi t\u00fc\u00fcpide kattuvuse suurendamine, teiseks, tuli tagada, et mypy t\u00f6\u00f6taks kiiremini. Oli t\u00e4iesti selge, et meie t\u00f6\u00f6 mypy kiirendamise ja ettev\u00f5tte projektidesse juurutamise osas oli veel kaugel l\u00f5puleviimisest. T\u00e4ielikult teades nende kahe \u00fclesande t\u00e4htsust, asusime nende lahendamise juurde.<\/p>\n<h2>Rohkem tootlikkust!<\/h2>\n<p>\nInkrementaalsed kontrollid kiirendasid mypy'd, kuid see t\u00f6\u00f6riist ei olnud endiselt piisavalt kiire. Paljud inkrementsed kontrollid kestsid umbes minute. Selle p\u00f5hjuseks olid ts\u00fcklilised importimised. See ei \u00fcllata t\u00f5en\u00e4oliselt kedagi, kes on t\u00f6\u00f6tanud suurte Python'i koodibaasidega. Meil oli sadu mooduleid, millest iga\u00fcks importis kaudselt k\u00f5ik teised. Kui \u00fckski fail ts\u00fcklis muudeti, pidid mypy t\u00f6\u00f6tlema k\u00f5ik failid, mis kuulusid sellesse ts\u00fcklisse, ja sageli ka k\u00f5ik moodulid, mis importisid mooduleid sellest ts\u00fcklist. \u00dcks neist ts\u00fcklitest oli tuntud kui<\/p>\n<p>Me kaalume ts\u00fckliliste s\u00f5ltuvuste \"lahendamist\", kuid meil polnud selleks ressursse. Koodi oli liiga palju, millega me polnud tuttavad. L\u00f5puks j\u00f5udsime alternatiivse l\u00e4henemiseni. Otsustasime muuta nii, et mypy t\u00f6\u00f6taks kiiresti ka \u201es\u00f5lmedes\u201d. Selle eesm\u00e4rgini j\u00f5udsime mypy daemoniga. Daemon on serveriprotsess, mis rakendab kahte huvitavat funktsionaalsust. Esiteks, ta hoiab kogu koodibaasi teavet m\u00e4lus. See t\u00e4hendab, et iga mypy k\u00e4ivitamise korral ei ole vaja laadida vahem\u00e4llu salvestatud andmeid, mis on seotud tuhandete imporditud s\u00f5ltuvustega. Teiseks anal\u00fc\u00fcsib ta hoolikalt, v\u00e4ikeste struktuuri\u00fcksuste tasandil, s\u00f5ltuvusi funktsioonide ja teiste entiteetide vahel. N\u00e4iteks, kui funktsioon <code>foo<\/code> kutsub \u00fcles funktsiooni <code>bar<\/code>, on olemas s\u00f5ltuvus <code>foo<\/code> alates <code>bar<\/code>. Kui fail muutub, t\u00f6\u00f6tleb daemon esmalt isoleeritult vaid muudetud faili. Seej\u00e4rel vaatab ta, millised muudatused on sellest failist v\u00e4ljapoole n\u00e4htavad, nagu muudetud funktsioonide signatuurid. Daemon kasutab detailset teavet importide kohta vaid nende funktsioonide uutikk kontrollimiseks, mis tegelikult kasutatakse muudetud funktsiooni. Tavaliselt tuleb sellisel l\u00e4henemisel kontrollida vaid v\u00e4ga v\u00e4heseid funktsioone.<\/p>\n<p>Kogu selle rakendamine ei olnud lihtne, kuna mypy algne teostus oli tugevalt suunatud \u00fche faili t\u00f6\u00f6tlemisele korraga. Me pidime silmitsi seisma paljude piirsituatsioonidega, mille tekkimine n\u00f5udis korduvaid kontrollimisi juhtudel, kui koodis midagi muudeti. N\u00e4iteks juhtub see siis, kui klassile m\u00e4\u00e4ratakse uus p\u00f5hiklass. P\u00e4rast seda, kui olime teinud, mida soovisime, suutsime enamikku inkrementaalsetest kontrollidest l\u00e4biviimise aega v\u00e4hendada vaid m\u00f5ne sekundi peale. See tundus meile suure v\u00f5iduna.<\/p>\n<h2>Veelgi suurem tootlikkus!<\/h2>\n<p>\nKoos eelpool mainitud eemaldusega MyPy vahem\u00e4lust lahendas MyPy deemon praktiliselt t\u00e4ielikult probleemid, mis tekkisid, kui programmeerija k\u00e4ivitas tihti t\u00fc\u00fcpi kontrolle, tehes muudatusi ainult v\u00e4hestes failides. Kuid s\u00fcsteemi j\u00f5udlus selle k\u00f5ige ebasoodsamas kasutusvariandis oli endiselt kaugel optimaalsest. MyPy puhas k\u00e4ivitamine v\u00f5is kesta \u00fcle 15 minuti. See oli oluliselt rohkem, kui me rahuldada sooviksime. Igasse n\u00e4dalasse muutus olukord \u00fcha hullemaks, kuna programmeerijad j\u00e4tkasid uue koodi kirjutamist ja olemasolevale koodile annotatsioone lisamist. Meie kasutajad igatsesid endiselt suuremat tootlikkust ning olime hea meelega valmis neid toetama.<\/p>\n<p>Otsustasime naasta \u00fche varasema idee juurde seoses mypy'ga. Nimelt \u2014 Python-koodi muutmine C-koodiks. Cythoni katsetused (see on s\u00fcsteem, mis v\u00f5imaldab t\u00f5lkida Pythonis kirjutatud koodi C-koodiks) ei andnud meile mingeid m\u00e4rgatavaid kiiruskasvuseid, seet\u00f5ttu otsustasime elustada idee luua oma kompilaator. Kuna mypy koodibaas (mis on kirjutatud Pythonis) sisaldas juba k\u00f5iki vajalikke t\u00fc\u00fcbiannotatsioone, tundus, et on v\u00e4\u00e4rt proovida kasutada neid annotatsioone s\u00fcsteemi t\u00f6\u00f6 kiirendamiseks. L\u00f5in kiiresti prototybi, et seda ideed kontrollida. See n\u00e4itas erinevates mikro-benchmarkides \u00fcle 10-kordset j\u00f5udluse t\u00f5usu. Meie idee oli kompileerida Python-moduulid C-moduulideks Cythoni vahenditega ning muuta t\u00fc\u00fcbiannotatsioonid t\u00fc\u00fcpide kontrollideks, mis teostatakse programmi k\u00e4ivitamise ajal (t\u00fc\u00fcbiannotatsioone eiratakse tavaliselt programmi k\u00e4ivitamise ajal ja neid kasutatakse ainult t\u00fc\u00fcpide kontrollimise s\u00fcsteemides). Tegelikult plaanisime viia mypy teostuse Pythonist keelde, mis oli loodud staatiliselt t\u00fc\u00fcbid, mis n\u00e4eks v\u00e4lja (ja enamasti t\u00f6\u00f6taks) t\u00e4pselt nagu Python. (See liik keeltest \u00fcksteisele migreerimist on muutunud mypy projekti traditsiooniks. Mypy algne teostus oli kirjutatud Alore'is, seej\u00e4rel oli segu Java ja Pythoni s\u00fcntaksist.)<\/p>\n<p>CPythoni laienduste API suunamine oli v\u00f5tmetegur, et mitte kaotada projektijuhtimise v\u00f5imalusi. Me ei pidanud rakendama virtuaalmasinat ega \u00fchtegi teeki, mida mypy vajas. Lisaks oleks meil endiselt juurdep\u00e4\u00e4s kogu Python \u00f6kos\u00fcsteemile, kus oleksid kergesti saadaval k\u00f5ik t\u00f6\u00f6riistad (nt pytest). See t\u00e4hendas, et saaksime arendamise k\u00e4igus j\u00e4tkata t\u00f5lgendatava Python-koodi kasutamist, mis v\u00f5imaldaks meil t\u00f6\u00f6tada v\u00e4ga kiire koodimuutmise ja testimise skeemiga, mitte oodata koodi kompileerimist. See n\u00e4gi v\u00e4lja nagu me saaksime suurep\u00e4raselt, nii \u00f6elda, kahel toolil istuda, ja meile meeldis see.<\/p>\n<p>Kompilaator, mille me nimeks panime mypyc (kuna see kasutab t\u00fc\u00fcpide anal\u00fc\u00fcsimiseks mypy front-endina), on osutunud v\u00e4ga edukaks projektiks. \u00dcldiselt oleme saavutanud umbes neli korda kiirema mypy sagedaste k\u00e4ivituste ilma vahem\u00e4cachemisse. Mypyci projekti tuuma arendamine k\u00e4sik\u00e4es v\u00e4ikese meeskonna, kuhu kuulusid Michael Sullivan, Ivan Levkivski, Hugh Han ja mina, v\u00f5ttis aega umbes neli kalendrikuud. See t\u00f6\u00f6maht oli palju v\u00e4iksem kui see, mis oleks vajalik mypy \u00fcmberkirjutamiseks n\u00e4iteks C++-s v\u00f5i Go-s. Ja projekti muudatusi tuli teha palju v\u00e4hem, kui oleks tulnud teha selle \u00fcmberkirjutamise korral teises keeles. Loodame samuti, et suudame viia mypyc sellisele tasemele, et Dropboxi teised programmeerijad saaksid seda kasutada oma koodi kompileerimiseks ja kiirusel.<\/p>\n<p>Selle taseme j\u00f5udmiseks pidime rakendama m\u00f5ningaid huvitavaid insenerilahendusi. Nii suudab kompilaator kiirendada paljude toimingute t\u00e4itmist, kasutades C madala taseme konstruktsioone. N\u00e4iteks muudetakse kompileeritud funktsiooni kutse C-funktsiooni kutseks. Selline kutse toimub palju kiiremini kui t\u00f5lgendatud funktsiooni kutse. M\u00f5ned toimingud, nagu n\u00e4iteks s\u00f5nastikes otsimine, tuginesid endiselt tavaliste C-API kutsete kasutamisele CPythonis, mis p\u00e4rast kompileerimist osutusid vaid veidi kiiremateks. \u00d5nnestus meil vabaneda t\u00f5lgendamisega seotud lisakoormusest s\u00fcsteemile, kuid antud juhul andis see vaid v\u00e4ikese v\u00f5idu j\u00f5udluses.<\/p>\n<p>Aegade k\u00f5ige levinumate \u201eaeglaste\u201c operatsioonide tuvastamiseks viisime l\u00e4bi koodiprofiilimise. Relvastatuna saadud andmetega \u00fcritasime kas \u00abh\u00e4\u00e4lestada\u00bb mypyc, et see genereeriks selliste operatsioonide jaoks kiiremat C-koodi, v\u00f5i \u00fcmber kirjutada vastav Python-kood kiiremaks muutmiseks (m\u00f5nikord ei olnud meil lihtsalt piisavalt lihtsat lahendust mingi probleemiga tegelemiseks). Python-koodi \u00fcmberkirjutamine osutus sageli lihtsamaks probleemilahenduseks kui sama transformatsiooni automaatne t\u00e4itmine kompilaatoris. Pikaajalises perspektiivis soovisime automatiseerida paljusid neist transformatsioonidest, kuid selles osas keskendusime, et v\u00f5imalikult v\u00e4he pingutades kiirendada mypyd. Ja selle eesm\u00e4rgi nimel l\u00f5ikasime me nurki.<\/p>\n<p>J\u00e4tkub\u2026<\/p>\n<p><b>Lugupeetud lugejad!<\/b> Millised muljed tekkisid teile mypy projektist, kui said sellest teada?<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/ruvds.com\/vps_start\/\"><img decoding=\"async\" alt=\"Tee 4 miljoni rea Python-koodi t\u00fc\u00fcpide kontrollimiseni. 2. osa\" src=\"\/wp-content\/uploads\/2019\/09\/e3c1dd40228b56d0196fd65e4df22a59.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><br \/>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/ruvds.com\/ru-rub\/#order\"><img decoding=\"async\" alt=\"Tee 4 miljoni rea Python-koodi t\u00fc\u00fcpide kontrollimiseni. 2. osa\" src=\"\/wp-content\/uploads\/2019\/09\/263173dd3ab487da330ff9063e3c180e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><br \/>\n<br \/>Allikas: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/468235\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u043c \u0432\u0442\u043e\u0440\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0432 Dropbox \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u043b\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0442\u0438\u043f\u043e\u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 \u0441\u0442\u0440\u043e\u043a Python-\u043a\u043e\u0434\u0430. \u2192 \u0427\u0438\u0442\u0430\u0442\u044c \u043f\u0435\u0440\u0432\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u041e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0442\u0438\u043f\u043e\u0432 (PEP 484) \u041c\u044b \u043f\u0440\u043e\u0432\u0435\u043b\u0438 \u043f\u0435\u0440\u0432\u044b\u0435 \u0441\u0435\u0440\u044c\u0451\u0437\u043d\u044b\u0435 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u044b \u0441 mypy \u0432 Dropbox \u0432\u043e \u0432\u0440\u0435\u043c\u044f Hack Week 2014. Hack Week \u2014 \u044d\u0442\u043e \u043c\u0435\u0440\u043e\u043f\u0440\u0438\u044f\u0442\u0438\u0435, \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u043c\u043e\u0435 Dropbox \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u043e\u0434\u043d\u043e\u0439 \u043d\u0435\u0434\u0435\u043b\u0438. \u0412 \u044d\u0442\u043e \u0432\u0440\u0435\u043c\u044f [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":28879,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-38479","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u043c \u0432\u0442\u043e\u0440\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0432 Dropbox \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u043b\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0442\u0438\u043f\u043e\u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 \u0441\u0442\u0440\u043e\u043a Python-\u043a\u043e\u0434\u0430.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/put-k-proverke-tipov-4-millionov-strok-python-koda-chast-2\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"et_EE\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041f\u0443\u0442\u044c \u043a \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435 \u0442\u0438\u043f\u043e\u0432 4 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 \u0441\u0442\u0440\u043e\u043a Python-\u043a\u043e\u0434\u0430. \u0427\u0430\u0441\u0442\u044c 2 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u043c \u0432\u0442\u043e\u0440\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0432 Dropbox \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u043b\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0442\u0438\u043f\u043e\u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 \u0441\u0442\u0440\u043e\u043a Python-\u043a\u043e\u0434\u0430.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/put-k-proverke-tipov-4-millionov-strok-python-koda-chast-2\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:23:56+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:23:56+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Teekond 4 miljoni rea Python-koodi t\u00fc\u00fcpide kontrollimiseni. Osa 2 | ProHoster","description":"T\u00e4na avaldame teise osa materjali t\u00f5lkest, kuidas Dropboxis korraldati t\u00fc\u00fcbi kontrollimist mitme miljoni rea Python koodi kohta.","canonical_url":"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/put-k-proverke-tipov-4-millionov-strok-python-koda-chast-2","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"et_EE","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041f\u0443\u0442\u044c \u043a \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435 \u0442\u0438\u043f\u043e\u0432 4 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 \u0441\u0442\u0440\u043e\u043a Python-\u043a\u043e\u0434\u0430. \u0427\u0430\u0441\u0442\u044c 2 | ProHoster","og:description":"\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u043c \u0432\u0442\u043e\u0440\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0432 Dropbox \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u043b\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0442\u0438\u043f\u043e\u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 \u0441\u0442\u0440\u043e\u043a Python-\u043a\u043e\u0434\u0430.","og:url":"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/put-k-proverke-tipov-4-millionov-strok-python-koda-chast-2","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:23:56+00:00","article:modified_time":"2019-10-31T19:23:56+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"38479","title":null,"description":null,"keywords":null,"keyphrases":{"focus":[],"additional":[]},"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-23 22:13:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 01:08:32","updated":"2026-08-11 12:50:31","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts\/38479","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/comments?post=38479"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts\/38479\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/media\/28879"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/media?parent=38479"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/categories?post=38479"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/tags?post=38479"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}