рдкрд╛рдпрдерди рдмреИрдХреЗрдВрдб рд╕реЗрд╡рд╛ рд╡рд┐рдХрд╛рд╕ рдЧрд╛рдЗрдб

рдирдорд╕реНрддреЗ, рдореЗрд░рд╛ рдирд╛рдо рдЕрд▓реЗрдХреНрдЬреЗрдВрдбрд░ рд╡рд╛рд╕реАрди рд╣реИ, рдореИрдВ рдПрдбреИрдбрд┐рд▓ рдореЗрдВ рдПрдХ рдмреИрдХреЗрдВрдб рдбреЗрд╡рд▓рдкрд░ рд╣реВрдВред рдЗрд╕ рд╕рд╛рдордЧреНрд░реА рдХрд╛ рд╡рд┐рдЪрд╛рд░ рдЗрд╕ рддрдереНрдп рд╕реЗ рд╢реБрд░реВ рд╣реБрдЖ рдХрд┐ рдореИрдВ рдпрд╛рдВрдбреЗрдХреНрд╕ рдмреИрдХреЗрдВрдб рдбреЗрд╡рд▓рдкрдореЗрдВрдЯ рд╕реНрдХреВрд▓ рдореЗрдВ рдкрд░рд┐рдЪрдпрд╛рддреНрдордХ рдЕрд╕рд╛рдЗрдирдореЗрдВрдЯ ( 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:

# REST API
$ 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'

# ,     (   ), 
#   __init__.py   machinery.
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': [
            # f-strings  setup.py   - 
            # .
            #   ,     Python 3.8, 
            # source distribution       
            #   Python.     
            # .
            '{0}-api = {0}.api.__main__:main'.format(module_name),
            '{0}-db = {0}.db.__main__:main'.format(module_name)
        ]
    },
    include_package_data=True
)

рдЖрдк рдирд┐рдореНрди рдХрдорд╛рдВрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╡рд┐рдХрд╛рд╕ рдореЛрдб рдореЗрдВ рдПрдХ рдкрд░рд┐рдпреЛрдЬрдирд╛ рд╕реНрдерд╛рдкрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ (рд╕рдВрдкрд╛рджрди рдпреЛрдЧреНрдп рдореЛрдб рдореЗрдВ, рдкрд╛рдпрдерди рдкреВрд░реЗ рдкреИрдХреЗрдЬ рдХреЛ рдПрдХ рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рд╕реНрдерд╛рдкрд┐рдд рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ site-packages, рд▓реЗрдХрд┐рди рдХреЗрд╡рд▓ рд▓рд┐рдВрдХ рдмрдирд╛рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдкреИрдХреЗрдЬ рдлрд╝рд╛рдЗрд▓реЛрдВ рдореЗрдВ рдХрд┐рдП рдЧрдП рдХреЛрдИ рднреА рдкрд░рд┐рд╡рд░реНрддрди рддреБрд░рдВрдд рджрд┐рдЦрд╛рдИ рджреЗрдВрдЧреЗ):

#      extra- "dev"
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 рдореЗрдВ рдПрдХ рдХреНрд╖реЗрддреНрд░ рджреНрд╡рд╛рд░рд╛ рджрд░реНрд╢рд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ ред

рд▓реЗрдХрд┐рди рдЗрд╕ рд╡рд┐рдзрд┐ рдХреЗ рдХрдИ рдиреБрдХрд╕рд╛рди рд╣реИрдВ
  1. 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
    

  2. relatives PostgreSQL, : relatives , . ( ) .

рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдореИрдВрдиреЗ рдХрд╛рдо рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╕рднреА рдбреЗрдЯрд╛ рдХреЛ рддреАрд╕рд░реЗ рд╕рд╛рдорд╛рдиреНрдп рд░реВрдк рдореЗрдВ рд▓рд╛рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ , рдФрд░ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕рдВрд░рдЪрдирд╛ рдкреНрд░рд╛рдкреНрдд рдХреА рдЧрдИ:



  1. рдЖрдпрд╛рдд рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдЗрдВрдХреНрд░реАрдореЗрдВрдЯрд┐рдВрдЧ рдХреЙрд▓рдо рд╣реЛрддрд╛ рд╣реИ import_idред рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рдПрдХ рд╡рд┐рджреЗрд╢реА рдХреБрдВрдЬреА рдЬрд╛рдБрдЪ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдпрд╣ рдЖрд╡рд╢реНрдпрдХ рд╣реИ citizensред
  2. рдирд╛рдЧрд░рд┐рдХ рддрд╛рд▓рд┐рдХрд╛ рдирд┐рд╡рд╛рд╕реА (рдкрд╛рд░рд┐рд╡рд╛рд░рд┐рдХ рд╕рдВрдмрдВрдзреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдХреЛ рдЫреЛрдбрд╝рдХрд░ рд╕рднреА рдХреНрд╖реЗрддреНрд░реЛрдВ) рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реНрдХреЗрд▓рд░ рдбреЗрдЯрд╛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддреА рд╣реИ ред

    рдПрдХ рдЬреЛрдбрд╝реА ( import_id, citizen_id) рдкреНрд░рд╛рдердорд┐рдХ рдХреБрдВрдЬреА рдХреЗ рд░реВрдк рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ , рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреА рд╡рд┐рд╢рд┐рд╖реНрдЯрддрд╛ рдХреА рдЧрд╛рд░рдВрдЯреА citizen_idрдврд╛рдВрдЪреЗ рдХреЗ рднреАрддрд░ import_idред

    рдПрдХ рд╡рд┐рджреЗрд╢реА рдХреБрдВрдЬреА citizens.import_id -> imports.import_idрдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддреА рд╣реИ рдХрд┐ рдлрд╝реАрд▓реНрдб citizens.import_idрдореЗрдВ рдХреЗрд╡рд▓ рдореМрдЬреВрджрд╛ рдЕрдирд▓реЛрдб рд╣реИрдВред
  3. 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ред

рдореЗрдЯрд╛рдбреЗрдЯрд╛ рд░рдЬрд┐рд╕реНрдЯреНрд░реА рдмрдирд╛рдПрдБ рдФрд░ рдирд╛рдордХрд░рдг рдкреИрдЯрд░реНрди рдкрд╛рд╕ рдХрд░реЗрдВ
# analyzer/db/schema.py
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',

    #  CHECK-constraint-
    '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 рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ рдХреЗ рд╕рд╛рде рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реНрдХреАрдорд╛ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреЗ рд╣реИрдВ
# analyzer/db/schema.py
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, рдЖрдкрдХреЛ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЪрд░рдг рдХрд░рдиреЗ рд╣реЛрдВрдЧреЗ:

  1. рдкреИрдХреЗрдЬ рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗ: pip install alembic
  2. рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдЕрд▓реЗрдореНрдмрд┐рдХ cd analyzer && alembic init db/alembic:ред

    рдпрд╣ рдХрдорд╛рдВрдб рдПрдХ рд╡рд┐рдиреНрдпрд╛рд╕ рдлрд╛рдЗрд▓ analyzer/alembic.iniрдФрд░ рдПрдХ рдлрд╝реЛрд▓реНрдбрд░ рдмрдирд╛рдПрдЧреА analyzer/db/alembicрдЬрд┐рд╕рдореЗрдВ рдирд┐рдореНрди рд╕рд╛рдордЧреНрд░реА рд╣реЛрдЧреА:
    • env.py- рд╣рд░ рдмрд╛рд░ рдЬрдм рдЖрдк рдЕрд▓реЗрдореНрдмрд┐рдХ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред sqlalchemy.MetaDataрдбреЗрдЯрд╛рдмреЗрд╕ рдХреА рд╡рд╛рдВрдЫрд┐рдд рд╕реНрдерд┐рддрд┐ рдХреЗ рд╡рд┐рд╡рд░рдг рдХреЗ рд╕рд╛рде рдПрд▓реЗрдореНрдмрд┐рдХ рд░рдЬрд┐рд╕реНрдЯреНрд░реА рд╕реЗ рдЬреЛрдбрд╝рддрд╛ рд╣реИ рдФрд░ рдЗрд╕рдореЗрдВ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рдирд┐рд░реНрджреЗрд╢ рд╢рд╛рдорд┐рд▓ рд╣реИрдВред
    • script.py.mako - рдЬрд┐рд╕ рдЖрдзрд╛рд░ рдкрд░ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдЙрддреНрдкрдиреНрди рд╣реЛрддрд╛ рд╣реИ, рдЙрд╕рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдЯреЗрдореНрдкреНрд▓реЗрдЯред
    • versions - рд╡рд╣ рдлрд╝реЛрд▓реНрдбрд░ рдЬрд┐рд╕рдореЗрдВ рдЕрд▓реЗрдореНрдмрд┐рдХ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдЦреЛрдЬреЗрдЧрд╛ (рдФрд░ рдЙрддреНрдкрдиреНрди рдХрд░реЗрдЧрд╛)ред
  3. рдбреЗрдЯрд╛рдмреЗрд╕ рдкрддреЗ рдХреЛ alembic.ini рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░реЗрдВ:

    ; analyzer/alembic.ini
    [alembic] 
    sqlalchemy.url = postgresql://user:hackme@localhost/analyzer
  4. рдбреЗрдЯрд╛рдмреЗрд╕ (рд░рдЬрд┐рд╕реНрдЯреНрд░реА sqlalchemy.MetaData) рдХреА рд╡рд╛рдВрдЫрд┐рдд рд╕реНрдерд┐рддрд┐ рдХрд╛ рд╡рд┐рд╡рд░рдг рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░реЗрдВ рддрд╛рдХрд┐ рдПрд▓реЗрдмрд┐рдХ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдЙрддреНрдкрдиреНрди рдХрд░ рд╕рдХреЗ:

    # analyzer/db/alembic/env.py
    from analyzer.db import schema
    target_metadata = schema.metadata

рдПрд▓реЗрдореНрдмрд┐рдХ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рдФрд░ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ рдЗрд╕ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдореЗрдВ рдХрдИ рдиреБрдХрд╕рд╛рди рд╣реИрдВ:

  1. рдЙрдкрдпреЛрдЧрд┐рддрд╛ рд╡рд░реНрддрдорд╛рди рдХрд╛рд░реНрдп рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдореЗрдВ alembicрдЦреЛрдЬ рдХрд░рддреА alembic.iniрд╣реИред рдЖрдк alembic.iniрдХрдорд╛рдВрдб рд▓рд╛рдЗрди рддрд░реНрдХ рдХреЗ рд▓рд┐рдП рдкрде рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдпрд╣ рдЕрд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИ: рдореИрдВ рдЕрддрд┐рд░рд┐рдХреНрдд рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рдмрд┐рдирд╛ рдХрд┐рд╕реА рднреА рдлрд╝реЛрд▓реНрдбрд░ рд╕реЗ рдХрдорд╛рдВрдб рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред
  2. рдХрд┐рд╕реА рд╡рд┐рд╢рд┐рд╖реНрдЯ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрд▓реЗрдореНрдмрд┐рдХ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдлрд╝рд╛рдЗрд▓ рдХреЛ рдмрджрд▓рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ alembic.iniред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдкрд░реНрдпрд╛рд╡рд░рдг рдЪрд░ рдФрд░ / рдпрд╛ рдХрдорд╛рдВрдб рд▓рд╛рдЗрди рддрд░реНрдХ рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдирд╛ рдЕрдзрд┐рдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реЛрдЧрд╛ --pg-urlред
  3. рдЙрдкрдпреЛрдЧрд┐рддрд╛ 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()
    
        #    Alembic
        config = Config(file_=options.config, ini_section=options.name,
                        cmd_opts=options)
    
        #   sqlalchemy.url   Alembic
        config.set_main_option('sqlalchemy.url', options.pg_url)
    
        #   alembic
        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()
    
        #     (alembic.ini),   
        #    
        if not os.path.isabs(options.config):
            options.config = os.path.join(PROJECT_PATH, options.config)
    
        #    Alembic
        config = Config(file_=options.config, ini_section=options.name,
                        cmd_opts=options)
    
        #      alembic   (,  alembic
        #   env.py,       )
        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))
    
        #   alembic
        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():
        ...
        #      GenderType   
        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')
    
    #      citizens,    
    #    
    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(
        #        ANALYZER_,
        #  ANALYZER_API_ADDRESS  ANALYZER_API_PORT
        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
        """
        #   os.environ    tuple,    
        # os.environ   
        for name in filter(rule, tuple(os.environ)):
            os.environ.pop(name)
    
    
    def main():
        #  
        args = parser.parse_args()
    
        #      ANALYZER_
        clear_environ(lambda i: i.startswith(ENV_VAR_PREFIX))
    
        #  
        app = create_app(args)
        ...
    
    
    if __name__ == '__main__':
        main()
  • stderr/ .

    9 , logging.basicConfig() stderr.

    , . aiomisc.

    aiomisc
    import 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 рдорд┐рд▓реЗрдЧрд╛ рдЬреЛ рдбреЗрдЯрд╛ рдкреНрд░рдХрд╛рд░ рд╕реЗ рдореЗрд▓ рдЦрд╛рддрд╛ рд╣реИ рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЛ рдХреНрд░рдордмрджреНрдз рдХрд░рддрд╛ рд╣реИред рдЗрд╕ рддрдереНрдп рдХреЗ рдЕрд▓рд╛рд╡рд╛ рдХрд┐ рд╡рд╕реНрддреБрдУрдВ рдХрд╛ рдХреНрд░рдордмрджреНрдзрддрд╛ рдПрдХ рд╣реА рд╕реНрдерд╛рди рдкрд░ рд╡рд░реНрдгрд┐рдд рд╣реИ, рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг рднреА рдЕрдзрд┐рдХ рд▓рдЪреАрд▓рд╛ рд╣реИ - рдпрд╣ рдЖрдкрдХреЛ рдмрд╣реБрдд рджрд┐рд▓рдЪрд╕реНрдк рд╕рдорд╛рдзрд╛рдиреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ (рд╣рдо рд╣реИрдВрдбрд▓рд░ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХреЗ рдорд╛рдорд▓реЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВрдЧреЗ )ред

Responsebody

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 рд╕реЗ рдЕрдзрд┐рдХ рддрд░реНрдХ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВред рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ citizens9 рдлрд╝реАрд▓реНрдб рд╣реИрдВ ред рддрджрдиреБрд╕рд╛рд░, 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 рдореЗрдЧрд╛рдмрд╛рдЗрдЯ рд▓реЗ рд╕рдХрддрд╛ рд╣реИ - рдпрд╣ рдХрд╛рдлреА рд╣реИ, рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдпрд╣ рджреЗрдЦрддреЗ рд╣реБрдП рдХрд┐ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рдХрдИ рдЕрдиреБрд░реЛрдз рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ рдЖ рд╕рдХрддреЗ рд╣реИрдВред рдХрд░реНрд╕рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдФрд░ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рднрд╛рдЧреЛрдВ рдореЗрдВ рднреЗрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рджрд┐рд▓рдЪрд╕реНрдк рддрд░реАрдХрд╛ рд╣реИ ред

рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рджреЛ рд╡рд╕реНрддреБрдУрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:

  1. рдПрдХ 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
    
  2. рдПрдХ рдзрд╛рд░рд╛рд╡рд╛рд╣рд┐рдХ AsyncGenJSONListPayloadрдЬреЛ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдЬрдирд░реЗрдЯрд░ рдкрд░ рдкреБрдирд░рд╛рд╡реГрддрд┐ рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рдПрдХ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдЬрдирд░реЗрдЯрд░ рд╕реЗ JSON рдХреЗ рдбреЗрдЯрд╛ рдХреЛ рдХреНрд░рдордмрджреНрдз рдХрд░рддрд╛ рд╣реИ рдФрд░ рднрд╛рдЧреЛрдВ рдореЗрдВ рдЧреНрд░рд╛рд╣рдХреЛрдВ рдХреЛ рдбреЗрдЯрд╛ рднреЗрдЬрддрд╛ рд╣реИред рдпрд╣ aiohttp.PAYLOAD_REGISTRYрд╡рд╕реНрддреБрдУрдВ рдХреЗ рдПрдХ рдзрд╛рд░рд╛рд╡рд╛рд╣рд┐рдХ рдХреЗ рд░реВрдк рдореЗрдВ рдкрдВрдЬреАрдХреГрдд рд╣реИ AsyncIterableред

    AsyncGenJSONListPayload рдХреЛрдб
    import json
    from functools import partial
    
    from aiohttp import Payload
    
    
    # ,    JSON  asyncpg.Record  datetime.date
    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:

рд╣реИрдВрдбрд▓рд░ рдХреЛрдб
# analyzer/api/handlers/citizens.py
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 рд╕реНрдерд┐рддрд┐ рдирд╣реАрдВ рджреЗ рдкрд╛рдПрдЧрд╛редAsyncGenJSONListPayloadAsyncIterableSelectQuerySelectQuery



рдЬрдм рдЕрдкрд╡рд╛рдж рд╣реЛрддрд╛ рд╣реИ, рддреЛ рдбрд┐рд╕реНрдХрдиреЗрдХреНрдЯ рдХрд░рдиреЗ рдХреЗ рдЕрд▓рд╛рд╡рд╛ рдХреБрдЫ рдирд╣реАрдВ рд░рд╣рддрд╛ рд╣реИред рдПрдХ рдЕрдкрд╡рд╛рдж, рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рд╕реБрд░рдХреНрд╖рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЧреНрд░рд╛рд╣рдХ рдареАрдХ рд╕реЗ рд╕рдордЭ рдирд╣реАрдВ рдкрд╛рдПрдЧрд╛ рдХрд┐ рдХреНрдпрд╛ рддреНрд░реБрдЯрд┐ рд╣реБрдИред

рджреВрд╕рд░реА рдУрд░, рдПрдХ рд╕рдорд╛рди рд╕реНрдерд┐рддрд┐ рдЙрддреНрдкрдиреНрди рд╣реЛ рд╕рдХрддреА рд╣реИ рднрд▓реЗ рд╣реА рдкреНрд░реЛрд╕реЗрд╕рд░ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рд╕рднреА рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рдбреЗрдЯрд╛ рдкреНрд░реЗрд╖рд┐рдд рдХрд░рддреЗ рд╕рдордп рдиреЗрдЯрд╡рд░реНрдХ рдЭрдкрдХрд╛рддрд╛ рд╣реИ - рдЗрд╕рд╕реЗ рдХреЛрдИ рднреА рд╕реБрд░рдХреНрд╖рд┐рдд рдирд╣реАрдВ рд╣реИред

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ред

рджреЛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╡рд┐рдХрд▓реНрдк рд╣реИрдВ:

  1. рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреЗ рд╕рд╛рде рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ, рдФрд░ рдкрд╛рдпрдерди рдкрдХреНрд╖ рдкрд░, рдорд╣реАрдиреЗ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдбреЗрдЯрд╛ рдПрдХрддреНрд░ рдХрд░реЗрдВ рдФрд░ рдЙрди рдорд╣реАрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╕реВрдЪрд┐рдпрд╛рдВ рдмрдирд╛рдПрдВ рдЬрд┐рдирдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдХреЛрдИ рдбреЗрдЯрд╛ рдирд╣реАрдВ рд╣реИред
  2. рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдПрдХ json рдЕрдиреБрд░реЛрдз рд╕рдВрдХрд▓рд┐рдд рдХрд░реЗрдВ рдФрд░ рд▓рд╛рдкрддрд╛ рдорд╣реАрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╕реНрдЯрдмреНрд╕ рдЬреЛрдбрд╝реЗрдВред

рдореИрдВ рдкрд╣рд▓реЗ рд╡рд┐рдХрд▓реНрдк рдкрд░ рдмрд╕ рдЧрдпрд╛ - рдиреЗрддреНрд░рд╣реАрди рдпрд╣ рдЕрдзрд┐рдХ рд╕рдордЭ рдореЗрдВ рдЖрддрд╛ рд╣реИ рдФрд░ рд╕рдорд░реНрдерд┐рдд рд╣реИред рдХрд┐рд╕реА рджрд┐рдП рдЧрдП рдорд╣реАрдиреЗ рдореЗрдВ рдЬрдиреНрдорджрд┐рди рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЛ JOINрдкрд╛рд░рд┐рд╡рд╛рд░рд┐рдХ рд╕рдВрдмрдВрдзреЛрдВ рдХреЗ рд╕рд╛рде рддрд╛рд▓рд┐рдХрд╛ рд╕реЗ рдмрдирд╛рдХрд░ рдкреНрд░рд╛рдкреНрдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ ( relations.citizen_id- рд╡рд╣ рдирд┐рд╡рд╛рд╕реА рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рд╣рдо рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреЗ рдЬрдиреНрдорджрд┐рди рдорд╛рдирддреЗ рд╣реИрдВ) рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ citizens(рдЬрдиреНрдо рдХреА рддрд╛рд░реАрдЦ рдЬрд┐рд╕рдореЗрдВ рд╕реЗ рдЖрдк рдорд╣реАрдиреЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ)ред

рдорд╛рд╣ рдорд╛рдиреЛрдВ рдореЗрдВ рдЕрдЧреНрд░рдгреА рд╢реВрдиреНрдп рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред birth_dateрдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдлрд╝реАрд▓реНрдб рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдорд╣реАрдиреЗ date_partрдореЗрдВ рдПрдХ рдЕрдЧреНрд░рдгреА рд╢реВрдиреНрдп рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕реЗ рдирд┐рдХрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВ рдкреНрд░рджрд░реНрд╢рди castрдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП integerSQL рдХреНрд╡реЗрд░реА рдореЗрдВред

рдЗрд╕ рддрдереНрдп рдХреЗ рдмрд╛рд╡рдЬреВрдж рдХрд┐ рд╣реИрдВрдбрд▓рд░ рдХреЛ рджреЛ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рдкреВрд░рд╛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ (рдЙрддрд░рд╛рдИ рдХреЗ рдЕрд╕реНрддрд┐рддреНрд╡ рдХреА рдЬрд╛рдВрдЪ рдХрд░реЗрдВ рдФрд░ рдЬрдиреНрдорджрд┐рди рдФрд░ рдЙрдкрд╣рд╛рд░реЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ), рд▓реЗрдирджреЗрди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ ред

рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ, PostgreSQL READ COMMITTED рдореЛрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рд╕рднреА рдирдП (рдЕрдиреНрдп рд▓реЗрдирджреЗрди рджреНрд╡рд╛рд░рд╛ рдЬреЛрдбрд╝реЗ рдЧрдП) рдФрд░ рдореМрдЬреВрджрд╛ (рдЕрдиреНрдп рд▓реЗрди-рджреЗрди рджреНрд╡рд╛рд░рд╛ рдкрд░рд┐рд╡рд░реНрддрд┐рдд) рд░рд┐рдХреЙрд░реНрдб рд╡рд░реНрддрдорд╛рди рд▓реЗрдирджреЗрди рдореЗрдВ рджрд┐рдЦрд╛рдИ рджреЗрддреЗ рд╣реИрдВ, рдЬрдм рд╡реЗ рд╕рдлрд▓рддрд╛рдкреВрд░реНрд╡рдХ рдкреВрд░рд╛ рд╣реЛ рдЬрд╛рддреЗ рд╣реИрдВред

рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд╕рдордп рдПрдХ рдирдпрд╛ рдЕрдкрд▓реЛрдб рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдпрд╣ рдореМрдЬреВрджрд╛ рд╡рд╛рд▓реЗ рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ред рдпрджрд┐ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рд╣реЛрдиреЗ рдХреЗ рд╕рдордп рдирд┐рд╡рд╛рд╕реА рдХреЛ рдмрджрд▓рдиреЗ рдХрд╛ рдЕрдиреБрд░реЛрдз рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдпрд╛ рддреЛ рдбреЗрдЯрд╛ рдЕрднреА рддрдХ рджрд┐рдЦрд╛рдИ рдирд╣реАрдВ рджреЗрдЧрд╛ (рдпрджрд┐ рд▓реЗрдирджреЗрди рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рдбреЗрдЯрд╛ рдкреВрд░рд╛ рдирд╣реАрдВ рд╣реБрдЖ рд╣реИ), рдпрд╛ рд▓реЗрдирджреЗрди рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдкреВрд░рд╛ рд╣реЛ рдЬрд╛рдПрдЧрд╛ рдФрд░ рд╕рднреА рдкрд░рд┐рд╡рд░реНрддрди рддреБрд░рдВрдд рджрд┐рдЦрд╛рдИ рджреЗрдВрдЧреЗред рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдЕрдЦрдВрдбрддрд╛ рдХрд╛ рдЙрд▓реНрд▓рдВрдШрди рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред

GET / рдЖрдпрд╛рдд / $ import_id / рдХрд╕реНрдмреЛрдВ / рд╕реНрдЯреЗрдЯ / рдкреНрд░рддрд┐рд╢рдд / рдЖрдпреБ


рд╣реИрдВрдбрд▓рд░ рдирд┐рд░реНрджрд┐рд╖реНрдЯ import_id рдХреЗ рд╕рд╛рде рдирдореВрдиреЗ рдореЗрдВ рд╢рд╣рд░ рджреНрд╡рд╛рд░рд╛ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреА рдЖрдпреБ (рдкреВрд░реНрдг рд╡рд░реНрд╖) рдХреА 50 рд╡реАрдВ, 75 рд╡реАрдВ рдФрд░ 99 рд╡реАрдВ рдкреНрд░рддрд┐рд╢рддрддрд╛ рдХреА рдЧрдгрдирд╛ рдХрд░рддрд╛ рд╣реИред рдЧреИрд░-рдореМрдЬреВрдж рдЕрдкрд▓реЛрдб рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ , HTTP рдкреНрд░рддрд┐рд╕рд╛рдж рджреЗрдирд╛ рдЪрд╛рд╣рд┐рдП 404: Not Foundред

рдЗрд╕ рддрдереНрдп рдХреЗ рдмрд╛рд╡рдЬреВрдж рдХрд┐ рдкреНрд░реЛрд╕реЗрд╕рд░ рджреЛ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддрд╛ рд╣реИ (рдЙрддрд░рд╛рдИ рдХреЗ рдЕрд╕реНрддрд┐рддреНрд╡ рдХреА рдЬрд╛рдВрдЪ рдХрд░рдирд╛ рдФрд░ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛), рд▓реЗрдирджреЗрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рдирд╣реАрдВ рд╣реИ ред

рджреЛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╡рд┐рдХрд▓реНрдк рд╣реИрдВ:

  1. рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреА рдЖрдпреБ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ, рд╢рд╣рд░ рджреНрд╡рд╛рд░рд╛ рд╕рдореВрд╣реАрдХреГрдд, рдФрд░ рдлрд┐рд░ рдкрд╛рдпрдерди рдХреА рдУрд░ рд╕реЗ рдЦрд╕рд░реЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкреНрд░рддрд┐рд╢рдд рдХреА рдЧрдгрдирд╛ рдХрд░реЗрдВ (рдЬреЛ рдХрд╛рд░реНрдп рдореЗрдВ рдПрдХ рд╕рдВрджрд░реНрдн рдХреЗ рд░реВрдк рдореЗрдВ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╣реИ) рдФрд░ рджреЛ рджрд╢рдорд▓рд╡ рд╕реНрдерд╛рдиреЛрдВ рддрдХ рдЧреЛрд▓ред
  2. 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:
        #      postgres  -
        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')
    #  DSN  ,    
    return postgres

рдЬрдм рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рдХрдИ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рд╣реЛрддреЗ рд╣реИрдВ, рддреЛ рдкреНрд░рддреНрдпреЗрдХ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдЙрдирдХреЗ рдЖрд╡реЗрджрди рдореЗрдВ рдмрд╣реБрдд рдЕрдзрд┐рдХ рд╕рдордп рд▓рдЧ рд╕рдХрддрд╛ рд╣реИред рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рдЧрддрд┐ рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдк рдПрдХ рдмрд╛рд░ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдХреЗ рд╕рд╛рде рдПрдХ рдбреЗрдЯрд╛рдмреЗрд╕ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдлрд┐рд░ рдЗрд╕реЗ рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ ред

рд╣реИрдВрдбрд▓рд░ рдХреЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЖрдкрдХреЛ рдПрдХ рд░рдирд┐рдВрдЧ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА, рд╕рд╛рде рд╣реА рдЗрд╕ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдирд╛ рдЖрд╕рд╛рди рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдЗрд╕рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХреЛ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рд░рдЦрд╛ рд╣реИ create_appрдЬреЛ рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдкреИрд░рд╛рдореАрдЯрд░ рд▓реЗрддрд╛ рд╣реИ: рдПрдХ рдбреЗрдЯрд╛рдмреЗрд╕, REST API рдХреЗ рд▓рд┐рдП рдПрдХ рдкреЛрд░реНрдЯ, рдФрд░ рдЕрдиреНрдпред

рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд▓реЙрдиреНрдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рддрд░реНрдХ рдХреЛ рдПрдХ рдЕрд▓рдЧ рд╕реНрдерд┐рд░рддрд╛ рдХреЗ рд░реВрдк рдореЗрдВ рднреА рджрд░реНрд╢рд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЙрдиреНрд╣реЗрдВ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдкрд░реАрдХреНрд╖рдг рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдФрд░ рдорд╛рдЗрдЧреНрд░реЗрдЯ рдХрд┐рдП рдЧрдП рдЕрд╕реНрдерд╛рдпреА рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рдкрддреЗ рдХреЛ рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдирд┐: рд╢реБрд▓реНрдХ рдкреЛрд░реНрдЯ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред

рдореБрдХреНрдд рдмрдВрджрд░рдЧрд╛рд╣ рдХрд╛ рдирд┐рд░реНрдзрд╛рд░рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ aiomisc_unused_portaiomisc рдкреИрдХреЗрдЬ рд╕реЗ рд╕реНрдерд┐рд░рддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ ред

рдПрдХ рдорд╛рдирдХ рд╕реНрдерд┐рд░рддрд╛ 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, рддреЛ рдирд┐рдореНрди рд╣реЛрдЧрд╛:

  1. postgres ( migrated_postgres).
  2. alembic_config Alembic, ( migrated_postgres).
  3. migrated_postgres ( arguments).
  4. aiomisc_unused_port ( arguments).
  5. arguments ( api_client).
  6. api_client .
  7. .
  8. api_client .
  9. postgres .

рдЬреБрдбрд╝рдирд╛рд░ рдЖрдкрдХреЛ рдХреЛрдб рдХреЗ рджреЛрд╣рд░рд╛рд╡ рд╕реЗ рдмрдЪрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдкрд░реАрдХреНрд╖рдгреЛрдВ рдореЗрдВ рдкрд░реНрдпрд╛рд╡рд░рдг рдХреЛ рддреИрдпрд╛рд░ рдХрд░рдиреЗ рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдПрдХ рдФрд░ рд╕рдВрднрд╛рд╡рд┐рдд рд╕реНрдерд╛рди рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдмрд╣реБрдд рд╕рд╛рд░реЗ рд╕рдорд╛рди рдХреЛрдб - рдЖрд╡реЗрджрди рдЕрдиреБрд░реЛрдз рд╣реЛрдВрдЧреЗред

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдПрдХ рдЕрдиреБрд░реЛрдз рдХрд░рддреЗ рд╣реБрдП, рд╣рдо рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд HTTP рд╕реНрдерд┐рддрд┐ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЕрдкреЗрдХреНрд╖рд╛ рдХрд░рддреЗ рд╣реИрдВред рджреВрд╕рд░реЗ, рдпрджрд┐ рд╕реНрдерд┐рддрд┐ рдЕрдкреЗрдХреНрд╖рд┐рдд рд╕реЗ рдореЗрд▓ рдЦрд╛рддреА рд╣реИ, рддреЛ рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдЖрдкрдХреЛ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдХрд┐ рдЙрдирдХреЗ рдкрд╛рд╕ рд╕рд╣реА рдкреНрд░рд╛рд░реВрдк рд╣реИред рдпрд╣рд╛рдВ рдПрдХ рдЧрд▓рддреА рдХрд░рдирд╛ рдЖрд╕рд╛рди рд╣реИ рдФрд░ рдПрдХ рд╣реИрдВрдбрд▓рд░ рд▓рд┐рдЦрдирд╛ рд╣реИ рдЬреЛ рд╕рд╣реА рдЧрдгрдирд╛ рдХрд░рддрд╛ рд╣реИ рдФрд░ рд╕рд╣реА рдкрд░рд┐рдгрд╛рдо рджреЗрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЧрд▓рдд рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкреНрд░рд╛рд░реВрдк рдХреЗ рдХрд╛рд░рдг рд╕реНрд╡рдд: рд╕рддреНрдпрд╛рдкрди рдкрд╛рд╕ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдХреБрдВрдЬреА рдХреЗ рд╕рд╛рде рдПрдХ рд╢рдмреНрджрдХреЛрд╢ рдореЗрдВ рдЙрддреНрддрд░ рдХреЛ рд▓рдкреЗрдЯрдирд╛ рднреВрд▓ рдЬрд╛рддреЗ рд╣реИрдВ data)ред рдпреЗ рд╕рднреА рдЬрд╛рдВрдЪреЗрдВ рдПрдХ рд╣реА рд╕реНрдерд╛рди рдкрд░ рдХреА рдЬрд╛ рд╕рдХрддреА рдереАрдВред

рдореЙрдбреНрдпреВрд▓ рдореЗрдВanalyzer.testing рдореИрдВрдиреЗ рдкреНрд░рддреНрдпреЗрдХ рд╣реИрдВрдбрд▓рд░ рдХреЛ рдПрдХ рд╣реЗрд▓реНрдкрд░ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рдХрд┐рдпрд╛ рд╣реИ рдЬреЛ HTTP рдХреА рд╕реНрдерд┐рддрд┐ рдХреА рдЬрд╛рдВрдЪ рдХрд░рддрд╛ рд╣реИ, рд╕рд╛рде рд╣реА рдорд╛рд░реНрд╢рдореИрд▓реЛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╕реНрд╡рд░реВрдк рднреАред

GET / рдЖрдпрд╛рдд / $ import_id / рдирд╛рдЧрд░рд┐рдХ


рдореИрдВрдиреЗ рдПрдХ рд╣реИрдВрдбрд▓рд░ рдХреЗ рд╕рд╛рде рд╢реБрд░реБрдЖрдд рдХрд░рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ рдЬреЛ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЛ рд╡рд╛рдкрд╕ рдХрд░рддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреА рд╕реНрдерд┐рддрд┐ рдХреЛ рдмрджрд▓рдиреЗ рд╡рд╛рд▓реЗ рдЕрдиреНрдп рд╣реИрдВрдбрд▓рд░ рдХреЗ рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдЙрдкрдпреЛрдЧреА рд╣реИред

рдореИрдВрдиреЗ рдЬрд╛рдирдмреВрдЭрдХрд░ рдХреЛрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИ рдЬреЛ рд╣реИрдВрдбрд▓рд░ рд╕реЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдбреЗрдЯрд╛ рдЬреЛрдбрд╝рддрд╛ рд╣реИ POST /imports, рд╣рд╛рд▓рд╛рдВрдХрд┐ рдЗрд╕реЗ рдПрдХ рдЕрд▓рдЧ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рдмрдирд╛рдирд╛ рдореБрд╢реНрдХрд┐рд▓ рдирд╣реАрдВ рд╣реИред рд╣реИрдВрдбрд▓рд░ рдХреЗ рдХреЛрдб рдХреЛ рдмрджрд▓рдиреЗ рдХреА рд╕рдВрдкрддреНрддрд┐ рд╣реИ, рдФрд░ рдЕрдЧрд░ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдЬреБрдбрд╝рдиреЗ рд╡рд╛рд▓реЗ рдХреЛрдб рдореЗрдВ рдХреЛрдИ рддреНрд░реБрдЯрд┐ рд╣реИ, рддреЛ рдПрдХ рдореМрдХрд╛ рд╣реИ рдХрд┐ рдкрд░реАрдХреНрд╖рдг рдЙрджреНрджреЗрд╢реНрдп рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рдо рдХрд░рдирд╛ рдмрдВрдж рдХрд░ рджреЗрдЧрд╛ рдФрд░ рдбреЗрд╡рд▓рдкрд░реНрд╕ рдХреЗ рд▓рд┐рдП рдирд┐рд╣рд┐рддрд╛рд░реНрде рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рджрд┐рдЦрд╛рдирд╛ рдмрдВрдж рдХрд░ рджреЗрдЧрд╛ред

рдЗрд╕ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкрд░реАрдХреНрд╖рдг рдбреЗрдЯрд╛ рд╕реЗрдЯ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛:

  • рдХрдИ рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреЗ рд╕рд╛рде рдЙрддрд╛рд░рдирд╛ред рдЬрд╛рдБрдЪ рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рдирд┐рд╡рд╛рд╕реА рдХреЗ рд▓рд┐рдП рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреЗ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛рдУрдВ рдХреЗ рд╕рд╛рде рдПрдХ рд╕реВрдЪреА рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдмрдирд╛рдИ рдЬрд╛рдПрдЧреАред
  • рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреЗ рдмрд┐рдирд╛ рдПрдХ рдирд┐рд╡рд╛рд╕реА рдХреЗ рд╕рд╛рде рдЙрддрд╛рд░рдирд╛ред рдЬрд╛рдБрдЪрддрд╛ рд╣реИ рдХрд┐ рдлрд╝реАрд▓реНрдб relativesрдПрдХ рдЦрд╛рд▓реА рд╕реВрдЪреА рд╣реИ ( LEFT JOINSQL рдХреНрд╡реЗрд░реА рдХреЗ рдХрд╛рд░рдг , рд░рд┐рд╢реНрддреЗрджрд╛рд░реЛрдВ рдХреА рд╕реВрдЪреА рдмрд░рд╛рдмрд░ рд╣реЛ рд╕рдХрддреА рд╣реИ [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')

#   11       
generate_citizen(birth_date=age2date(years=11))

рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рд╣реИрдВрдбрд▓рд░ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдЕрдирд▓реЛрдбрд┐рдВрдЧ рдХреЗ рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рдмреАрдЪ рдЕрдВрддрд░ рдХрд░рддрд╛ рд╣реИ, рдореИрдВрдиреЗ рджреВрд╕рд░реЗ рд╢рд╣рд░ рдХреЗ рдПрдХ рдирд┐рд╡рд╛рд╕реА рдХреЗ рд╕рд╛рде рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд рдЕрдирд▓реЛрдб рдЬреЛрдбрд╝рд╛: рдпрджрд┐ рд╣реИрдВрдбрд▓рд░ рдЧрд▓рддреА рд╕реЗ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ, рддреЛ рдкрд░рд┐рдгрд╛рдореЛрдВ рдореЗрдВ рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд рд╢рд╣рд░ рджрд┐рдЦрд╛рдИ рджреЗрдЧрд╛ рдФрд░ рдкрд░реАрдХреНрд╖рдг рдЯреВрдЯ рдЬрд╛рдПрдЧрд╛ред

рдПрдХ рджрд┐рд▓рдЪрд╕реНрдк рддрдереНрдп: рдЬрдм рдореИрдВрдиреЗ 29 рдлрд░рд╡рд░реА, 2020 рдХреЛ рдпрд╣ рдкрд░реАрдХреНрд╖рдг рд▓рд┐рдЦрд╛ рдерд╛, рддреЛ рдореИрдВрдиреЗ рдЕрдЪрд╛рдирдХ рдлрд╝реЗрдХрд░ рдореЗрдВ рдмрдЧ рдХреЗ рдХрд╛рд░рдг рдирд┐рд╡рд╛рд╕рд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдЕрдирд▓реЛрдб рдХрд░рдирд╛ рдмрдВрдж рдХрд░ рджрд┐рдпрд╛ (2020 рдПрдХ рд▓реАрдк рдИрдпрд░ рд╣реИ, рдФрд░ рдЕрдиреНрдп рд╡рд░реНрд╖ рдЬреЛ рдлрд╝реЗрдХрд░ рдиреЗ рдЪреБрдиреЗ рдереЗ, рдЙрдирдореЗрдВ рд╣рдореЗрд╢рд╛ рд▓реАрдк рд╡рд░реНрд╖ рдирд╣реАрдВ рдереЗред 29 рдлрд░рд╡рд░реА рдХреЛ рдирд╣реАрдВ рдерд╛)ред рдпрд╛рдж рд░рдЦреЗрдВ рдХрд┐ рддрд╛рд░реАрдЦреЗрдВ рд░рд┐рдХреЙрд░реНрдб рдХрд░реЗрдВ рдФрд░ рдХрд┐рдирд╛рд░реЗ рдХреЗ рдорд╛рдорд▓реЛрдВ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░реЗрдВ!

рдорд╛рдЗрдЧреНрд░реЗрд╢рди


рдкрд╣рд▓реА рдирдЬрд╝рд░ рдореЗрдВ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдХреЛрдб рд╕реНрдкрд╖реНрдЯ рдФрд░ рдХрдо рд╕реЗ рдХрдо рддреНрд░реБрдЯрд┐ рд╡рд╛рд▓рд╛ рд▓рдЧрддрд╛ рд╣реИ, рдЗрд╕рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХреНрдпреЛрдВ рдХрд░реЗрдВ? рдпрд╣ рдПрдХ рдмрд╣реБрдд рд╣реА рдЦрддрд░рдирд╛рдХ рддреНрд░реБрдЯрд┐ рд╣реИ: рдкрд▓рд╛рдпрди рдХреА рд╕рдмрд╕реЗ рдХрдкрдЯрдкреВрд░реНрдг рдЧрд▓рддрд┐рдпрд╛рдБ рд╕рдмрд╕реЗ рдЕрд╕рдВрдЧрдд рдХреНрд╖рдг рдореЗрдВ рдЦреБрдж рдХреЛ рдкреНрд░рдХрдЯ рдХрд░ рд╕рдХрддреА рд╣реИрдВред рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдЕрдЧрд░ рд╡реЗ рдбреЗрдЯрд╛ рдХреЛ рдЦрд░рд╛рдм рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╡реЗ рдЕрдирд╛рд╡рд╢реНрдпрдХ рдбрд╛рдЙрдирдЯрд╛рдЗрдо рдХрд╛ рдХрд╛рд░рдг рдмрди рд╕рдХрддреЗ рд╣реИрдВред

рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ рдореМрдЬреВрдж рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдбреЗрдЯрд╛рдмреЗрд╕ рдХреА рд╕рдВрд░рдЪрдирд╛ рдХреЛ рдмрджрд▓ рджреЗрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдбреЗрдЯрд╛ рдХреЛ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рдЗрд╕ рддрд░рд╣ рдХреЗ рдкрд▓рд╛рдпрди рд╕реЗ рдХрд┐рди рд╕рд╛рдорд╛рдиреНрдп рдЧрд▓рддрд┐рдпреЛрдВ рдХреЛ рдмрдЪрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ?

  • downgrade ( , , ).

    , (--): , тАФ .
  • C .
  • ( ).

рдЗрдирдореЗрдВ рд╕реЗ рдЕрдзрд┐рдХрд╛рдВрд╢ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХрд╛ рдкрддрд╛ рд╕реАрдврд╝реА рдкрд░реАрдХреНрд╖рдг рджреНрд╡рд╛рд░рд╛ рд▓рдЧрд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ ред рдЙрдирдХрд╛ рд╡рд┐рдЪрд╛рд░ - рдПрдХ рдПрдХрд▓ рдкреНрд░рд╡рд╛рд╕ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд▓рдЧрд╛рддрд╛рд░ рддрд░реАрдХреЛрдВ рдкреНрд░рджрд░реНрд╢рди upgrade, downgrade, upgradeрдкреНрд░рддреНрдпреЗрдХ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдХреЗ рд▓рд┐рдПред рдЗрд╕ рддрд░рд╣ рдХреА рдкрд░реАрдХреНрд╖рд╛ рдПрдХ рдмрд╛рд░ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рд╢рд╛рдорд┐рд▓ рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реИ, рдЗрд╕реЗ рд╕рдорд░реНрдерди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ рдФрд░ рдИрдорд╛рдирджрд╛рд░реА рд╕реЗ рдХрд╛рдо рдХрд░реЗрдВрдЧреЗред

рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдкреНрд░рд╡рд╛рд╕рди, рд╕рдВрд░рдЪрдирд╛ рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдбреЗрдЯрд╛ рдХреЛ рдмрджрд▓ рджреЗрдЧрд╛, рддреЛ рдХрдо рд╕реЗ рдХрдо рдПрдХ рдЕрд▓рдЧ рдкрд░реАрдХреНрд╖рдг рд▓рд┐рдЦрдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реЛрдЧрд╛, рдпрд╣ рдЬрд╛рдБрдЪрддреЗ рд╣реБрдП рдХрд┐ рдбреЗрдЯрд╛ рд╕рд╣реА рддрд░реАрдХреЗ рд╕реЗ рдмрджрд▓рддрд╛ рд╣реИ upgradeрдФрд░ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рд╕реНрдерд┐рддрд┐ рдореЗрдВ рд╡рд╛рдкрд╕ рдЖ рдЬрд╛рддрд╛ рд╣реИ downgradeред рдмрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ: рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рд╡рд╛рд╕рди рдХреЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рдкрд░рд┐рдпреЛрдЬрдирд╛ , рдЬрд┐рд╕реЗ рдореИрдВрдиреЗ рдореЙрд╕реНрдХреЛ рдкрд╛рдпрдерди рдореЗрдВ рдЕрд▓реЗрдореНрдмрд┐рдХ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдПрдХ рд░рд┐рдкреЛрд░реНрдЯ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рдХрд┐рдпрд╛ рдерд╛ ред

рд╕рднрд╛


рдЕрдВрддрд┐рдо рдХрд▓рд╛рдХреГрддрд┐ рдЬрд┐рд╕реЗ рд╣рдо рддреИрдирд╛рдд рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ рдФрд░ рдЬрд┐рд╕реЗ рд╣рдо рдЕрд╕реЗрдВрдмрд▓реА рдХреЗ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рд╡рд╣ рдбреЙрдХрдЯрд░ рдЫрд╡рд┐ рд╣реИред рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдкрд╛рдпрдерди рдХреЗ рд╕рд╛рде рдЖрдзрд╛рд░ рдЫрд╡рд┐ рдХрд╛ рдЪрдпрди рдХрд░рдирд╛ рд╣реЛрдЧрд╛ ред рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рдЫрд╡рд┐ рдХрд╛ python:latestрд╡рдЬрди ~ 1 рдЬреАрдмреА рд╣реИ рдФрд░, рдпрджрд┐ рдЖрдзрд╛рд░ рдЫрд╡рд┐ рдХреЗ рд░реВрдк рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдЖрд╡реЗрджрди рдХреЗ рд╕рд╛рде рдЫрд╡рд┐ рдмрд╣реБрдд рдмрдбрд╝реА рд╣реЛрдЧреАред рдЕрд▓реНрдкрд╛рдЗрди рдУрдПрд╕ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рдЪрд┐рддреНрд░ рд╣реИрдВ , рдЬрд┐рдирдХрд╛ рдЖрдХрд╛рд░ рдмрд╣реБрдд рдЫреЛрдЯрд╛ рд╣реИред рд▓реЗрдХрд┐рди рд╕реНрдерд╛рдкрд┐рдд рдкреИрдХреЗрдЬреЛрдВ рдХреА рдмрдврд╝рддреА рд╕рдВрдЦреНрдпрд╛ рдХреЗ рд╕рд╛рде, рдЕрдВрддрд┐рдо рдЫрд╡рд┐ рдХрд╛ рдЖрдХрд╛рд░ рдмрдврд╝реЗрдЧрд╛, рдФрд░ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдЕрд▓реНрдкрд╛рдЗрди рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдПрдХрддреНрд░ рдХреА рдЧрдИ рдЫрд╡рд┐ рдЗрддрдиреА рдЫреЛрдЯреА рдирд╣реАрдВ рд╣реЛрдЧреАред рдореИрдВрдиреЗ рдмреЗрд╕ рдЗрдореЗрдЬ рдХреЗ рд░реВрдк рдореЗрдВ рд╕реНрдиреЗрдХрдкреИрдХрд░ / рдЕрдЬрдЧрд░ рдХреЛ рдЪреБрдирд╛ - рдЗрд╕рдХрд╛ рд╡рдЬрди рдЕрд▓реНрдкрд╛рдЗрди рдЪрд┐рддреНрд░реЛрдВ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдереЛрдбрд╝рд╛ рдЕрдзрд┐рдХ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдЙрдмрдВрдЯреВ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рд╣реИ, рдЬреЛ рдкреИрдХреЗрдЬ рдФрд░ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдПрдХ рд╡рд┐рд╢рд╛рд▓ рдЪрдпрди рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред

рджреВрд╕рд░рд╛ рд░рд╛рд╕реНрддрд╛рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд╕рд╛рде рдЫрд╡рд┐ рдХрд╛ рдЖрдХрд╛рд░ рдХрдо рдХрд░реЗрдВ - рдЕрдВрддрд┐рдо рдЫрд╡рд┐ рдореЗрдВ рдЕрд╕реЗрдВрдмрд▓реА рдХреЗ рд▓рд┐рдП рдХрдВрдкрд╛рдЗрд▓рд░, рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдФрд░ рд╣реЗрдбрд░ рдХреЗ рд╕рд╛рде рдлрд╛рдЗрд▓реЗрдВ рд╢рд╛рдорд┐рд▓ рдирд╣реАрдВ рд╣реИрдВ, рдЬреЛ рдХрд┐ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдирд╣реАрдВ рд╣реИрдВред

рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдк рдбреЙрдХрд░ рдХреЗ рдорд▓реНрдЯреА-рд╕реНрдЯреЗрдЬ рдЕрд╕реЗрдВрдмрд▓реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ :

  1. рдПрдХ "рднрд╛рд░реА" рдЫрд╡рд┐ snakepacker/python:all(~ 1 рдЬреАрдмреА, ~ 500 рдПрдордмреА рд╕рдВрдкреАрдбрд╝рд┐рдд) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рдПрдХ рдЖрднрд╛рд╕реА рд╡рд╛рддрд╛рд╡рд░рдг рдмрдирд╛рдПрдВ, рд╕рднреА рдирд┐рд░реНрднрд░рддрд╛рдПрдВ рдФрд░ рдЙрд╕ рдкрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдкреИрдХреЗрдЬ рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВред рдпрд╣ рдЫрд╡рд┐ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рд╡рд┐рдзрд╛рдирд╕рднрд╛ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИ, рдЗрд╕рдореЗрдВ рдПрдХ рд╕рдВрдХрд▓рдХ, рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдФрд░ рд╣реЗрдбрд░ рдХреЗ рд╕рд╛рде рдлрд╛рдЗрд▓реЗрдВ рд╣реЛ рд╕рдХрддреА рд╣реИрдВред

    FROM snakepacker/python:all as builder
    
    #   
    RUN python3.8 -m venv /usr/share/python3/app
    
    #  source distribution     
    COPY dist/ /mnt/dist/
    RUN /usr/share/python3/app/bin/pip install /mnt/dist/*
  2. рд╣рдо рд╕рдорд╛рдкреНрдд рдЖрднрд╛рд╕реА рд╡рд╛рддрд╛рд╡рд░рдг рдХреЛ рдПрдХ "рдкреНрд░рдХрд╛рд╢" рдЫрд╡рд┐ snakepacker/python:3.8(~ 100 рдПрдордмреА, рд╕рдВрдкреАрдбрд╝рд┐рдд ~ 50 рдПрдордмреА) рдореЗрдВ рдХреЙрдкреА рдХрд░рддреЗ рд╣реИрдВ , рдЬрд┐рд╕рдореЗрдВ рдХреЗрд╡рд▓ рдкрд╛рдпрдерди рдХреЗ рдЖрд╡рд╢реНрдпрдХ рд╕рдВрд╕реНрдХрд░рдг рдХрд╛ рджреБрднрд╛рд╖рд┐рдпрд╛ рд╣реЛрддрд╛ рд╣реИред

    рдорд╣рддреНрд╡рдкреВрд░реНрдг: рдПрдХ рдЖрднрд╛рд╕реА рд╡рд╛рддрд╛рд╡рд░рдг рдореЗрдВ, рдирд┐рд░рдкреЗрдХреНрд╖ рдкрде рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЗрд╕реЗ рдЙрд╕реА рдкрддреЗ рдкрд░ рдХреЙрдкреА рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдЬрд┐рд╕ рдкрд░ рдпрд╣ рдХрд▓реЗрдХреНрдЯрд░ рдХрдВрдЯреЗрдирд░ рдореЗрдВ рдЗрдХрдЯреНрдард╛ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред

    FROM snakepacker/python:3.8 as api
    
    #       builder
    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"]

рдЫрд╡рд┐ рдХреЗ рдирд┐рд░реНрдорд╛рдг рдореЗрдВ рд▓рдЧрдиреЗ рд╡рд╛рд▓реЗ рд╕рдордп рдХреЛ рдХрдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП , рд╡рд░реНрдЪреБрдЕрд▓ рд╡рд╛рддрд╛рд╡рд░рдг рдореЗрдВ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдирд┐рд░реНрднрд░ рдореЙрдбреНрдпреВрд▓ рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдлрд┐рд░ рдбреЙрдХрдЯрд░ рдЙрдиреНрд╣реЗрдВ рдХреИрд╢ рдХрд░ рджреЗрдЧрд╛ рдФрд░ рдЕрдЧрд░ рд╡реЗ рдирд╣реАрдВ рдмрджрд▓реЗ рд╣реИрдВ рддреЛ рдЙрдиреНрд╣реЗрдВ рдлрд┐рд░ рд╕реЗ рд╕реНрдерд╛рдкрд┐рдд рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗред

рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдбреЙрдХрд░рдлрд╛рдЗрд▓
###############      ################
#  тАФ ┬л┬╗ (~1 ,    ~500 )    
#    
FROM snakepacker/python:all as builder

#      pip
RUN python3.8 -m venv /usr/share/python3/app
RUN /usr/share/python3/app/bin/pip install -U pip

#   ,  .   
# Docker   ,  requirements.txt  
COPY requirements.txt /mnt/
RUN /usr/share/python3/app/bin/pip install -Ur /mnt/requirements.txt

#  source distribution     
COPY dist/ /mnt/dist/
RUN /usr/share/python3/app/bin/pip install /mnt/dist/* \
    && /usr/share/python3/app/bin/pip check

###########################   ############################
#    ┬л┬╗ (~100 ,    ~50 )   Python
FROM snakepacker/python:3.8 as api

#         builder
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рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИCIPostgreSQL рдХреЗ рд╕рд╛рде рдПрдХ рдХрдВрдЯреЗрдирд░ рдЙрдард╛рддрд╛ рд╣реИ, рдЗрд╕рдХреЗ рдЙрдкрд▓рдмреНрдз рд╣реЛрдиреЗ рдХрд╛ рдЗрдВрддрдЬрд╛рд░ рдХрд░рддрд╛ рд╣реИ, рдФрд░ 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@.serviceAnsible рджреНрд╡рд╛рд░рд╛ рдмрдирд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред @рдирд╛рдо рдореЗрдВ рдкреНрд░рддреАрдХ рдкреНрд░рдгрд╛рд▓реА рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдЗрдХрд╛рдИ рдПрдХ рдЯреЗрдореНрдкрд▓реЗрдЯ рд╣реИред рдпрд╣ рдЖрдкрдХреЛ 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

рднреВрдорд┐рдХрд╛analyzerdocker-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
# 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 = [
            #     .   
            # PATCH-  relatives    
            # ,     - 
            # (     ,    
            # ).
            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ред

All Articles