рдирдорд╕реНрддреЗ, рдореЗрд░рд╛ рдирд╛рдо рдЕрд▓реЗрдХреНрдЬреЗрдВрдбрд░ рд╡рд╛рд╕реАрди рд╣реИ, рдореИрдВ рдПрдбреИрдбрд┐рд▓ рдореЗрдВ рдПрдХ рдмреИрдХреЗрдВрдб рдбреЗрд╡рд▓рдкрд░ рд╣реВрдВред рдЗрд╕ рд╕рд╛рдордЧреНрд░реА рдХрд╛ рд╡рд┐рдЪрд╛рд░ рдЗрд╕ рддрдереНрдп рд╕реЗ рд╢реБрд░реВ рд╣реБрдЖ рдХрд┐ рдореИрдВ рдпрд╛рдВрдбреЗрдХреНрд╕ рдмреИрдХреЗрдВрдб рдбреЗрд╡рд▓рдкрдореЗрдВрдЯ рд╕реНрдХреВрд▓ рдореЗрдВ рдкрд░рд┐рдЪрдпрд╛рддреНрдордХ рдЕрд╕рд╛рдЗрдирдореЗрдВрдЯ ( Ya.Disk ) рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛ ред рдореИрдВрдиреЗ рдХреБрдЫ рддрдХрдиреАрдХреЛрдВ рдХреА рдкрд╕рдВрдж, рдкрд░реАрдХреНрд╖рдг рдкрджреНрдзрддрд┐ рдХреА рд╕рднреА рдмрд╛рд░реАрдХрд┐рдпреЛрдВ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд┐рдпрд╛ ... рдпрд╣ рдмрд┐рд▓реНрдХреБрд▓ рднреА рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдирд╣реАрдВ рдирд┐рдХрд▓рд╛, рд▓реЗрдХрд┐рди рдкрд╛рдпрдерди рдореЗрдВ рдмреИрдХрдПрдВрдб рдХреИрд╕реЗ рд▓рд┐рдЦрдирд╛ рд╣реИ, рдЗрд╕ рдкрд░ рдПрдХ рдмрд╣реБрдд рд╡рд┐рд╕реНрддреГрдд рдорд╛рд░реНрдЧрджрд░реНрд╢рд┐рдХрд╛ред рдкреНрд░рд╛рд░рдВрднрд┐рдХ рд╡рд┐рдЪрд╛рд░ рд╕реЗ рд╕реЗрд╡рд╛ рдХреЗ рд▓рд┐рдП рдХреЗрд╡рд▓ рдЖрд╡рд╢реНрдпрдХрддрд╛рдПрдВ рдереАрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЬреЛ рдЙрдкрдХрд░рдг рдФрд░ рдкреНрд░реМрджреНрдпреЛрдЧрд┐рдХрд┐рдпреЛрдВ рдХреЛ рдЕрд▓рдЧ рдХрд░рдирд╛ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИред рдирддреАрдЬрддрди, рдореИрдВ рд╕реМ рд╣рдЬрд╛рд░ рдкрд╛рддреНрд░реЛрдВ рдкрд░ рдЬрд╛рдЧ рдЧрдпрд╛ред рдмрд╣реБрдд рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рд╕рдм рдХреБрдЫ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдЖрд╡рд╢реНрдпрдХ рдерд╛ред рддреЛ, рдЕрдЧрд▓реЗ 100 рдХрд┐рд▓реЛрдмрд╛рдЗрдЯ рдХреЗ рд▓рд┐рдП рдХрд╛рд░реНрдпрдХреНрд░рдо: рдЙрдкрдХрд░рдг рдХреА рдкрд╕рдВрдж рд╕реЗ рддреИрдирд╛рддреА рддрдХ рдПрдХ рд╕реЗрд╡рд╛ рдмреИрдХрдПрдВрдб рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдХреИрд╕реЗ рдХрд░реЗрдВред
TL; DR: рдпрд╣рд╛рдВ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд╕рд╛рде GitHub рдкреНрд░рддрд┐рдирд┐рдзрд┐ рд╣реИ, рдФрд░ рдЬреЛ рдкреНрдпрд╛рд░ рдХрд░рддрд╛ рд╣реИ (рдЕрд╕рд▓реА) longreads - рдХреГрдкрдпрд╛, рдмрд┐рд▓реНрд▓реА рдХреЗ рдиреАрдЪреЗредрд╣рдо рдкрд╛рдпрдерди рдореЗрдВ REST API рд╕реЗрд╡рд╛ рдХрд╛ рд╡рд┐рдХрд╛рд╕ рдФрд░ рдкрд░реАрдХреНрд╖рдг рдХрд░реЗрдВрдЧреЗ, рдЗрд╕реЗ рдПрдХ рд╣рд▓реНрдХреЗ рдбреЙрдХрдЯрд░ рдХрдВрдЯреЗрдирд░ рдореЗрдВ рдкреИрдХ рдХрд░реЗрдВрдЧреЗ рдФрд░ рдЗрд╕реЗ Ansible рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рддреИрдирд╛рдд рдХрд░реЗрдВрдЧреЗредрдЖрдк рд╡рд┐рднрд┐рдиреНрди рдЙрдкрдХрд░рдгреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ REST API рд╕реЗрд╡рд╛ рдХреЛ рд╡рд┐рднрд┐рдиреНрди рддрд░реАрдХреЛрдВ рд╕реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╡рд░реНрдгрд┐рдд рд╕рдорд╛рдзрд╛рди рдПрдХрдорд╛рддреНрд░ рд╕рд╣реА рдирд╣реАрдВ рд╣реИ, рдореИрдВрдиреЗ рдЕрдкрдиреЗ рд╡реНрдпрдХреНрддрд┐рдЧрдд рдЕрдиреБрднрд╡ рдФрд░ рд╡рд░реАрдпрддрд╛рдУрдВ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдФрд░ рдЙрдкрдХрд░рдг рдЪреБрдирд╛ред
рд╣рдо рдХреНрдпрд╛ рдХрд░реЗрдВ?
рдХрд▓реНрдкрдирд╛ рдХреАрдЬрд┐рдП рдХрд┐ рдПрдХ рдСрдирд▓рд╛рдЗрди рдЙрдкрд╣рд╛рд░ рд╕реНрдЯреЛрд░ рд╡рд┐рднрд┐рдиреНрди рдХреНрд╖реЗрддреНрд░реЛрдВ рдореЗрдВ рдПрдХ рдХрд╛рд░реНрд░рд╡рд╛рдИ рд╢реБрд░реВ рдХрд░рдиреЗ рдХреА рдпреЛрдЬрдирд╛ рдмрдирд╛ рд░рд╣рд╛ рд╣реИред рдмрд┐рдХреНрд░реА рд░рдгрдиреАрддрд┐ рдкреНрд░рднрд╛рд╡реА рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП, рдмрд╛рдЬрд╛рд░ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд╕реНрдЯреЛрд░ рдореЗрдВ рдПрдХ рд╕рдкреНрд▓рд╛рдпрд░ рд╣реЛрддрд╛ рд╣реИ рдЬреЛ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд╕рд╛рде рдирд┐рдпрдорд┐рдд рд░реВрдк рд╕реЗ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдореЗрд▓ рджреНрд╡рд╛рд░рд╛) рдбреЗрдЯрд╛ рднреЗрдЬрддрд╛ рд╣реИредрдЖрдЗрдП рдПрдХ рдкрд╛рдпрдерди рд░реЗрд╕реНрдЯ рдПрдкреАрдЖрдИ рд╕реЗрд╡рд╛ рд╡рд┐рдХрд╕рд┐рдд рдХрд░реЗрдВ рдЬреЛ рдкреНрд░рджрд╛рди рдХрд┐рдП рдЧрдП рдбреЗрдЯрд╛ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░реЗрдЧреА рдФрд░ рд╡рд┐рднрд┐рдиреНрди рд╢рд╣рд░реЛрдВ рдореЗрдВ рд╡рд┐рднрд┐рдиреНрди рдЖрдпреБ рд╡рд░реНрдЧ рдХреЗ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдЙрдкрд╣рд╛рд░реЛрдВ рдХреА рдорд╛рдВрдЧ рдХреА рдкрд╣рдЪрд╛рди рдХрд░реЗрдЧреАредрд╣рдо рд╕реЗрд╡рд╛ рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╣реИрдВрдбрд▓рд░ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВ:POST /imports
рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдПрдХ рдирдпрд╛ рдЕрдкрд▓реЛрдб рдЬреЛрдбрд╝рддрд╛ рд╣реИ;
GET /imports/$import_id/citizens
рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдирд┐рд░реНрд╡рд╣рди рдХреЗ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЛ рд╡рд╛рдкрд╕ рдХрд░рддрд╛ рд╣реИ;
PATCH /imports/$import_id/citizens/$citizen_id
рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдЙрддрд░рд╛рдИ рдореЗрдВ рдирд┐рд╡рд╛рд╕реА (рдФрд░ рдЙрд╕рдХреЗ рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ) рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди;
GET /imports/$import_id/citizens/birthdays
, ( ), ;
GET /imports/$import_id/towns/stat/percentile/age
50-, 75- 99- ( ) .
?
рддреЛ, рд╣рдо рдкрд░рд┐рдЪрд┐рдд рдЪреМрдЦрдЯреЗ, рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдФрд░ DBMS рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкрд╛рдпрдерди рдореЗрдВ рдПрдХ рд╕реЗрд╡рд╛ рд▓рд┐рдЦ тАЛтАЛрд░рд╣реЗ рд╣реИрдВредрдореЗрдВ 4 рд╡реНрдпрд╛рдЦреНрдпрд╛рди рд╡реАрдбрд┐рдпреЛ рдмреЗрд╢рдХ, рд╡рд┐рднрд┐рдиреНрди DBMSs рдФрд░ рдЙрдирдХреА рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рд╡рд░реНрдгрд┐рдд рд╣реИрдВред рдореЗрд░реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдкреЛрд╕реНрдЯрдЧреНрд░реЗрд╕реАрдХреНрдпреВ рдбреАрдмреАрдПрдордПрд╕ рдХреЛ рдЪреБрдирд╛ , рдЬрд┐рд╕рдиреЗ рдЦреБрдж рдХреЛ рд░реВрд╕реА рдореЗрдВ рдЙрддреНрдХреГрд╖реНрдЯ рдкреНрд░рд▓реЗрдЦрди рдХреЗ рд╕рд╛рде рдПрдХ рд╡рд┐рд╢реНрд╡рд╕рдиреАрдп рд╕рдорд╛рдзрд╛рди рдХреЗ рд░реВрдк рдореЗрдВ рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдпрд╛ рд╣реИ , рдПрдХ рдордЬрдмреВрдд рд░реВрд╕реА рд╕рдореБрджрд╛рдп (рдЖрдк рд╣рдореЗрд╢рд╛ рд░реВрд╕реА рдореЗрдВ рдПрдХ рдкреНрд░рд╢реНрди рдХрд╛ рдЙрддреНрддрд░ рдкрд╛ рд╕рдХрддреЗ рд╣реИрдВ), рдФрд░ рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдореБрдлреНрдд рдкрд╛рдареНрдпрдХреНрд░рдо рднреА ред рд╕рдВрдмрдВрдзрдкрд░рдХ рдореЙрдбрд▓ рдХрд╛рдлреА рдмрд╣реБрдореБрдЦреА рдФрд░ рдХрдИ рдбреЗрд╡рд▓рдкрд░реНрд╕ рджреНрд╡рд╛рд░рд╛ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рд╕рдордЭрд╛ рдЬрд╛рддрд╛ рд╣реИред рд╣рд╛рд▓рд╛рдБрдХрд┐ рдпрд╣реА рдХрд╛рдо рдХрд┐рд╕реА NoSQL DBMS рдкрд░ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рд╣рдо PostgreSQL рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВрдЧреЗредрд╕реЗрд╡рд╛ рдХрд╛ рдореБрдЦреНрдп рдЙрджреНрджреЗрд╢реНрдп - рдбреЗрдЯрд╛рдмреЗрд╕ рдФрд░ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЗ рдмреАрдЪ рдиреЗрдЯрд╡рд░реНрдХ рдкрд░ рдбреЗрдЯрд╛ рдЯреНрд░рд╛рдВрд╕рдорд┐рд╢рди - рдкреНрд░реЛрд╕реЗрд╕рд░ рдкрд░ рдПрдХ рдмрдбрд╝рд╛ рднрд╛рд░ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдПрдХ рд╕рдордп рдореЗрдВ рдХрдИ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рдореЗрдВ 10 рд╡реНрдпрд╛рдЦреНрдпрд╛рди рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд┐рдпрд╛ред рдпрд╣ рдЖрдкрдХреЛ рдХреБрд╢рд▓рддрд╛рдкреВрд░реНрд╡рдХ рдПрдХ рд╣реА OS рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЗ рднреАрддрд░ рдХрдИ рдЧреНрд░рд╛рд╣рдХреЛрдВ рдХреА рд╕реЗрд╡рд╛ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдлреНрд▓рд╛рд╕реНрдХ / Django рдореЗрдВ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ рдЬрд╛рдиреЗ рд╡рд╛рд▓рд╛ рдкреНрд░реА-рдлреЛрд░реНрдХ рдореЙрдбрд▓, рдЬреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рд╕реЗ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЗ рд▓рд┐рдП рдХрдИ рдкреНрд░рдХреНрд░рд┐рдпрд╛рдПрдВ рдмрдирд╛рддрд╛ рд╣реИ, рдЙрдирдореЗрдВ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдореЗрдореЛрд░реА рдХрд╛ рдЙрдкрднреЛрдЧ рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЬреНрдпрд╛рджрд╛рддрд░ рд╕рдордп рдмреЗрдХрд╛рд░ рд╣реЛрддрд╛ рд╣реИред ) рдЗрд╕рд▓рд┐рдП, рд╕реЗрд╡рд╛ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЗ рд░реВрдк рдореЗрдВ, рдореИрдВрдиреЗ рдПрд╕рд┐рдВрдХреНрд░реЛрдирд╕ aiohttp рдХреЛ рдЪреБрдирд╛ ред рд╡реАрдбрд┐рдпреЛ рдкрд╛рдареНрдпрдХреНрд░рдо рдХрд╛ 5 рд╡рд╛рдБ рд╡реНрдпрд╛рдЦреНрдпрд╛рди SQLAlchemy рдмрддрд╛рддрд╛ рд╣реИ
рдЖрдкрдХреЛ рдЬрдЯрд┐рд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЛ рднрд╛рдЧреЛрдВ рдореЗрдВ рд╡рд┐рдШрдЯрд┐рдд рдХрд░рдиреЗ, рдЙрдирдХрд╛ рдкреБрди: рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ, рдлрд╝реАрд▓реНрдб рдХреЗ рдбрд╛рдпрдирд╛рдорд┐рдХ рд╕реЗрдЯ рдХреЗ рд╕рд╛рде рдХреНрд╡реЗрд░реАрдЬрд╝ рдЙрддреНрдкрдиреНрди рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, PATCH- рдкреНрд░реЛрд╕реЗрд╕рд░ рдЖрдВрд╢рд┐рдХ рдирд┐рд╡рд╛рд╕реА рдХреЛ рдордирдорд╛рдиреЗ рдврдВрдЧ рд╕реЗ рдЕрдкрдбреЗрдЯ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ) рдФрд░ рд╕реАрдзреЗ рд╡реНрдпрд╛рд╡рд╕рд╛рдпрд┐рдХ рддрд░реНрдХ рдкрд░ рдзреНрдпрд╛рди рдХреЗрдВрджреНрд░рд┐рдд рдХрд░рддрд╛ рд╣реИред Asyncpg рдбреНрд░рд╛рдЗрд╡рд░ рдЗрди рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рд╕рдВрднрд╛рд▓ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рдбреЗрдЯрд╛ рдХреЛ рд╕рдмрд╕реЗ рддреЗрдЬрд╝ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░ рд╕рдХрддрд╛ рд╣реИ , рдФрд░ asyncpgsa рдЙрдиреНрд╣реЗрдВ рдорд┐рддреНрд░ рдмрдирд╛рдиреЗ рдореЗрдВ рдорджрдж рдХрд░реЗрдЧрд╛ редрдбреЗрдЯрд╛рдмреЗрд╕ рдХреА рд╕реНрдерд┐рддрд┐ рдХреЛ рдкреНрд░рдмрдВрдзрд┐рдд рдХрд░рдиреЗ рдФрд░ рдкрд▓рд╛рдпрди рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореЗрд░рд╛ рдкрд╕рдВрджреАрджрд╛ рдЙрдкрдХрд░рдг рдПрд▓реЗрдореНрдмрд┐рдХ рд╣реИ ред рд╡реИрд╕реЗ, рдореИрдВрдиреЗ рд╣рд╛рд▓ рд╣реА рдореЗрдВ рдореЙрд╕реНрдХреЛ рдкрд╛рдпрдерди рдореЗрдВ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХреА рдереА редрд╕рддреНрдпрд╛рдкрди рдХреЗ рддрд░реНрдХ рдХреЛ рдорд╛рд░реНрд╢рдореИрд▓реЛ рдпреЛрдЬрдирд╛рдУрдВ (рдкрд░рд┐рд╡рд╛рд░ рдХреЗ рд╕рдВрдмрдВрдзреЛрдВ рдХреА рдЬрд╛рдВрдЪ рд╕рд╣рд┐рдд) рджреНрд╡рд╛рд░рд╛ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рд╡рд░реНрдгрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ ред Aiohttp-Spec рдореЙрдбреНрдпреВрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛рдореИрдВрдиреЗ рдбреЗрдЯрд╛ рд╕рддреНрдпрд╛рдкрди рдХреЗ рд▓рд┐рдП aiohttp-handlers рдФрд░ рдпреЛрдЬрдирд╛рдУрдВ рдХреЛ рд▓рд┐рдВрдХ рдХрд┐рдпрд╛ рдерд╛, рдФрд░ рдмреЛрдирд╕ рд╕реНрд╡реИрдЧрд░ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдкреНрд░рд▓реЗрдЦрди рдЙрддреНрдкрдиреНрди рдХрд░рдиреЗ рдФрд░ рдЗрд╕реЗ рдЧреНрд░рд╛рдлрд┐рдХрд▓ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдореЗрдВ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдерд╛ редрд▓реЗрдЦрди рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ 3 рд╡реНрдпрд╛рдЦреНрдпрд╛рдиреЛрдВpytest
рдореЗрдВ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЪреБрдирд╛ ред рдЗрд╕ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХреЛ рдбреАрдмрдЧ рдФрд░ рдкреНрд░реЛрдлрд╝рд╛рдЗрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ PyCharm рдбрд┐рдмрдЧрд░ ( рд╡реНрдпрд╛рдЦреНрдпрд╛рди 9 ) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ред рдореЗрдВ 7 рд╡реНрдпрд╛рдЦреНрдпрд╛рди рд╡рд░реНрдгрди рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдХрд┐рд╕реА рднреА рдХрдВрдкреНрдпреВрдЯрд░ рдХреЗ рд▓рд┐рдП рдбреЛрдХрд░ (рдпрд╛ рдпрд╣рд╛рдВ рддрдХ рдХрд┐ рд╡рд┐рднрд┐рдиреНрди рдУрдПрд╕ рдкрд░) рдЕрджреНрдпрддрди / рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡реЗрджрди рд╡рд╛рддрд╛рд╡рд░рдг рд╕рдорд╛рдпреЛрдЬрд┐рдд рдХрд░рдиреЗ рдФрд░ рдЖрд╕рд╛рди рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП / рд╕рд░реНрд╡рд░ рдкрд░ рдЖрд╡реЗрджрди рдХреЛ рдирд╖реНрдЯ рдХрд░рдиреЗ рдХреЗ рдмрд┐рдирд╛ рдкреИрдХ рдЪрд▓рд╛ рд╕рдХреЗрдВрдЧреЗред рддреИрдирд╛рддреА рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдЕрдиреНрд╕рд┐рдмрд▓ рдХреЛ рдЪреБрдирд╛ред рдпрд╣ рдЖрдкрдХреЛ рд╕рд░реНрд╡рд░ рдФрд░ рдЙрд╕рдХреА рд╕реЗрд╡рд╛рдУрдВ рдХреА рд╡рд╛рдВрдЫрд┐рдд рд╕реНрдерд┐рддрд┐ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, ssh рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдФрд░ рд╡рд┐рд╢реЗрд╖ рд╕реЙрдлреНрдЯрд╡реЗрдпрд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИредрд╡рд┐рдХрд╛рд╕
рдореИрдВрдиреЗ рдкрд╛рдпрдерди рдкреИрдХреЗрдЬ рдХреЛ рдПрдХ рдирд╛рдо analyzer
рджреЗрдиреЗ рдФрд░ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕рдВрд░рдЪрдирд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛ :
рдлрд╝рд╛рдЗрд▓ рдореЗрдВ analyzer/__init__.py
рдореИрдВрдиреЗ рдкреИрдХреЗрдЬ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕рд╛рдорд╛рдиреНрдп рдЬрд╛рдирдХрд╛рд░реА рдкреЛрд╕реНрдЯ рдХреА: рд╡рд┐рд╡рд░рдг ( рдбреЙрдХрд╕реНрдЯреНрд░рд┐рдВрдЧ ), рд╕рдВрд╕реНрдХрд░рдг, рд▓рд╛рдЗрд╕реЗрдВрд╕, рдбреЗрд╡рд▓рдкрд░ рд╕рдВрдкрд░реНрдХредрдЗрд╕реЗ рдмрд┐рд▓реНрдЯ-рдЗрди рдорджрдж рд╕реЗ рджреЗрдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ$ python
>>> import analyzer
>>> help(analyzer)
Help on package analyzer:
NAME
analyzer
DESCRIPTION
REST API, .
PACKAGE CONTENTS
api (package)
db (package)
utils (package)
DATA
__all__ = ('__author__', '__email__', '__license__', '__maintainer__',...
__email__ = 'alvassin@yandex.ru'
__license__ = 'MIT'
__maintainer__ = 'Alexander Vasin'
VERSION
0.0.1
AUTHOR
Alexander Vasin
FILE
/Users/alvassin/Work/backendschool2019/analyzer/__init__.py
рдкреИрдХреЗрдЬ рдореЗрдВ рджреЛ рдЗрдирдкреБрдЯ рдкреЙрдЗрдВрдЯ рд╣реИрдВ - REST API рд╕рд░реНрд╡рд┐рд╕ ( analyzer/api/__main__.py
) рдФрд░ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реНрдЯреЗрдЯ рдореИрдиреЗрдЬрдореЗрдВрдЯ рдпреВрдЯрд┐рд▓рд┐рдЯреА ( analyzer/db/__main__.py
)ред рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ __main__.py
рдПрдХ рдХрд╛рд░рдг рдХреЗ рд▓рд┐рдП рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ - рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдРрд╕рд╛ рдирд╛рдо рдзреНрдпрд╛рди рдЖрдХрд░реНрд╖рд┐рдд рдХрд░рддрд╛ рд╣реИ, рдпрд╣ рд╕реНрдкрд╖реНрдЯ рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдлрд╝рд╛рдЗрд▓ рдПрдХ рдкреНрд░рд╡реЗрд╢ рдмрд┐рдВрджреБ рд╣реИредрджреВрд╕рд░реЗ, рдкреНрд░рд╡реЗрд╢ рдмрд┐рдВрджреБрдУрдВ рдХреЗ рд▓рд┐рдП рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж python -m
:
$ python -m analyzer.api --help
$ python -m analyzer.db --help
рдЖрдкрдХреЛ setup.py рдХреЗ рд╕рд╛рде рд╢реБрд░реБрдЖрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреНрдпреЛрдВ рд╣реИ?
рдЖрдЧреЗ рджреЗрдЦрддреЗ рд╣реБрдП, рд╣рдо рд╕реЛрдЪрддреЗ рд╣реИрдВ рдХрд┐ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдХреИрд╕реЗ рд╡рд┐рддрд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдП: рдЗрд╕реЗ рдЬрд╝рд┐рдк рдореЗрдВ рдкреИрдХ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ (рд╕рд╛рде рд╣реА рдкрд╣рд┐рдпрд╛ / рдЕрдВрдбрд╛-) рд╕рдВрдЧреНрд░рд╣, рдПрдХ рдЖрд░рдкреАрдПрдо рдкреИрдХреЗрдЬ, macOS рдХреЗ рд▓рд┐рдП рдПрдХ pkg рдлрд╝рд╛рдЗрд▓ рдФрд░ рдПрдХ рджреВрд░рд╕реНрде рдХрдВрдкреНрдпреВрдЯрд░, рд╡рд░реНрдЪреБрдЕрд▓ рдорд╢реАрди, рдореИрдХрдмреБрдХ рдпрд╛ рдбреЙрдХрд░ рдкрд░ рд╕реНрдерд╛рдкрд┐рдд рдХрдВрдЯреЗрдирд░редрдлрд╝рд╛рдЗрд▓ setup.py
рдХрд╛ рдореБрдЦреНрдп рдЙрджреНрджреЗрд╢реНрдп рдХреЗ рд▓рд┐рдП рдЖрд╡реЗрджрди рдХреЗ рд╕рд╛рде рдкреИрдХреЗрдЬ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдирд╛ рд╣реИ ред рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдкреИрдХреЗрдЬ (рдирд╛рдо, рд╕рдВрд╕реНрдХрд░рдг, рд▓реЗрдЦрдХ, рдЖрджрд┐) рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕рд╛рдорд╛рдиреНрдп рдЬрд╛рдирдХрд╛рд░реА рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдП, рд▓реЗрдХрд┐рди рдЗрд╕рдореЗрдВ рдЖрдк рдХрд╛рдо рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдореЙрдбреНрдпреВрд▓, "рдЕрддрд┐рд░рд┐рдХреНрдд" рдирд┐рд░реНрднрд░рддрд╛ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП), рдкреНрд░рд╡реЗрд╢ рдмрд┐рдВрджреБ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдирд┐рд╖реНрдкрд╛рджрди рдпреЛрдЧреНрдп рдХрдорд╛рдВрдб) рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред ) рдФрд░ рджреБрднрд╛рд╖рд┐рдпрд╛ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВред рд╕реЗрдкреНрдЯреЛрдкреВрд▓рд╕ рдкреНрд▓рдЧрдЗрдиреНрд╕ рдЖрдкрдХреЛ рд╡рд░реНрдгрд┐рдд рдкреИрдХреЗрдЬ рд╕реЗ рд╡рд┐рд░реВрдкрдг рд╕рд╛рдХреНрд╖реНрдп рдПрдХрддреНрд░ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреЗ рд╣реИрдВред рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рдкреНрд▓рдЧрдЗрдиреНрд╕ рд╣реИрдВ: рдЬрд╝рд┐рдк, рдЕрдВрдбрд╛, рдЖрд░рдкреАрдПрдо, рдореИрдХрдУрдПрд╕ рдкреАрдкреАрдЬреАред рд╢реЗрд╖ рдкреНрд▓рдЧрдЗрдиреНрд╕ PyPI рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╡рд┐рддрд░рд┐рдд рдХрд┐рдП рдЧрдП рд╣реИрдВ: рдкрд╣рд┐рдпрд╛ ,distutils/setuptools
xar , pex редрдиреАрдЪреЗ рдХреА рдкрдВрдХреНрддрд┐ рдореЗрдВ, рдПрдХ рдлрд╝рд╛рдЗрд▓ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреЗ рд╣реБрдП, рд╣рдореЗрдВ рд╢рд╛рдирджрд╛рд░ рдЕрд╡рд╕рд░ рдорд┐рд▓рддреЗ рд╣реИрдВред рдЗрд╕реАрд▓рд┐рдП рдПрдХ рдирдП рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХрд╛ рд╡рд┐рдХрд╛рд╕ рд╢реБрд░реВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП setup.py
редрдлрд╝рдВрдХреНрд╢рди рдореЗрдВ, setup()
рдирд┐рд░реНрднрд░ рдореЙрдбреНрдпреВрд▓ рдХреЛ рдПрдХ рд╕реВрдЪреА рджреНрд╡рд╛рд░рд╛ рджрд░реНрд╢рд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ:setup(..., install_requires=["aiohttp", "SQLAlchemy"])
рд▓реЗрдХрд┐рди рдореИрдВрдиреЗ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдлрд╛рдЗрд▓реЛрдВ рдореЗрдВ рдирд┐рд░реНрднрд░рддрд╛ рдХрд╛ рд╡рд░реНрдгрди рдХрд┐рдпрд╛ рд╣реИ requirements.txt
рдФрд░ requirements.dev.txt
рдЬрд┐рдирдХреА рд╕рд╛рдордЧреНрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ setup.py
ред рдпрд╣ рдореЗрд░реЗ рд▓рд┐рдП рдЕрдзрд┐рдХ рд▓рдЪреАрд▓рд╛ рд▓рдЧрддрд╛ рд╣реИ, рд╕рд╛рде рд╣реА рдПрдХ рд░рд╣рд╕реНрдп рднреА рд╣реИ: рдмрд╛рдж рдореЗрдВ рдпрд╣ рдЖрдкрдХреЛ рдбреЙрдХрдЯрд░ рдЫрд╡рд┐ рдХреЛ рддреЗрдЬреА рд╕реЗ рдмрдирд╛рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛ред рдЖрд╡реЗрджрди рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдЖрд╢реНрд░рд┐рддреЛрдВ рдХреЛ рдПрдХ рдЕрд▓рдЧ рдХрджрдо рдХреЗ рд░реВрдк рдореЗрдВ рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдФрд░ рдбреЙрдХрдЯрд░ рдХрдВрдЯреЗрдирд░ рдХреЗ рдкреБрдирд░реНрдирд┐рд░реНрдорд╛рдг рдХреЗ рджреМрд░рд╛рди, рдпрд╣ рдХреИрд╢ рдореЗрдВ рд╣реИредрд╣реЛрдирд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП setup.py
рдлрд╛рдЗрд▓реЛрдВ рд╕реЗ рдирд┐рд░реНрднрд░рддрд╛ рдХреЛ рдкрдврд╝рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо requirements.txt
рдФрд░ requirements.dev.txt
, рд╕рдорд╛рд░реЛрд╣ рд▓рд┐рдЦрд╛ рд╣реИ:def load_requirements(fname: str) -> list:
requirements = []
with open(fname, 'r') as fp:
for req in parse_requirements(fp.read()):
extras = '[{}]'.format(','.join(req.extras)) if req.extras else ''
requirements.append(
'{}{}{}'.format(req.name, extras, req.specifier)
)
return requirements
рдпрд╣ рдзреНрдпрд╛рди рджреЗрдиреЗ рдпреЛрдЧреНрдп рд╣реИ рдХрд┐ рд▓рд╛рдпрдХ рд╣реИ setuptools
рдЬрдм рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╡рд┐рдзрд╛рдирд╕рднрд╛ рд╕реНрд░реЛрдд рд╡рд┐рддрд░рдг рдХреЗрд╡рд▓ рд╡рд┐рдзрд╛рдирд╕рднрд╛ рдлрд╝рд╛рдЗрд▓реЗрдВ рд╢рд╛рдорд┐рд▓ .py
, .c
, .cpp
рдФрд░ .h
ред рдПрдХ рдирд┐рд░реНрднрд░рддрд╛ рдлрд╝рд╛рдЗрд▓ requirements.txt
рдФрд░ requirements.dev.txt
рдмреИрдЧ рдХреЛ рд╣рд┐рдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЙрдиреНрд╣реЗрдВ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП MANIFEST.in
редрд╕реЗрдЯрдЕрдк рдкреВрд░реА рддрд░рд╣ рд╕реЗimport os
from importlib.machinery import SourceFileLoader
from pkg_resources import parse_requirements
from setuptools import find_packages, setup
module_name = 'analyzer'
module = SourceFileLoader(
module_name, os.path.join(module_name, '__init__.py')
).load_module()
def load_requirements(fname: str) -> list:
requirements = []
with open(fname, 'r') as fp:
for req in parse_requirements(fp.read()):
extras = '[{}]'.format(','.join(req.extras)) if req.extras else ''
requirements.append(
'{}{}{}'.format(req.name, extras, req.specifier)
)
return requirements
setup(
name=module_name,
version=module.__version__,
author=module.__author__,
author_email=module.__email__,
license=module.__license__,
description=module.__doc__,
long_description=open('README.rst').read(),
url='https://github.com/alvassin/backendschool2019',
platforms='all',
classifiers=[
'Intended Audience :: Developers',
'Natural Language :: Russian',
'Operating System :: MacOS',
'Operating System :: POSIX',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: Implementation :: CPython'
],
python_requires='>=3.8',
packages=find_packages(exclude=['tests']),
install_requires=load_requirements('requirements.txt'),
extras_require={'dev': load_requirements('requirements.dev.txt')},
entry_points={
'console_scripts': [
'{0}-api = {0}.api.__main__:main'.format(module_name),
'{0}-db = {0}.db.__main__:main'.format(module_name)
]
},
include_package_data=True
)
рдЖрдк рдирд┐рдореНрди рдХрдорд╛рдВрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╡рд┐рдХрд╛рд╕ рдореЛрдб рдореЗрдВ рдПрдХ рдкрд░рд┐рдпреЛрдЬрдирд╛ рд╕реНрдерд╛рдкрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ (рд╕рдВрдкрд╛рджрди рдпреЛрдЧреНрдп рдореЛрдб рдореЗрдВ, рдкрд╛рдпрдерди рдкреВрд░реЗ рдкреИрдХреЗрдЬ рдХреЛ рдПрдХ рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рд╕реНрдерд╛рдкрд┐рдд рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ site-packages
, рд▓реЗрдХрд┐рди рдХреЗрд╡рд▓ рд▓рд┐рдВрдХ рдмрдирд╛рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдкреИрдХреЗрдЬ рдлрд╝рд╛рдЗрд▓реЛрдВ рдореЗрдВ рдХрд┐рдП рдЧрдП рдХреЛрдИ рднреА рдкрд░рд┐рд╡рд░реНрддрди рддреБрд░рдВрдд рджрд┐рдЦрд╛рдИ рджреЗрдВрдЧреЗ):
pip install -e '.[dev]'
pip install -e .
рдирд┐рд░реНрднрд░рддрд╛ рд╕рдВрд╕реНрдХрд░рдг рдХреИрд╕реЗ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░реЗрдВ?
рдпрд╣ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд╣реИ рдЬрдм рдбреЗрд╡рд▓рдкрд░реНрд╕ рд╕рдХреНрд░рд┐рдп рд░реВрдк рд╕реЗ рдЕрдкрдиреЗ рдкреИрдХреЗрдЬ рдкрд░ рдХрд╛рдо рдХрд░ рд░рд╣реЗ рд╣реИрдВ - рдмрдЧ рд╕рдХреНрд░рд┐рдп рд░реВрдк рд╕реЗ рдЙрдирдореЗрдВ рддрдп рдХрд┐рдП рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ, рдирдИ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдкреНрд░рдХрдЯ рд╣реЛрддреА рд╣реИ рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рддреЗрдЬреА рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХреА рдЬрд╛ рд╕рдХрддреА рд╣реИред рд▓реЗрдХрд┐рди рдХрднреА-рдХрднреА рдЖрд╢реНрд░рд┐рдд рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рдкрд┐рдЫрдбрд╝реЗ рд╕рдВрдЧрдд рдирд╣реАрдВ рд╣реЛрддреЗ рд╣реИрдВ рдФрд░ рдЖрдкрдХреЗ рдЖрд╡реЗрджрди рдореЗрдВ рддреНрд░реБрдЯрд┐рдпрд╛рдВ рд╣реЛ рд╕рдХрддреА рд╣реИрдВ рдпрджрд┐ рдЖрдк рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдкрд╣рд▓реЗ рд╕реЗ рдирд╣реАрдВ рд╕реЛрдЪрддреЗ рд╣реИрдВредрдкреНрд░рддреНрдпреЗрдХ рдирд┐рд░реНрднрд░ рдкреИрдХреЗрдЬ рдХреЗ рд▓рд┐рдП, рдЖрдк рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╕рдВрд╕реНрдХрд░рдг рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП aiohttp==3.6.2
ред рдлрд┐рд░ рдЖрд╡реЗрджрди рдХреЛ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдЖрд╢реНрд░рд┐рдд рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЗ рдЙрди рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдХреЗ рд╕рд╛рде рдмрдирд╛рдП рдЬрд╛рдиреЗ рдХреА рдЧрд╛рд░рдВрдЯреА рджреА рдЬрд╛рдПрдЧреА рдЬрд┐рдирдХреЗ рд╕рд╛рде рдЗрд╕рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рд▓реЗрдХрд┐рди рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдореЗрдВ рдПрдХ рдЦрд╛рдореА рд╣реИ - рдЕрдЧрд░ рдбреЗрд╡рд▓рдкрд░реНрд╕ рдПрдХ рднрд░реЛрд╕реЗрдордВрдж рдкреИрдХреЗрдЬ рдореЗрдВ рдПрдХ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдмрдЧ рдХреЛ рдареАрдХ рдХрд░рддреЗ рд╣реИрдВ рдЬреЛ рдкрд┐рдЫрдбрд╝реЗ рд╕рдВрдЧрддрддрд╛ рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рддреЛ рдпрд╣ рдлрд┐рдХреНрд╕ рдЖрд╡реЗрджрди рдореЗрдВ рдирд╣реАрдВ рдорд┐рд▓реЗрдЧрд╛ред рд╕рд┐рдореЗрдВрдЯрд┐рдХрд╡рд░реНрдЬрдирд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдПрдХ рддрд░реАрдХрд╛ рд╣реИ, рдЬреЛ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рд╕рдВрд╕реНрдХрд░рдг рдкреНрд░рд╕реНрддреБрдд рдХрд░рдиреЗ рдХрд╛ рд╕реБрдЭрд╛рд╡ рджреЗрддрд╛ рд╣реИ MAJOR.MINOR.PATCH
:MAJOR
- рдЬрдм рдкрд┐рдЫрдбрд╝реЗ рдЕрд╕рдВрдЧрдд рдкрд░рд┐рд╡рд░реНрддрди рдмрдврд╝ рдЬрд╛рддреЗ рд╣реИрдВ;MINOR
- рдкрд┐рдЫрдбрд╝реЗ рд╕рдВрдЧрддрддрд╛ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди рдХреЗ рд╕рд╛рде рдирдИ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдЬреЛрдбрд╝рддреЗ рд╕рдордп рдмрдврд╝ рдЬрд╛рддреА рд╣реИ;PATCH
- рдкрд╢реНрдЪрдЧрд╛рдореА рд╕рдВрдЧрддрддрд╛ рд╕рдорд░реНрдерди рдХреЗ рд╕рд╛рде рдмрдЧ рдлрд┐рдХреНрд╕ рдЬреЛрдбрд╝рддреЗ рд╕рдордп рд╡реГрджреНрдзрд┐ рд╣реЛрддреА рд╣реИред
рдПрдХ рдЖрд╢реНрд░рд┐рдд рдкреИрдХреЗрдЬ рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг (рдЬрд┐рдирдореЗрдВ рд╕реЗ рд▓реЗрдЦрдХреЛрдВ рдЖрдорддреМрд░ рдкрд░ README рдФрд░ рдЪреИрдВрдЬ рдлрд╛рдЗрд▓реЛрдВ рдореЗрдВ рд░рд┐рдкреЛрд░реНрдЯ рдХрд░ рд░рд╣реЗ рд╣реИрдВ) рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╣реИ, рдпрд╣ рдкрд░реНрдпрд╛рдкреНрдд рд╣реИ рдХрд╛ рдореВрд▓реНрдп рддрдп рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП MAJOR
, MINOR
рдФрд░ рдкреИрдЪ-рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рд▓рд┐рдП рдиреНрдпреВрдирддрдо рдореВрд▓реНрдп рдХреЛ рд╕реАрдорд┐рдд рдХрд░рдиреЗ рдХреЗ: >= MAJOR.MINOR.PATCH, == MAJOR.MINOR.*
редрдЗрд╕ рддрд░рд╣ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЛ ~ = рдСрдкрд░реЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ ред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрд╣ aiohttp~=3.6.2
рдкреАрдЖрдИрдкреА рдХреЛ aiohttp
рд╕рдВрд╕реНрдХрд░рдг 3.6.3 рдХреЗ рд▓рд┐рдП рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛ , рд▓реЗрдХрд┐рди 3.7 рдирд╣реАрдВредрдпрджрд┐ рдЖрдк рдирд┐рд░реНрднрд░рддрд╛ рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдХреЗ рдЕрдВрддрд░рд╛рд▓ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рдПрдХ рдФрд░ рд▓рд╛рдн рджреЗрдЧрд╛ - рдирд┐рд░реНрднрд░ рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЗ рдмреАрдЪ рдХреЛрдИ рд╕рдВрд╕реНрдХрд░рдг рд╕рдВрдШрд░реНрд╖ рдирд╣реАрдВ рд╣реЛрдЧрд╛редрдпрджрд┐ рдЖрдк рдПрдХ рдРрд╕реА рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд╡рд┐рдХрд╕рд┐рдд рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрд▓рдЧ рдирд┐рд░реНрднрд░рддрд╛ рдкреИрдХреЗрдЬ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рддреЛ рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╕рдВрд╕реНрдХрд░рдг рдирд╣реАрдВ, рдмрд▓реНрдХрд┐ рдПрдХ рдЕрдВрддрд░рд╛рд▓ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдВред рдлрд┐рд░ рдЖрдкрдХреЗ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдмрд╣реБрдд рдЖрд╕рд╛рди рд╣реЛ рдЬрд╛рдПрдЧрд╛ (рдЕрдЪрд╛рдирдХ рдЙрдирдХреЗ рдЖрд╡реЗрджрди рдХреЗ рд▓рд┐рдП рдПрдХ рд╣реА рдирд┐рд░реНрднрд░рддрд╛ рдкреИрдХреЗрдЬ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рд▓реЗрдХрд┐рди рдПрдХ рдЕрд▓рдЧ рд╕рдВрд╕реНрдХрд░рдг рдХреА)редрд╕рд┐рдореЗрдВрдЯрд┐рдХ рд╡рд░реНрдЬрдирд┐рдВрдЧ рдХреЗрд╡рд▓ рдкреИрдХреЗрдЬрд░реНрд╕ рдХреЗ рд▓реЗрдЦрдХреЛрдВ рдФрд░ рдЙрдкрднреЛрдХреНрддрд╛рдУрдВ рдХреЗ рдмреАрдЪ рдПрдХ рд╕рдордЭреМрддрд╛ рд╣реИред рдпрд╣ рдЧрд╛рд░рдВрдЯреА рдирд╣реАрдВ рджреЗрддрд╛ рдХрд┐ рд▓реЗрдЦрдХ рдмрдЧ рдХреЗ рдмрд┐рдирд╛ рдХреЛрдб рд▓рд┐рдЦрддреЗ рд╣реИрдВ рдФрд░ рдЕрдкрдиреЗ рдкреИрдХреЗрдЬ рдХреЗ рдирдП рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ рдЧрд▓рддреА рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗредрдбреЗрдЯрд╛рдмреЗрд╕
рд╣рдо рдпреЛрдЬрдирд╛ рдХреЛ рдбрд┐рдЬрд╛рдЗрди рдХрд░рддреЗ рд╣реИрдВ
POST / рдЖрдпрд╛рдд рд╣реИрдВрдбрд▓рд░ рдХрд╛ рд╡рд░реНрдгрди рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд╕рд╛рде рдЙрддрд░рд╛рдИ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ:рдЙрджрд╛рд╣рд░рдг рдЕрдкрд▓реЛрдб рдХрд░реЗрдВ{
"citizens": [
{
"citizen_id": 1,
"town": "",
"street": " ",
"building": "1675",
"apartment": 7,
"name": " ",
"birth_date": "26.12.1986",
"gender": "male",
"relatives": [2]
},
{
"citizen_id": 2,
"town": "",
"street": " ",
"building": "1675",
"apartment": 7,
"name": " ",
"birth_date": "01.04.1997",
"gender": "male",
"relatives": [1]
},
{
"citizen_id": 3,
"town": "",
"street": " ",
"building": "2",
"apartment": 11,
"name": " ",
"birth_date": "23.11.1986",
"gender": "female",
"relatives": []
},
...
]
}
рдкрд╣рд▓реЗ рд╕реЛрдЪрд╛ рдЧрдпрд╛ рдерд╛ рдХрд┐ рдирд┐рд╡рд╛рд╕реА рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕рднреА рдЬрд╛рдирдХрд╛рд░реА рдПрдХ рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХреА рдЬрд╛рдП citizens
, рдЬрд╣рд╛рдВ рд╕рдВрдмрдВрдз рдХреЛ рдкреВрд░реНрдгрд╛рдВрдХреЛрдВ рдХреА рд╕реВрдЪреА рдХреЗ рд░реВрдкrelatives
рдореЗрдВ рдПрдХ рдХреНрд╖реЗрддреНрд░ рджреНрд╡рд╛рд░рд╛ рджрд░реНрд╢рд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ редрд▓реЗрдХрд┐рди рдЗрд╕ рд╡рд┐рдзрд┐ рдХреЗ рдХрдИ рдиреБрдХрд╕рд╛рди рд╣реИрдВGET /imports/$import_id/citizens/birthdays
, , citizens
. relatives
UNNEST
.
, 10- :
SELECT
relations.citizen_id,
relations.relative_id,
date_part('month', relatives.birth_date) as relative_birth_month
FROM (
SELECT
citizens.import_id,
citizens.citizen_id,
UNNEST(citizens.relatives) as relative_id
FROM citizens
WHERE import_id = 1
) as relations
INNER JOIN citizens as relatives ON
relations.import_id = relatives.import_id AND
relations.relative_id = relatives.citizen_id
relatives
PostgreSQL, : relatives
, . ( ) .
рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдореИрдВрдиреЗ рдХрд╛рдо рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╕рднреА рдбреЗрдЯрд╛ рдХреЛ рддреАрд╕рд░реЗ рд╕рд╛рдорд╛рдиреНрдп рд░реВрдк рдореЗрдВ рд▓рд╛рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ , рдФрд░ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕рдВрд░рдЪрдирд╛ рдкреНрд░рд╛рдкреНрдд рдХреА рдЧрдИ:
- рдЖрдпрд╛рдд рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдЗрдВрдХреНрд░реАрдореЗрдВрдЯрд┐рдВрдЧ рдХреЙрд▓рдо рд╣реЛрддрд╛ рд╣реИ
import_id
ред рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рдПрдХ рд╡рд┐рджреЗрд╢реА рдХреБрдВрдЬреА рдЬрд╛рдБрдЪ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдпрд╣ рдЖрд╡рд╢реНрдпрдХ рд╣реИ citizens
ред
- рдирд╛рдЧрд░рд┐рдХ рддрд╛рд▓рд┐рдХрд╛ рдирд┐рд╡рд╛рд╕реА (рдкрд╛рд░рд┐рд╡рд╛рд░рд┐рдХ рд╕рдВрдмрдВрдзреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдХреЛ рдЫреЛрдбрд╝рдХрд░ рд╕рднреА рдХреНрд╖реЗрддреНрд░реЛрдВ) рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реНрдХреЗрд▓рд░ рдбреЗрдЯрд╛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддреА рд╣реИ ред
рдПрдХ рдЬреЛрдбрд╝реА ( import_id
, citizen_id
) рдкреНрд░рд╛рдердорд┐рдХ рдХреБрдВрдЬреА рдХреЗ рд░реВрдк рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ , рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреА рд╡рд┐рд╢рд┐рд╖реНрдЯрддрд╛ рдХреА рдЧрд╛рд░рдВрдЯреА citizen_id
рдврд╛рдВрдЪреЗ рдХреЗ рднреАрддрд░ import_id
ред
рдПрдХ рд╡рд┐рджреЗрд╢реА рдХреБрдВрдЬреА citizens.import_id -> imports.import_id
рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддреА рд╣реИ рдХрд┐ рдлрд╝реАрд▓реНрдб citizens.import_id
рдореЗрдВ рдХреЗрд╡рд▓ рдореМрдЬреВрджрд╛ рдЕрдирд▓реЛрдб рд╣реИрдВред
- relations .
( ): citizens
relations
.
(import_id
, citizen_id
, relative_id
) , import_id
citizen_id
c relative_id
.
: (relations.import_id, relations.citizen_id) -> (citizens.import_id, citizens.citizen_id)
(relations.import_id, relations.relative_id) -> (citizens.import_id, citizens.citizen_id)
, , citizen_id
relative_id
.
рдпрд╣ рд╕рдВрд░рдЪрдирд╛ PostgreSQL рдЯреВрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдбреЗрдЯрд╛ рдХреА рдЕрдЦрдВрдбрддрд╛ рдХреЛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддреА рд╣реИ , рдпрд╣ рдЖрдкрдХреЛ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреЗ рд╕рд╛рде рдХреБрд╢рд▓рддрд╛ рд╕реЗ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИ, рд▓реЗрдХрд┐рди рдкреНрд░рддрд┐рд╕реНрдкрд░реНрдзреА рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд╕рд╛рде рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдЕрдкрдбреЗрдЯ рдХрд░рддреЗ рд╕рдордп рдПрдХ рджреМрдбрд╝ рдХреА рд╕реНрдерд┐рддрд┐ рдХреЗ рдЕрдзреАрди рд╣реИ (рд╣рдо PCHCH рд╣реИрдВрдбрд▓рд░ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкрд░ рдХрд░реАрдм рд╕реЗ рдирдЬрд╝рд░ рдбрд╛рд▓реЗрдВрдЧреЗ)редSQLAlchemy рдореЗрдВ рд╕реНрдХреАрдорд╛ рдХрд╛ рд╡рд░реНрдгрди рдХрд░реЗрдВ
рдореЗрдВ рдЕрдзреНрдпрд╛рдп 5, рдореИрдВ рдХреИрд╕реЗ SQLAlchemy рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХреНрд╡реЗрд░реА рдмрдирд╛рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХреА рдереА, рддреЛ рдЖрдк рд╡рд┐рд╢реЗрд╖ рд╡рд╕реНрддреБрдУрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реНрдХреАрдорд╛ рдХрд╛ рд╡рд┐рд╡рд░рдг рджреЗрдирд╛ рд╣реЛрдЧрд╛: рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рд╡рд░реНрдгрд┐рдд рд╣реИрдВ sqlalchemy.Table
рдФрд░ рдПрдХ рд░рдЬрд┐рд╕реНрдЯреНрд░реА рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╛рдзреНрдп рдХрд░ рд░рд╣реЗ рд╣реИрдВ sqlalchemy.MetaData
рдХрд┐ рджреБрдХрд╛рдиреЛрдВ рд╕рднреА рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдореЗрдЯрд╛-рдЬрд╛рдирдХрд╛рд░реАред рд╡реИрд╕реЗ, рд░рдЬрд┐рд╕реНрдЯреНрд░реА MetaData
рди рдХреЗрд╡рд▓ рдкрд╛рдпрдерди рдореЗрдВ рд╡рд░реНрдгрд┐рдд рдореЗрдЯрд╛-рдЬрд╛рдирдХрд╛рд░реА рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░ рд╕рдХрддреА рд╣реИ, рдмрд▓реНрдХрд┐ SQLAlchemy рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреА рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╕реНрдерд┐рддрд┐ рдХрд╛ рднреА рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХрд░рддреА рд╣реИредрдпрд╣ рд╕реБрд╡рд┐рдзрд╛ рдПрд▓реЗрдореНрдмрд┐рдХ рдХреЛ рдкрд░рд┐рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдХреА рддреБрд▓рдирд╛ рдХрд░рдиреЗ рдФрд░ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдПрдХ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдХреЛрдб рдЙрддреНрдкрдиреНрди рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИредрд╡реИрд╕реЗ, рдкреНрд░рддреНрдпреЗрдХ рдбреЗрдЯрд╛рдмреЗрд╕ рдХрд╛ рдЕрдкрдирд╛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдирд╛рдордХрд░рдг рдпреЛрдЬрдирд╛ рд╣реИред рддрд╛рдХрд┐ рдЖрдк рдирдП рдЕрд╡рд░реЛрдзреЛрдВ рдХреЗ рдирд╛рдордХрд░рдг рдореЗрдВ рд╕рдордп рдмрд░реНрдмрд╛рдж рди рдХрд░реЗрдВ рдпрд╛ рдЖрдкрдХреЛ рд╣рдЯрд╛рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреНрдпрд╛ рдмрд╛рдзрд╛ рд╣реИ, рдпрд╣ рдЦреЛрдЬрдирд╛ / рдпрд╛рдж рдХрд░рдирд╛, SQLAlchemy рдирд╛рдордХрд░рдг рдкрд░рдВрдкрд░рд╛рдУрдВ рдХреЗ рдирд╛рдордХрд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рд╕реБрдЭрд╛рд╡ рджреЗрддрд╛ рд╣реИ ред рдЙрдиреНрд╣реЗрдВ рд░рдЬрд┐рд╕реНрдЯреНрд░реА рдореЗрдВ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ MetaData
редрдореЗрдЯрд╛рдбреЗрдЯрд╛ рд░рдЬрд┐рд╕реНрдЯреНрд░реА рдмрдирд╛рдПрдБ рдФрд░ рдирд╛рдордХрд░рдг рдкреИрдЯрд░реНрди рдкрд╛рд╕ рдХрд░реЗрдВ
from sqlalchemy import MetaData
convention = {
'all_column_names': lambda constraint, table: '_'.join([
column.name for column in constraint.columns.values()
]),
'ix': 'ix__%(table_name)s__%(all_column_names)s',
'uq': 'uq__%(table_name)s__%(all_column_names)s',
'ck': 'ck__%(table_name)s__%(constraint_name)s',
'fk': 'fk__%(table_name)s__%(all_column_names)s__%(referred_table_name)s',
'pk': 'pk__%(table_name)s'
}
metadata = MetaData(naming_convention=convention)
рдпрджрд┐ рдЖрдк рдирд╛рдордХрд░рдг рдХреЗ рдкреИрдЯрд░реНрди рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдПрд▓реЗрдореНрдмрд┐рдХ рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдкреНрд░рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреА рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдкреАрдврд╝реА рдХреЗ рджреМрд░рд╛рди рдХрд░реЗрдЧрд╛ рдФрд░ рдЙрдирдХреЗ рдЕрдиреБрд╕рд╛рд░ рд╕рднреА рдмрд╛рдзрд╛рдУрдВ рдХрд╛ рдирд╛рдо рджреЗрдЧрд╛ред рднрд╡рд┐рд╖реНрдп рдореЗрдВ, MetaData
рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдирд╛рдИ рдЧрдИ рд░рдЬрд┐рд╕реНрдЯреНрд░реА рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА:рд╣рдо SQLAlchemy рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ рдХреЗ рд╕рд╛рде рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реНрдХреАрдорд╛ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреЗ рд╣реИрдВ
from enum import Enum, unique
from sqlalchemy import (
Column, Date, Enum as PgEnum, ForeignKey, ForeignKeyConstraint, Integer,
String, Table
)
@unique
class Gender(Enum):
female = 'female'
male = 'male'
imports_table = Table(
'imports',
metadata,
Column('import_id', Integer, primary_key=True)
)
citizens_table = Table(
'citizens',
metadata,
Column('import_id', Integer, ForeignKey('imports.import_id'),
primary_key=True),
Column('citizen_id', Integer, primary_key=True),
Column('town', String, nullable=False, index=True),
Column('street', String, nullable=False),
Column('building', String, nullable=False),
Column('apartment', Integer, nullable=False),
Column('name', String, nullable=False),
Column('birth_date', Date, nullable=False),
Column('gender', PgEnum(Gender, name='gender'), nullable=False),
)
relations_table = Table(
'relations',
metadata,
Column('import_id', Integer, primary_key=True),
Column('citizen_id', Integer, primary_key=True),
Column('relative_id', Integer, primary_key=True),
ForeignKeyConstraint(
('import_id', 'citizen_id'),
('citizens.import_id', 'citizens.citizen_id')
),
ForeignKeyConstraint(
('import_id', 'relative_id'),
('citizens.import_id', 'citizens.citizen_id')
),
)
рдЕрд▓реЗрдореНрдмрд┐рдХ рдХреЛ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░реЗрдВ
рдЬрдм рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реНрдХреАрдорд╛ рдХрд╛ рд╡рд░реНрдгрди рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдЙрддреНрдкрдиреНрди рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реЛрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рдкрд╣рд▓реЗ рдПрд▓реЗрдореНрдмрд┐рдХ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдирд╛ рд╣реЛрдЧрд╛, рдЬрд┐рд╕рдХреА рдЪрд░реНрдЪрд╛ рдЕрдзреНрдпрд╛рдп 5 рдореЗрдВ рднреА рдХреА рдЧрдИ рд╣реИ редрдХрдорд╛рдВрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП alembic
, рдЖрдкрдХреЛ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЪрд░рдг рдХрд░рдиреЗ рд╣реЛрдВрдЧреЗ:- рдкреИрдХреЗрдЬ рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗ:
pip install alembic
- рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдЕрд▓реЗрдореНрдмрд┐рдХ
cd analyzer && alembic init db/alembic
:ред
рдпрд╣ рдХрдорд╛рдВрдб рдПрдХ рд╡рд┐рдиреНрдпрд╛рд╕ рдлрд╛рдЗрд▓ analyzer/alembic.ini
рдФрд░ рдПрдХ рдлрд╝реЛрд▓реНрдбрд░ рдмрдирд╛рдПрдЧреА analyzer/db/alembic
рдЬрд┐рд╕рдореЗрдВ рдирд┐рдореНрди рд╕рд╛рдордЧреНрд░реА рд╣реЛрдЧреА:
env.py
- рд╣рд░ рдмрд╛рд░ рдЬрдм рдЖрдк рдЕрд▓реЗрдореНрдмрд┐рдХ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред sqlalchemy.MetaData
рдбреЗрдЯрд╛рдмреЗрд╕ рдХреА рд╡рд╛рдВрдЫрд┐рдд рд╕реНрдерд┐рддрд┐ рдХреЗ рд╡рд┐рд╡рд░рдг рдХреЗ рд╕рд╛рде рдПрд▓реЗрдореНрдмрд┐рдХ рд░рдЬрд┐рд╕реНрдЯреНрд░реА рд╕реЗ рдЬреЛрдбрд╝рддрд╛ рд╣реИ рдФрд░ рдЗрд╕рдореЗрдВ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рдирд┐рд░реНрджреЗрд╢ рд╢рд╛рдорд┐рд▓ рд╣реИрдВред
script.py.mako
- рдЬрд┐рд╕ рдЖрдзрд╛рд░ рдкрд░ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдЙрддреНрдкрдиреНрди рд╣реЛрддрд╛ рд╣реИ, рдЙрд╕рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдЯреЗрдореНрдкреНрд▓реЗрдЯредversions
- рд╡рд╣ рдлрд╝реЛрд▓реНрдбрд░ рдЬрд┐рд╕рдореЗрдВ рдЕрд▓реЗрдореНрдмрд┐рдХ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдЦреЛрдЬреЗрдЧрд╛ (рдФрд░ рдЙрддреНрдкрдиреНрди рдХрд░реЗрдЧрд╛)ред
- рдбреЗрдЯрд╛рдмреЗрд╕ рдкрддреЗ рдХреЛ alembic.ini рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░реЗрдВ:
; analyzer/alembic.ini
[alembic]
sqlalchemy.url = postgresql://user:hackme@localhost/analyzer
- рдбреЗрдЯрд╛рдмреЗрд╕ (рд░рдЬрд┐рд╕реНрдЯреНрд░реА
sqlalchemy.MetaData
) рдХреА рд╡рд╛рдВрдЫрд┐рдд рд╕реНрдерд┐рддрд┐ рдХрд╛ рд╡рд┐рд╡рд░рдг рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░реЗрдВ рддрд╛рдХрд┐ рдПрд▓реЗрдмрд┐рдХ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдЙрддреНрдкрдиреНрди рдХрд░ рд╕рдХреЗ:
from analyzer.db import schema
target_metadata = schema.metadata
рдПрд▓реЗрдореНрдмрд┐рдХ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рдФрд░ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ рдЗрд╕ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдореЗрдВ рдХрдИ рдиреБрдХрд╕рд╛рди рд╣реИрдВ:- рдЙрдкрдпреЛрдЧрд┐рддрд╛ рд╡рд░реНрддрдорд╛рди рдХрд╛рд░реНрдп рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдореЗрдВ
alembic
рдЦреЛрдЬ рдХрд░рддреА alembic.ini
рд╣реИред рдЖрдк alembic.ini
рдХрдорд╛рдВрдб рд▓рд╛рдЗрди рддрд░реНрдХ рдХреЗ рд▓рд┐рдП рдкрде рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдпрд╣ рдЕрд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИ: рдореИрдВ рдЕрддрд┐рд░рд┐рдХреНрдд рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рдмрд┐рдирд╛ рдХрд┐рд╕реА рднреА рдлрд╝реЛрд▓реНрдбрд░ рд╕реЗ рдХрдорд╛рдВрдб рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред - рдХрд┐рд╕реА рд╡рд┐рд╢рд┐рд╖реНрдЯ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрд▓реЗрдореНрдмрд┐рдХ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдлрд╝рд╛рдЗрд▓ рдХреЛ рдмрджрд▓рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ
alembic.ini
ред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдкрд░реНрдпрд╛рд╡рд░рдг рдЪрд░ рдФрд░ / рдпрд╛ рдХрдорд╛рдВрдб рд▓рд╛рдЗрди рддрд░реНрдХ рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдирд╛ рдЕрдзрд┐рдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реЛрдЧрд╛ --pg-url
ред - рдЙрдкрдпреЛрдЧрд┐рддрд╛
alembic
рдХрд╛ рдирд╛рдо рд╣рдорд╛рд░реА рд╕реЗрд╡рд╛ рдХреЗ рдирд╛рдо рдХреЗ рд╕рд╛рде рдмрд╣реБрдд рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рд╕рдВрдмрдВрдз рдирд╣реАрдВ рд░рдЦрддрд╛ рд╣реИ (рдФрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЕрдЬрдЧрд░ рдмрд┐рд▓реНрдХреБрд▓ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рдПрд▓реЗрдореНрдмрд┐рдХ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рднреА рдирд╣реАрдВ рдЬрд╛рдирддрд╛ рд╣реИ)ред рдпрд╣ рдЕрдВрдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реЛрдЧрд╛ рдпрджрд┐ рд╕реЗрд╡рд╛ рдХреЗ рд╕рднреА рдирд┐рд╖реНрдкрд╛рджрди рдпреЛрдЧреНрдп рдЖрджреЗрд╢реЛрдВ рдореЗрдВ рдПрдХ рд╕рд╛рдорд╛рдиреНрдп рдЙрдкрд╕рд░реНрдЧ рдерд╛, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП analyzer-*
ред
рдЗрди рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЛ рдПрдХ рдЫреЛрдЯреЗ рдЖрд╡рд░рдг рдХреЗ рд╕рд╛рде рд╣рд▓ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред analyzer/db/__main__.py:
- рдЕрд▓реЗрдореНрдмрд┐рдХ рдХрдорд╛рдВрдб рд▓рд╛рдЗрди рдХреЗ рддрд░реНрдХреЛрдВ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдорд╛рдирдХ рдореЙрдбреНрдпреВрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ
argparse
ред рдпрд╣ рдЖрдкрдХреЛ --pg-url
рдкрд░реНрдпрд╛рд╡рд░рдг рдЪрд░ рд╕реЗ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдорд╛рди рдХреЗ рд╕рд╛рде рдПрдХ рд╡реИрдХрд▓реНрдкрд┐рдХ рддрд░реНрдХ рдЬреЛрдбрд╝рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ ANALYZER_PG_URL
ред
рдХреЛрдбimport os
from alembic.config import CommandLine, Config
from analyzer.utils.pg import DEFAULT_PG_URL
def main():
alembic = CommandLine()
alembic.parser.add_argument(
'--pg-url', default=os.getenv('ANALYZER_PG_URL', DEFAULT_PG_URL),
help='Database URL [env var: ANALYZER_PG_URL]'
)
options = alembic.parser.parse_args()
config = Config(file_=options.config, ini_section=options.name,
cmd_opts=options)
config.set_main_option('sqlalchemy.url', options.pg_url)
exit(alembic.run_cmd(config, options))
if __name__ == '__main__':
main()
- рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдкрде
alembic.ini
рдирд┐рд╖реНрдкрд╛рджрди рдпреЛрдЧреНрдп рдлрд╝рд╛рдЗрд▓ рдХреЗ рд╕реНрдерд╛рди рдХреЗ рд╕рд╛рдкреЗрдХреНрд╖ рдЧрдгрдирд╛ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рди рдХрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреА рд╡рд░реНрддрдорд╛рди рдХрд╛рд░реНрдпрд╢реАрд▓ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдХреЗ рд▓рд┐рдПред
рдХреЛрдбimport os
from alembic.config import CommandLine, Config
from pathlib import Path
PROJECT_PATH = Path(__file__).parent.parent.resolve()
def main():
alembic = CommandLine()
options = alembic.parser.parse_args()
if not os.path.isabs(options.config):
options.config = os.path.join(PROJECT_PATH, options.config)
config = Config(file_=options.config, ini_section=options.name,
cmd_opts=options)
alembic_location = config.get_main_option('script_location')
if not os.path.isabs(alembic_location):
config.set_main_option('script_location',
os.path.join(PROJECT_PATH, alembic_location))
exit(alembic.run_cmd(config, options))
if __name__ == '__main__':
main()
рдЬрдм рдбреЗрдЯрд╛рдмреЗрд╕ рдХреА рд╕реНрдерд┐рддрд┐ рдХреЛ рдкреНрд░рдмрдВрдзрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧрд┐рддрд╛ рддреИрдпрд╛рд░ рд╣реЛ рдЬрд╛рддреА рд╣реИ, рддреЛ рдЗрд╕реЗ setup.py
рдЕрдВрддрд┐рдо рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рд▓рд┐рдП рд╕рдордЭ рдореЗрдВ рдЖрдиреЗ рд╡рд╛рд▓реЗ рдирд╛рдо рдХреЗ рд╕рд╛рде рдПрдХ рдирд┐рд╖реНрдкрд╛рджрди рдпреЛрдЧреНрдп рдХрдорд╛рдВрдб рдХреЗ рд░реВрдк рдореЗрдВ рдкрдВрдЬреАрдХреГрдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ analyzer-db
:Setup.py рдореЗрдВ рдПрдХ рдирд┐рд╖реНрдкрд╛рджрди рдпреЛрдЧреНрдп рдХрдорд╛рдВрдб рд░рдЬрд┐рд╕реНрдЯрд░ рдХрд░реЗрдВfrom setuptools import setup
setup(..., entry_points={
'console_scripts': [
'analyzer-db = analyzer.db.__main__:main'
]
})
рдореЙрдбреНрдпреВрд▓ рдХреЛ рдлрд┐рд░ рд╕реЗ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рдПрдХ рдлрд╝рд╛рдЗрд▓ рдЙрддреНрдкрдиреНрди рд╣реЛрдЧреА env/bin/analyzer-db
рдФрд░ рдХрдорд╛рдВрдб analyzer-db
рдЙрдкрд▓рдмреНрдз рд╣реЛ рдЬрд╛рдПрдЧреА:$ pip install -e '.[dev]'
рд╣рдо рдкрд▓рд╛рдпрди рдкреИрджрд╛ рдХрд░рддреЗ рд╣реИрдВ
рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдЙрддреНрдкрдиреНрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рджреЛ рд░рд╛рдЬреНрдпреЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ: рд╡рд╛рдВрдЫрд┐рдд (рдЬрд┐рд╕реЗ рд╣рдордиреЗ SQLAlchemy рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ рдХреЗ рд╕рд╛рде рд╡рд░реНрдгрд┐рдд рдХрд┐рдпрд╛ рд╣реИ) рдФрд░ рд╡рд╛рд╕реНрддрд╡рд┐рдХ (рдбреЗрдЯрд╛рдмреЗрд╕, рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдЦрд╛рд▓реА рд╣реИ)редрдореИрдВрдиреЗ рддрдп рдХрд┐рдпрд╛ рдХрд┐ рдбрд╛рдХрдЯрд░ рдХреЗ рд╕рд╛рде рдкреЛрд╕реНрдЯрдЧреНрд░реИрдЬ рдХреЛ рдмрдврд╝рд╛рдиреЗ рдХрд╛ рд╕рдмрд╕реЗ рдЖрд╕рд╛рди рддрд░реАрдХрд╛ make postgres
рдкреГрд╖реНрдарднреВрдорд┐ рдореЗрдВ 5432 рдкреЛрд░реНрдЯ рдкрд░ рдкреЛрд╕реНрдЯрдЧреНрд░реЗрдХреНрдпреВрдПрд▓ рдХреЗ рд╕рд╛рде рдПрдХ рдХрдВрдЯреЗрдирд░ рдЪрд▓рд╛рдиреЗ рд╡рд╛рд▓рд╛ рдПрдХ рдХрдорд╛рдВрдб рдЬреЛрдбрд╝рдирд╛ рдерд╛ :PostgreSQL рдЙрдард╛рдПрдБ рдФрд░ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдЬрдирд░реЗрдЯ рдХрд░реЗрдВ$ make postgres
...
$ analyzer-db revision --message="Initial" --autogenerate
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO [alembic.runtime.migration] Will assume transactional DDL.
INFO [alembic.autogenerate.compare] Detected added table 'imports'
INFO [alembic.autogenerate.compare] Detected added table 'citizens'
INFO [alembic.autogenerate.compare] Detected added index 'ix__citizens__town' on '['town']'
INFO [alembic.autogenerate.compare] Detected added table 'relations'
Generating /Users/alvassin/Work/backendschool2019/analyzer/db/alembic/versions/d5f704ed4610_initial.py ... done
рдЕрд▓реЗрдореНрдмрд┐рдХ рдЖрдо рддреМрд░ рдкрд░ рдкрд▓рд╛рдпрди рдкреИрджрд╛ рдХрд░рдиреЗ рдХреЗ рдирд┐рдпрдорд┐рдд рдХрд╛рдо рдХрд╛ рдПрдХ рдЕрдЪреНрдЫрд╛ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореИрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкрд░ рдзреНрдпрд╛рди рдЖрдХрд░реНрд╖рд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ:- рдмрдирд╛рдП рдЧрдП рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдореЗрдВ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдбреЗрдЯрд╛ рдкреНрд░рдХрд╛рд░ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ (рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ -
gender
) рдмрдирд╛рдП рдЬрд╛рддреЗ рд╣реИрдВ , рд▓реЗрдХрд┐рди рдЙрдиреНрд╣реЗрдВ рд╣рдЯрд╛рдиреЗ рдХрд╛ рдХреЛрдб downgrade
рдЙрддреНрдкрдиреНрди рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред рдпрджрд┐ рдЖрдк рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╡рд╛рдкрд╕ рд░реЛрд▓ рдХрд░реЗрдВ, рдФрд░ рдлрд┐рд░ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдлрд┐рд░ рд╕реЗ рд▓рд╛рдЧреВ рдХрд░реЗрдВ, рдЗрд╕рд╕реЗ рдПрдХ рддреНрд░реБрдЯрд┐ рд╣реЛрдЧреА рдХреНрдпреЛрдВрдХрд┐ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдбреЗрдЯрд╛ рдкреНрд░рдХрд╛рд░ рдкрд╣рд▓реЗ рд╕реЗ рдореМрдЬреВрдж рд╣реИред
рд▓рд┐рдВрдЧ рдбреЗрдЯрд╛ рдкреНрд░рдХрд╛рд░ рдХреЛ рдбрд╛рдЙрдирдЧреНрд░реЗрдб рдкрджреНрдзрддрд┐ рдореЗрдВ рд╣рдЯрд╛рдПрдВfrom alembic import op
from sqlalchemy import Column, Enum
GenderType = Enum('female', 'male', name='gender')
def upgrade():
...
op.create_table('citizens', ...,
Column('gender', GenderType, nullable=False))
...
def downgrade():
op.drop_table('citizens')
GenderType.drop(op.get_bind())
- рд╡рд┐рдзрд┐ рдореЗрдВ,
downgrade
рдХреБрдЫ рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЛ рдХрднреА-рдХрднреА рд╣рдЯрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ (рдпрджрд┐ рд╣рдо рдкреВрд░реА рддрд╛рд▓рд┐рдХрд╛ рдХреЛ рд╣рдЯрд╛ рджреЗрддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рдЗрд╕рдХреЗ рдЕрдиреБрдХреНрд░рдорд┐рдд рдХреЛ рдЕрд▓рдЧ рд╕реЗ рдирд╣реАрдВ рд╣рдЯрд╛ рд╕рдХрддреЗ):
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдПdef downgrade():
op.drop_table('relations')
op.drop_index(op.f('ix__citizens__town'), table_name='citizens')
op.drop_table('citizens')
op.drop_table('imports')
рдЬрдм рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдареАрдХ рдФрд░ рддреИрдпрд╛рд░ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рд╣рдо рдЗрд╕реЗ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВ:$ analyzer-db upgrade head
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO [alembic.runtime.migration] Will assume transactional DDL.
INFO [alembic.runtime.migration] Running upgrade -> d5f704ed4610, Initial
рдЖрд╡реЗрджрди
рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рдХрд┐ рдЖрдк рд╣реИрдВрдбрд▓рд░ рдмрдирд╛рдирд╛ рд╢реБрд░реВ рдХрд░реЗрдВ, рдЖрдкрдХреЛ aiohttp рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдирд╛ рд╣реЛрдЧрд╛редрдпрджрд┐ рдЖрдк aiohttp quickstart рдХреЛ рджреЗрдЦрддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВimport logging
from aiohttp import web
def main():
logging.basicConfig(level=logging.DEBUG)
app = web.Application()
app.router.add_route(...)
web.run_app(app)
рдпрд╣ рдХреЛрдб рдХрдИ рдкреНрд░рд╢реНрди рдЙрдард╛рддрд╛ рд╣реИ рдФрд░ рдЗрд╕рдореЗрдВ рдХрдИ рдиреБрдХрд╕рд╛рди рд╣реИрдВ:- рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдХреИрд╕реЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░реЗрдВ? рдХрдо рд╕реЗ рдХрдо, рдЖрдкрдХреЛ рдХреНрд▓рд╛рдЗрдВрдЯ рд╕реЗ рдХрдиреЗрдХреНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реЛрд╕реНрдЯ рдФрд░ рдкреЛрд░реНрдЯ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдирд╛ рд╣реЛрдЧрд╛, рд╕рд╛рде рд╣реА рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдХрдиреЗрдХреНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд╛рдирдХрд╛рд░реА рднреАред
рдореБрдЭреЗ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдореЙрдбреНрдпреВрд▓ рдХреА рдорджрдж рд╕реЗ рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдирд╛ рдкрд╕рдВрдж рд╣реИ ConfigArgParse
: рдпрд╣ рдорд╛рдирдХ рдПрдХ рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд░рддрд╛ рд╣реИ argparse
рдФрд░ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЗ рд▓рд┐рдП рдХрдорд╛рдВрдб рд▓рд╛рдЗрди рддрд░реНрдХ, рдкрд░реНрдпрд╛рд╡рд░рдг рдЪрд░ (рдбреЙрдХрдЯрд░ рдХрдВрдЯреЗрдирд░реЛрдВ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдкрд░рд┐рд╣рд╛рд░реНрдп) рдФрд░ рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓реЛрдВ (рд╕рд╛рде рд╣реА рдЗрди рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рдорд┐рд▓рд╛рдХрд░) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред ConfigArgParse
рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ , рдЖрдк рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рдореВрд▓реНрдпреЛрдВ рдХреЛ рднреА рдорд╛рдиреНрдп рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
ConfigArgParse рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдорд╛рдкрджрдВрдбреЛрдВ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдгfrom aiohttp import web
from configargparse import ArgumentParser, ArgumentDefaultsHelpFormatter
from analyzer.utils.argparse import positive_int
parser = ArgumentParser(
auto_env_var_prefix='ANALYZER_',
formatter_class=ArgumentDefaultsHelpFormatter
)
parser.add_argument('--api-address', default='0.0.0.0',
help='IPv4/IPv6 address API server would listen on')
parser.add_argument('--api-port', type=positive_int, default=8081,
help='TCP port API server would listen on')
def main():
args = parser.parse_args()
app = web.Application()
web.run_app(app, host=args.api_address, port=args.api_port)
if __name__ == '__main__':
main()
, ConfigArgParse
, argparse
, ( -h
--help
). :
$ python __main__.py --help
usage: __main__.py [-h] [--api-address API_ADDRESS] [--api-port API_PORT]
If an arg is specified in more than one place, then commandline values override environment variables which override defaults.
optional arguments:
-h, --help show this help message and exit
--api-address API_ADDRESS
IPv4/IPv6 address API server would listen on [env var: ANALYZER_API_ADDRESS] (default: 0.0.0.0)
--api-port API_PORT TCP port API server would listen on [env var: ANALYZER_API_PORT] (default: 8081)
- тАФ , ┬л┬╗ . , .
os.environ.clear()
, Python (, asyncio
?), , ConfigArgParser
.
import os
from typing import Callable
from configargparse import ArgumentParser
from yarl import URL
from analyzer.api.app import create_app
from analyzer.utils.pg import DEFAULT_PG_URL
ENV_VAR_PREFIX = 'ANALYZER_'
parser = ArgumentParser(auto_env_var_prefix=ENV_VAR_PREFIX)
parser.add_argument('--pg-url', type=URL, default=URL(DEFAULT_PG_URL),
help='URL to use to connect to the database')
def clear_environ(rule: Callable):
"""
,
rule
"""
for name in filter(rule, tuple(os.environ)):
os.environ.pop(name)
def main():
args = parser.parse_args()
clear_environ(lambda i: i.startswith(ENV_VAR_PREFIX))
app = create_app(args)
...
if __name__ == '__main__':
main()
- stderr/ .
9 , logging.basicConfig()
stderr
.
, . aiomisc.
aiomiscimport logging
from aiomisc.log import basic_config
basic_config(logging.DEBUG, buffered=True)
- , ? ,
fork
, (, Windows ).
import os
from sys import argv
import forklib
from aiohttp.web import Application, run_app
from aiomisc import bind_socket
from setproctitle import setproctitle
def main():
sock = bind_socket(address='0.0.0.0', port=8081, proto_name='http')
setproctitle(f'[Master] {os.path.basename(argv[0])}')
def worker():
setproctitle(f'[Worker] {os.path.basename(argv[0])}')
app = Application()
run_app(app, sock=sock)
forklib.fork(os.cpu_count(), worker, auto_restart=True)
if __name__ == '__main__':
main()
- - ? , ( тАФ ) ,
nobody
. тАФ .
import os
import pwd
from aiohttp.web import run_app
from aiomisc import bind_socket
from analyzer.api.app import create_app
def main():
sock = bind_socket(address='0.0.0.0', port=8085, proto_name='http')
user = pwd.getpwnam('nobody')
os.setgid(user.pw_gid)
os.setuid(user.pw_uid)
app = create_app(...)
run_app(app, sock=sock)
if __name__ == '__main__':
main()
create_app
, .
рд╕рднреА рд╕рдлрд▓ рд╣реИрдВрдбрд▓рд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рдПрдВ JSON рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рд╡рд╛рдкрд╕ рдЖ рдЬрд╛рдПрдВрдЧреАред рдпрд╣ рдЧреНрд░рд╛рд╣рдХреЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рдХреНрд░рдордмрджреНрдз рд░реВрдк рдореЗрдВ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рднреА рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реЛрдЧрд╛ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрд╣ рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдХрд┐рди рдХреНрд╖реЗрддреНрд░реЛрдВ рдиреЗ рд╕рддреНрдпрд╛рдкрди рдкрд╛рд░рд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИ)редрдкреНрд░рд▓реЗрдЦрди aiohttp
рдПрдХ рд╡рд┐рдзрд┐ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ json_response
рдЬреЛ рдПрдХ рд╡рд╕реНрддреБ рд▓реЗрддрд╛ рд╣реИ, рдЗрд╕реЗ JSON рдореЗрдВ рдХреНрд░рдордмрджреНрдз рдХрд░рддрд╛ рд╣реИ, рдФрд░ aiohttp.web.Response
рдПрдХ рд╣реЗрдбрд░ Content-Type: application/json
рдФрд░ рдХреНрд░рдордмрджреНрдз рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдПрдХ рдирдИ рд╡рд╕реНрддреБ рджреЗрддрд╛ рд╣реИ редJson_response рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдбреЗрдЯрд╛ рдХреЛ рдХреНрд░рдордмрджреНрдз рдХреИрд╕реЗ рдХрд░реЗрдВfrom aiohttp.web import Application, View, run_app
from aiohttp.web_response import json_response
class SomeView(View):
async def get(self):
return json_response({'hello': 'world'})
app = Application()
app.router.add_route('*', '/hello', SomeView)
run_app(app)
рд▓реЗрдХрд┐рди рдПрдХ рдФрд░ рддрд░реАрдХрд╛ рд╣реИ: aiohttp рдЖрдкрдХреЛ рд░рдЬрд┐рд╕реНрдЯреНрд░реА рдореЗрдВ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдкреНрд░рдХрд╛рд░ рдХреЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдбреЗрдЯрд╛ рдХреЗ рд▓рд┐рдП рдПрдХ рдордирдорд╛рдиреЗ рдврдВрдЧ рд╕реЗ рдзрд╛рд░рд╛рд╡рд╛рд╣рд┐рдХ рдХреЛ рдкрдВрдЬреАрдХреГрдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ aiohttp.PAYLOAD_REGISTRY
ред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЖрдк рдЯрд╛рдЗрдкрд┐рдВрдЧ рдореИрдкрд┐рдВрдЧaiohttp.JsonPayload
рдХреА рд╡рд╕реНрддреБрдУрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рдзрд╛рд░рд╛рд╡рд╛рд╣рд┐рдХ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ ред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╣реИрдВрдбрд▓рд░ рдХреЗ рд▓рд┐рдП рдкреИрд░рд╛рдореАрдЯрд░ рдореЗрдВ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдПрдХ рд╡рд╕реНрддреБ рд╡рд╛рдкрд╕ рдХрд░рдирд╛ рдкрд░реНрдпрд╛рдкреНрдд рд╣реЛрдЧрд╛ ред aiohttp рдПрдХ serializer рдорд┐рд▓реЗрдЧрд╛ рдЬреЛ рдбреЗрдЯрд╛ рдкреНрд░рдХрд╛рд░ рд╕реЗ рдореЗрд▓ рдЦрд╛рддрд╛ рд╣реИ рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЛ рдХреНрд░рдордмрджреНрдз рдХрд░рддрд╛ рд╣реИред рдЗрд╕ рддрдереНрдп рдХреЗ рдЕрд▓рд╛рд╡рд╛ рдХрд┐ рд╡рд╕реНрддреБрдУрдВ рдХрд╛ рдХреНрд░рдордмрджреНрдзрддрд╛ рдПрдХ рд╣реА рд╕реНрдерд╛рди рдкрд░ рд╡рд░реНрдгрд┐рдд рд╣реИ, рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг рднреА рдЕрдзрд┐рдХ рд▓рдЪреАрд▓рд╛ рд╣реИ - рдпрд╣ рдЖрдкрдХреЛ рдмрд╣реБрдд рджрд┐рд▓рдЪрд╕реНрдк рд╕рдорд╛рдзрд╛рдиреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ (рд╣рдо рд╣реИрдВрдбрд▓рд░ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХреЗ рдорд╛рдорд▓реЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВрдЧреЗ )редResponse
body
GET /imports/$import_id/citizens
Aiohttp.PAYLOAD_REGISTRY рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдбреЗрдЯрд╛ рдХреЛ рдХреИрд╕реЗ рдЕрдиреБрдХреНрд░рдорд┐рдд рдХрд░реЗрдВfrom types import MappingProxyType
from typing import Mapping
from aiohttp import PAYLOAD_REGISTRY, JsonPayload
from aiohttp.web import run_app, Application, Response, View
PAYLOAD_REGISTRY.register(JsonPayload, (Mapping, MappingProxyType))
class SomeView(View):
async def get(self):
return Response(body={'hello': 'world'})
app = Application()
app.router.add_route('*', '/hello', SomeView)
run_app(app)
рдпрд╣ рд╕рдордЭрдирд╛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ рдХрд┐ json_response
, рдЬреИрд╕реЗ aiohttp.JsonPayload
, рд╡реЗ рдПрдХ рдорд╛рдирдХ рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ рдЬреЛ json.dumps
рдЬрдЯрд┐рд▓ рдбреЗрдЯрд╛ рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЛ рдХреНрд░рдордмрджреНрдз рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, datetime.date
рдпрд╛ asyncpg.Record
( asyncpg
рдЗрд╕ рд╡рд░реНрдЧ рдХреЗ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рд░рд┐рдХреЙрд░реНрдб рд▓реМрдЯрд╛рддрд╛ рд╣реИ)ред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдХреБрдЫ рдЬрдЯрд┐рд▓ рд╡рд╕реНрддреБрдУрдВ рдореЗрдВ рдЕрдиреНрдп рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ: рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдПрдХ рд░рд┐рдХреЙрд░реНрдб рдореЗрдВ рдПрдХ рдкреНрд░рдХрд╛рд░ рдХрд╛ рдХреНрд╖реЗрддреНрд░ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ datetime.date
редрдкрд╛рдпрдерди рдбреЗрд╡рд▓рдкрд░реНрд╕ рдиреЗ рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╕рдВрдмреЛрдзрд┐рдд рдХрд┐рдпрд╛ рд╣реИ: рд╡рд┐рдзрд┐ json.dumps
рдЖрдкрдХреЛ default
рдХрд┐рд╕реА рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рддрд░реНрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИ рдЬрд┐рд╕реЗ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ рдЬрдм рдХрд┐рд╕реА рдЕрдкрд░рд┐рдЪрд┐рдд рд╡рд╕реНрддреБ рдХреЛ рдХреНрд░рдордмрджреНрдз рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реЛрддрд╛ рд╣реИред рдлрд╝рдВрдХреНрд╢рди рд╕реЗ рдпрд╣ рдЙрдореНрдореАрдж рдХреА рдЬрд╛рддреА рд╣реИ рдХрд┐ рд╡рд╣ рдЕрдкрд░рд┐рдЪрд┐рдд рд╡рд╕реНрддреБ рдХреЛ рдПрдХ рдкреНрд░рдХрд╛рд░ рд╕реЗ рдбрд╛рд▓реЗ рдЬреЛ рдХрд┐ рдЬрд╕рди рдореЙрдбреНрдпреВрд▓ рдХреЛ рдЕрдиреБрдХреНрд░рдорд┐рдд рдХрд░ рд╕рдХреЗредрдордирдорд╛рдиреА рд╡рд╕реНрддреБрдУрдВ рдХреЛ рдХреНрд░рдордмрджреНрдз рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП JsonPayload рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдХреИрд╕реЗ рдХрд░реЗрдВimport json
from datetime import date
from functools import partial, singledispatch
from typing import Any
from aiohttp.payload import JsonPayload as BaseJsonPayload
from aiohttp.typedefs import JSONEncoder
@singledispatch
def convert(value):
raise NotImplementedError(f'Unserializable value: {value!r}')
@convert.register(Record)
def convert_asyncpg_record(value: Record):
"""
,
asyncpg
"""
return dict(value)
@convert.register(date)
def convert_date(value: date):
"""
date тАФ
.
..
"""
return value.strftime('%d.%m.%Y')
dumps = partial(json.dumps, default=convert)
class JsonPayload(BaseJsonPayload):
def __init__(self,
value: Any,
encoding: str = 'utf-8',
content_type: str = 'application/json',
dumps: JSONEncoder = dumps,
*args: Any,
**kwargs: Any) -> None:
super().__init__(value, encoding, content_type, dumps, *args, **kwargs)
рд╣реИрдВрдбрд▓рд░
aiohttp рдЖрдкрдХреЛ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдХрд╛рд░реНрдпреЛрдВ рдФрд░ рдХрдХреНрд╖рд╛рдУрдВ рдХреЗ рд╕рд╛рде рд╣реИрдВрдбрд▓рд░ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдХрдХреНрд╖рд╛рдПрдВ рдЕрдзрд┐рдХ рдПрдХреНрд╕реНрдЯреЗрдВрд╕рд┐рдмрд▓ рд╣реИрдВ: рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдПрдХ рд╣реИрдВрдбрд▓рд░ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рдХреЛрдб рдХреЛ рдПрдХ рд╕реНрдерд╛рди рдкрд░ рд░рдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ рджреВрд╕рд░реА рдмрд╛рдд, рдХрдХреНрд╖рд╛рдПрдВ рдЖрдкрдХреЛ рдХреЛрдб рджреЛрд╣рд░рд╛рд╡ рд╕реЗ рдЫреБрдЯрдХрд╛рд░рд╛ рдкрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд┐рд░рд╛рд╕рдд рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИрдВ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдкреНрд░рддреНрдпреЗрдХ рд╣реИрдВрдбрд▓рд░ рдХреЛ рдбреЗрдЯрд╛рдмреЗрд╕ рдХрдиреЗрдХреНрд╢рди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ)редрд╣реИрдВрдбрд▓рд░ рдмреЗрд╕ рдХреНрд▓рд╛рд╕from aiohttp.web_urldispatcher import View
from asyncpgsa import PG
class BaseView(View):
URL_PATH: str
@property
def pg(self) -> PG:
return self.request.app['pg']
рдЪреВрдВрдХрд┐ рдПрдХ рдмрдбрд╝реА рдлрд╝рд╛рдЗрд▓ рдХреЛ рдкрдврд╝рдирд╛ рдореБрд╢реНрдХрд┐рд▓ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВрдиреЗ рд╣реИрдВрдбрд▓рд░ рдХреЛ рдлрд╝рд╛рдЗрд▓реЛрдВ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛ред рдЫреЛрдЯреА рдлрд╛рдЗрд▓реЗрдВ рдХрдордЬреЛрд░ рдХрдиреЗрдХреНрдЯрд┐рд╡рд┐рдЯреА рдХреЛ рдкреНрд░реЛрддреНрд╕рд╛рд╣рд┐рдд рдХрд░рддреА рд╣реИрдВ, рдФрд░ рдпрджрд┐, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╣реИрдВрдбрд▓рд░ рдХреЗ рдЕрдВрджрд░ рд░рд┐рдВрдЧ рдЖрдпрд╛рдд рд╣реЛрддреЗ рд╣реИрдВ, рддреЛ рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рд╕рдВрд╕реНрдерд╛рдУрдВ рдХреА рд╕рдВрд░рдЪрдирд╛ рдХреЗ рд╕рд╛рде рдХреБрдЫ рдЧрд▓рдд рд╣реЛ рд╕рдХрддрд╛ рд╣реИредрдкреЛрд╕реНрдЯ / рдЖрдпрд╛рдд
рдЗрдирдкреБрдЯ рд╣реИрдВрдбрд▓рд░ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде json рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИред Aiohttp рдореЗрдВ рдЕрдзрд┐рдХрддрдо рд╕реНрд╡реАрдХрд╛рд░реНрдп рдЕрдиреБрд░реЛрдз рдЖрдХрд╛рд░ рд╡рд┐рдХрд▓реНрдк рджреНрд╡рд╛рд░рд╛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ client_max_size
рдФрд░ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ 2 рдПрдордмреА рд╣реИ ред рдпрджрд┐ рд╕реАрдорд╛ рдкрд╛рд░ рд╣реЛ рдЬрд╛рддреА рд╣реИ, рддреЛ aiohttp 413 рдХреА рд╕реНрдерд┐рддрд┐ рдХреЗ рд╕рд╛рде рдПрдХ HTTP рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд▓реМрдЯрд╛рдПрдЧрд╛: рдЕрдиреБрд░реЛрдз рдмрд╣реБрдд рдмрдбрд╝реА рддреНрд░реБрдЯрд┐редрдЗрд╕реА рд╕рдордп, рд╕рдмрд╕реЗ рд▓рдВрдмреА рд░реЗрдЦрд╛рдУрдВ рдФрд░ рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреЗ рд╕рд╛рде рд╕рд╣реА рдЬреЛрдВрд╕ рдХрд╛ рд╡рдЬрди ~ 63 рдореЗрдЧрд╛рдмрд╛рдЗрдЯ рд╣реЛрдЧрд╛, рдЗрд╕рд▓рд┐рдП рдЕрдиреБрд░реЛрдз рдХреЗ рдЖрдХрд╛рд░ рдкрд░ рдкреНрд░рддрд┐рдмрдВрдзреЛрдВ рдХреЛ рд╡рд┐рд╕реНрддрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИредрдЗрд╕рдХреЗ рдмрд╛рдж, рдЖрдкрдХреЛ рдбреЗрдЯрд╛ рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдФрд░ рдЙрд╕реЗ рдирд┐рд╖реНрдХреНрд░рд┐рдп рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ ред рдпрджрд┐ рд╡реЗ рдЧрд▓рдд рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ рдПрдХ HTTP рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ 400: Bad Request
редрдореБрдЭреЗ рджреЛ рдпреЛрдЬрдирд╛рдУрдВ рдХреА рдЬрд░реВрд░рдд рдереА Marhsmallow
ред рдкрд╣рд▓рд╛ рд╡реНрдпрдХреНрддрд┐ CitizenSchema
, рдкреНрд░рддреНрдпреЗрдХ рд╡реНрдпрдХреНрддрд┐рдЧрдд рдирд┐рд╡рд╛рд╕реА рдХреЗ рдбреЗрдЯрд╛ рдХреА рдЬрд╛рдВрдЪ рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдСрдмреНрдЬреЗрдХреНрдЯ рдореЗрдВ рдЦреБрд╢ рдЬрдиреНрдорджрд┐рди рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЛ рднреА рджрд┐рдЦрд╛рддрд╛ рд╣реИ datetime.date
:- рдбреЗрдЯрд╛ рдкреНрд░рдХрд╛рд░, рдкреНрд░рд╛рд░реВрдк рдФрд░ рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреА рдЙрдкрд▓рдмреНрдзрддрд╛;
- рдЕрдкрд░рд┐рдЪрд┐рдд рдЦреЗрддреЛрдВ рдХреА рдХрдореА;
- рдЬрдиреНрдо рдХреА рддрд╛рд░реАрдЦ рдХреЛ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдЗрдВрдЧрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП
DD.MM.YYYY
рдФрд░ рднрд╡рд┐рд╖реНрдп рд╕реЗ рдЗрд╕рдХрд╛ рдХреЛрдИ рдорд╣рддреНрд╡ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ; - рдкреНрд░рддреНрдпреЗрдХ рдирд┐рд╡рд╛рд╕реА рдХреЗ рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреА рд╕реВрдЪреА рдореЗрдВ рдЗрд╕ рдЕрдкрд▓реЛрдб рдореЗрдВ рдореМрдЬреВрдж рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рдЕрдирдиреНрдп рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рд╣реЛрдиреЗ рдЪрд╛рд╣рд┐рдПред
рджреВрд╕рд░реА рдпреЛрдЬрдирд╛ ImportSchema
,, рдПрдХ рдкреВрд░реЗ рдХреЗ рд░реВрдк рдореЗрдВ рдЙрддрд╛рд░рдиреЗ рдХреА рдЬрд╛рдБрдЪ рдХрд░рддрд╛ рд╣реИ:citizen_id
рдЙрддрд░рд╛рдИ рдХреЗ рднреАрддрд░ рдкреНрд░рддреНрдпреЗрдХ рдирд┐рд╡рд╛рд╕реА рдЕрджреНрд╡рд┐рддреАрдп рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП;- рдкрд╛рд░рд┐рд╡рд╛рд░рд┐рдХ рд╕рдВрдмрдВрдз рджреЛ-рддрд░рдлрд╝рд╛ рд╣реЛрдиреЗ рдЪрд╛рд╣рд┐рдП (рдпрджрд┐ рдирд┐рд╡рд╛рд╕реА # 1 рдХрд╛ рд╕рдВрдмрдВрдзрд┐рдпреЛрдВ рдХреА рд╕реВрдЪреА рдореЗрдВ рдирд┐рд╡рд╛рд╕реА # 2 рд╣реИ, рддреЛ рдирд┐рд╡рд╛рд╕реА # 2 рдХрд╛ рднреА рдПрдХ рд░рд┐рд╢реНрддреЗрджрд╛рд░ # 1 рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП)ред
рдпрджрд┐ рдбреЗрдЯрд╛ рд╕рд╣реА рд╣реИ, рддреЛ рдЙрдиреНрд╣реЗрдВ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдПрдХ рдирдП рдЕрджреНрд╡рд┐рддреАрдп рдХреЗ рд╕рд╛рде рдЬреЛрдбрд╝рд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПimport_id
редрдбреЗрдЯрд╛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рд╡рд┐рднрд┐рдиреНрди рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдореЗрдВ рдХрдИ рдкреНрд░рд╢реНрди рдХрд░рдиреЗ рд╣реЛрдВрдЧреЗред рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рддреНрд░реБрдЯрд┐ рдпрд╛ рдЕрдкрд╡рд╛рдж рдХреА рд╕реНрдерд┐рддрд┐ рдореЗрдВ рдЖрдВрд╢рд┐рдХ рд░реВрдк рд╕реЗ рдЬреЛрдбрд╝реЗ рдЧрдП рдбреЗрдЯрд╛ рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЬрдм рдкреВрд░реНрдг рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкреНрд░рд╛рдкреНрдд рдирд╣реАрдВ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рдбрд┐рд╕реНрдХрдиреЗрдХреНрдЯ рдХрд░ рд░рд╣рд╛ рд╣реИ, рддреЛ aiohttp рдПрдХ рдХреИрдирдХреЗрд▓рдбреНрд░рд╛рдпрдб рдЕрдкрд╡рд╛рдж рдХреЛ рдлреЗрдВрдХ рджреЗрдЧрд╛ ), рдЖрдкрдХреЛ рдПрдХ рд▓реЗрдирджреЗрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ редрднрд╛рдЧреЛрдВ рдореЗрдВ рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдореЗрдВ рдбреЗрдЯрд╛ рдЬреЛрдбрд╝рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИ , рдХреНрдпреЛрдВрдХрд┐ PostgreSQL рдХреЗ рдПрдХ рдкреНрд░рд╢реНрди рдореЗрдВ 32,767 рд╕реЗ рдЕрдзрд┐рдХ рддрд░реНрдХ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВред рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ citizens
9 рдлрд╝реАрд▓реНрдб рд╣реИрдВ ред рддрджрдиреБрд╕рд╛рд░, 1 рдХреНрд╡реЗрд░реА рдХреЗ рд▓рд┐рдП, рдХреЗрд╡рд▓ 32,767 / 9 = 3,640 рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рдЗрд╕ рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рдбрд╛рд▓рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ рдПрдХ рдЕрдкрд▓реЛрдб рдореЗрдВ 10,000 рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рддрдХ рд╣реЛ рд╕рдХрддрд╛ рд╣реИредGET / рдЖрдпрд╛рдд / $ import_id / рдирд╛рдЧрд░рд┐рдХ
рд╣реИрдВрдбрд▓рд░ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХреЗ рд╕рд╛рде рд╕рднреА рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЛ рдЙрддрд╛рд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд╛рдкрд╕ рдХрд░ рджреЗрддрд╛ рд╣реИ import_id
ред рдпрджрд┐ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдЕрдкрд▓реЛрдб рдореМрдЬреВрдж рдирд╣реАрдВ рд╣реИ , рддреЛ рдЖрдкрдХреЛ 404 рд╡рд╛рдкрд╕ рдХрд░рдирд╛ рд╣реЛрдЧрд╛: рдирд╣реАрдВ рдорд┐рд▓рд╛ HTTP рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ред рдпрд╣ рд╡реНрдпрд╡рд╣рд╛рд░ рд╣реИрдВрдбрд▓рд░ рдХреЗ рд▓рд┐рдП рд╕рд╛рдорд╛рдиреНрдп рдкреНрд░рддреАрдд рд╣реЛрддрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рдореМрдЬреВрджрд╛ рдЕрдирд▓реЛрдб рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВрдиреЗ рд╕рддреНрдпрд╛рдкрди рдХреЛрдб рдХреЛ рдПрдХ рдЕрд▓рдЧ рд╡рд░реНрдЧ рдореЗрдВ рдЦреАрдВрдЪ рд▓рд┐рдпрд╛редрдЕрдирд▓реЛрдб рдХреЗ рд╕рд╛рде рд╣реИрдВрдбрд▓рд░ рдХреЗ рд▓рд┐рдП рдмреЗрд╕ рдХреНрд▓рд╛рд╕from aiohttp.web_exceptions import HTTPNotFound
from sqlalchemy import select, exists
from analyzer.db.schema import imports_table
class BaseImportView(BaseView):
@property
def import_id(self):
return int(self.request.match_info.get('import_id'))
async def check_import_exists(self):
query = select([
exists().where(imports_table.c.import_id == self.import_id)
])
if not await self.pg.fetchval(query):
raise HTTPNotFound()
рдкреНрд░рддреНрдпреЗрдХ рдирд┐рд╡рд╛рд╕реА рдХреЗ рд▓рд┐рдП рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ LEFT JOIN
рдЯреЗрдмрд▓ рд╕реЗ рдЯреЗрдмрд▓ citizens
рдкрд░ рдкреНрд░рджрд░реНрд╢рди рдХрд░рдирд╛ рд╣реЛрдЧрд╛ relations
, relations.relative_id
рдЬрд┐рд╕рдХреЗ рджреНрд╡рд╛рд░рд╛ рд╕рдореВрд╣реАрдХреГрдд рдлрд╝реАрд▓реНрдб рдХреЛ рдПрдХрддреНрд░ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ import_id
рдФрд░ citizen_id
редрдпрджрд┐ рдирд┐рд╡рд╛рд╕реА рдХрд╛ рдХреЛрдИ рд░рд┐рд╢реНрддреЗрджрд╛рд░ рдирд╣реАрдВ рд╣реИ, рддреЛ рд╡рд╣ LEFT JOIN
рдХреНрд╖реЗрддреНрд░ рдореЗрдВ рдЙрд╕рдХреЗ рд▓рд┐рдП relations.relative_id
рдореВрд▓реНрдп рд╡рд╛рдкрд╕ рдХрд░ рджреЗрдЧрд╛ NULL
рдФрд░ рдПрдХрддреНрд░реАрдХрд░рдг рдХреЗ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреА рд╕реВрдЪреА рджрд┐рдЦреЗрдЧреА [NULL]
редрдЗрд╕ рдЧрд▓рдд рдорд╛рди рдХреЛ рдареАрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ array_remove рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ редрдбреЗрдЯрд╛рдмреЗрд╕ рдПрдХ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рддрд╛рд░реАрдЦ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддрд╛ рд╣реИ YYYY-MM-DD
, рд▓реЗрдХрд┐рди рд╣рдореЗрдВ рдПрдХ рдкреНрд░рд╛рд░реВрдк рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ DD.MM.YYYY
редрддрдХрдиреАрдХреА рд░реВрдк рд╕реЗ, рдЖрдк рдПрд╕рдХреНрдпреВрдПрд▓ рдХреНрд╡реЗрд░реА рдХреЗ рд╕рд╛рде рдпрд╛ рдкрд╛рдпрдерди рдкрдХреНрд╖ рдкрд░ рддрд┐рдерд┐ рдХреЛ рдкреНрд░рд╛рд░реВрдкрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд╕рд╛рде рд╣реА рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЛ рдХреНрд░рдордмрджреНрдз рдХрд░рддреЗ рд╕рдордп json.dumps
(asyncpg birth_date
рд╡рд░реНрдЧ рдорд╛рди рдХреЗ рд░реВрдк рдореЗрдВ рдлрд╝реАрд▓реНрдб рдорд╛рди рд▓реМрдЯрд╛рддрд╛ рд╣реИdatetime.date
)рдореИрдВрдиреЗ рдкрд╛рдпрдерди рдХреА рдУрд░ рд╕реЗ рдХреНрд░рдордмрджреНрдзрддрд╛ рдХреЛ рдЪреБрдирд╛, рдпрд╣ рджреЗрдЦрддреЗ рд╣реБрдП рдХрд┐ рдпрд╣ рдПрдХрд▓ рдкреНрд░рд╛рд░реВрдк рдХреЗ рд╕рд╛рде рдкрд░рд┐рдпреЛрдЬрдирд╛ birth_date
рдХрд╛ рдПрдХрдорд╛рддреНрд░ рдЙрджреНрджреЗрд╢реНрдп datetime.date
рд╣реИ (рдЕрдиреБрднрд╛рдЧ "рдбреЗрдЯрд╛ рдХреЛ рд╕реАрд░рд┐рдпрд▓ рдХрд░рдирд╛" рджреЗрдЦреЗрдВ )редрдЗрд╕ рддрдереНрдп рдХреЗ рдмрд╛рд╡рдЬреВрдж рдХрд┐ рдкреНрд░реЛрд╕реЗрд╕рд░ рджреЛ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддрд╛ рд╣реИ (рдЙрддрд░рд╛рдИ рдХреЗ рдЕрд╕реНрддрд┐рддреНрд╡ рдХреА рдЬрд╛рдВрдЪ рдХрд░рдирд╛ рдФрд░ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрдиреБрд░реЛрдз), рд▓реЗрдирджреЗрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рдирд╣реАрдВ рд╣реИ ред рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ, PostgreSQL рдЕрд▓рдЧрд╛рд╡ рд╕реНрддрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ, READ COMMITTED
рдФрд░ рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдПрдХ рд▓реЗрди-рджреЗрди рдХреЗ рднреАрддрд░ рднреА рдЕрдиреНрдп рдореЗрдВ рд╕рднреА рдкрд░рд┐рд╡рд░реНрддрди рд╣реЛрддреЗ рд╣реИрдВ, рд╕рдлрд▓рддрд╛рдкреВрд░реНрд╡рдХ рдкреВрд░реНрдг рдХрд┐рдП рдЧрдП рд▓реЗрдирджреЗрди рджрд┐рдЦрд╛рдИ рджреЗрдВрдЧреЗ (рдирдИ рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рдЬреЛрдбрд╝рддреЗ рд╣реБрдП, рдореМрдЬреВрджрд╛ рд╡рд╛рд▓реЗ рдмрджрд▓рддреЗ рд╣реИрдВ)редрдкрд╛рда рджреГрд╢реНрдп рдореЗрдВ рд╕рдмрд╕реЗ рдмрдбрд╝рд╛ рдЕрдкрд▓реЛрдб ~ 63 рдореЗрдЧрд╛рдмрд╛рдЗрдЯ рд▓реЗ рд╕рдХрддрд╛ рд╣реИ - рдпрд╣ рдХрд╛рдлреА рд╣реИ, рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдпрд╣ рджреЗрдЦрддреЗ рд╣реБрдП рдХрд┐ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рдХрдИ рдЕрдиреБрд░реЛрдз рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ рдЖ рд╕рдХрддреЗ рд╣реИрдВред рдХрд░реНрд╕рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдФрд░ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рднрд╛рдЧреЛрдВ рдореЗрдВ рднреЗрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рджрд┐рд▓рдЪрд╕реНрдк рддрд░реАрдХрд╛ рд╣реИ редрдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рджреЛ рд╡рд╕реНрддреБрдУрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:- рдПрдХ
SelectQuery
рдкреНрд░рдХрд╛рд░ рдХреА рд╡рд╕реНрддреБ AsyncIterable
рдЬреЛ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рд░рд┐рдХреЙрд░реНрдб рд▓реМрдЯрд╛рддреА рд╣реИред рдкрд╣рд▓реА рдХреЙрд▓ рдкрд░, рдпрд╣ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдЬреБрдбрд╝рддрд╛ рд╣реИ, рдПрдХ рдЯреНрд░рд╛рдВрдЬреЗрдХреНрд╢рди рдЦреЛрд▓рддрд╛ рд╣реИ рдФрд░ рдПрдХ рдХрд░реНрд╕рд░ рдмрдирд╛рддрд╛ рд╣реИ; рдЖрдЧреЗ рдХреЗ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдХреЗ рджреМрд░рд╛рди, рдпрд╣ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рд░рд┐рдХреЙрд░реНрдб рд▓реМрдЯрд╛рддрд╛ рд╣реИред рдЗрд╕реЗ рд╣реИрдВрдбрд▓рд░ рдиреЗ рд▓реМрдЯрд╛ рджрд┐рдпрд╛ рд╣реИред
SelectQuery рдХреЛрдбfrom collections import AsyncIterable
from asyncpgsa.transactionmanager import ConnectionTransactionContextManager
from sqlalchemy.sql import Select
class SelectQuery(AsyncIterable):
"""
, PostgreSQL
, ,
"""
PREFETCH = 500
__slots__ = (
'query', 'transaction_ctx', 'prefetch', 'timeout'
)
def __init__(self, query: Select,
transaction_ctx: ConnectionTransactionContextManager,
prefetch: int = None,
timeout: float = None):
self.query = query
self.transaction_ctx = transaction_ctx
self.prefetch = prefetch or self.PREFETCH
self.timeout = timeout
async def __aiter__(self):
async with self.transaction_ctx as conn:
cursor = conn.cursor(self.query, prefetch=self.prefetch,
timeout=self.timeout)
async for row in cursor:
yield row
- рдПрдХ рдзрд╛рд░рд╛рд╡рд╛рд╣рд┐рдХ
AsyncGenJSONListPayload
рдЬреЛ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдЬрдирд░реЗрдЯрд░ рдкрд░ рдкреБрдирд░рд╛рд╡реГрддрд┐ рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рдПрдХ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдЬрдирд░реЗрдЯрд░ рд╕реЗ JSON рдХреЗ рдбреЗрдЯрд╛ рдХреЛ рдХреНрд░рдордмрджреНрдз рдХрд░рддрд╛ рд╣реИ рдФрд░ рднрд╛рдЧреЛрдВ рдореЗрдВ рдЧреНрд░рд╛рд╣рдХреЛрдВ рдХреЛ рдбреЗрдЯрд╛ рднреЗрдЬрддрд╛ рд╣реИред рдпрд╣ aiohttp.PAYLOAD_REGISTRY
рд╡рд╕реНрддреБрдУрдВ рдХреЗ рдПрдХ рдзрд╛рд░рд╛рд╡рд╛рд╣рд┐рдХ рдХреЗ рд░реВрдк рдореЗрдВ рдкрдВрдЬреАрдХреГрдд рд╣реИ AsyncIterable
ред
AsyncGenJSONListPayload рдХреЛрдбimport json
from functools import partial
from aiohttp import Payload
dumps = partial(json.dumps, default=convert, ensure_ascii=False)
class AsyncGenJSONListPayload(Payload):
"""
AsyncIterable,
JSON
"""
def __init__(self, value, encoding: str = 'utf-8',
content_type: str = 'application/json',
root_object: str = 'data',
*args, **kwargs):
self.root_object = root_object
super().__init__(value, content_type=content_type, encoding=encoding,
*args, **kwargs)
async def write(self, writer):
await writer.write(
('{"%s":[' % self.root_object).encode(self._encoding)
)
first = True
async for row in self._value:
if not first:
await writer.write(b',')
else:
first = False
await writer.write(dumps(row).encode(self._encoding))
await writer.write(b']}')
рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╣реИрдВрдбрд▓рд░ рдореЗрдВ рдПрдХ рдСрдмреНрдЬреЗрдХреНрдЯ рдмрдирд╛рдирд╛ рд╕рдВрднрд╡ рд╣реЛрдЧрд╛ SelectQuery
, рд▓реЗрди-рджреЗрди рдЦреЛрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ SQL рдХреНрд╡реЗрд░реА рдФрд░ рдЗрд╕реЗ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдкрд╛рд╕ рдХрд░реЗрдВ, рдФрд░ рд╡рд╛рдкрд╕ рд▓реМрдЯреЗрдВ Response body
:рд╣реИрдВрдбрд▓рд░ рдХреЛрдб
from aiohttp.web_response import Response
from aiohttp_apispec import docs, response_schema
from analyzer.api.schema import CitizensResponseSchema
from analyzer.db.schema import citizens_table as citizens_t
from analyzer.utils.pg import SelectQuery
from .query import CITIZENS_QUERY
from .base import BaseImportView
class CitizensView(BaseImportView):
URL_PATH = r'/imports/{import_id:\d+}/citizens'
@docs(summary=' ')
@response_schema(CitizensResponseSchema())
async def get(self):
await self.check_import_exists()
query = CITIZENS_QUERY.where(
citizens_t.c.import_id == self.import_id
)
body = SelectQuery(query, self.pg.transaction())
return Response(body=body)
aiohttp
рдпрд╣ рд░рдЬрд┐рд╕реНрдЯреНрд░реА рдореЗрдВ рдЯрд╛рдЗрдк рдХреА рд╡рд╕реНрддреБрдУрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рдкрдВрдЬреАрдХреГрдд aiohttp.PAYLOAD_REGISTRY
рдзрд╛рд░рд╛рд╡рд╛рд╣рд┐рдХ рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рддрд╛ рд╣реИ ред рдлрд┐рд░ рдХреНрд░рдо-рдирд┐рд░реНрдорд╛рддрд╛ рдСрдмреНрдЬреЗрдХреНрдЯ рдкрд░ рдкреБрдирд░рд╛рд╡реГрддрд┐ рдХрд░реЗрдЧрд╛ рдФрд░ рдЧреНрд░рд╛рд╣рдХ рдХреЛ рдбреЗрдЯрд╛ рднреЗрдЬреЗрдЧрд╛ред рдкрд╣рд▓реА рдХреЙрд▓ рдкрд░, рдСрдмреНрдЬреЗрдХреНрдЯ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдПрдХ рдХрдиреЗрдХреНрд╢рди рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ, рдПрдХ рд▓реЗрди-рджреЗрди рдЦреЛрд▓рддрд╛ рд╣реИ рдФрд░ рдПрдХ рдХрд░реНрд╕рд░ рдмрдирд╛рддрд╛ рд╣реИ, рдЖрдЧреЗ рдХреЗ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдХреЗ рджреМрд░рд╛рди, рдпрд╣ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдХрд░реНрд╕рд░ рдХреЗ рд╕рд╛рде рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдЧрд╛ рдФрд░ рдЙрдиреНрд╣реЗрдВ рд▓рд╛рдЗрди рд╕реЗ рд▓рд╛рдЗрди рдореЗрдВ рд▓реМрдЯрд╛ рджреЗрдЧрд╛ред рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдкреНрд░рддреНрдпреЗрдХ рдЕрдиреБрд░реЛрдз рдХреЗ рд╕рд╛рде рдбреЗрдЯрд╛ рдХреА рд╕рдВрдкреВрд░реНрдг рд░рд╛рд╢рд┐ рдХреЗ рд▓рд┐рдП рдореЗрдореЛрд░реА рдЖрд╡рдВрдЯрд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рджреЗрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕рдХреА рдПрдХ рдЦрд╝рд╛рд╕рд┐рдпрдд рд╣реИ: рдпрджрд┐ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рддреНрд░реБрдЯрд┐ рдХреЗ рдмрд╛рдж (HTTP рд╕реНрдерд┐рддрд┐, рд╣реЗрдбрд░ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рднреЗрдЬрд╛ рдЬрд╛ рдЪреБрдХрд╛ рд╣реИ, рдФрд░ рдбреЗрдЯрд╛ рд▓рд┐рдЦрд╛ рдЬрд╛ рд░рд╣рд╛ рд╣реИ) рддреЛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рд╕рдВрдмрдВрдзрд┐рдд HTTP рд╕реНрдерд┐рддрд┐ рдирд╣реАрдВ рджреЗ рдкрд╛рдПрдЧрд╛редAsyncGenJSONListPayload
AsyncIterable
SelectQuery
SelectQuery
рдЬрдм рдЕрдкрд╡рд╛рдж рд╣реЛрддрд╛ рд╣реИ, рддреЛ рдбрд┐рд╕реНрдХрдиреЗрдХреНрдЯ рдХрд░рдиреЗ рдХреЗ рдЕрд▓рд╛рд╡рд╛ рдХреБрдЫ рдирд╣реАрдВ рд░рд╣рддрд╛ рд╣реИред рдПрдХ рдЕрдкрд╡рд╛рдж, рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рд╕реБрд░рдХреНрд╖рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЧреНрд░рд╛рд╣рдХ рдареАрдХ рд╕реЗ рд╕рдордЭ рдирд╣реАрдВ рдкрд╛рдПрдЧрд╛ рдХрд┐ рдХреНрдпрд╛ рддреНрд░реБрдЯрд┐ рд╣реБрдИредрджреВрд╕рд░реА рдУрд░, рдПрдХ рд╕рдорд╛рди рд╕реНрдерд┐рддрд┐ рдЙрддреНрдкрдиреНрди рд╣реЛ рд╕рдХрддреА рд╣реИ рднрд▓реЗ рд╣реА рдкреНрд░реЛрд╕реЗрд╕рд░ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рд╕рднреА рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рдбреЗрдЯрд╛ рдкреНрд░реЗрд╖рд┐рдд рдХрд░рддреЗ рд╕рдордп рдиреЗрдЯрд╡рд░реНрдХ рдЭрдкрдХрд╛рддрд╛ рд╣реИ - рдЗрд╕рд╕реЗ рдХреЛрдИ рднреА рд╕реБрд░рдХреНрд╖рд┐рдд рдирд╣реАрдВ рд╣реИредPATCH / рдЖрдпрд╛рдд / $ import_id / рдирд╛рдЧрд░рд┐рдХ / $ Cit_id
рд╣реИрдВрдбрд▓рд░ рдХреЛ рдЕрдирд▓реЛрдб рдХреЗ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ import_id
, рдирд┐рд╡рд╛рд╕реА рдХреЗ citizen_id
рд╕рд╛рде-рд╕рд╛рде рдирд┐рд╡рд╛рд╕реА рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдирдП рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде json рдкреНрд░рд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИред рдЧреИрд░-рдореМрдЬреВрдж рдЧреИрд░-рд▓реЛрдбрд┐рдВрдЧ рдпрд╛ рдирд┐рд╡рд╛рд╕реА рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ , HTTP рдкреНрд░рддрд┐рд╕рд╛рдж рджреЗрдирд╛ рдЪрд╛рд╣рд┐рдП 404: Not Found
редрдЧреНрд░рд╛рд╣рдХ рджреНрд╡рд╛рд░рд╛ рдкреНрд░реЗрд╖рд┐рдд рдбреЗрдЯрд╛ рдХреЛ рд╕рддреНрдпрд╛рдкрд┐рдд рдФрд░ deserialized рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП ред рдпрджрд┐ рд╡реЗ рдЧрд▓рдд рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ рдПрдХ HTTP рдкреНрд░рддрд┐рд╕рд╛рдж рд╡рд╛рдкрд╕ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ 400: Bad Request
ред рдореИрдВрдиреЗ рдПрдХ рдорд╛рд░реНрд╢рдореИрд▓реЛ рдпреЛрдЬрдирд╛ рд▓рд╛рдЧреВ рдХреА, PatchCitizenSchema
рдЬреЛ рдЬрд╛рдБрдЪрддреА рд╣реИ:- рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдлрд╝реАрд▓реНрдб рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛ рдХрд╛ рдкреНрд░рдХрд╛рд░ рдФрд░ рдкреНрд░рд╛рд░реВрдкред
- рдЬрдиреНрдо рдХреА рддрд╛рд░реАрдЦред рдЗрд╕реЗ рдПрдХ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП
DD.MM.YYYY
рдФрд░ рднрд╡рд┐рд╖реНрдп рд╕реЗ рдЗрд╕рдХрд╛ рдорд╣рддреНрд╡ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддрд╛ рд╣реИред - рдкреНрд░рддреНрдпреЗрдХ рдирд┐рд╡рд╛рд╕реА рдХреЗ рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреА рдПрдХ рд╕реВрдЪреАред рдЗрд╕рдореЗрдВ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рд╡рд┐рд╢рд┐рд╖реНрдЯ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рд╣реЛрдиреЗ рдЪрд╛рд╣рд┐рдПред
рдлрд╝реАрд▓реНрдб рдореЗрдВ рдЗрдВрдЧрд┐рдд рдХрд┐рдП рдЧрдП рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреЗ рдЕрд╕реНрддрд┐рддреНрд╡ рдХреЛ relatives
рдЕрд▓рдЧ рд╕реЗ рдЬрд╛рдБрдЪ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ: рдпрджрд┐ рдХрд┐рд╕реА relations
рдЧреИрд░-рдореМрдЬреВрдж рдирд┐рд╡рд╛рд╕реА рдХреЛ рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ PostgreSQL рдПрдХ рддреНрд░реБрдЯрд┐ рд▓реМрдЯрд╛рдПрдЧрд╛ ForeignKeyViolationError
рдЬрд┐рд╕реЗ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдФрд░ HTTP рд╕реНрдерд┐рддрд┐ рд╡рд╛рдкрд╕ рдЖ рд╕рдХрддреА рд╣реИ 400: Bad Request
редрдпрджрд┐ рдХрд┐рд╕реА рдЧреИрд░-рдореМрдЬреВрдж рдирд┐рд╡рд╛рд╕реА рдпрд╛ рдЙрддрд░рд╛рдИ рдХреЗ рд▓рд┐рдП рдХреНрд▓рд╛рдЗрдВрдЯ рдиреЗ рдЧрд▓рдд рдбреЗрдЯрд╛ рднреЗрдЬрд╛ рд╣реИ рддреЛ рдХреНрдпрд╛ рд╕реНрдерд┐рддрд┐ рд╡рд╛рдкрд╕ рдЖрдиреА рдЪрд╛рд╣рд┐рдП ? рдпрд╣ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЕрдирд▓реЛрдбрд┐рдВрдЧ рдФрд░ рдПрдХ рдирд┐рд╡рд╛рд╕реА (рдпрджрд┐ рдХреЛрдИ рдирд╣реАрдВ рд╣реИ, рддреЛ рд╡рд╛рдкрд╕реА 404: Not Found
) рдХреЗ рдЕрд╕реНрддрд┐рддреНрд╡ рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╢рдмреНрджрд╢рдГ рдЕрдзрд┐рдХ рд╕рд╣реА рд╣реИ рдФрд░ рдХреЗрд╡рд▓ рддрднреА рдХреНрд▓рд╛рдЗрдВрдЯ рдиреЗ рд╕рд╣реА рдбреЗрдЯрд╛ рднреЗрдЬрд╛ рд╣реИ (рдпрджрд┐ рдирд╣реАрдВ, рддреЛ рд╡рд╛рдкрд╕реА 400: Bad Request
)ред рд╡реНрдпрд╡рд╣рд╛рд░ рдореЗрдВ, рдкрд╣рд▓реЗ рдбреЗрдЯрд╛ рдХреА рдЬрд╛рдВрдЪ рдХрд░рдирд╛ рдЕрдХреНрд╕рд░ рд╕рд╕реНрддрд╛ рд╣реЛрддрд╛ рд╣реИ, рдФрд░ рдХреЗрд╡рд▓ рдЕрдЧрд░ рд╡реЗ рд╕рд╣реА рд╣реИрдВ, рддреЛ рдбреЗрдЯрд╛рдмреЗрд╕ рддрдХ рдкрд╣реБрдВрдЪреЗрдВредрджреЛрдиреЛрдВ рд╡рд┐рдХрд▓реНрдк рд╕реНрд╡реАрдХрд╛рд░реНрдп рд╣реИрдВ, рд▓реЗрдХрд┐рди рдореИрдВрдиреЗ рдПрдХ рд╕рд╕реНрддрд╛ рджреВрд╕рд░рд╛ рд╡рд┐рдХрд▓реНрдк рдЪреБрдирдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛, рдХреНрдпреЛрдВрдХрд┐ рдХрд┐рд╕реА рднреА рд╕реНрдерд┐рддрд┐ рдореЗрдВ рдСрдкрд░реЗрд╢рди рдХрд╛ рдкрд░рд┐рдгрд╛рдо рдПрдХ рддреНрд░реБрдЯрд┐ рд╣реИ рдЬреЛ рдХреБрдЫ рднреА рдкреНрд░рднрд╛рд╡рд┐рдд рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ (рдЧреНрд░рд╛рд╣рдХ рдбреЗрдЯрд╛ рдХреЛ рд╕рд╣реА рдХрд░реЗрдЧрд╛ рдФрд░ рдлрд┐рд░ рдкрддрд╛ рд▓рдЧрд╛рдПрдЧрд╛ рдХрд┐ рдирд┐рд╡рд╛рд╕реА рдореМрдЬреВрдж рдирд╣реАрдВ рд╣реИ)редрдпрджрд┐ рдбреЗрдЯрд╛ рд╕рд╣реА рд╣реИ, рддреЛ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдирд┐рд╡рд╛рд╕реА рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдЕрдкрдбреЗрдЯ рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИ ред рд╣реИрдВрдбрд▓рд░ рдореЗрдВ, рдЖрдкрдХреЛ рд╡рд┐рднрд┐рдиреНрди рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдХрдИ рдкреНрд░рд╢реНрди рдХрд░рдиреЗ рд╣реЛрдВрдЧреЗред рдпрджрд┐ рдХреЛрдИ рддреНрд░реБрдЯрд┐ рдпрд╛ рдЕрдкрд╡рд╛рдж рд╣реЛрддрд╛ рд╣реИ, рддреЛ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рдкреВрд░реНрд╡рд╡рдд рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП, рдЗрд╕рд▓рд┐рдП рд▓реЗрдирджреЗрди рдореЗрдВ рдкреНрд░рд╢реНрдиреЛрдВ рдХрд╛ рдирд┐рд╖реНрдкрд╛рджрди рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП редрд╡рд┐рдзрд┐ PATCH
рдЖрдкрдХреЛ рдирд┐рд╡рд╛рд╕реА рдХреЗ рд▓рд┐рдП рдХреЗрд╡рд▓ рдХреБрдЫ рдлрд╝реАрд▓реНрдб рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИ редрд╣реИрдВрдбрд▓рд░ рдХреЛ рдЗрд╕ рддрд░рд╣ рд╕реЗ рд▓рд┐рдЦрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдпрд╣ рдЙрд╕ рдбреЗрдЯрд╛ рддрдХ рдкрд╣реБрдВрдЪрддреЗ рд╕рдордп рдХреНрд░реИрд╢ рди рд╣реЛ рдЬрд╛рдП рдЬрд┐рд╕реЗ рдХреНрд▓рд╛рдЗрдВрдЯ рдиреЗ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИ, рдФрд░ рдЙрди рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдкрд░ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ рдЬрд┐рдирдореЗрдВ рдбреЗрдЯрд╛ рдирд╣реАрдВ рдмрджрд▓рд╛ рд╣реИредрдпрджрд┐ рдХреНрд▓рд╛рдЗрдВрдЯ рдиреЗ рдлрд╝реАрд▓реНрдб рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд┐рдпрд╛ рд╣реИ relatives
, рддреЛ рдореМрдЬреВрджрд╛ рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИред рдпрджрд┐ рдпрд╣ рдмрджрд▓ рдЧрдпрд╛ рд╣реИ, рддреЛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░реЗрдВ relatives
рдХрд┐ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдЧреНрд░рд╛рд╣рдХ рдХреЗ рдЕрдиреБрд░реЛрдз рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЛ рд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рддрд╛рд▓рд┐рдХрд╛ рд╕реЗ рдХреМрди рд╕реЗ рд░рд┐рдХреЙрд░реНрдб рд╣рдЯрд╛рдП рдЬрд╛рдиреЗ рдЪрд╛рд╣рд┐рдП рдФрд░ рдХрд┐рдирдХреЛ рдЬреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛ред рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ, PostgreSQL рд▓реЗрдирджреЗрди рдЕрд▓рдЧрд╛рд╡ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ READ COMMITTED
ред рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рд╡рд░реНрддрдорд╛рди рд▓реЗрдирджреЗрди рдХреЗ рд╣рд┐рд╕реНрд╕реЗ рдХреЗ рд░реВрдк рдореЗрдВ, рдкрд░рд┐рд╡рд░реНрддрди рдЕрдиреНрдп рдкреВрд░реНрдг рд▓реЗрдирджреЗрди рдХреЗ рдореМрдЬреВрджрд╛ (рд╕рд╛рде рд╣реА рдирдП) рд░рд┐рдХреЙрд░реНрдб рджрд┐рдЦрд╛рдИ рджреЗрдВрдЧреЗред рдЗрд╕рд╕реЗ рдкреНрд░рддрд┐рд╕реНрдкрд░реНрдзреА рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЗ рдмреАрдЪ рджреМрдбрд╝ рдХреА рд╕реНрдерд┐рддрд┐ рдкреИрджрд╛ рд╣реЛ рд╕рдХрддреА рд╣реИ редрдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рдЕрдирд▓реЛрдбрд┐рдВрдЧ рд╣реИ#1
ред #2
, #3
рд░рд┐рд╢реНрддреЗрджрд╛рд░реА рдХреЗ рдмрд┐рдирд╛ред рдпрд╣ рд╕реЗрд╡рд╛ рдирд┐рд╡рд╛рд╕реА # 1: {"relatives": [2]}
рдФрд░ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд╛рде рджреЛ рдЕрдиреБрд░реЛрдз рдкреНрд░рд╛рдкреНрдд рдХрд░рддреА рд╣реИ {"relatives": [3]}
ред aiohttp рджреЛ рд╣реИрдВрдбрд▓рд░ рдмрдирд╛рдПрдЧрд╛ рдЬреЛ рдПрдХ рд╕рд╛рде PostgreSQL рд╕реЗ рдирд┐рд╡рд╛рд╕реА рдХреА рд╡рд░реНрддрдорд╛рди рд╕реНрдерд┐рддрд┐ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВрдЧреЗредрдкреНрд░рддреНрдпреЗрдХ рд╣реИрдВрдбрд▓рд░ рдПрдХ рдПрдХрд▓ рд╕рдВрдмрдВрдзрд┐рдд рд╕рдВрдмрдВрдз рдХрд╛ рдкрддрд╛ рдирд╣реАрдВ рд▓рдЧрд╛рдПрдЧрд╛ рдФрд░ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд░рд┐рд╢реНрддреЗрджрд╛рд░ рдХреЗ рд╕рд╛рде рдПрдХ рдирдпрд╛ рд╕рдВрдмрдВрдз рдЬреЛрдбрд╝рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд░реЗрдЧрд╛ред рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рдирд┐рд╡рд╛рд╕реА # 1 рдореЗрдВ рд░рд┐рд╢реНрддреЗрджрд╛рд░ рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рд╣реА рдлрд╝реАрд▓реНрдб рд╣реИ [2,3]
ред
рдЗрд╕ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рд╕реНрдкрд╖реНрдЯ рдирд╣реАрдВ рдХрд╣рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рджреМрдбрд╝ рдХреЗ рдкрд░рд┐рдгрд╛рдо рдХреЛ рддрдп рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рджреЛ рд╡рд┐рдХрд▓реНрдк рд╣реЛрдиреЗ рдХреА рдЙрдореНрдореАрдж рд╣реИ: рдХреЗрд╡рд▓ рдкрд╣рд▓рд╛ рдЕрдиреБрд░реЛрдз рдкреВрд░рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдФрд░ рджреВрд╕рд░рд╛ HTTP рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП409: Conflict
(рддрд╛рдХрд┐ рдЧреНрд░рд╛рд╣рдХ рдЕрдиреБрд░реЛрдз рдХреЛ рджреЛрд╣рд░рд╛рдП), рдпрд╛ рдмрджрд▓реЗ рдореЗрдВ рдЕрдиреБрд░реЛрдз рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП (рджреВрд╕рд░рд╛ рдЕрдиреБрд░реЛрдз рдкрд╣рд▓реЗ рдкреВрд░рд╛ рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рд╣реА рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛)редрдкрд╣рд▓рд╛ рд╡рд┐рдХрд▓реНрдк рдЖрдЗрд╕реЛрд▓реЗрд╢рди рдореЛрдб рдХреЛ рдЪрд╛рд▓реВ рдХрд░рдХреЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИSERIALIZABLE
ред рдпрджрд┐ рдЕрдиреБрд░реЛрдз рдХреЗ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рджреМрд░рд╛рди рдХреЛрдИ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдбреЗрдЯрд╛ рдХреЛ рдмрджрд▓рдиреЗ рдФрд░ рдкреНрд░рдмрдВрдзрд┐рдд рдХрд░рдиреЗ рдореЗрдВ рдХрд╛рдордпрд╛рдм рд░рд╣рд╛, рддреЛ рдПрдХ рдЕрдкрд╡рд╛рдж рдлреЗрдВрдХ рджрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдЬрд┐рд╕реЗ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рдЗрд╕реА HTTP рд╕реНрдерд┐рддрд┐ рд╡рд╛рдкрд╕ рдЖ рдЧрдИредрдЗрд╕ рд╕рдорд╛рдзрд╛рди рдХрд╛ рдиреБрдХрд╕рд╛рди - PostgreSQL рдореЗрдВ рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рддрд╛рд▓реЗ, SERIALIZABLE
рдПрдХ рдЕрдкрд╡рд╛рдж рдлреЗрдВрдХ рджреЗрдВрдЧреЗ, рднрд▓реЗ рд╣реА рдкреНрд░рддрд┐рд╕реНрдкрд░реНрдзреА рдкреНрд░рд╢реНрди рд╡рд┐рднрд┐рдиреНрди рдЕрдирд▓реЛрдбрд┐рдВрдЧ рд╕реЗ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рд░рд┐рдХреЙрд░реНрдб рдХреЛ рдмрджрд▓ рджреЗрдВредрдЖрдк рд╕рд┐рдлрд╛рд░рд┐рд╢ рд▓реЙрдХ рддрдВрддреНрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рднреА рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ ред рдпрджрд┐ рдЖрдк рдРрд╕рд╛ рд▓реЙрдХ рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ import_id
, рддреЛ рд╡рд┐рднрд┐рдиреНрди рдЕрдирд▓реЛрдбрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдкреНрд░рддрд┐рд╕реНрдкрд░реНрдзреА рдЕрдиреБрд░реЛрдз рд╕рдорд╛рдирд╛рдВрддрд░ рдореЗрдВ рдЪрд▓рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдВрдЧреЗредрдПрдХ рдЕрдкрд▓реЛрдб рдореЗрдВ рдкреНрд░рддрд┐рд╕реНрдкрд░реНрдзреА рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдк рдХрд┐рд╕реА рднреА рд╡рд┐рдХрд▓реНрдк рдХреЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рд▓рд╛рдЧреВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ: рдлрд╝рдВрдХреНрд╢рди pg_try_advisory_xact_lock
рд▓реЙрдХ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддрд╛ рд╣реИ рдФрд░рдпрд╣ рддреБрд░рдВрдд рдмреБрд▓рд┐рдпрди рдкрд░рд┐рдгрд╛рдо рд▓реМрдЯрд╛рддрд╛ рд╣реИ (рдпрджрд┐ рддрд╛рд▓рд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рд╕рдВрднрд╡ рдирд╣реАрдВ рдерд╛ - рдПрдХ рдЕрдкрд╡рд╛рдж рдлреЗрдВрдХрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ), рд▓реЗрдХрд┐рди рдпрд╣ pg_advisory_xact_lock
рддрдм рддрдХ рдЗрдВрддрдЬрд╛рд░ рдХрд░рддрд╛ рд╣реИ рдЬрдм рддрдХ рдХрд┐рдЕрд╡рд░реЛрдз рдХреЗ рд▓рд┐рдП рд╕рдВрд╕рд╛рдзрди рдЙрдкрд▓рдмреНрдз рдирд╣реАрдВ рд╣реЛ рдЬрд╛рддрд╛ (рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рдХреНрд░рдорд┐рдХ рд░реВрдк рд╕реЗ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдореИрдВ рдЗрд╕ рд╡рд┐рдХрд▓реНрдк рдкрд░ рдмрд╕ рдЧрдпрд╛)редрдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рд╣реИрдВрдбрд▓рд░ рдХреЛ рдЕрджреНрдпрддрди рдирд┐рд╡рд╛рд╕реА рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╡рд░реНрддрдорд╛рди рдЬрд╛рдирдХрд╛рд░реА рд╡рд╛рдкрд╕ рдХрд░рдиреА рд╣реЛрдЧреА ред рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЗ рд▓рд┐рдП рдЕрдкрдиреЗ рдЕрдиреБрд░реЛрдз рд╕реЗ рдбреЗрдЯрд╛ рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЦреБрдж рдХреЛ рд╕реАрдорд┐рдд рдХрд░рдирд╛ рд╕рдВрднрд╡ рдерд╛ (рдЪреВрдВрдХрд┐ рд╣рдо рдЧреНрд░рд╛рд╣рдХ рдХреА рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд▓реМрдЯрд╛ рд░рд╣реЗ рд╣реИрдВ, рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рдХреЛрдИ рдЕрдкрд╡рд╛рдж рдирд╣реАрдВ рдереЗ рдФрд░ рд╕рднреА рдЕрдиреБрд░реЛрдз рд╕рдлрд▓рддрд╛рдкреВрд░реНрд╡рдХ рдкреВрд░рд╛ рд╣реЛ рдЧрдП рдереЗ)ред рдпрд╛ - рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░рдиреЗ рдФрд░ рдкрд░рд┐рдгрд╛рдореЛрдВ рд╕реЗ рдПрдХ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдЙрддреНрдкрдиреНрди рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдкреНрд░рд╢реНрдиреЛрдВ рдореЗрдВ RETURNING рдХреАрд╡рд░реНрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВред рд▓реЗрдХрд┐рди рдпреЗ рджреЛрдиреЛрдВ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╣рдореЗрдВ рд░рд╛рдЬреНрдпреЛрдВ рдХреА рджреМрдбрд╝ рдХреЗ рд╕рд╛рде рдорд╛рдорд▓реЗ рдХреЛ рджреЗрдЦрдиреЗ рдФрд░ рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рджреЗрдВрдЧреЗредрд╕реЗрд╡рд╛ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рдЙрдЪреНрдЪ рд▓реЛрдб рдЖрд╡рд╢реНрдпрдХрддрд╛рдПрдВ рдирд╣реАрдВ рдереАрдВ, рдЗрд╕рд▓рд┐рдП рдореИрдВрдиреЗ рдлрд┐рд░ рд╕реЗ рдирд┐рд╡рд╛рд╕реА рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕рднреА рдбреЗрдЯрд╛ рдХрд╛ рдЕрдиреБрд░реЛрдз рдХрд░рдиреЗ рдФрд░ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдПрдХ рдИрдорд╛рдирджрд╛рд░ рдкрд░рд┐рдгрд╛рдо рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛редGET / рдЖрдпрд╛рдд / $ import_id / рдирд╛рдЧрд░рд┐рдХ / рдЬрдиреНрдорджрд┐рди
рд╣реИрдВрдбрд▓рд░ рдЙрдкрд╣рд╛рд░реЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреА рдЧрдгрдирд╛ рдХрд░рддрд╛ рд╣реИ рдЬреЛ рдЙрддрд░рд╛рдИ рдХреЗ рдкреНрд░рддреНрдпреЗрдХ рдирд┐рд╡рд╛рд╕реА рдХреЛ рдЕрдкрдиреЗ рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ (рдкрд╣рд▓реЗ рдХреЗ рдЖрджреЗрд╢) рдХреЛ рдорд┐рд▓реЗрдЧреАред рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХреЗ рд╕рд╛рде рдЕрдкрд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдВрдЦреНрдпрд╛ рдХреЛ рдорд╣реАрдиреЗ рддрдХ рд╕рдореВрд╣реАрдХреГрдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ import_id
ред рдЧреИрд░-рдореМрдЬреВрдж рдЕрдкрд▓реЛрдб рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ , HTTP рдкреНрд░рддрд┐рд╕рд╛рдж рджреЗрдирд╛ рдЪрд╛рд╣рд┐рдП 404: Not Found
редрджреЛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╡рд┐рдХрд▓реНрдк рд╣реИрдВ:- рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреЗ рд╕рд╛рде рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ, рдФрд░ рдкрд╛рдпрдерди рдкрдХреНрд╖ рдкрд░, рдорд╣реАрдиреЗ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдбреЗрдЯрд╛ рдПрдХрддреНрд░ рдХрд░реЗрдВ рдФрд░ рдЙрди рдорд╣реАрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╕реВрдЪрд┐рдпрд╛рдВ рдмрдирд╛рдПрдВ рдЬрд┐рдирдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдХреЛрдИ рдбреЗрдЯрд╛ рдирд╣реАрдВ рд╣реИред
- рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдПрдХ json рдЕрдиреБрд░реЛрдз рд╕рдВрдХрд▓рд┐рдд рдХрд░реЗрдВ рдФрд░ рд▓рд╛рдкрддрд╛ рдорд╣реАрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╕реНрдЯрдмреНрд╕ рдЬреЛрдбрд╝реЗрдВред
рдореИрдВ рдкрд╣рд▓реЗ рд╡рд┐рдХрд▓реНрдк рдкрд░ рдмрд╕ рдЧрдпрд╛ - рдиреЗрддреНрд░рд╣реАрди рдпрд╣ рдЕрдзрд┐рдХ рд╕рдордЭ рдореЗрдВ рдЖрддрд╛ рд╣реИ рдФрд░ рд╕рдорд░реНрдерд┐рдд рд╣реИред рдХрд┐рд╕реА рджрд┐рдП рдЧрдП рдорд╣реАрдиреЗ рдореЗрдВ рдЬрдиреНрдорджрд┐рди рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЛ JOIN
рдкрд╛рд░рд┐рд╡рд╛рд░рд┐рдХ рд╕рдВрдмрдВрдзреЛрдВ рдХреЗ рд╕рд╛рде рддрд╛рд▓рд┐рдХрд╛ рд╕реЗ рдмрдирд╛рдХрд░ рдкреНрд░рд╛рдкреНрдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ ( relations.citizen_id
- рд╡рд╣ рдирд┐рд╡рд╛рд╕реА рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рд╣рдо рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреЗ рдЬрдиреНрдорджрд┐рди рдорд╛рдирддреЗ рд╣реИрдВ) рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ citizens
(рдЬрдиреНрдо рдХреА рддрд╛рд░реАрдЦ рдЬрд┐рд╕рдореЗрдВ рд╕реЗ рдЖрдк рдорд╣реАрдиреЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ)редрдорд╛рд╣ рдорд╛рдиреЛрдВ рдореЗрдВ рдЕрдЧреНрд░рдгреА рд╢реВрдиреНрдп рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред birth_date
рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдлрд╝реАрд▓реНрдб рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдорд╣реАрдиреЗ date_part
рдореЗрдВ рдПрдХ рдЕрдЧреНрд░рдгреА рд╢реВрдиреНрдп рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕реЗ рдирд┐рдХрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВ рдкреНрд░рджрд░реНрд╢рди cast
рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП integer
SQL рдХреНрд╡реЗрд░реА рдореЗрдВредрдЗрд╕ рддрдереНрдп рдХреЗ рдмрд╛рд╡рдЬреВрдж рдХрд┐ рд╣реИрдВрдбрд▓рд░ рдХреЛ рджреЛ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рдкреВрд░рд╛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ (рдЙрддрд░рд╛рдИ рдХреЗ рдЕрд╕реНрддрд┐рддреНрд╡ рдХреА рдЬрд╛рдВрдЪ рдХрд░реЗрдВ рдФрд░ рдЬрдиреНрдорджрд┐рди рдФрд░ рдЙрдкрд╣рд╛рд░реЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ), рд▓реЗрдирджреЗрди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ редрдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ, PostgreSQL READ COMMITTED рдореЛрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рд╕рднреА рдирдП (рдЕрдиреНрдп рд▓реЗрдирджреЗрди рджреНрд╡рд╛рд░рд╛ рдЬреЛрдбрд╝реЗ рдЧрдП) рдФрд░ рдореМрдЬреВрджрд╛ (рдЕрдиреНрдп рд▓реЗрди-рджреЗрди рджреНрд╡рд╛рд░рд╛ рдкрд░рд┐рд╡рд░реНрддрд┐рдд) рд░рд┐рдХреЙрд░реНрдб рд╡рд░реНрддрдорд╛рди рд▓реЗрдирджреЗрди рдореЗрдВ рджрд┐рдЦрд╛рдИ рджреЗрддреЗ рд╣реИрдВ, рдЬрдм рд╡реЗ рд╕рдлрд▓рддрд╛рдкреВрд░реНрд╡рдХ рдкреВрд░рд╛ рд╣реЛ рдЬрд╛рддреЗ рд╣реИрдВредрдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд╕рдордп рдПрдХ рдирдпрд╛ рдЕрдкрд▓реЛрдб рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдпрд╣ рдореМрдЬреВрджрд╛ рд╡рд╛рд▓реЗ рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ред рдпрджрд┐ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рд╣реЛрдиреЗ рдХреЗ рд╕рдордп рдирд┐рд╡рд╛рд╕реА рдХреЛ рдмрджрд▓рдиреЗ рдХрд╛ рдЕрдиреБрд░реЛрдз рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдпрд╛ рддреЛ рдбреЗрдЯрд╛ рдЕрднреА рддрдХ рджрд┐рдЦрд╛рдИ рдирд╣реАрдВ рджреЗрдЧрд╛ (рдпрджрд┐ рд▓реЗрдирджреЗрди рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рдбреЗрдЯрд╛ рдкреВрд░рд╛ рдирд╣реАрдВ рд╣реБрдЖ рд╣реИ), рдпрд╛ рд▓реЗрдирджреЗрди рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдкреВрд░рд╛ рд╣реЛ рдЬрд╛рдПрдЧрд╛ рдФрд░ рд╕рднреА рдкрд░рд┐рд╡рд░реНрддрди рддреБрд░рдВрдд рджрд┐рдЦрд╛рдИ рджреЗрдВрдЧреЗред рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдЕрдЦрдВрдбрддрд╛ рдХрд╛ рдЙрд▓реНрд▓рдВрдШрди рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛редGET / рдЖрдпрд╛рдд / $ import_id / рдХрд╕реНрдмреЛрдВ / рд╕реНрдЯреЗрдЯ / рдкреНрд░рддрд┐рд╢рдд / рдЖрдпреБ
рд╣реИрдВрдбрд▓рд░ рдирд┐рд░реНрджрд┐рд╖реНрдЯ import_id рдХреЗ рд╕рд╛рде рдирдореВрдиреЗ рдореЗрдВ рд╢рд╣рд░ рджреНрд╡рд╛рд░рд╛ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреА рдЖрдпреБ (рдкреВрд░реНрдг рд╡рд░реНрд╖) рдХреА 50 рд╡реАрдВ, 75 рд╡реАрдВ рдФрд░ 99 рд╡реАрдВ рдкреНрд░рддрд┐рд╢рддрддрд╛ рдХреА рдЧрдгрдирд╛ рдХрд░рддрд╛ рд╣реИред рдЧреИрд░-рдореМрдЬреВрдж рдЕрдкрд▓реЛрдб рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ , HTTP рдкреНрд░рддрд┐рд╕рд╛рдж рджреЗрдирд╛ рдЪрд╛рд╣рд┐рдП 404: Not Found
редрдЗрд╕ рддрдереНрдп рдХреЗ рдмрд╛рд╡рдЬреВрдж рдХрд┐ рдкреНрд░реЛрд╕реЗрд╕рд░ рджреЛ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддрд╛ рд╣реИ (рдЙрддрд░рд╛рдИ рдХреЗ рдЕрд╕реНрддрд┐рддреНрд╡ рдХреА рдЬрд╛рдВрдЪ рдХрд░рдирд╛ рдФрд░ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛), рд▓реЗрдирджреЗрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рдирд╣реАрдВ рд╣реИ редрджреЛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╡рд┐рдХрд▓реНрдк рд╣реИрдВ:- рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреА рдЖрдпреБ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ, рд╢рд╣рд░ рджреНрд╡рд╛рд░рд╛ рд╕рдореВрд╣реАрдХреГрдд, рдФрд░ рдлрд┐рд░ рдкрд╛рдпрдерди рдХреА рдУрд░ рд╕реЗ рдЦрд╕рд░реЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкреНрд░рддрд┐рд╢рдд рдХреА рдЧрдгрдирд╛ рдХрд░реЗрдВ (рдЬреЛ рдХрд╛рд░реНрдп рдореЗрдВ рдПрдХ рд╕рдВрджрд░реНрдн рдХреЗ рд░реВрдк рдореЗрдВ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╣реИ) рдФрд░ рджреЛ рджрд╢рдорд▓рд╡ рд╕реНрдерд╛рдиреЛрдВ рддрдХ рдЧреЛрд▓ред
- PostgreSQL: percentile_cont , SQL-, numpy .
рджреВрд╕рд░реЗ рд╡рд┐рдХрд▓реНрдк рдХреЗ рд▓рд┐рдП рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдФрд░ рдкреЛрд╕реНрдЯрдЧреНрд░реИрд╕реАрдХреНрдпреВ рдХреЗ рдмреАрдЪ рдХрдо рдбреЗрдЯрд╛ рдЯреНрд░рд╛рдВрд╕рдлрд░ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕рдореЗрдВ рдмрд╣реБрдд рд╕реНрдкрд╖реНрдЯ рдЦрд░рд╛рдмреА рдирд╣реАрдВ рд╣реЛрддреА рд╣реИ: рдкреЛрд╕реНрдЯрдЧреНрд░реИрд╕реАрдХреНрдпреВ рдореЗрдВ, рд░рд╛рдЙрдВрдбрд┐рдВрдЧ рдЧрдгрд┐рддреАрдп рд╣реИ, ( SELECT ROUND(2.5)
рд░рд┐рдЯрд░реНрди 3), рдФрд░ рдкрд╛рдпрдерди - рдЕрдХрд╛рдЙрдВрдЯрд┐рдВрдЧ рдореЗрдВ, рдирд┐рдХрдЯрддрдо рдкреВрд░реНрдгрд╛рдВрдХ рддрдХ ( round(2.5)
рд░рд┐рдЯрд░реНрди 2)редрд╣реИрдВрдбрд▓рд░ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, PostgreSQL рдФрд░ рдкрд╛рдпрдерди рджреЛрдиреЛрдВ рдореЗрдВ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╕рдорд╛рди рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП (рдкрд╛рдпрдерди рдореЗрдВ рдЧрдгрд┐рддреАрдп рдЧреЛрд▓рд╛рдИ рдХреЗ рд╕рд╛рде рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдирд╛ рдЖрд╕рд╛рди рджрд┐рдЦрддрд╛ рд╣реИ)ред рдпрд╣ рдзреНрдпрд╛рди рджреЗрдиреЗ рдпреЛрдЧреНрдп рд╣реИ рдХрд┐ рдкреНрд░рддрд┐рд╢рдд рдХреА рдЧрдгрдирд╛ рдХрд░рддреЗ рд╕рдордп, рдЦрд╕реНрддрд╛ рдФрд░ рдкреЛрд╕реНрдЯрдЧреНрд░реЗрд╕реАрдХреНрдпреВрдПрд▓ рдереЛрдбрд╝рд╛ рдЕрд▓рдЧ рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рд▓реМрдЯ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЧреЛрд▓рд╛рдИ рдХреЛ рджреЗрдЦрддреЗ рд╣реБрдП, рдпрд╣ рдЕрдВрддрд░ рдзреНрдпрд╛рди рджреЗрдиреЗ рдпреЛрдЧреНрдп рдирд╣реАрдВ рд╣реЛрдЧрд╛редрдкрд░рд┐рдХреНрд╖рдг
рдЗрд╕ рдЖрд╡реЗрджрди рдореЗрдВ рдХреНрдпрд╛ рдЬрд╛рдБрдЪ рдХреА рдЬрд╛рдиреА рдЪрд╛рд╣рд┐рдП? рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдХрд┐ рд╣реИрдВрдбрд▓рд░ рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рдХреЛ рдкреВрд░рд╛ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдПрдХ рд╡рд╛рддрд╛рд╡рд░рдг рдореЗрдВ рдЖрд╡рд╢реНрдпрдХ рдХрд╛рд░реНрдп рдХрд░рддреЗ рд╣реИрдВ рдЬрд┐рддрдирд╛ рд╕рдВрднрд╡ рд╣реЛ рдЙрддрдирд╛ рдореБрдХрд╛рдмрд▓рд╛ рдкрд░реНрдпрд╛рд╡рд░рдг рдХреЗ рдХрд░реАрдм рд╣реЛрддрд╛ рд╣реИред рджреВрд╕рд░реЗ, рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдЬреЛ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреА рд╕реНрдерд┐рддрд┐ рдХреЛ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЗ рдмрд┐рдирд╛ рдмрджрд▓рддреЗ рд╣реИрдВред рддреАрд╕рд░рд╛, рдХрдИ рд╕рд╣рд╛рдпрдХ рдХрд╛рд░реНрдп рд╣реИрдВ рдЬрд┐рдиреНрд╣реЗрдВ рдкрд░реАрдХреНрд╖рдгреЛрдВ рджреНрд╡рд╛рд░рд╛ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдХрд╡рд░ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИредрдореИрдВрдиреЗ рдЕрдкрдиреЗ рд▓рдЪреАрд▓реЗрдкрди рдФрд░ рдЙрдкрдпреЛрдЧ рдореЗрдВ рдЖрд╕рд╛рдиреА рдХреЗ рдХрд╛рд░рдг рдкрд╛рдЗрд╕реНрдЯреЗрд╕реНрдЯ рдврд╛рдВрдЪреЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛ ред рдпрд╣ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЗ рд▓рд┐рдП рд╡рд╛рддрд╛рд╡рд░рдг рддреИрдпрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рддрдВрддреНрд░ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ - рдЬреБрдбрд╝рдирд╛рд░ , рдЕрд░реНрдерд╛рддреН , рдПрдХ рдбреЗрдХреЛрд░реЗрдЯрд░ рдХреЗ рд╕рд╛рде рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИpytest.mark.fixture
рдЬрд┐рдирдХреЗ рдирд╛рдо рдкрд░реАрдХреНрд╖рдг рдореЗрдВ рдкреИрд░рд╛рдореАрдЯрд░ рджреНрд╡рд╛рд░рд╛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд┐рдП рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВред рдпрджрд┐ рдкрд╛рдЗрд╕реНрдЯреЗрд╕реНрдЯ рдкрд░реАрдХреНрд╖рдг рдПрдиреЛрдЯреЗрд╢рди рдореЗрдВ рдПрдХ рд╕реНрдерд┐рд░рддрд╛ рдирд╛рдо рдХреЗ рд╕рд╛рде рдПрдХ рдкреИрд░рд╛рдореАрдЯрд░ рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рддрд╛ рд╣реИ, рддреЛ рд╡рд╣ рдЗрд╕ рд╕реНрдерд┐рд░рддрд╛ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░реЗрдЧрд╛ рдФрд░ рдЗрд╕ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рдореВрд▓реНрдп рдореЗрдВ рдкрд░рд┐рдгрд╛рдо рдкрд╛рд░рд┐рдд рдХрд░реЗрдЧрд╛ред рдФрд░ рдпрджрд┐ рд╕реНрдерд┐рд░рддрд╛ рдПрдХ рдЬрдирд░реЗрдЯрд░ рд╣реИ, рддреЛ рдкрд░реАрдХреНрд╖рдг рдкреИрд░рд╛рдореАрдЯрд░ рд╡рд╛рдкрд╕ рд▓реМрдЯрд╛рдП рдЧрдП рдорд╛рди рдХреЛ рд▓реЗ рдЬрд╛рдПрдЧрд╛ yield
, рдФрд░ рдкрд░реАрдХреНрд╖рдг рдЦрддреНрдо рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж, рд╕реНрдерд┐рд░рддрд╛ рдХрд╛ рджреВрд╕рд░рд╛ рднрд╛рдЧ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ , рдЬреЛ рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдпрд╛ рдХрд░реАрдмреА рдХрдиреЗрдХреНрд╢рди рдХреЛ рд╕рд╛рдл рдХрд░ рд╕рдХрддрд╛ рд╣реИредрдЕрдзрд┐рдХрд╛рдВрд╢ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдПрдХ PostgreSQL рдбреЗрдЯрд╛рдмреЗрд╕ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рдПрдХ рджреВрд╕рд░реЗ рд╕реЗ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЛ рдЕрд▓рдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдк рдкреНрд░рддреНрдпреЗрдХ рдкрд░реАрдХреНрд╖рдг рд╕реЗ рдкрд╣рд▓реЗ рдПрдХ рдЕрд▓рдЧ рдбреЗрдЯрд╛рдмреЗрд╕ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рдмрд╛рдж рдЗрд╕реЗ рд╣рдЯрд╛ рд╕рдХрддреЗ рд╣реИрдВредрдкреНрд░рддреНрдпреЗрдХ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдПрдХ рдлрд╝рд┐рдХреНрдЪрд░ рдбреЗрдЯрд╛рдмреЗрд╕ рдмрдирд╛рдПрдБimport os
import uuid
import pytest
from sqlalchemy import create_engine
from sqlalchemy_utils import create_database, drop_database
from yarl import URL
from analyzer.utils.pg import DEFAULT_PG_URL
PG_URL = os.getenv('CI_ANALYZER_PG_URL', DEFAULT_PG_URL)
@pytest.fixture
def postgres():
tmp_name = '.'.join([uuid.uuid4().hex, 'pytest'])
tmp_url = str(URL(PG_URL).with_path(tmp_name))
create_database(tmp_url)
try:
yield tmp_url
finally:
drop_database(tmp_url)
def test_db(postgres):
"""
, PostgreSQL
"""
engine = create_engine(postgres)
assert engine.execute('SELECT 1').scalar() == 1
engine.dispose()
Sqlalchemy_utils
рдореЙрдбреНрдпреВрд▓ рдиреЗ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдбреЗрдЯрд╛рдмреЗрд╕ рдФрд░ рдбреНрд░рд╛рдЗрд╡рд░реЛрдВ рдХреА рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрддреЗ рд╣реБрдП, рдЗрд╕ рдХрд╛рд░реНрдп рдХрд╛ рдПрдХ рдмрдбрд╝рд╛ рдХрд╛рдо рдХрд┐рдпрд╛ ред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, PostgreSQL CREATE DATABASE
рд▓реЗрдирджреЗрди рдмреНрд▓реЙрдХ рдореЗрдВ рдирд┐рд╖реНрдкрд╛рджрди рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рджреЗрддрд╛ рд╣реИ ред рдПрдХ рдбреЗрдЯрд╛рдмреЗрд╕ рдмрдирд╛рддреЗ рд╕рдордп, рдЗрд╕рдХрд╛ sqlalchemy_utils
рдЕрдиреБрд╡рд╛рдж psycopg2
(рдЬреЛ рдЖрдорддреМрд░ рдкрд░ рдПрдХ рд▓реЗрдирджреЗрди рдореЗрдВ рд╕рднреА рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддрд╛ рд╣реИ) рдХреЛ рдСрдЯреЛрдХреЙрдорд┐рдЯ рдореЛрдб рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИредрдПрдХ рдЕрдиреНрдп рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╡рд┐рд╢реЗрд╖рддрд╛: рдпрджрд┐ рдХрдо рд╕реЗ рдХрдо рдПрдХ рдЧреНрд░рд╛рд╣рдХ PostgreSQL рд╕реЗ рдЬреБрдбрд╝рд╛ рд╣реИ, рддреЛ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЛ рд╣рдЯрд╛рдпрд╛ рдирд╣реАрдВ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди sqlalchemy_utils
рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЛ рд╣рдЯрд╛рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рд╕рднреА рдЧреНрд░рд╛рд╣рдХреЛрдВ рдХреЛ рдбрд┐рд╕реНрдХрдиреЗрдХреНрдЯ рдХрд░ рджреЗрддрд╛ рд╣реИред рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЛ рд╕рдлрд▓рддрд╛рдкреВрд░реНрд╡рдХ рд╣рдЯрд╛ рджрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ рднрд▓реЗ рд╣реА рдЗрд╕рдХреЗ рд╕рд╛рде рд╕рдХреНрд░рд┐рдп рдХрдиреЗрдХреНрд╢рди рдХреЗ рд╕рд╛рде рдХреБрдЫ рдкрд░реАрдХреНрд╖рдг рд▓рдЯрдХрд╛ рд╣реБрдЖ рд╣реЛредрд╣рдореЗрдВ рд╡рд┐рднрд┐рдиреНрди рд░рд╛рдЬреНрдпреЛрдВ рдореЗрдВ PostgreSQL рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ: рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдХреЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдПрдХ рд╕реНрд╡рдЪреНрдЫ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЬрдмрдХрд┐ рд╣реИрдВрдбрд▓рд░ рдХреЛ рдпрд╣ рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдХрд┐ рд╕рднреА рдорд╛рдЗрдЧреНрд░реЗрд╢рди рд▓рд╛рдЧреВ рд╣реЛрдВред рдЖрдк рдкреНрд░реЛрдЧреНрд░рд╛рдо рдХреЛ рдПрд▓реЗрдореНрдмрд┐рдХ рдХрдорд╛рдВрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреА рд╕реНрдерд┐рддрд┐ рдХреЛ рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВ, рдЙрдиреНрд╣реЗрдВ рдХреЙрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрд▓реЗрдореНрдмрд┐рдХ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдСрдмреНрдЬреЗрдХреНрдЯ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИредрдПрдХ рд╕реНрдерд┐рд░рддрд╛ рдЕрд▓реЗрдореНрдмрд┐рдХ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдСрдмреНрдЬреЗрдХреНрдЯ рдмрдирд╛рдПрдБfrom types import SimpleNamespace
import pytest
from analyzer.utils.pg import make_alembic_config
@pytest.fixture()
def alembic_config(postgres):
cmd_options = SimpleNamespace(config='alembic.ini', name='alembic',
pg_url=postgres, raiseerr=False, x=None)
return make_alembic_config(cmd_options)
рдХреГрдкрдпрд╛ рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдЬреБрдбрд╝рдирд╛рд░ alembic_config
рдХрд╛ рдПрдХ рдкреИрд░рд╛рдореАрдЯрд░ рд╣реИ postgres
- pytest
рди рдХреЗрд╡рд▓ рдЬреБрдбрд╝рдирд╛рд░ рдкрд░ рдкрд░реАрдХреНрд╖рдг рдХреА рдирд┐рд░реНрднрд░рддрд╛ рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рдмрд▓реНрдХрд┐ рдЬреБрдбрд╝рдирд╛рд░ рдХреЗ рдмреАрдЪ рдирд┐рд░реНрднрд░рддрд╛ рднреАредрдпрд╣ рддрдВрддреНрд░ рдЖрдкрдХреЛ рд▓рдЪреАрд▓реЗ рдврдВрдЧ рд╕реЗ рдЕрд▓рдЧ рддрд░реНрдХ рдФрд░ рдмрд╣реБрдд рд╕рдВрдХреНрд╖рд┐рдкреНрдд рдФрд░ рдкреБрди: рдкреНрд░рдпреЛрдЬреНрдп рдХреЛрдб рд▓рд┐рдЦрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИредрд╣реИрдВрдбрд▓рд░
рдкрд░реАрдХреНрд╖рдг рд╕рдВрдЪрд╛рд▓рдХреЛрдВ рдХреЛ рдмрдирд╛рдП рдЧрдП рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдФрд░ рдбреЗрдЯрд╛ рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рдорд╛рдЗрдЧреНрд░реЗрд╢рди рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдкреНрд░реЛрдЧреНрд░рд╛рдореЗрдЯрд┐рдХ рд░реВрдк рд╕реЗ рдЕрдкрдЧреНрд░реЗрдб рдПрд▓реЗрдореНрдмрд┐рдХ рдХрдорд╛рдВрдб рдХреЛ рдХреЙрд▓ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдЗрд╕реЗ рдХреЙрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдПрд▓реЗрдореНрдмрд┐рдХ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЗ рд╕рд╛рде рдПрдХ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рд╣рдордиреЗ рдкрд╣рд▓реЗ рд╕реЗ рдЬреБрдбрд╝рдирд╛рд░ рдХреЗ рд╕рд╛рде рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛ рд╣реИ alembic_config
ред рдорд╛рдЗрдЧреНрд░реЗрд╢рди рд╡рд╛рд▓рд╛ рдбреЗрдЯрд╛рдмреЗрд╕ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рд╕реНрд╡рддрдВрддреНрд░ рдЗрдХрд╛рдИ рдХреА рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ, рдФрд░ рдЗрд╕реЗ рдПрдХ рд╕реНрдерд┐рд░рддрд╛ рдХреЗ рд░реВрдк рдореЗрдВ рджрд░реНрд╢рд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:from alembic.command import upgrade
@pytest.fixture
async def migrated_postgres(alembic_config, postgres):
upgrade(alembic_config, 'head')
return postgres
рдЬрдм рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рдХрдИ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рд╣реЛрддреЗ рд╣реИрдВ, рддреЛ рдкреНрд░рддреНрдпреЗрдХ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдЙрдирдХреЗ рдЖрд╡реЗрджрди рдореЗрдВ рдмрд╣реБрдд рдЕрдзрд┐рдХ рд╕рдордп рд▓рдЧ рд╕рдХрддрд╛ рд╣реИред рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рдЧрддрд┐ рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдк рдПрдХ рдмрд╛рд░ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдХреЗ рд╕рд╛рде рдПрдХ рдбреЗрдЯрд╛рдмреЗрд╕ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдлрд┐рд░ рдЗрд╕реЗ рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ редрд╣реИрдВрдбрд▓рд░ рдХреЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЖрдкрдХреЛ рдПрдХ рд░рдирд┐рдВрдЧ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА, рд╕рд╛рде рд╣реА рдЗрд╕ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдирд╛ рдЖрд╕рд╛рди рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдЗрд╕рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХреЛ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рд░рдЦрд╛ рд╣реИ create_app
рдЬреЛ рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдкреИрд░рд╛рдореАрдЯрд░ рд▓реЗрддрд╛ рд╣реИ: рдПрдХ рдбреЗрдЯрд╛рдмреЗрд╕, REST API рдХреЗ рд▓рд┐рдП рдПрдХ рдкреЛрд░реНрдЯ, рдФрд░ рдЕрдиреНрдпредрдПрдкреНрд▓рд┐рдХреЗрд╢рди рд▓реЙрдиреНрдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рддрд░реНрдХ рдХреЛ рдПрдХ рдЕрд▓рдЧ рд╕реНрдерд┐рд░рддрд╛ рдХреЗ рд░реВрдк рдореЗрдВ рднреА рджрд░реНрд╢рд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЙрдиреНрд╣реЗрдВ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдкрд░реАрдХреНрд╖рдг рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдФрд░ рдорд╛рдЗрдЧреНрд░реЗрдЯ рдХрд┐рдП рдЧрдП рдЕрд╕реНрдерд╛рдпреА рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рдкрддреЗ рдХреЛ рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдирд┐: рд╢реБрд▓реНрдХ рдкреЛрд░реНрдЯ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛редрдореБрдХреНрдд рдмрдВрджрд░рдЧрд╛рд╣ рдХрд╛ рдирд┐рд░реНрдзрд╛рд░рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ aiomisc_unused_port
aiomisc рдкреИрдХреЗрдЬ рд╕реЗ рд╕реНрдерд┐рд░рддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ редрдПрдХ рдорд╛рдирдХ рд╕реНрдерд┐рд░рддрд╛ aiohttp_unused_port
рднреА рдареАрдХ рд╣реЛрдЧреА, рд▓реЗрдХрд┐рди рдпрд╣ рдореБрдлреНрдд рдмрдВрджрд░рдЧрд╛рд╣реЛрдВ рдХреЛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдлрд╝рдВрдХреНрд╢рди рджреЗрддрд╛ рд╣реИ, рдЬрдмрдХрд┐ рдпрд╣ aiomisc_unused_port
рддреБрд░рдВрдд рдкреЛрд░реНрдЯ рдирдВрдмрд░ рд▓реМрдЯрд╛рддрд╛ рд╣реИред рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдХреЗрд╡рд▓ рдПрдХ рдореБрдлреНрдд рдкреЛрд░реНрдЯ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВрдиреЗ рдХреЙрд▓ рдХреЗ рд╕рд╛рде рдХреЛрдб рдХреА рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд рдкрдВрдХреНрддрд┐ рдирд╣реАрдВ рд▓рд┐рдЦрдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ aiohttp_unused_port
ред@pytest.fixture
def arguments(aiomisc_unused_port, migrated_postgres):
return parser.parse_args(
[
'--log-level=debug',
'--api-address=127.0.0.1',
f'--api-port={aiomisc_unused_port}',
f'--pg-url={migrated_postgres}'
]
)
рд╣реИрдВрдбрд▓рд░ рдХреЗ рд╕рд╛рде рд╕рднреА рдкрд░реАрдХреНрд╖рдг рд░реАрд╕реНрдЯ рдПрдкреАрдЖрдИ рдХреЗ рд▓рд┐рдП рдЕрдиреБрд░реЛрдз рдХрд░рддрд╛ рд╣реИ, рд╕реАрдзреЗ рдЖрд╡реЗрджрди рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреА aiohttp
рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдореИрдВрдиреЗ рдПрдХ рд╕реНрдерд┐рд░рддрд╛ рдмрдирд╛рдИ рдЬреЛ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдХреЛ рд▓реЙрдиреНрдЪ рдХрд░рддреА рд╣реИ рдФрд░ рдХрд╛рд░рдЦрд╛рдиреЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ aiohttp_client
рдПрдХ рдорд╛рдирдХ рдкрд░реАрдХреНрд╖рдг рдХреНрд▓рд╛рдЗрдВрдЯ рдмрдирд╛рддрд╛ рд╣реИ рдФрд░ рдЖрд╡реЗрджрди рд╕реЗ рдЬреБрдбрд╝рд╛ рд╣реЛрддрд╛ рд╣реИ aiohttp.test_utils.TestClient
редfrom analyzer.api.app import create_app
@pytest.fixture
async def api_client(aiohttp_client, arguments):
app = create_app(arguments)
client = await aiohttp_client(app, server_kwargs={
'port': arguments.api_port
})
try:
yield client
finally:
await client.close()
рдЕрдм, рдпрджрд┐ рдЖрдк рдкрд░реАрдХреНрд╖рдг рдорд╛рдкрджрдВрдбреЛрдВ рдореЗрдВ рд╕реНрдерд┐рд░рддрд╛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рддреЗ рд╣реИрдВ api_client
, рддреЛ рдирд┐рдореНрди рд╣реЛрдЧрд╛:postgres
( migrated_postgres
).alembic_config
Alembic, ( migrated_postgres
).migrated_postgres
( arguments
).aiomisc_unused_port
( arguments
).arguments
( api_client
).api_client
.- .
api_client
.postgres
.
рдЬреБрдбрд╝рдирд╛рд░ рдЖрдкрдХреЛ рдХреЛрдб рдХреЗ рджреЛрд╣рд░рд╛рд╡ рд╕реЗ рдмрдЪрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдкрд░реАрдХреНрд╖рдгреЛрдВ рдореЗрдВ рдкрд░реНрдпрд╛рд╡рд░рдг рдХреЛ рддреИрдпрд╛рд░ рдХрд░рдиреЗ рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдПрдХ рдФрд░ рд╕рдВрднрд╛рд╡рд┐рдд рд╕реНрдерд╛рди рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдмрд╣реБрдд рд╕рд╛рд░реЗ рд╕рдорд╛рди рдХреЛрдб - рдЖрд╡реЗрджрди рдЕрдиреБрд░реЛрдз рд╣реЛрдВрдЧреЗредрд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдПрдХ рдЕрдиреБрд░реЛрдз рдХрд░рддреЗ рд╣реБрдП, рд╣рдо рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд HTTP рд╕реНрдерд┐рддрд┐ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЕрдкреЗрдХреНрд╖рд╛ рдХрд░рддреЗ рд╣реИрдВред рджреВрд╕рд░реЗ, рдпрджрд┐ рд╕реНрдерд┐рддрд┐ рдЕрдкреЗрдХреНрд╖рд┐рдд рд╕реЗ рдореЗрд▓ рдЦрд╛рддреА рд╣реИ, рддреЛ рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдЖрдкрдХреЛ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдХрд┐ рдЙрдирдХреЗ рдкрд╛рд╕ рд╕рд╣реА рдкреНрд░рд╛рд░реВрдк рд╣реИред рдпрд╣рд╛рдВ рдПрдХ рдЧрд▓рддреА рдХрд░рдирд╛ рдЖрд╕рд╛рди рд╣реИ рдФрд░ рдПрдХ рд╣реИрдВрдбрд▓рд░ рд▓рд┐рдЦрдирд╛ рд╣реИ рдЬреЛ рд╕рд╣реА рдЧрдгрдирд╛ рдХрд░рддрд╛ рд╣реИ рдФрд░ рд╕рд╣реА рдкрд░рд┐рдгрд╛рдо рджреЗрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЧрд▓рдд рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкреНрд░рд╛рд░реВрдк рдХреЗ рдХрд╛рд░рдг рд╕реНрд╡рдд: рд╕рддреНрдпрд╛рдкрди рдкрд╛рд╕ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдХреБрдВрдЬреА рдХреЗ рд╕рд╛рде рдПрдХ рд╢рдмреНрджрдХреЛрд╢ рдореЗрдВ рдЙрддреНрддрд░ рдХреЛ рд▓рдкреЗрдЯрдирд╛ рднреВрд▓ рдЬрд╛рддреЗ рд╣реИрдВ data
)ред рдпреЗ рд╕рднреА рдЬрд╛рдВрдЪреЗрдВ рдПрдХ рд╣реА рд╕реНрдерд╛рди рдкрд░ рдХреА рдЬрд╛ рд╕рдХрддреА рдереАрдВредрдореЙрдбреНрдпреВрд▓ рдореЗрдВanalyzer.testing
рдореИрдВрдиреЗ рдкреНрд░рддреНрдпреЗрдХ рд╣реИрдВрдбрд▓рд░ рдХреЛ рдПрдХ рд╣реЗрд▓реНрдкрд░ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рдХрд┐рдпрд╛ рд╣реИ рдЬреЛ HTTP рдХреА рд╕реНрдерд┐рддрд┐ рдХреА рдЬрд╛рдВрдЪ рдХрд░рддрд╛ рд╣реИ, рд╕рд╛рде рд╣реА рдорд╛рд░реНрд╢рдореИрд▓реЛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╕реНрд╡рд░реВрдк рднреАредGET / рдЖрдпрд╛рдд / $ import_id / рдирд╛рдЧрд░рд┐рдХ
рдореИрдВрдиреЗ рдПрдХ рд╣реИрдВрдбрд▓рд░ рдХреЗ рд╕рд╛рде рд╢реБрд░реБрдЖрдд рдХрд░рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ рдЬреЛ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЛ рд╡рд╛рдкрд╕ рдХрд░рддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреА рд╕реНрдерд┐рддрд┐ рдХреЛ рдмрджрд▓рдиреЗ рд╡рд╛рд▓реЗ рдЕрдиреНрдп рд╣реИрдВрдбрд▓рд░ рдХреЗ рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдЙрдкрдпреЛрдЧреА рд╣реИредрдореИрдВрдиреЗ рдЬрд╛рдирдмреВрдЭрдХрд░ рдХреЛрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИ рдЬреЛ рд╣реИрдВрдбрд▓рд░ рд╕реЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдбреЗрдЯрд╛ рдЬреЛрдбрд╝рддрд╛ рд╣реИ POST /imports
, рд╣рд╛рд▓рд╛рдВрдХрд┐ рдЗрд╕реЗ рдПрдХ рдЕрд▓рдЧ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рдмрдирд╛рдирд╛ рдореБрд╢реНрдХрд┐рд▓ рдирд╣реАрдВ рд╣реИред рд╣реИрдВрдбрд▓рд░ рдХреЗ рдХреЛрдб рдХреЛ рдмрджрд▓рдиреЗ рдХреА рд╕рдВрдкрддреНрддрд┐ рд╣реИ, рдФрд░ рдЕрдЧрд░ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдЬреБрдбрд╝рдиреЗ рд╡рд╛рд▓реЗ рдХреЛрдб рдореЗрдВ рдХреЛрдИ рддреНрд░реБрдЯрд┐ рд╣реИ, рддреЛ рдПрдХ рдореМрдХрд╛ рд╣реИ рдХрд┐ рдкрд░реАрдХреНрд╖рдг рдЙрджреНрджреЗрд╢реНрдп рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рдо рдХрд░рдирд╛ рдмрдВрдж рдХрд░ рджреЗрдЧрд╛ рдФрд░ рдбреЗрд╡рд▓рдкрд░реНрд╕ рдХреЗ рд▓рд┐рдП рдирд┐рд╣рд┐рддрд╛рд░реНрде рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рджрд┐рдЦрд╛рдирд╛ рдмрдВрдж рдХрд░ рджреЗрдЧрд╛редрдЗрд╕ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкрд░реАрдХреНрд╖рдг рдбреЗрдЯрд╛ рд╕реЗрдЯ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛:- рдХрдИ рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреЗ рд╕рд╛рде рдЙрддрд╛рд░рдирд╛ред рдЬрд╛рдБрдЪ рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рдирд┐рд╡рд╛рд╕реА рдХреЗ рд▓рд┐рдП рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреЗ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛рдУрдВ рдХреЗ рд╕рд╛рде рдПрдХ рд╕реВрдЪреА рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдмрдирд╛рдИ рдЬрд╛рдПрдЧреАред
- рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреЗ рдмрд┐рдирд╛ рдПрдХ рдирд┐рд╡рд╛рд╕реА рдХреЗ рд╕рд╛рде рдЙрддрд╛рд░рдирд╛ред рдЬрд╛рдБрдЪрддрд╛ рд╣реИ рдХрд┐ рдлрд╝реАрд▓реНрдб
relatives
рдПрдХ рдЦрд╛рд▓реА рд╕реВрдЪреА рд╣реИ ( LEFT JOIN
SQL рдХреНрд╡реЗрд░реА рдХреЗ рдХрд╛рд░рдг , рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреА рд╕реВрдЪреА рдмрд░рд╛рдмрд░ рд╣реЛ рд╕рдХрддреА рд╣реИ [None]
)ред - рдПрдХ рдирд┐рд╡рд╛рд╕реА рдХреЗ рд╕рд╛рде рдЙрддрд╛рд░рдирд╛ рдЬреЛ рд╕реНрд╡рдпрдВ рдХрд╛ рд░рд┐рд╢реНрддреЗрджрд╛рд░ рд╣реИред
- рдЦрд╛рд▓реА рдЙрддрд╛рд░рдирд╛ред рдЬрд╛рдБрдЪрддрд╛ рд╣реИ рдХрд┐ рд╣реИрдВрдбрд▓рд░ рдЦрд╛рд▓реА рдЙрддрд░рд╛рдИ рдЬреЛрдбрд╝рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ рдФрд░ рдПрдХ рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде рджреБрд░реНрдШрдЯрдирд╛ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред
рдкреНрд░рддреНрдпреЗрдХ рдЕрдкрд▓реЛрдб рдкрд░ рдПрдХ рд╣реА рдкрд░реАрдХреНрд╖рдг рдХреЛ рдЕрд▓рдЧ рд╕реЗ рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдПрдХ рдФрд░ рдмрд╣реБрдд рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рдкрд╛рдЗрд╕реНрдЯреЗрд╕реНрдЯ рдореИрдХреЗрдирд┐рдЬреНрдо - рдкреИрд░рд╛рдореАрдЯрд░рд╛рдЗрдЬреЗрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ ред рдпрд╣ рддрдВрддреНрд░ рдЖрдкрдХреЛ рдбреЗрдХреЛрд░реЗрдЯрд░ рдореЗрдВ рдкрд░реАрдХреНрд╖рдг рдлрд╝рдВрдХреНрд╢рди рдХреЛ рд▓рдкреЗрдЯрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ pytest.mark.parametrize
рдФрд░ рдЗрд╕рдореЗрдВ рд╡рд░реНрдгрди рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рд╡реНрдпрдХреНрддрд┐рдЧрдд рдкрд░реАрдХреНрд╖рдг рдорд╛рдорд▓реЗ рдХреЗ рд▓рд┐рдП рдкрд░реАрдХреНрд╖рдг рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреНрдпрд╛ рдкреИрд░рд╛рдореАрдЯрд░ рд▓реЗрдирд╛ рдЪрд╛рд╣рд┐рдПредрдХреИрд╕реЗ рдПрдХ рдкрд░реАрдХреНрд╖рдг рдХреЗ рдорд╛рдирдХреАрдХрд░рдг рдХреЗ рд▓рд┐рдПimport pytest
from analyzer.utils.testing import generate_citizen
datasets = [
[
generate_citizen(citizen_id=1, relatives=[2, 3]),
generate_citizen(citizen_id=2, relatives=[1]),
generate_citizen(citizen_id=3, relatives=[1])
],
[
generate_citizen(relatives=[])
],
[
generate_citizen(citizen_id=1, name='', gender='male',
birth_date='17.02.2020', relatives=[1])
],
[],
]
@pytest.mark.parametrize('dataset', datasets)
async def test_get_citizens(api_client, dataset):
"""
4 ,
"""
рдЗрд╕рд▓рд┐рдП, рдкрд░реАрдХреНрд╖рдг рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдЕрдкрд▓реЛрдб рдХреЛ рдЬреЛрдбрд╝ рджреЗрдЧрд╛, рдлрд┐рд░, рд╣реИрдВрдбрд▓рд░ рдХреЗ рдЕрдиреБрд░реЛрдз рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рдпрд╣ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдЧрд╛ рдФрд░ рдкреНрд░рд╛рдкреНрдд рдПрдХ рдХреЗ рд╕рд╛рде рд╕рдВрджрд░реНрдн рдЕрдкрд▓реЛрдб рдХреА рддреБрд▓рдирд╛ рдХрд░реЗрдЧрд╛ред рд▓реЗрдХрд┐рди рдЖрдк рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреА рддреБрд▓рдирд╛ рдХреИрд╕реЗ рдХрд░рддреЗ рд╣реИрдВ?рдкреНрд░рддреНрдпреЗрдХ рдирд┐рд╡рд╛рд╕реА рдореЗрдВ рд╕реНрдХреЗрд▓рд░ рдлрд╝реАрд▓реНрдб рдФрд░ рдлрд╝реАрд▓реНрдб рд╣реЛрддреЗ рд╣реИрдВ relatives
- рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреЗ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛рдУрдВ рдХреА рдПрдХ рд╕реВрдЪреАред рдкрд╛рдпрдерди рдореЗрдВ рдПрдХ рд╕реВрдЪреА рдПрдХ рдЖрджреЗрд╢рд┐рдд рдкреНрд░рдХрд╛рд░ рд╣реИ, рдФрд░ рдЬрдм рдкреНрд░рддреНрдпреЗрдХ рд╕реВрдЪреА рдХреЗ рддрддреНрд╡реЛрдВ рдХреЗ рдХреНрд░рдо рдХреА рддреБрд▓рдирд╛ рдХрд░рдирд╛ рдорд╛рдпрдиреЗ рд░рдЦрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рднрд╛рдИ-рдмрд╣рдиреЛрдВ рдХреЗ рд╕рд╛рде рд╕реВрдЪрд┐рдпреЛрдВ рдХреА рддреБрд▓рдирд╛ рдХрд░рддреЗ рд╕рдордп, рдЖрджреЗрд╢ рдХреЛ рдХреЛрдИ рдлрд░реНрдХ рдирд╣реАрдВ рдкрдбрд╝рддрд╛редрдпрджрд┐ рдЖрдк relatives
рддреБрд▓рдирд╛ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рд╕реЗрдЯ рдкрд░ рд▓рд╛рддреЗ рд╣реИрдВ , рддреЛ рдЬрдм рддреБрд▓рдирд╛ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдРрд╕реА рд╕реНрдерд┐рддрд┐ рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдЬрд╣рд╛рдВ рдХреНрд╖реЗрддреНрд░ рдХреЗ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ relatives
рдиреЗ рдбреБрдкреНрд▓рд┐рдХреЗрдЯ рдХрд┐рдпрд╛ рд╣реИред рдпрджрд┐ рдЖрдк рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреЗ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛рдУрдВ рдХреЗ рд╕рд╛рде рд╕реВрдЪреА рдХреЛ рд╕реЙрд░реНрдЯ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреЗ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛рдУрдВ рдХреЗ рд╡рд┐рднрд┐рдиреНрди рдХреНрд░рдо рдХреА рд╕рдорд╕реНрдпрд╛ рдХреЛ рджрд░рдХрд┐рдирд╛рд░ рдХрд░ рджреЗрдЧрд╛, рд▓реЗрдХрд┐рди рд╕рд╛рде рд╣реА рд╕рд╛рде рдбреБрдкреНрд▓рд┐рдХреЗрдЯ рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдПрдЧрд╛редрдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рджреЛ рд╕реВрдЪрд┐рдпреЛрдВ рдХреА рддреБрд▓рдирд╛ рдХрд░рддреЗ рд╕рдордп, рдПрдХ рд╕рдорд╛рди рд╕рдорд╕реНрдпрд╛ рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░ рд╕рдХрддрд╛ рд╣реИ: рддрдХрдиреАрдХреА рд░реВрдк рд╕реЗ, рдЕрдирд▓реЛрдбрд┐рдВрдЧ рдореЗрдВ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХрд╛ рдХреНрд░рдо рдорд╣рддреНрд╡рдкреВрд░реНрдг рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рдирд╛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ рдХрд┐ рдПрдХ рд╣реА рд▓реЛрдбрд┐рдВрдЧ рдореЗрдВ рдПрдХ рд╣реА рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рдХреЗ рд╕рд╛рде рджреЛ рдирд┐рд╡рд╛рд╕реА рд╣реИрдВ рдФрд░ рджреВрд╕рд░реЗ рдореЗрдВ рдирд╣реАрдВред рдЗрд╕рд▓рд┐рдП, рдкреНрд░рддреНрдпреЗрдХ рдирд┐рд╡рд╛рд╕реА рдХреЗ рд▓рд┐рдП рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ, рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреЗ рд╕рд╛рде рд╕реВрдЪреА рдХреЛ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдкреНрд░рддреНрдпреЗрдХ рдЕрдирд▓реЛрдбрд┐рдВрдЧ рдореЗрдВ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЛ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИредрдЪреВрдВрдХрд┐ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреА рддреБрд▓рдирд╛ рдХрд░рдиреЗ рдХрд╛ рдХрд╛рд░реНрдп рдПрдХ рд╕реЗ рдЕрдзрд┐рдХ рдмрд╛рд░ рдЙрддреНрдкрдиреНрди рд╣реЛрдЧрд╛, рдореИрдВрдиреЗ рджреЛ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛: рдПрдХ рджреЛ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреА рддреБрд▓рдирд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдФрд░ рджреВрд╕рд░рд╛ рджреЛ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреА рддреБрд▓рдирд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП:рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреА рддреБрд▓рдирд╛ рдХрд░реЗрдВfrom typing import Iterable, Mapping
def normalize_citizen(citizen):
"""
"""
return {**citizen, 'relatives': sorted(citizen['relatives'])}
def compare_citizens(left: Mapping, right: Mapping) -> bool:
"""
"""
return normalize_citizen(left) == normalize_citizen(right)
def compare_citizen_groups(left: Iterable, right: Iterable) -> bool:
"""
,
"""
left = [normalize_citizen(citizen) for citizen in left]
left.sort(key=lambda citizen: citizen['citizen_id'])
right = [normalize_citizen(citizen) for citizen in right]
right.sort(key=lambda citizen: citizen['citizen_id'])
return left == right
рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдпрд╣ рд╣реИрдВрдбрд▓рд░ рдЕрдиреНрдп рдЙрддрд░рд╛рдИ рдХреЗ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЛ рд╡рд╛рдкрд╕ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдореИрдВрдиреЗ рдкреНрд░рддреНрдпреЗрдХ рдкрд░реАрдХреНрд╖рдг рд╕реЗ рдкрд╣рд▓реЗ рдПрдХ рдирд┐рд╡рд╛рд╕реА рдХреЗ рд╕рд╛рде рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд рдЙрддрд░рд╛рдИ рдЬреЛрдбрд╝рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛редрдкреЛрд╕реНрдЯ / рдЖрдпрд╛рдд
рдореИрдВрдиреЗ рд╣реИрдВрдбрд▓рд░ рдХреЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдбреЗрдЯрд╛рд╕реЗрдЯ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛ рд╣реИ:- рд╕рд╣реА рдбреЗрдЯрд╛, рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рд╕рдлрд▓рддрд╛рдкреВрд░реНрд╡рдХ рдЬреЛрдбрд╝реЗ рдЬрд╛рдиреЗ рдХреА рдЙрдореНрдореАрдж рд╣реИред
- ( ).
. , , insert , . - ( , ).
, .
- .
, . :)
, aiohttp PostgreSQL 32 767 ( ).
- рдЦрд╛рд▓реА рдЙрддрд╛рд░рдирд╛
рд╣реИрдВрдбрд▓рд░ рдХреЛ рдРрд╕реЗ рдорд╛рдорд▓реЗ рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрдирд╛ рдЪрд╛рд╣рд┐рдП рдФрд░ рдЧрд┐рд░рдирд╛ рдирд╣реАрдВ рдЪрд╛рд╣рд┐рдП, рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рдЦрд╛рд▓реА рд╕рдореНрдорд┐рд▓рд┐рдд рдкреНрд░рджрд░реНрд╢рди рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рдиреА рдЪрд╛рд╣рд┐рдПред
- рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдбреЗрдЯрд╛, 400 рдХреА HTTP рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреА рдЕрдкреЗрдХреНрд╖рд╛ рдХрд░реЗрдВ: рдЦрд░рд╛рдм рдЕрдиреБрд░реЛрдзред
- рдЬрдиреНрдо рдХреА рддрд╛рд░реАрдЦ рдЧрд▓рдд рд╣реИ (рднрд╡рд┐рд╖реНрдп рдХрд╛рд▓)ред
- рдирд╛рдЧрд░рд┐рдХ_ рдЕрдкрд▓реЛрдб рдХреЗ рднреАрддрд░ рдЕрджреНрд╡рд┐рддреАрдп рдирд╣реАрдВ рд╣реИред
- рд░рд┐рд╢реНрддреЗрджрд╛рд░реА рдХреЛ рдЧрд▓рдд рддрд░реАрдХреЗ рд╕реЗ рдЗрдВрдЧрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ (рдХреЗрд╡рд▓ рдПрдХ рдирд┐рд╡рд╛рд╕реА рд╕реЗ рджреВрд╕рд░реЗ рд╡реНрдпрдХреНрддрд┐ рдХреЗ рд▓рд┐рдП рд╣реИ, рд▓реЗрдХрд┐рди рдХреЛрдИ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдирд╣реАрдВ рд╣реИ)ред
- рдЙрддрд░рд╛рдИ рдореЗрдВ рдирд┐рд╡рд╛рд╕реА рдХрд╛ рдЕрд╕реНрддрд┐рддреНрд╡рд╣реАрди рд░рд┐рд╢реНрддреЗрджрд╛рд░ рд╣реИред
- рдкрд╛рд░рд┐рд╡рд╛рд░рд┐рдХ рд╕рдВрдмрдВрдз рдЕрджреНрд╡рд┐рддреАрдп рдирд╣реАрдВ рд╣реИрдВред
рдпрджрд┐ рдкреНрд░реЛрд╕реЗрд╕рд░ рд╕рдлрд▓рддрд╛рдкреВрд░реНрд╡рдХ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдФрд░ рдбреЗрдЯрд╛ рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛ рд╣реИ, рддреЛ рдЖрдкрдХреЛ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЛ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рд╢рд╛рдорд┐рд▓ рдХрд░рдиреЗ рдФрд░ рдорд╛рдирдХ рдЕрдирд▓реЛрдбрд┐рдВрдЧ рдХреЗ рд╕рд╛рде рдЙрдирдХреА рддреБрд▓рдирд╛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдкрд░реАрдХреНрд╖рдг рдХрд┐рдП рдЧрдП рд╣реИрдВрдбрд▓рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ GET /imports/$import_id/citizens
, рдФрд░ рддреБрд▓рдирд╛ рдХреЗ рд▓рд┐рдП, рдПрдХ рдлрд╝рдВрдХреНрд╢рди compare_citizen_groups
редPATCH / рдЖрдпрд╛рдд / $ import_id / рдирд╛рдЧрд░рд┐рдХ / $ Cit_id
рдбреЗрдЯрд╛ рдХрд╛ рд╕рддреНрдпрд╛рдкрди рдХрдИ рдорд╛рдпрдиреЛрдВ рдореЗрдВ рд╕рдорд╛рди рд╣реИ рдЬреЛ рдХрд┐ POST /imports
рдХреБрдЫ рдЕрдкрд╡рд╛рджреЛрдВ рдХреЗ рд╕рд╛рде рд╣реИрдВрдбрд▓рд░ рдореЗрдВ рд╡рд░реНрдгрд┐рдд рд╣реИ: рдХреЗрд╡рд▓ рдПрдХ рдирд┐рд╡рд╛рд╕реА рд╣реИ рдФрд░ рдЧреНрд░рд╛рд╣рдХ рдХреЗрд╡рд▓ рдЙрди рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЛ рдкрд╛рд░рд┐рдд рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдЬреЛ рд╡рд╣ рдЪрд╛рд╣рддрд╛ рд╣реИ редрдореИрдВрдиреЗ рдпрд╣ рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЧрд▓рдд рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕реЗрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛ рдХрд┐ рд╣реИрдВрдбрд▓рд░ рдПрдХ HTTP рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд▓реМрдЯрд╛рдПрдЧрд╛ 400: Bad request
:- рдлрд╝реАрд▓реНрдб рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╣реИ, рд▓реЗрдХрд┐рди рдПрдХ рдЧрд▓рдд рдбреЗрдЯрд╛ рдкреНрд░рдХрд╛рд░ рдФрд░ / рдпрд╛ рдкреНрд░рд╛рд░реВрдк рд╣реИ
- рдЬрдиреНрдо рдХреА рддрд╛рд░реАрдЦ рдЧрд▓рдд рд╣реИ (рднрд╡рд┐рд╖реНрдп рдХрд╛ рд╕рдордп)ред
- рдлрд╝реАрд▓реНрдб
relatives
рдореЗрдВ рдПрдХ рд░рд┐рд╢реНрддреЗрджрд╛рд░ рд╣реЛрддрд╛ рд╣реИ рдЬреЛ рдЙрддрд░рд╛рдИ рдореЗрдВ рдореМрдЬреВрдж рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред
рдпрд╣ рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░рдирд╛ рднреА рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдХрд┐ рд╣реИрдВрдбрд▓рд░ рдирд┐рд╡рд╛рд╕реА рдФрд░ рдЙрд╕рдХреЗ рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдХреЛ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдЕрдкрдбреЗрдЯ рдХрд░рддрд╛ рд╣реИредрдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рддреАрди рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рдЕрдкрд▓реЛрдб рдмрдирд╛рдПрдВ, рдЬрд┐рдирдореЗрдВ рд╕реЗ рджреЛ рд░рд┐рд╢реНрддреЗрджрд╛рд░ рд╣реИрдВ, рдФрд░ рд╕рднреА рд╕реНрдХреЗрд▓рд░ рдлрд╝реАрд▓реНрдб рдХреЗ рд▓рд┐рдП рдирдП рдорд╛рди рдФрд░ рдлрд╝реАрд▓реНрдб рдореЗрдВ рдПрдХ рдирдП рд░рд┐рд╢реНрддреЗрджрд╛рд░ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рдХреЗ рд╕рд╛рде рдПрдХ рдЕрдиреБрд░реЛрдз рднреЗрдЬреЗрдВ relatives
редрдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдкрд░реАрдХреНрд╖рдг рд╕реЗ рдкрд╣рд▓реЗ рд╣реИрдВрдбрд▓рд░ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдЕрдирд▓реЛрдбрд┐рдВрдЧ рдХреЗ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рдмреАрдЪ рдЕрдВрддрд░ рдХрд░рддрд╛ рд╣реИ (рдФрд░, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХ рд╣реА рдЕрдирд▓реЛрдбрд┐рдВрдЧ рд╕реЗ рдПрдХ рд╣реА рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рд╡рд╛рд▓реЗ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЛ рдирд╣реАрдВ рдмрджрд▓рддрд╛ рд╣реИ), рдореИрдВрдиреЗ рддреАрди рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд рдЕрдирд▓реЛрдбрд┐рдВрдЧ рдмрдирд╛рдИ, рдЬрд┐рдирдХреЗ рдкрд╛рд╕ рд╕рдорд╛рди рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рд╣реИрдВредрд╣реИрдВрдбрд▓рд░ рдХреЛ рд╕реНрдХреЗрд▓рд░ рдлрд╝реАрд▓реНрдб рдХреЗ рдирдП рдореВрд▓реНрдпреЛрдВ рдХреЛ рд╕рд╣реЗрдЬрдирд╛ рд╣реЛрдЧрд╛, рдПрдХ рдирдпрд╛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд░рд┐рд╢реНрддреЗрджрд╛рд░ рдЬреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛ рдФрд░ рдПрдХ рдкреБрд░рд╛рдиреЗ рдХреЗ рд╕рд╛рде рд╕рдВрдмрдВрдз рдХреЛ рджреВрд░ рдХрд░рдирд╛ рд╣реЛрдЧрд╛, рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╕рд╛рдкреЗрдХреНрд╖ рдирд╣реАрдВред рд░рд┐рд╢реНрддреЗрджрд╛рд░реА рдореЗрдВ рд╕рднреА рдкрд░рд┐рд╡рд░реНрддрди рджреНрд╡рд┐рдкрдХреНрд╖реАрдп рд╣реЛрдиреЗ рдЪрд╛рд╣рд┐рдПред рдЕрдиреНрдп рдЕрдирд▓реЛрдбрд┐рдВрдЧ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПредрдЪреВрдВрдХрд┐ рдРрд╕рд╛ рд╣реИрдВрдбрд▓рд░ рджреМрдбрд╝ рдХреА рд╕реНрдерд┐рддрд┐ рдХреЗ рдЕрдзреАрди рд╣реЛ рд╕рдХрддрд╛ рд╣реИ (рдпрд╣ рд╡рд┐рдХрд╛рд╕ рдЦрдВрдб рдореЗрдВ рдЪрд░реНрдЪрд╛ рдХреА рдЧрдИ рдереА), рдореИрдВрдиреЗ рджреЛ рдЕрддрд┐рд░рд┐рдХреНрдд рдкрд░реАрдХреНрд╖рдг рдЬреЛрдбрд╝реЗ ред рдПрдХ рд░реЗрд╕ рд░рд╛рдЬреНрдп рдХреЗ рд╕рд╛рде рд╕рдорд╕реНрдпрд╛ рдХреЛ рдкреБрди: рдкреЗрд╢ рдХрд░рддрд╛ рд╣реИ (рд╣реИрдВрдбрд▓рд░ рдХреНрд▓рд╛рд╕ рдХреЛ рдирд┐рдХрд╛рд▓рддрд╛ рд╣реИ рдФрд░ рд▓реЙрдХ рдХреЛ рд╣рдЯрд╛рддрд╛ рд╣реИ), рджреВрд╕рд░рд╛ рдпрд╣ рд╕рд╛рдмрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рд░реЗрд╕ рд╕реНрдЯреЗрдЯ рдХреЗ рд╕рд╛рде рд╕рдорд╕реНрдпрд╛ рдХрд╛ рдкреБрди: рдкреНрд░рдЬрдирди рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИредGET / рдЖрдпрд╛рдд / $ import_id / рдирд╛рдЧрд░рд┐рдХ / рдЬрдиреНрдорджрд┐рди
рдЗрд╕ рд╣реИрдВрдбрд▓рд░ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдбреЗрдЯрд╛рд╕реЗрдЯ рдХрд╛ рдЪрдпрди рдХрд┐рдпрд╛:- рдПрдХ рдЙрддрд░рд╛рдИ рдЬрд┐рд╕рдореЗрдВ рдПрдХ рдирд┐рд╡рд╛рд╕реА рдПрдХ рдорд╣реАрдиреЗ рдореЗрдВ рдПрдХ рд░рд┐рд╢реНрддреЗрджрд╛рд░ рдФрд░ рджреВрд╕рд░реЗ рдореЗрдВ рджреЛ рд░рд┐рд╢реНрддреЗрджрд╛рд░ рд╣реЛрддреЗ рд╣реИрдВред
- рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреЗ рдмрд┐рдирд╛ рдПрдХ рдирд┐рд╡рд╛рд╕реА рдХреЗ рд╕рд╛рде рдЙрддрд╛рд░рдирд╛ред рдЬрд╛рдБрдЪ рдХрд░рддрд╛ рд╣реИ рдХрд┐ рд╣реИрдВрдбрд▓рд░ рдЧрдгрдирд╛ рдореЗрдВ рдЗрд╕реЗ рдзреНрдпрд╛рди рдореЗрдВ рдирд╣реАрдВ рд░рдЦрддрд╛ рд╣реИред
- рдЦрд╛рд▓реА рдЙрддрд╛рд░рдирд╛ред рдЬрд╛рдБрдЪ рдХрд░рддрд╛ рд╣реИ рдХрд┐ рд╣реИрдВрдбрд▓рд░ рд╡рд┐рдлрд▓ рдирд╣реАрдВ рд╣реЛрдЧрд╛ рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдореЗрдВ 12 рдорд╣реАрдиреЛрдВ рдХреЗ рд╕рд╛рде рд╕рд╣реА рд╢рдмреНрджрдХреЛрд╢ рд▓реМрдЯрд╛рдПрдЧрд╛ред
- рдПрдХ рдирд┐рд╡рд╛рд╕реА рдХреЗ рд╕рд╛рде рдЙрддрд╛рд░рдирд╛ рдЬреЛ рд╕реНрд╡рдпрдВ рдХрд╛ рд░рд┐рд╢реНрддреЗрджрд╛рд░ рд╣реИред рдЬрд╛рдБрдЪ рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдПрдХ рдирд┐рд╡рд╛рд╕реА рдЕрдкрдиреЗ рдЬрдиреНрдо рдХреЗ рдорд╣реАрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЙрдкрд╣рд╛рд░ рдЦрд░реАрджреЗрдЧрд╛ред
рд╣реИрдВрдбрд▓рд░ рдХреЛ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рд╕рднреА рдорд╣реАрдиреЗ рд╡рд╛рдкрд╕ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП, рднрд▓реЗ рд╣реА рдЗрди рдорд╣реАрдиреЛрдВ рдореЗрдВ рдХреЛрдИ рдЬрдиреНрдорджрд┐рди рди рд╣реЛред рджреЛрд╣рд░рд╛рд╡ рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдмрдирд╛рдпрд╛ рдЬрд┐рд╕рдореЗрдВ рдЖрдк рд╢рдмреНрджрдХреЛрд╢ рдХреЛ рдкрд╛рд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рддрд╛рдХрд┐ рдпрд╣ рд▓рд╛рдкрддрд╛ рдорд╣реАрдиреЛрдВ рдХреЗ рдореВрд▓реНрдпреЛрдВ рдХреЗ рд╕рд╛рде рдкреВрд░рдХ рд╣реЛредрдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рд╣реИрдВрдбрд▓рд░ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдЕрдирд▓реЛрдбрд┐рдВрдЧ рдХреЗ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рдмреАрдЪ рдЕрдВрддрд░ рдХрд░рддрд╛ рд╣реИ, рдореИрдВрдиреЗ рджреЛ рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд рдЕрдирд▓реЛрдбрд┐рдВрдЧ рдЬреЛрдбрд╝рд╛ред рдпрджрд┐ рд╣реИрдВрдбрд▓рд░ рдЧрд▓рддреА рд╕реЗ рдЧрдгрдирд╛ рдореЗрдВ рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ, рддреЛ рдкрд░рд┐рдгрд╛рдо рдЧрд▓рдд рд╣реЛрдВрдЧреЗ рдФрд░ рд╣реИрдВрдбрд▓рд░ рдПрдХ рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде рдЧрд┐рд░ рдЬрд╛рдПрдЧрд╛редGET / рдЖрдпрд╛рдд / $ import_id / рдХрд╕реНрдмреЛрдВ / рд╕реНрдЯреЗрдЯ / рдкреНрд░рддрд┐рд╢рдд / рдЖрдпреБ
рдЗрд╕ рдкрд░реАрдХреНрд╖рдг рдХреА рдЦрд╝рд╛рд╕рд┐рдпрдд рдпрд╣ рд╣реИ рдХрд┐ рдЗрд╕рдХреЗ рдХрд╛рдо рдХреЗ рдкрд░рд┐рдгрд╛рдо рд╡рд░реНрддрдорд╛рди рд╕рдордп рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддреЗ рд╣реИрдВ: рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреА рдЖрдпреБ рдХреА рдЧрдгрдирд╛ рд╡рд░реНрддрдорд╛рди рддрд┐рдерд┐ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдХреА рдЬрд╛рддреА рд╣реИред рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдкрд░реАрдХреНрд╖рд╛ рдкрд░рд┐рдгрд╛рдо рд╕рдордп рдХреЗ рд╕рд╛рде рдирд╣реАрдВ рдмрджрд▓рддреЗ рд╣реИрдВ, рд╡рд░реНрддрдорд╛рди рддрд┐рдерд┐, рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рдЬрдиреНрдо рдХреА рддрд╛рд░реАрдЦ рдФрд░ рдЕрдкреЗрдХреНрд╖рд┐рдд рдкрд░рд┐рдгрд╛рдо рджрд░реНрдЬ рдХрд┐рдП рдЬрд╛рдиреЗ рдЪрд╛рд╣рд┐рдПред рдЗрд╕рд╕реЗ рдХрд┐рд╕реА рднреА, рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдХрд┐рдирд╛рд░реЗ рдХреЗ рдорд╛рдорд▓реЛрдВ рдХреЛ рдкреБрди: рдкреЗрд╢ рдХрд░рдирд╛ рдЖрд╕рд╛рди рд╣реЛ рдЬрд╛рдПрдЧрд╛редрд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рдлрд┐рдХреНрд╕ рдбреЗрдЯ рдХреНрдпрд╛ рд╣реИ? рд╣реИрдВрдбрд▓рд░ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреА рдЖрдпреБ рдХреА рдЧрдгрдирд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП PostgreSQL рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ AGE
, рдЬреЛ рдкрд╣рд▓реЗ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЛ рдЙрд╕ рддрд╛рд░реАрдЦ рдХреЗ рд░реВрдк рдореЗрдВ рд▓реЗрддрд╛ рд╣реИ рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рдЖрдпреБ рдХреА рдЧрдгрдирд╛ рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдФрд░ рджреВрд╕рд░рд╛ рдЖрдзрд╛рд░ рддрд┐рдерд┐ (рдПрдХ рдирд┐рд░рдВрддрд░ рджреНрд╡рд╛рд░рд╛ рдкрд░рд┐рднрд╛рд╖рд┐рдд TownAgeStatView.CURRENT_DATE
) рдХреЗ рд░реВрдк рдореЗрдВ рд╣реИредрд╣рдо рдкрд░реАрдХреНрд╖рдг рд╕рдордп рдХреЗ рд╕рд╛рде рд╣реИрдВрдбрд▓рд░ рдореЗрдВ рдЖрдзрд╛рд░ рддрд┐рдерд┐ рдХреЛ рдмрджрд▓рддреЗ рд╣реИрдВfrom unittest.mock import patch
import pytz
CURRENT_DATE = datetime(2020, 2, 17, tzinfo=pytz.utc)
@patch('analyzer.api.handlers.TownAgeStatView.CURRENT_DATE', new=CURRENT_DATE)
async def test_get_ages(...):
...
рд╣реИрдВрдбрд▓рд░ рдХреЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдбреЗрдЯрд╛ рд╕реЗрдЯреЛрдВ рдХрд╛ рдЪрдпрди рдХрд┐рдпрд╛ (рд╕рднреА рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдореИрдВрдиреЗ рдПрдХ рд╢рд╣рд░ рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд┐рдпрд╛, рдХреНрдпреЛрдВрдХрд┐ рд╣реИрдВрдбрд▓рд░ рд╢рд╣рд░ рдХреЗ рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреЛ рдПрдХрддреНрд░ рдХрд░рддрд╛ рд╣реИ:- рдХрдИ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдЙрддрд╛рд░рдирд╛ рдЬрд┐рдирдХрд╛ рдЬрдиреНрдорджрд┐рди рдХрд▓ рд╣реИ (рдЙрдореНрд░ - рдХрдИ рд╕рд╛рд▓ рдФрд░ 364 рджрд┐рди)ред рдЬрд╛рдБрдЪрддрд╛ рд╣реИ рдХрд┐ рдкреНрд░реЛрд╕реЗрд╕рд░ рдЧрдгрдирд╛ рдореЗрдВ рдкреВрд░реЗ рд╡рд░реНрд╖ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред
- рдПрдХ рдирд┐рд╡рд╛рд╕реА рдХреЗ рд╕рд╛рде рдЙрддрд╛рд░рдирд╛ рдЬрд┐рд╕рдХрд╛ рдЬрдиреНрдорджрд┐рди рдЖрдЬ рд╣реИ (рдЙрдореНрд░ - рдареАрдХ рдХреБрдЫ рд╕рд╛рд▓)ред рдпрд╣ рдХреНрд╖реЗрддреНрд░реАрдп рдорд╛рдорд▓реЗ рдХреА рдЬрд╛рдВрдЪ рдХрд░рддрд╛ рд╣реИ - рдПрдХ рдирд┐рд╡рд╛рд╕реА рдХреА рдЙрдореНрд░ рдЬрд┐рд╕рдХрд╛ рдЖрдЬ рдЬрдиреНрдорджрд┐рди рд╣реИ, рдЙрд╕рдХреА рдЧрдгрдирд╛ 1 рд╡рд░реНрд╖ рд╕реЗ рдХрдо рдирд╣реАрдВ рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдПред
- рдЦрд╛рд▓реА рдЙрддрд╛рд░рдирд╛ред рд╣реИрдВрдбрд▓рд░ рдЙрд╕ рдкрд░ рдирд╣реАрдВ рдЧрд┐рд░рдирд╛ рдЪрд╛рд╣рд┐рдПред
рдкреНрд░рддрд┐рд╢рддрдХ рдХреА рдЧрдгрдирд╛ рдХреЗ рд▓рд┐рдП numpy
рдмреЗрдВрдЪрдорд╛рд░реНрдХ - рд░реИрдЦрд┐рдХ рдкреНрд░рдХреНрд╖реЗрдк рдХреЗ рд╕рд╛рде, рдФрд░ рдЙрдирдХреЗ рд▓рд┐рдП рдЧрдгрдирд╛ рдХреА рдЧрдИ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдкрд░рд┐рдгрд╛рдоредрдЖрдкрдХреЛ рднрд┐рдиреНрди рджрд╢рдорд▓рд╡ рдорд╛рдиреЛрдВ рдХреЛ рджреЛ рджрд╢рдорд▓рд╡ рд╕реНрдерд╛рдиреЛрдВ рдкрд░ рднреА рдЧреЛрд▓ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдпрджрд┐ рдЖрдкрдиреЗ рд╣реИрдВрдбрд▓рд░ рдореЗрдВ рд░рд╛рдЙрдВрдбрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП PostgreSQL рдФрд░ рд░реЗрдлрд░реЗрдВрд╕ рдбреЗрдЯрд╛ рдХреА рдЧрдгрдирд╛ рдХреЗ рд▓рд┐рдП Python рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рд╣реИ, рддреЛ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ Python 3 рдФрд░ PostgreSQL рдореЗрдВ рд░рд╛рдЙрдВрдбрд┐рдВрдЧ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдкрд░рд┐рдгрд╛рдо рджреЗ рд╕рдХрддреЗ рд╣реИрдВ редрдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП# Python 3
round(2.5)
> 2
-- PostgreSQL
SELECT ROUND(2.5)
> 3
рддрдереНрдп рдпрд╣ рд╣реИ рдХрд┐ рдкрд╛рдпрдерди рдмреИрдВрдХ рдХреЗ рд╕рдореАрдк рдХреЗ рд╣рд┐рд╕реНрд╕реЗ рдХрд╛ рднреА рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ , рдФрд░ рдкреЛрд╕реНрдЯрдЧреНрд░реЗрдХреНрд╕реЗрд▓ рдЧрдгрд┐рддреАрдп (рдЕрд░реНрдз-рдЕрдк) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ ред рдпрджрд┐ рдкреЛрд╕реНрдЯрдЧреНрд░реЗрд╕реАрдХреНрдпреВ рдореЗрдВ рдЧрдгрдирд╛ рдФрд░ рд░рд╛рдЙрдВрдбрд┐рдВрдЧ рдХреА рдЬрд╛рддреА рд╣реИ, рддреЛ рдкрд░реАрдХреНрд╖рдг рдореЗрдВ рднреА рдЧрдгрд┐рддреАрдп рдЧреЛрд▓рд╛рдИ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╕рд╣реА рд╣реЛрдЧрд╛редрд╕рдмрд╕реЗ рдкрд╣рд▓реЗ рдореИрдВрдиреЗ рдПрдХ рдкрд╛рда рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдЬрдиреНрдо рдХреА рддрд╛рд░реАрдЦреЛрдВ рдХреЗ рд╕рд╛рде рдбреЗрдЯрд╛ рд╕реЗрдЯ рдХрд╛ рд╡рд░реНрдгрди рдХрд┐рдпрд╛ рдерд╛, рд▓реЗрдХрд┐рди рдЗрд╕ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдПрдХ рдкрд░реАрдХреНрд╖рдг рдХреЛ рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдерд╛: рд╣рд░ рдмрд╛рд░ рдореБрдЭреЗ рдпрд╣ рдпрд╛рдж рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдореЗрд░реЗ рджрд┐рдорд╛рдЧ рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рдирд┐рд╡рд╛рд╕реА рдХреА рдЙрдореНрд░ рдХреА рдЧрдгрдирд╛ рдХрд░рдирд╛ рдерд╛ рдХрд┐ рдПрдХ рд╡рд┐рд╢реЗрд╖ рдбреЗрдЯрд╛ рд╕реЗрдЯ рдХреНрдпрд╛ рдЬрд╛рдБрдЪ рд░рд╣рд╛ рдерд╛ред рдмреЗрд╢рдХ, рдЖрдк рдХреЛрдб рдореЗрдВ рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдореИрдВрдиреЗ рдереЛрдбрд╝рд╛ рдЖрдЧреЗ рдЬрд╛рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ рдФрд░ рдПрдХ рд╕рдорд╛рд░реЛрд╣ рд▓рд┐рдЦрд╛ рдЬреЛ age2date
рдЖрдкрдХреЛ рдЙрдореНрд░ рдХреЗ рд░реВрдк рдореЗрдВ рдЬрдиреНрдо рдХреА рддрд╛рд░реАрдЦ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ: рд╡рд░реНрд╖реЛрдВ рдФрд░ рджрд┐рдиреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛редрдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЗрд╕ рддрд░рд╣import pytz
from analyzer.utils.testing import generate_citizen
CURRENT_DATE = datetime(2020, 2, 17, tzinfo=pytz.utc)
def age2date(years: int, days: int = 0, base_date=CURRENT_DATE) -> str:
birth_date = copy(base_date).replace(year=base_date.year - years)
birth_date -= timedelta(days=days)
return birth_date.strftime(BIRTH_DATE_FORMAT)
generate_citizen(birth_date='17.02.2009')
generate_citizen(birth_date=age2date(years=11))
рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рд╣реИрдВрдбрд▓рд░ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдЕрдирд▓реЛрдбрд┐рдВрдЧ рдХреЗ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рдмреАрдЪ рдЕрдВрддрд░ рдХрд░рддрд╛ рд╣реИ, рдореИрдВрдиреЗ рджреВрд╕рд░реЗ рд╢рд╣рд░ рдХреЗ рдПрдХ рдирд┐рд╡рд╛рд╕реА рдХреЗ рд╕рд╛рде рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд рдЕрдирд▓реЛрдб рдЬреЛрдбрд╝рд╛: рдпрджрд┐ рд╣реИрдВрдбрд▓рд░ рдЧрд▓рддреА рд╕реЗ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ, рддреЛ рдкрд░рд┐рдгрд╛рдореЛрдВ рдореЗрдВ рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд рд╢рд╣рд░ рджрд┐рдЦрд╛рдИ рджреЗрдЧрд╛ рдФрд░ рдкрд░реАрдХреНрд╖рдг рдЯреВрдЯ рдЬрд╛рдПрдЧрд╛редрдПрдХ рджрд┐рд▓рдЪрд╕реНрдк рддрдереНрдп: рдЬрдм рдореИрдВрдиреЗ 29 рдлрд░рд╡рд░реА, 2020 рдХреЛ рдпрд╣ рдкрд░реАрдХреНрд╖рдг рд▓рд┐рдЦрд╛ рдерд╛, рддреЛ рдореИрдВрдиреЗ рдЕрдЪрд╛рдирдХ рдлрд╝реЗрдХрд░ рдореЗрдВ рдмрдЧ рдХреЗ рдХрд╛рд░рдг рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдЕрдирд▓реЛрдб рдХрд░рдирд╛ рдмрдВрдж рдХрд░ рджрд┐рдпрд╛ (2020 рдПрдХ рд▓реАрдк рдИрдпрд░ рд╣реИ, рдФрд░ рдЕрдиреНрдп рд╡рд░реНрд╖ рдЬреЛ рдлрд╝реЗрдХрд░ рдиреЗ рдЪреБрдиреЗ рдереЗ, рдЙрдирдореЗрдВ рд╣рдореЗрд╢рд╛ рд▓реАрдк рд╡рд░реНрд╖ рдирд╣реАрдВ рдереЗред 29 рдлрд░рд╡рд░реА рдХреЛ рдирд╣реАрдВ рдерд╛)ред рдпрд╛рдж рд░рдЦреЗрдВ рдХрд┐ рддрд╛рд░реАрдЦреЗрдВ рд░рд┐рдХреЙрд░реНрдб рдХрд░реЗрдВ рдФрд░ рдХрд┐рдирд╛рд░реЗ рдХреЗ рдорд╛рдорд▓реЛрдВ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░реЗрдВ!
рдорд╛рдЗрдЧреНрд░реЗрд╢рди
рдкрд╣рд▓реА рдирдЬрд╝рд░ рдореЗрдВ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдХреЛрдб рд╕реНрдкрд╖реНрдЯ рдФрд░ рдХрдо рд╕реЗ рдХрдо рддреНрд░реБрдЯрд┐ рд╡рд╛рд▓рд╛ рд▓рдЧрддрд╛ рд╣реИ, рдЗрд╕рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХреНрдпреЛрдВ рдХрд░реЗрдВ? рдпрд╣ рдПрдХ рдмрд╣реБрдд рд╣реА рдЦрддрд░рдирд╛рдХ рддреНрд░реБрдЯрд┐ рд╣реИ: рдкрд▓рд╛рдпрди рдХреА рд╕рдмрд╕реЗ рдХрдкрдЯрдкреВрд░реНрдг рдЧрд▓рддрд┐рдпрд╛рдБ рд╕рдмрд╕реЗ рдЕрд╕рдВрдЧрдд рдХреНрд╖рдг рдореЗрдВ рдЦреБрдж рдХреЛ рдкреНрд░рдХрдЯ рдХрд░ рд╕рдХрддреА рд╣реИрдВред рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдЕрдЧрд░ рд╡реЗ рдбреЗрдЯрд╛ рдХреЛ рдЦрд░рд╛рдм рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╡реЗ рдЕрдирд╛рд╡рд╢реНрдпрдХ рдбрд╛рдЙрдирдЯрд╛рдЗрдо рдХрд╛ рдХрд╛рд░рдг рдмрди рд╕рдХрддреЗ рд╣реИрдВредрдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ рдореМрдЬреВрдж рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдбреЗрдЯрд╛рдмреЗрд╕ рдХреА рд╕рдВрд░рдЪрдирд╛ рдХреЛ рдмрджрд▓ рджреЗрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдбреЗрдЯрд╛ рдХреЛ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рдЗрд╕ рддрд░рд╣ рдХреЗ рдкрд▓рд╛рдпрди рд╕реЗ рдХрд┐рди рд╕рд╛рдорд╛рдиреНрдп рдЧрд▓рддрд┐рдпреЛрдВ рдХреЛ рдмрдЪрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ?downgrade
( , , ).
, (--): , тАФ .
- C .
- ( ).
рдЗрдирдореЗрдВ рд╕реЗ рдЕрдзрд┐рдХрд╛рдВрд╢ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХрд╛ рдкрддрд╛ рд╕реАрдврд╝реА рдкрд░реАрдХреНрд╖рдг рджреНрд╡рд╛рд░рд╛ рд▓рдЧрд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ ред рдЙрдирдХрд╛ рд╡рд┐рдЪрд╛рд░ - рдПрдХ рдПрдХрд▓ рдкреНрд░рд╡рд╛рд╕ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд▓рдЧрд╛рддрд╛рд░ рддрд░реАрдХреЛрдВ рдкреНрд░рджрд░реНрд╢рди upgrade
, downgrade
, upgrade
рдкреНрд░рддреНрдпреЗрдХ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдХреЗ рд▓рд┐рдПред рдЗрд╕ рддрд░рд╣ рдХреА рдкрд░реАрдХреНрд╖рд╛ рдПрдХ рдмрд╛рд░ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рд╢рд╛рдорд┐рд▓ рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реИ, рдЗрд╕реЗ рд╕рдорд░реНрдерди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ рдФрд░ рдИрдорд╛рдирджрд╛рд░реА рд╕реЗ рдХрд╛рдо рдХрд░реЗрдВрдЧреЗредрд▓реЗрдХрд┐рди рдЕрдЧрд░ рдкреНрд░рд╡рд╛рд╕рди, рд╕рдВрд░рдЪрдирд╛ рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдбреЗрдЯрд╛ рдХреЛ рдмрджрд▓ рджреЗрдЧрд╛, рддреЛ рдХрдо рд╕реЗ рдХрдо рдПрдХ рдЕрд▓рдЧ рдкрд░реАрдХреНрд╖рдг рд▓рд┐рдЦрдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реЛрдЧрд╛, рдпрд╣ рдЬрд╛рдБрдЪрддреЗ рд╣реБрдП рдХрд┐ рдбреЗрдЯрд╛ рд╕рд╣реА рддрд░реАрдХреЗ рд╕реЗ рдмрджрд▓рддрд╛ рд╣реИ upgrade
рдФрд░ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рд╕реНрдерд┐рддрд┐ рдореЗрдВ рд╡рд╛рдкрд╕ рдЖ рдЬрд╛рддрд╛ рд╣реИ downgrade
ред рдмрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ: рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рд╡рд╛рд╕рди рдХреЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рдкрд░рд┐рдпреЛрдЬрдирд╛ , рдЬрд┐рд╕реЗ рдореИрдВрдиреЗ рдореЙрд╕реНрдХреЛ рдкрд╛рдпрдерди рдореЗрдВ рдЕрд▓реЗрдореНрдмрд┐рдХ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдПрдХ рд░рд┐рдкреЛрд░реНрдЯ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рдХрд┐рдпрд╛ рдерд╛ редрд╕рднрд╛
рдЕрдВрддрд┐рдо рдХрд▓рд╛рдХреГрддрд┐ рдЬрд┐рд╕реЗ рд╣рдо рддреИрдирд╛рдд рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ рдФрд░ рдЬрд┐рд╕реЗ рд╣рдо рдЕрд╕реЗрдВрдмрд▓реА рдХреЗ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рд╡рд╣ рдбреЙрдХрдЯрд░ рдЫрд╡рд┐ рд╣реИред рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдкрд╛рдпрдерди рдХреЗ рд╕рд╛рде рдЖрдзрд╛рд░ рдЫрд╡рд┐ рдХрд╛ рдЪрдпрди рдХрд░рдирд╛ рд╣реЛрдЧрд╛ ред рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рдЫрд╡рд┐ рдХрд╛ python:latest
рд╡рдЬрди ~ 1 рдЬреАрдмреА рд╣реИ рдФрд░, рдпрджрд┐ рдЖрдзрд╛рд░ рдЫрд╡рд┐ рдХреЗ рд░реВрдк рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдЖрд╡реЗрджрди рдХреЗ рд╕рд╛рде рдЫрд╡рд┐ рдмрд╣реБрдд рдмрдбрд╝реА рд╣реЛрдЧреАред рдЕрд▓реНрдкрд╛рдЗрди рдУрдПрд╕ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рдЪрд┐рддреНрд░ рд╣реИрдВ , рдЬрд┐рдирдХрд╛ рдЖрдХрд╛рд░ рдмрд╣реБрдд рдЫреЛрдЯрд╛ рд╣реИред рд▓реЗрдХрд┐рди рд╕реНрдерд╛рдкрд┐рдд рдкреИрдХреЗрдЬреЛрдВ рдХреА рдмрдврд╝рддреА рд╕рдВрдЦреНрдпрд╛ рдХреЗ рд╕рд╛рде, рдЕрдВрддрд┐рдо рдЫрд╡рд┐ рдХрд╛ рдЖрдХрд╛рд░ рдмрдврд╝реЗрдЧрд╛, рдФрд░ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдЕрд▓реНрдкрд╛рдЗрди рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдПрдХрддреНрд░ рдХреА рдЧрдИ рдЫрд╡рд┐ рдЗрддрдиреА рдЫреЛрдЯреА рдирд╣реАрдВ рд╣реЛрдЧреАред рдореИрдВрдиреЗ рдмреЗрд╕ рдЗрдореЗрдЬ рдХреЗ рд░реВрдк рдореЗрдВ рд╕реНрдиреЗрдХрдкреИрдХрд░ / рдЕрдЬрдЧрд░ рдХреЛ рдЪреБрдирд╛ - рдЗрд╕рдХрд╛ рд╡рдЬрди рдЕрд▓реНрдкрд╛рдЗрди рдЪрд┐рддреНрд░реЛрдВ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдереЛрдбрд╝рд╛ рдЕрдзрд┐рдХ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдЙрдмрдВрдЯреВ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рд╣реИ, рдЬреЛ рдкреИрдХреЗрдЬ рдФрд░ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдПрдХ рд╡рд┐рд╢рд╛рд▓ рдЪрдпрди рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИредрджреВрд╕рд░рд╛ рд░рд╛рд╕реНрддрд╛рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд╕рд╛рде рдЫрд╡рд┐ рдХрд╛ рдЖрдХрд╛рд░ рдХрдо рдХрд░реЗрдВ - рдЕрдВрддрд┐рдо рдЫрд╡рд┐ рдореЗрдВ рдЕрд╕реЗрдВрдмрд▓реА рдХреЗ рд▓рд┐рдП рдХрдВрдкрд╛рдЗрд▓рд░, рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдФрд░ рд╣реЗрдбрд░ рдХреЗ рд╕рд╛рде рдлрд╛рдЗрд▓реЗрдВ рд╢рд╛рдорд┐рд▓ рдирд╣реАрдВ рд╣реИрдВ, рдЬреЛ рдХрд┐ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдирд╣реАрдВ рд╣реИрдВредрдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдк рдбреЙрдХрд░ рдХреЗ рдорд▓реНрдЯреА-рд╕реНрдЯреЗрдЬ рдЕрд╕реЗрдВрдмрд▓реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ :- рдПрдХ "рднрд╛рд░реА" рдЫрд╡рд┐
snakepacker/python:all
(~ 1 рдЬреАрдмреА, ~ 500 рдПрдордмреА рд╕рдВрдкреАрдбрд╝рд┐рдд) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рдПрдХ рдЖрднрд╛рд╕реА рд╡рд╛рддрд╛рд╡рд░рдг рдмрдирд╛рдПрдВ, рд╕рднреА рдирд┐рд░реНрднрд░рддрд╛рдПрдВ рдФрд░ рдЙрд╕ рдкрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдкреИрдХреЗрдЬ рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВред рдпрд╣ рдЫрд╡рд┐ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рд╡рд┐рдзрд╛рдирд╕рднрд╛ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИ, рдЗрд╕рдореЗрдВ рдПрдХ рд╕рдВрдХрд▓рдХ, рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдФрд░ рд╣реЗрдбрд░ рдХреЗ рд╕рд╛рде рдлрд╛рдЗрд▓реЗрдВ рд╣реЛ рд╕рдХрддреА рд╣реИрдВред
FROM snakepacker/python:all as builder
RUN python3.8 -m venv /usr/share/python3/app
COPY dist/ /mnt/dist/
RUN /usr/share/python3/app/bin/pip install /mnt/dist/*
- рд╣рдо рд╕рдорд╛рдкреНрдд рдЖрднрд╛рд╕реА рд╡рд╛рддрд╛рд╡рд░рдг рдХреЛ рдПрдХ "рдкреНрд░рдХрд╛рд╢" рдЫрд╡рд┐
snakepacker/python:3.8
(~ 100 рдПрдордмреА, рд╕рдВрдкреАрдбрд╝рд┐рдд ~ 50 рдПрдордмреА) рдореЗрдВ рдХреЙрдкреА рдХрд░рддреЗ рд╣реИрдВ , рдЬрд┐рд╕рдореЗрдВ рдХреЗрд╡рд▓ рдкрд╛рдпрдерди рдХреЗ рдЖрд╡рд╢реНрдпрдХ рд╕рдВрд╕реНрдХрд░рдг рдХрд╛ рджреБрднрд╛рд╖рд┐рдпрд╛ рд╣реЛрддрд╛ рд╣реИред
рдорд╣рддреНрд╡рдкреВрд░реНрдг: рдПрдХ рдЖрднрд╛рд╕реА рд╡рд╛рддрд╛рд╡рд░рдг рдореЗрдВ, рдирд┐рд░рдкреЗрдХреНрд╖ рдкрде рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЗрд╕реЗ рдЙрд╕реА рдкрддреЗ рдкрд░ рдХреЙрдкреА рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдЬрд┐рд╕ рдкрд░ рдпрд╣ рдХрд▓реЗрдХреНрдЯрд░ рдХрдВрдЯреЗрдирд░ рдореЗрдВ рдЗрдХрдЯреНрдард╛ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред
FROM snakepacker/python:3.8 as api
COPY --from=builder /usr/share/python3/app /usr/share/python3/app
RUN ln -snf /usr/share/python3/app/bin/analyzer-* /usr/local/bin/
CMD ["analyzer-api"]
рдЫрд╡рд┐ рдХреЗ рдирд┐рд░реНрдорд╛рдг рдореЗрдВ рд▓рдЧрдиреЗ рд╡рд╛рд▓реЗ рд╕рдордп
рдХреЛ рдХрдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП , рд╡рд░реНрдЪреБрдЕрд▓ рд╡рд╛рддрд╛рд╡рд░рдг рдореЗрдВ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдирд┐рд░реНрднрд░ рдореЙрдбреНрдпреВрд▓ рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдлрд┐рд░ рдбреЙрдХрдЯрд░ рдЙрдиреНрд╣реЗрдВ рдХреИрд╢ рдХрд░ рджреЗрдЧрд╛ рдФрд░ рдЕрдЧрд░ рд╡реЗ рдирд╣реАрдВ рдмрджрд▓реЗ рд╣реИрдВ рддреЛ рдЙрдиреНрд╣реЗрдВ рдлрд┐рд░ рд╕реЗ рд╕реНрдерд╛рдкрд┐рдд рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗредрдкреВрд░реА рддрд░рд╣ рд╕реЗ рдбреЙрдХрд░рдлрд╛рдЗрд▓
FROM snakepacker/python:all as builder
RUN python3.8 -m venv /usr/share/python3/app
RUN /usr/share/python3/app/bin/pip install -U pip
COPY requirements.txt /mnt/
RUN /usr/share/python3/app/bin/pip install -Ur /mnt/requirements.txt
COPY dist/ /mnt/dist/
RUN /usr/share/python3/app/bin/pip install /mnt/dist/* \
&& /usr/share/python3/app/bin/pip check
FROM snakepacker/python:3.8 as api
COPY --from=builder /usr/share/python3/app /usr/share/python3/app
RUN ln -snf /usr/share/python3/app/bin/analyzer-* /usr/local/bin/
CMD ["analyzer-api"]
рдЕрд╕реЗрдВрдмрд▓реА рдХреА рдЖрд╕рд╛рдиреА рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдПрдХ рдХрдорд╛рдВрдб рдЬреЛрдбрд╝рд╛ make upload
рдЬреЛ рдбреЙрдХрд░ рдЗрдореЗрдЬ рдХреЛ рдЗрдХрдЯреНрдард╛ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ hub.docker.com рдкрд░ рдЕрдкрд▓реЛрдб рдХрд░рддрд╛ рд╣реИредCi
рдЕрдм рдЬрдм рдХреЛрдб рдкрд░реАрдХреНрд╖рдгреЛрдВ рд╕реЗ рдЖрдЪреНрдЫрд╛рджрд┐рдд рд╣реИ рдФрд░ рд╣рдо рдПрдХ рдбреЙрдХрд░ рдЫрд╡рд┐ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ, рддреЛ рдЗрди рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдХрд░рдиреЗ рдХрд╛ рд╕рдордп рдЖ рдЧрдпрд╛ рд╣реИред рдкрд╣рд▓реА рдмрд╛рдд рдЬреЛ рдзреНрдпрд╛рди рдореЗрдВ рдЖрддреА рд╣реИ: рдкреВрд▓ рдЕрдиреБрд░реЛрдз рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реАрдХреНрд╖рдг рдЪрд▓рд╛рдПрдВ, рдФрд░ рдорд╛рд╕реНрдЯрд░ рд╢рд╛рдЦрд╛ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рдЬреЛрдбрд╝рддреЗ рд╕рдордп, рдПрдХ рдирдИ рдбреЙрдХрдЯрд░ рдЫрд╡рд┐ рдПрдХрддреНрд░ рдХрд░реЗрдВ рдФрд░ рдЗрд╕реЗ рдбреЙрдХрд░ рд╣рдм (рдпрд╛ рдЧрд┐рдЯрд╣рдм рдкреИрдХреЗрдЬ , рдпрджрд┐ рдЖрдк рдЫрд╡рд┐ рдХреЛ рд╕рд╛рд░реНрд╡рдЬрдирд┐рдХ рд░реВрдк рд╕реЗ рд╡рд┐рддрд░рд┐рдд рдирд╣реАрдВ рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ) рдкрд░ рдЕрдкрд▓реЛрдб рдХрд░реЗрдВ редрдореИрдВрдиреЗ рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ GitHub Actions рдХреЗ рд╕рд╛рде рд╣рд▓ рдХрд┐рдпрд╛ ред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдПрдХ рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рдПрдХ YAML рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдирд╛ .github/workflows
рдФрд░ рдЙрд╕рдореЗрдВ рдПрдХ рд╡рд░реНрдХрдлрд╝реНрд▓реЛ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рдерд╛ (рджреЛ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд╕рд╛рде: test
рдФрд░ publish
), рдЬрд┐рд╕реЗ рдореИрдВрдиреЗ рдирд╛рдо рджрд┐рдпрд╛ рдерд╛ CI
ред рд╕реЗрд╡рд╛рдУрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП рд╣рд░ рдмрд╛рд░ рд╡рд░реНрдХрдлрд╝реНрд▓реЛ рд╢реБрд░реВ рд╣реЛрдиреЗ рдкрд░рдХрд╛рд░реНрдп test
рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИCI
PostgreSQL рдХреЗ рд╕рд╛рде рдПрдХ рдХрдВрдЯреЗрдирд░ рдЙрдард╛рддрд╛ рд╣реИ, рдЗрд╕рдХреЗ рдЙрдкрд▓рдмреНрдз рд╣реЛрдиреЗ рдХрд╛ рдЗрдВрддрдЬрд╛рд░ рдХрд░рддрд╛ рд╣реИ, рдФрд░ pytest
рдХрдВрдЯреЗрдирд░ рдореЗрдВ рд▓реЙрдиреНрдЪ рдХрд░рддрд╛ рд╣реИ snakepacker/python:all
редрдпрджрд┐ рдХрд╛рд░реНрдп publish
рд╢рд╛рдЦрд╛ рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛ рд╣реИ master
рдФрд░ рдпрджрд┐ рдХрд╛рд░реНрдп test
рд╕рдлрд▓ рдерд╛ , рддреЛ рд╣реА рдХрд╛рд░реНрдп рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣ рдХрдВрдЯреЗрдирд░ рджреНрд╡рд╛рд░рд╛ рд╕реНрд░реЛрдд рд╡рд┐рддрд░рдг snakepacker/python:all
рдПрдХрддреНрд░ рдХрд░рддрд╛ рд╣реИ, рдлрд┐рд░ рдбреЙрдХрд░ рдЫрд╡рд┐ рдПрдХрддреНрд░ рдХрд░рддрд╛ рд╣реИ рдФрд░ рд▓реЛрдб рдХрд░рддрд╛ рд╣реИ docker/build-push-action@v1
редрд╡рд░реНрдХрдлрд╝реНрд▓реЛ рдХрд╛ рдкреВрд░реНрдг рд╡рд┐рд╡рд░рдгname: CI
# Workflow
# - master
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
# workflow
test:
runs-on: ubuntu-latest
services:
postgres:
image: docker://postgres
ports:
- 5432:5432
env:
POSTGRES_USER: user
POSTGRES_PASSWORD: hackme
POSTGRES_DB: analyzer
steps:
- uses: actions/checkout@v2
- name: test
uses: docker://snakepacker/python:all
env:
CI_ANALYZER_PG_URL: postgresql://user:hackme@postgres/analyzer
with:
args: /bin/bash -c "pip install -U '.[dev]' && pylama && wait-for-port postgres:5432 && pytest -vv --cov=analyzer --cov-report=term-missing tests"
# Docker-
publish:
# master
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
# , test
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: sdist
uses: docker://snakepacker/python:all
with:
args: make sdist
- name: build-push
uses: docker/build-push-action@v1
with:
username: ${{ secrets.REGISTRY_LOGIN }}
password: ${{ secrets.REGISTRY_TOKEN }}
repository: alvassin/backendschool2019
target: api
tags: 0.0.1, latest
рдЕрдм, GitHub рдкрд░ рдХреНрд░рд┐рдпрд╛рдПрдБ рдЯреИрдм рдореЗрдВ рдорд╛рд╕реНрдЯрд░ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рдЬреЛрдбрд╝рддреЗ рд╕рдордп, рдЖрдк рдкрд░реАрдХреНрд╖рдг рдХреА рд▓реЙрдиреНрдЪрд┐рдВрдЧ, рдбреЙрдХрдЯрд░ рдЫрд╡рд┐ рдХреА рдЕрд╕реЗрдВрдмрд▓реА рдФрд░ рд▓реЛрдбрд┐рдВрдЧ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ:
рдФрд░ рдорд╛рд╕реНрдЯрд░ рд╢рд╛рдЦрд╛ рдореЗрдВ рдПрдХ рдкреВрд▓ рдЕрдиреБрд░реЛрдз рдмрдирд╛рддреЗ рд╕рдордп, рдХрд╛рд░реНрдп рдХреЗ рдкрд░рд┐рдгрд╛рдо рднреА рдЗрд╕рдореЗрдВ рдкреНрд░рджрд░реНрд╢рд┐рдд рд╣реЛрдВрдЧреЗ test
:
рддреИрдирд╛рддреА
рдкреНрд░рджрд╛рди рдХрд┐рдП рдЧрдП рд╕рд░реНрд╡рд░ рдкрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рддреИрдирд╛рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдбреЙрдХрд░, рдбреЙрдХрд░ рдХрдореНрдкреЛрдЬ рдХреЛ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдФрд░ рдкреЛрд╕реНрдЯрдЧреНрд░реЗрдХреНрдпреВрдПрд▓ рдХреЗ рд╕рд╛рде рдХрдВрдЯреЗрдирд░ рд╢реБрд░реВ рдХрд░реЗрдВ рдФрд░ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рд▓рд╛рдЧреВ рдХрд░реЗрдВредрдЗрди рдЪрд░рдгреЛрдВ рдХреЛ Ansible рдХреЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдкреНрд░рдмрдВрдзрди рд╕рд┐рд╕реНрдЯрдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдпрд╣ рдкрд╛рдпрдерди рдореЗрдВ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рд╣реИ, рд╡рд┐рд╢реЗрд╖ рдПрдЬреЗрдВрдЯреЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ (рд╕реАрдзреЗ ssh рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЬреЛрдбрд╝рддрд╛ рд╣реИ), рдЬрд┐рдиреНрдЬрд╛ рдЯреЗрдореНрдкрд▓реЗрдЯреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ рдФрд░ YAML рдлрд╝рд╛рдЗрд▓реЛрдВ рдореЗрдВ рд╡рд╛рдВрдЫрд┐рдд рд░рд╛рдЬреНрдп рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдШреЛрд╖рдгрд╛рддреНрдордХ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдЖрдкрдХреЛ рд╕рд┐рд╕реНрдЯрдо рдХреА рд╡рд░реНрддрдорд╛рди рд╕реНрдерд┐рддрд┐ рдФрд░ рд╕рд┐рд╕реНрдЯрдо рдХреЛ рд╡рд╛рдВрдЫрд┐рдд рд╕реНрдерд┐рддрд┐ рдореЗрдВ рд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реЛрдЪрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рджреЗрддрд╛ рд╣реИред рдпрд╣ рд╕рднреА рдХрд╛рд░реНрдп рдЕрдиреНрд╕рд┐рдмрд▓ рдореЙрдбреНрдпреВрд▓ рдХреЗ рдХрдВрдзреЛрдВ рдкрд░ рдЯрд┐рдХреА рд╣реБрдИ рд╣реИредAnsible рдЖрдкрдХреЛ рддрд╛рд░реНрдХрд┐рдХ рд░реВрдк рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рднреВрдорд┐рдХрд╛рдУрдВ рдореЗрдВ рд╕рдореВрд╣рд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ рдФрд░ рдлрд┐рд░ рдЙрдирдХрд╛ рдкреБрди: рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред рд╣рдореЗрдВ рджреЛ рднреВрдорд┐рдХрд╛рдУрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА:docker
(рд╕реНрдерд╛рдкрд┐рдд рдХрд░рддрд╛ рд╣реИ рдФрд░ рдбреЙрдХрд░ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рддрд╛ рд╣реИ) рдФрд░ analyzer
(рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рддрд╛ рд╣реИ)редрднреВрдорд┐рдХрд╛docker
рдбреЙрдХрдЯрд░ рдХреЗ рд╕рд╛рде рдПрдХ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреЛ рд╕рд┐рд╕реНрдЯрдо рдореЗрдВ рдЬреЛрдбрд╝рддреА рд╣реИ, рд╕рдВрдХреБрд▓ рдХреЛ рд╕реНрдерд╛рдкрд┐рдд рдФрд░ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рддреА рд╣реИ docker-ce
рдФрд░ docker-compose
редрд╡реИрдХрд▓реНрдкрд┐рдХ рд░реВрдк рд╕реЗ, рдЖрдк рд╕рд░реНрд╡рд░ рд░рд┐рдмреВрдЯ рдХреЗ рдмрд╛рдж рдлрд┐рд░ рд╕реЗ рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП REST API рд╕реЗрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЙрдмрдВрдЯреВ рдЖрдкрдХреЛ рдПрдХ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝реЗрд╢рди рд╕рд┐рд╕реНрдЯрдо рдХреА рдорджрдж рд╕реЗ рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ systemd
ред рдпрд╣ рд╡рд┐рднрд┐рдиреНрди рд╕рдВрд╕рд╛рдзрдиреЛрдВ (рдбреЗрдореЙрди, рд╕реЙрдХреЗрдЯреНрд╕, рдорд╛рдЙрдВрдЯ рдкреЙрдЗрдВрдЯ рдФрд░ рдЕрдиреНрдп) рдХрд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХрд░рдиреЗ рд╡рд╛рд▓реА рдЗрдХрд╛рдЗрдпреЛрдВ рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рддрд╛ рд╣реИред Systemd рдореЗрдВ рдПрдХ рдирдИ рдЗрдХрд╛рдИ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдПрдХ рдЕрд▓рдЧ .service рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдЗрд╕рдХреЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдирд╛ рд╣реЛрдЧрд╛ рдФрд░ рдЗрд╕ рдлрд╝рд╛рдЗрд▓ рдХреЛ рд╡рд┐рд╢реЗрд╖ рдлрд╝реЛрд▓реНрдбрд░реЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдореЗрдВ рд░рдЦрдирд╛ рдЪрд╛рд╣рд┐рдП, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдореЗрдВ /etc/systemd/system
ред рдлрд┐рд░ рдпреВрдирд┐рдЯ рдХреЛ рд▓реЙрдиреНрдЪ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рд╕рд╛рде рд╣реА рдЗрд╕рдХреЗ рд▓рд┐рдП рдСрдЯреЛрд▓реЙрдб рдХреЛ рд╕рдХреНрд╖рдо рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИредрдкреИрдХреЗрдЬdocker-ce
рд╕реНрдерд╛рдкрдирд╛ рдХреЗ рджреМрд░рд╛рди, рдпрд╣ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдпреВрдирд┐рдЯ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЗ рд╕рд╛рде рдПрдХ рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдЧрд╛ - рдЖрдкрдХреЛ рдХреЗрд╡рд▓ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдЪрд▓ рд░рд╣рд╛ рд╣реИ рдФрд░ рд╕рд┐рд╕реНрдЯрдо рд╢реБрд░реВ рд╣реЛрдиреЗ рдкрд░ рдЪрд╛рд▓реВ рд╣реЛрддрд╛ рд╣реИред рдбреЙрдХрд░ рдХрдореНрдкреЛрдЬ рдХреЗ рд▓рд┐рдП docker-compose@.service
Ansible рджреНрд╡рд╛рд░рд╛ рдмрдирд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред @
рдирд╛рдо рдореЗрдВ рдкреНрд░рддреАрдХ рдкреНрд░рдгрд╛рд▓реА рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдЗрдХрд╛рдИ рдПрдХ рдЯреЗрдореНрдкрд▓реЗрдЯ рд╣реИред рдпрд╣ рдЖрдкрдХреЛ docker-compose
рдПрдХ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд╕рд╛рде рд╕реЗрд╡рд╛ рд╢реБрд░реВ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ - рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╣рдорд╛рд░реА рд╕реЗрд╡рд╛ рдХреЗ рдирд╛рдо рдХреЗ рд╕рд╛рде, рдЬрд┐рд╕реЗ %i
рдпреВрдирд┐рдЯ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓ рдХреЗ рдмрдЬрд╛рдп рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ :[Unit]
Description=%i service with docker compose
Requires=docker.service
After=docker.service
[Service]
Type=oneshot
RemainAfterExit=true
WorkingDirectory=/etc/docker/compose/%i
ExecStart=/usr/local/bin/docker-compose up -d --remove-orphans
ExecStop=/usr/local/bin/docker-compose down
[Install]
WantedBy=multi-user.target
рднреВрдорд┐рдХрд╛analyzer
docker-compose.yml
рдкрддреЗ рдкрд░ рдЯреЗрдореНрдкрд▓реЗрдЯ рд╕реЗ рдПрдХ рдлрд╝рд╛рдЗрд▓ рдЙрддреНрдкрдиреНрди рдХрд░реЗрдЧреА/etc/docker/compose/analyzer
, рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рд▓реЙрдиреНрдЪ рдХреА рдЧрдИ рд╕реЗрд╡рд╛ рдХреЗ рд░реВрдк рдореЗрдВ рдкрдВрдЬреАрдХреГрдд рдХрд░реЗрдВ systemd
рдФрд░ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рд▓рд╛рдЧреВ рдХрд░реЗрдВред рдЬрдм рднреВрдорд┐рдХрд╛рдПрдВ рддреИрдпрд╛рд░ рд╣реЛ рдЬрд╛рддреА рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ рдкреНрд▓реЗрдмреБрдХ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред---
- name: Gathering facts
hosts: all
become: yes
gather_facts: yes
- name: Install docker
hosts: docker
become: yes
gather_facts: no
roles:
- docker
- name: Install analyzer
hosts: api
become: yes
gather_facts: no
roles:
- analyzer
рдореЗрдЬрдмрд╛рдиреЛрдВ рдХреА рд╕реВрдЪреА, рд╕рд╛рде рд╣реА рднреВрдорд┐рдХрд╛рдУрдВ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдЪрд░, рд╕реВрдЪреА рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд┐рдП рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВ hosts.ini
ред[api]
130.193.51.154
[docker:children]
api
[api:vars]
analyzer_image = alvassin/backendschool2019
analyzer_pg_user = user
analyzer_pg_password = hackme
analyzer_pg_dbname = analyzer
рд╕рднреА Ansible рдлрд╝рд╛рдЗрд▓реЗрдВ рддреИрдпрд╛рд░ рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж, рдЗрд╕реЗ рдЪрд▓рд╛рдПрдВ:$ ansible-playbook -i hosts.ini deploy.yml
рддрдирд╛рд╡ рдкрд░реАрдХреНрд╖рдг рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ, , . , -
. : , тАФ , 10 . , (, , CI-): .
, , , 10 . ? , , . , , .
RPS, : . , ,
import_id
,
POST /imports
. .
, Python 3,
Locust.
,
locustfile.py
locust
. - .
Locust . , .
self.round
.
locustfile.py
import logging
from http import HTTPStatus
from locust import HttpLocust, constant, task, TaskSet
from locust.exception import RescheduleTask
from analyzer.api.handlers import (
CitizenBirthdaysView, CitizensView, CitizenView, TownAgeStatView
)
from analyzer.utils.testing import generate_citizen, generate_citizens, url_for
class AnalyzerTaskSet(TaskSet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.round = 0
def make_dataset(self):
citizens = [
generate_citizen(citizen_id=1, relatives=[2]),
generate_citizen(citizen_id=2, relatives=[1]),
*generate_citizens(citizens_num=9998, relations_num=1000,
start_citizen_id=3)
]
return {citizen['citizen_id']: citizen for citizen in citizens}
def request(self, method, path, expected_status, **kwargs):
with self.client.request(
method, path, catch_response=True, **kwargs
) as resp:
if resp.status_code != expected_status:
resp.failure(f'expected status {expected_status}, '
f'got {resp.status_code}')
logging.info(
'round %r: %s %s, http status %d (expected %d), took %rs',
self.round, method, path, resp.status_code, expected_status,
resp.elapsed.total_seconds()
)
return resp
def create_import(self, dataset):
resp = self.request('POST', '/imports', HTTPStatus.CREATED,
json={'citizens': list(dataset.values())})
if resp.status_code != HTTPStatus.CREATED:
raise RescheduleTask
return resp.json()['data']['import_id']
def get_citizens(self, import_id):
url = url_for(CitizensView.URL_PATH, import_id=import_id)
self.request('GET', url, HTTPStatus.OK,
name='/imports/{import_id}/citizens')
def update_citizen(self, import_id):
url = url_for(CitizenView.URL_PATH, import_id=import_id, citizen_id=1)
self.request('PATCH', url, HTTPStatus.OK,
name='/imports/{import_id}/citizens/{citizen_id}',
json={'relatives': [i for i in range(3, 10)]})
def get_birthdays(self, import_id):
url = url_for(CitizenBirthdaysView.URL_PATH, import_id=import_id)
self.request('GET', url, HTTPStatus.OK,
name='/imports/{import_id}/citizens/birthdays')
def get_town_stats(self, import_id):
url = url_for(TownAgeStatView.URL_PATH, import_id=import_id)
self.request('GET', url, HTTPStatus.OK,
name='/imports/{import_id}/towns/stat/percentile/age')
@task
def workflow(self):
self.round += 1
dataset = self.make_dataset()
import_id = self.create_import(dataset)
self.get_citizens(import_id)
self.update_citizen(import_id)
self.get_birthdays(import_id)
self.get_town_stats(import_id)
class WebsiteUser(HttpLocust):
task_set = AnalyzerTaskSet
wait_time = constant(1)
100 c , , :

, ( тАФ 95 , тАФ ). .

тАФ Ansible ~20.15 ~20.30 Locust.

рдФрд░ рдХреНрдпрд╛ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ?
рдЖрд╡реЗрджрди рдХреЛ рдкреНрд░реЛрдлрд╛рдЗрд▓ рдХрд░рдиреЗ рд╕реЗ рдкрддрд╛ рдЪрд▓рд╛ рдХрд┐ JSON рдХреНрд░рдорд╛рдВрдХрди рдФрд░ рдбрд┐рд╕реЗрд░рд┐рдЕрд▓рд╛рдЗрдЬрд╝реЗрд╢рди рдкрд░ рдХреБрд▓ рдХреНрд╡реЗрд░реА рдирд┐рд╖реНрдкрд╛рджрди рд╕рдордп рдХрд╛ рд▓рдЧрднрдЧ рдПрдХ рдЪреМрдерд╛рдИ рдЦрд░реНрдЪ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ: рд╕реЗрд╡рд╛ рд╕реЗ рднреЗрдЬреЗ рдЧрдП рдФрд░ рдкреНрд░рд╛рдкреНрдд рдХрд┐рдП рдЧрдП рдмрд╣реБрдд рд╕рд╛рд░реЗ рдбреЗрдЯрд╛ рд╣реИрдВред рдСрд░реНрдЬрд╝реЛрди рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрди рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЛ рдХрд╛рдлреА рддреЗрдЬ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ , рд▓реЗрдХрд┐рди рд╕реЗрд╡рд╛ рдХреЛ рдереЛрдбрд╝рд╛ рддреИрдпрд╛рд░ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ - orjson
рдпрд╣ рдорд╛рдирдХ рдореЙрдбреНрдпреВрд▓ рдХреЗ рд▓рд┐рдП рдбреНрд░реЙрдк-рдЗрди рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрди рдирд╣реАрдВ рд╣реИ json
рдЖрдорддреМрд░ рдкрд░, рдЙрддреНрдкрд╛рджрди рдХреЛ рдЧрд▓рддреА рдХреЛ рд╕рд╣рди рдХрд░рдиреЗ рдФрд░ рд▓реЛрдб рдХреЗ рд╕рд╛рде рд╕рд╛рдордирд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реЗрд╡рд╛ рдХреА рдХрдИ рдкреНрд░рддрд┐рдпреЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рд╕реЗрд╡рд╛рдУрдВ рдХреЗ рдПрдХ рд╕рдореВрд╣ рдХрд╛ рдкреНрд░рдмрдВрдзрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдПрдХ рдЙрдкрдХрд░рдг рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ рдЬреЛ рдпрд╣ рджрд░реНрд╢рд╛рддрд╛ рд╣реИ рдХрд┐ рд╕реЗрд╡рд╛ рдХреА рдПрдХ рдкреНрд░рддрд┐ "рдЬреАрд╡рд┐рдд" рд╣реИ рдпрд╛ рдирд╣реАрдВред рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рдПрдХ рд╣реИрдВрдбрд▓рд░ рджреНрд╡рд╛рд░рд╛ рд╣рд▓ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ /health
, рдЬреЛ рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд▓рд┐рдП, рдХрд╛рдо рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╕рднреА рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреЛ рдкреНрд░рджреВрд╖рд┐рдд рдХрд░рддрд╛ рд╣реИред рдЕрдЧрд░SELECT 1
рдПрдХ рд╕реЗрдХрдВрдб рд╕реЗ рднреА рдХрдо рд╕рдордп рдореЗрдВ рдирд┐рд╖реНрдкрд╛рджрд┐рдд, рдлрд┐рд░ рд╕реЗрд╡рд╛ рдЬреАрд╡рд┐рдд рд╣реИред рдпрджрд┐ рдирд╣реАрдВ, рддреЛ рдЖрдкрдХреЛ рдЗрд╕ рдкрд░ рдзреНрдпрд╛рди рджреЗрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИредрдЬрдм рдХреЛрдИ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдиреЗрдЯрд╡рд░реНрдХ рдХреЗ рд╕рд╛рде рдмрд╣реБрдд рдЧрд╣рдирддрд╛ рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рддреЛ uvloop рдкреНрд░рджрд░реНрд╢рди рдХреЛ рдардВрдбрд╛ рдХрд░ рд╕рдХрддрд╛ рд╣реИредрдПрдХ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдХрд╛рд░рдХ рдХреЛрдб рдХреА рдкрдардиреАрдпрддрд╛ рд╣реИред рдореЗрд░реЗ рдПрдХ рд╕рд╛рдереА, рдпреВрд░реА рд╢рд┐рдХрд╛рдиреЛрд╡ рдиреЗ, рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд╕рддреНрдпрд╛рдкрди рдФрд░ рдХреЛрдб рдХреЗ рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рд▓рд┐рдП рдХрдИ рдЙрдкрдХрд░рдгреЛрдВ рдХреЗ рд╕рдВрдпреЛрдЬрди рдХреЗ рд▓рд┐рдП рдПрдХ рдЧреНрд░реЗ рдореЙрдбреНрдпреВрд▓ рд▓рд┐рдЦрд╛ рдерд╛ , рдЬреЛ рдХрд┐ pre-commit
рдПрдХ рдПрдХрд▓ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓ рдпрд╛ рдкрд░реНрдпрд╛рд╡рд░рдг рдЪрд░ рдХреЗ рд╕рд╛рде рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ Git рд╣реБрдХ рдХреЛ рдЬреЛрдбрд╝рдирд╛ рдЖрд╕рд╛рди рд╣реИ ред рдЧреНрд░реЗ рдЖрдкрдХреЛ рдЖрдпрд╛рдд ( рдЖрдЗрд╕реЛрд░реНрдЯ ) рдХреЛ рд╕реЙрд░реНрдЯ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рднрд╛рд╖рд╛ рдХреЗ рдирдП рд╕рдВрд╕реНрдХрд░рдгреЛрдВ ( pyupgrad ) рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдЕрдЬрдЧрд░ рдХреЗ рднрд╛рд╡реЛрдВ рдХрд╛ рдЕрдиреБрдХреВрд▓рди рдХрд░рддрд╛ рд╣реИ, рдлрд╝рдВрдХреНрд╢рди рдХреЙрд▓, рдЖрдпрд╛рдд, рд╕реВрдЪрд┐рдпреЛрдВ, рдЖрджрд┐ рдХреЗ рдЕрдВрдд рдореЗрдВ рдХреЙрдорд╛ рдЬреЛрдбрд╝рддрд╛ рд╣реИредрдРрдб-рдЯреНрд░реЗрд▓рд┐рдВрдЧ-рдЕрд▓реНрдкрд╡рд┐рд░рд╛рдо ), рдФрд░ рдПрдХрд▓ рдлрд╝реЙрд░реНрдо ( рдПрдХреАрдХреГрдд ) рдХреЗ рд▓рд┐рдП рднреА рдЙрджреНрдзрд░рдг ред* * *
рдпрд╣ рд╕рдм рдореЗрд░реЗ рд▓рд┐рдП рд╣реИ: рд╣рдордиреЗ рд╡рд┐рдХрд╕рд┐рдд рдХрд┐рдпрд╛, рдкрд░реАрдХреНрд╖рдгреЛрдВ рд╕реЗ рдЖрдЪреНрдЫрд╛рджрд┐рдд рдХрд┐рдпрд╛, рд╕реЗрд╡рд╛ рдХреЛ рдЗрдХрдЯреНрдард╛ рдХрд┐рдпрд╛ рдФрд░ рддреИрдирд╛рдд рдХрд┐рдпрд╛, рдФрд░ рд▓реЛрдб рдкрд░реАрдХреНрд╖рдг рднреА рдХрд┐рдпрд╛редрд╕реНрд╡реАрдХреГрддрд┐рдпрд╛рдБ
рдореИрдВ рдЙрди рд▓реЛрдЧреЛрдВ рдХреЗ рдкреНрд░рддрд┐ рдЕрдкрдиреА рдЧрд╣рд░реА рдХреГрддрдЬреНрдЮрддрд╛ рд╡реНрдпрдХреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ, рдЬрд┐рдиреНрд╣реЛрдВрдиреЗ рдЗрд╕ рд▓реЗрдЦ рдХреЛ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП, рдХреЛрдб рдХреА рд╕рдореАрдХреНрд╖рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЕрдкрдиреЗ рд╡рд┐рдЪрд╛рд░реЛрдВ рдФрд░ рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдХреЛ рдкреНрд░рд╕реНрддреБрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдордп рдирд┐рдХрд╛рд▓рд╛: рдорд╛рд░рд┐рдпрд╛ рдЬрд╝реЗрд▓рдиреЛрд╡рд╛ рдХреЛ Zelma, рд╡реНрд▓рд╛рджрд┐рдореАрд░ рд╕реЛрд▓реЛрдореИрдЯрд┐рди leenr, рдЕрдирд╛рд╕реНрддрд╛рд╕рд┐рдпрд╛ рд╕реЗрдореЗрдиреЛрд╡рд╛ Morkov, рдпреВрд░реА рд╢рд┐рдХрд╛рдиреЛрд╡ dizballanze, рдорд┐рдЦрд╛рдЗрд▓ рд╢реБрд╖реНрдкрдиреЛрд╡ mishush, рдкрд╛рд╡реЗрд▓ рдореЛрд╕рд┐рди pavkazzz рдФрд░ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рджрд┐рдорд┐рддреНрд░реА рдУрд░рд▓реЛрд╡ рдХреЛ orlovdlред