Differences between revisions 2 and 3
Revision 2 as of 2019-04-05 12:11:38
Size: 6894
Editor: FrBrGeorge
Comment:
Revision 3 as of 2019-04-08 06:19:24
Size: 10866
Editor: FrBrGeorge
Comment:
Deletions are marked like this. Additions are marked like this.
Line 140: Line 140:
'''TODO'''
- issue
- wiki
- pages
При разработке проекта необходимо выстраивать информационное пространство
Line 145: Line 142:
На примере [[https://help.github.com/en|GitHub]]
 * [[https://help.github.com/en/articles/managing-your-work-with-issues|issue tracker]]
 * [[https://help.github.com/en/articles/documenting-your-project-with-wikis|wiki]]
  * Доступ к wiki не обязательно совпадает с доступом к репозиторию. Например, команда можно работать по `merge`-схеме, а в вики при этом пишут все
  * [[https://help.github.com/en#github-pages-basics|github.io]]
 * [[https://help.github.com/en/articles/managing-project-boards|Управление проектами]]

Ведение совместного репозитория:
 1. «`merge`»-схема (классическая)
  * Каждый участник проекта ведёт свой публичный репозиторий, которой он синхронизует с проектом
  * Один из этих репозиториев считается финальным. Доступ на `push` в этот репозиторий (как и в любой другой при этой схеме) имеет либо вообще один человек (т. н. '''выпускающий'''), либо очень небольшая команда (в основном, на замену выпускающему)
   * Выпускающий часто сопровождает и второй — линейный — репозиторий, в котором он ведёт свою часть ''разработки''
   * !GutHub рассылает уведомления об обновлениях в основном репозитории
  * Когда приходит пора, разработчик ставит в известность выпускающего, что его опубликованный код (обычно по определённому тегу) пора помержить (!GitHub: pull request, часто — почтой, иногда какая-то автоматика конкретного портала, например, специально оформленный тег)
  * Выпускающий изучает соответствующий код, попутно исправляя и/или обсуждая с автором недочёты, и по по окончании процесса пуллит его.
 1. «`push`»-схема (историческая)
  * Работа ведётся в общем репозитории, доступ на `push` в который имеют все разработчики
  * Для параллельной разработке используются ветки, одна из которых объявляется основной
  * Когда приходит пора синхронизации, разработчик мержится с основной веткой, после чего пушит результат обратно в неё
  * !GutHub рассылает уведомления об обновлениях

Merge-схема
 * Хорошо масштабируется на большое сообщество
 * Хорошо работает, когда опыт разработчиков неодинаков
 * Заложена в архитектуру и систему команд git
 * Позволяет взаимодействовать в offline (например, пересылать изменения по почте)
Push-схема
 * Хорошо подходит для маленьких сообществ с одинаково высоким опытом
 * Требует дополнительной дисциплины / online-взаимодействия
 * Не до конца поддерживается в git (например, в git ''вообще'' нет понятия «права доступа» — к веткам, коммитам и каким-то «частям кода»)
  * В !GitHub есть
Line 146: Line 174:
'''TODO''' === Семестровый проект ===
<<Include(../GraduateProject)>>
Line 148: Line 177:
Я в ближайшие пару дней буду делать proposal относительно семестровой работы по курсу. Если коротко:
Работа — это git-репозиторий с кодом на Python3,
 * который я могу склонировать и запустить
 * в котором есть более одного участника, и я могу посмотреть статистику участия
 * в котором есть немножко тестов (с использованием любого тест-фреймворка, годится встроенный питоний)
 *в котором есть немножко документации
  * программной (с использованием любого фреймворка, годится встроенный питоний, но можно и sphinx)
  * пользовательской (либо sphinx, либо прямо на GH)
  * описание проекта и постановка задачи на GH
 * в котором есть немножко локализации (с теми же оговорками)
=== Как начать ===
Для регистрации необходимо оформить issue [[https://github.com/FrBrGeorge/PythonDevelopment2019/issues|вот тут]], в котором указать ссылку на ваш репозиторий и взаимно-однозначное соответствие ников людям, который будут получать оценки :)
Line 159: Line 180:
Немножко — это реально немножко, чтобы я видел, что работа проделана. Например, если вы задумали какое-то приложение из реал пайфа, и в нём довольно много логики, обмазать ''всю'' её тестами будет долго. Но пяток должен быть. В репозитории ''уже'' должен быть файл README.md с постановкой задачи и (в случае GUI) проект интерфейса с коротенькими подписями, какой блок виджетов за то отвечает.

Если вы не знаете, какую задачу вам решать, или с кем скооперироваться, оформляете issue с просьбой ''выдать'' вам учебно-тренировочную задачу и/или подобрать товарища по команде.

{{{#!wiki caution
'''Внимание!'''

Выдача задания и особенно подбор партнёра — случайный процесс, который может не привести к появлению команды/решаемой задачи!
}}}
 

Таймеры, события и GitHub

Таймер в эмуляции событийного подхода через mainloop() на самом деле не так просто сделать.

  • «Однопоточный» вариант. Tkinter умеет выполнить callback в указанное время (через указанный интервал). Для того, чтобы он запускался всё время, в сам этот callback вставляется планировщик его следующего вызова:

       1 import tkinter as tk
       2 import time
       3 
       4 class App():
       5     def __init__(self):
       6         self.root = tk.Tk()
       7         self.label = tk.Label(text="")
       8         self.label.grid()
       9         self.update_clock()
      10         self.root.mainloop()
      11 
      12     def update_clock(self):
      13         now = time.strftime("%H:%M:%S")
      14         self.label.configure(text=now)
      15         self.root.after(1000, self.update_clock)
      16 
      17 app=App()
    
  • Внешний вариант. Мы можем использовать любой фреймфорк, в котором есть часики, и дёргать callback-и оттуда.
    • Пример для threading:

         1 from threading import Thread, Event
         2 
         3 class MyThread(Thread):
         4     def __init__(self, event):
         5         Thread.__init__(self)
         6         self.stopped = event
         7 
         8     def run(self):
         9         while not self.stopped.wait(0.5):
        10             print("my thread")
        11 
        12 stopFlag = Event()
        13 thread = MyThread(stopFlag)
        14 thread.start()
        15 input("А вы пока нажмите Enter\n")
        16 stopFlag.set()
        17 print("Тогда всё")
      
    • Совместим threading и tkinter:

         1 import tkinter as tk
         2 import time
         3 from threading import Thread, Event
         4 
         5 class MyThread(Thread):
         6     def __init__(self, event, root):
         7         Thread.__init__(self)
         8         self.stopped = event
         9         self.root = root
        10 
        11     def run(self):
        12         while not self.stopped.wait(1):
        13             self.root.update_clock()
        14 
        15 class App():
        16     def __init__(self):
        17         self.root = tk.Tk()
        18         self.label = tk.Label(text="")
        19         self.label.grid()
        20         self.button = tk.Button(text="Quit", command = self.delayed_quit)
        21         self.button.grid()
        22         self.update_clock()
        23         self.stopped = Event()
        24         self.thread = MyThread(self.stopped, self)
        25         self.thread.start()
        26         self.root.mainloop()
        27 
        28     def delayed_quit(self):
        29         self.stopped.set()
        30         self.root.after(3000, self.root.quit)
        31         self.label.configure(text="Wait 3 secs")
        32 
        33     def update_clock(self):
        34         now = time.strftime("%H:%M:%S")
        35         self.label.configure(text=now)
        36 
        37 app=App()
      

      Недостаток этого способа — в том, что мы вынуждены работать в двух моделях событий — tkiner-овской и thread-овой.

  • «Правильный» подход: все события должны быть tkinter-овскими, таймер их только генерирует и подбрасывает в очередь событий:
       1 import time
       2 from tkinter import *
       3 from threading import Thread, Event;
       4 
       5 class Clock(Thread):
       6     def __init__(self, root, grain=1, event="<<Tick>>"):
       7         super().__init__()
       8         self.root = root    # Окно, которому посылать событие
       9         self.grain = grain  # Размер одного тика в секундах (м. б дробный)
      10         self.event = event  # TKinter-событие, которое надо посылать
      11         self.done = Event() # threading-событие, которое останавливет тред
      12 
      13     def run(self):
      14         while not self.done.wait(self.grain):
      15             self.root.event_generate(self.event)
      16 
      17 class App(Frame):
      18     def __init__(self, master=None, **kwargs):
      19         Frame.__init__(self, master, **kwargs)
      20         self.grid()
      21         self.Clock = Clock(self)
      22         self.Time = StringVar()
      23         self.update_clock()
      24         self.Screen = Label(textvariable=self.Time)
      25         self.Screen.grid(row=0, column=0)
      26         self.Start = Button(text="Start", command=self.start)
      27         self.Start.grid(row=0, column=1)
      28         self.Quit = Button(text="Quit", command=self.quit)
      29         self.Quit.grid(row=0, column=2)
      30         self.bind(self.Clock.event, self.tick)
      31         # тред надо остановить, даже если окно просто закрыли
      32         self.bind("<Destroy>", self.quit)
      33 
      34     def tick(self, event):
      35         self.update_clock()
      36 
      37     def start(self):
      38         self.Clock.start()
      39 
      40     def quit(self, *events):
      41         self.Clock.done.set()
      42         self.master.quit()
      43 
      44     def update_clock(self):
      45         self.Time.set(time.strftime("%H:%M:%S"))
      46 
      47 Tick = App()
      48 Tick.mainloop()
    

    Здесь используется т. н. синтетическое событие (в терминах tkintervirtual event), которое мы называем сами (это как class MyEvent(Event): в Python)

GitHub

При разработке проекта необходимо выстраивать информационное пространство

На примере GitHub

Ведение совместного репозитория:

  1. «merge»-схема (классическая)

    • Каждый участник проекта ведёт свой публичный репозиторий, которой он синхронизует с проектом
    • Один из этих репозиториев считается финальным. Доступ на push в этот репозиторий (как и в любой другой при этой схеме) имеет либо вообще один человек (т. н. выпускающий), либо очень небольшая команда (в основном, на замену выпускающему)

      • Выпускающий часто сопровождает и второй — линейный — репозиторий, в котором он ведёт свою часть разработки

      • GutHub рассылает уведомления об обновлениях в основном репозитории

    • Когда приходит пора, разработчик ставит в известность выпускающего, что его опубликованный код (обычно по определённому тегу) пора помержить (GitHub: pull request, часто — почтой, иногда какая-то автоматика конкретного портала, например, специально оформленный тег)

    • Выпускающий изучает соответствующий код, попутно исправляя и/или обсуждая с автором недочёты, и по по окончании процесса пуллит его.
  2. «push»-схема (историческая)

    • Работа ведётся в общем репозитории, доступ на push в который имеют все разработчики

    • Для параллельной разработке используются ветки, одна из которых объявляется основной
    • Когда приходит пора синхронизации, разработчик мержится с основной веткой, после чего пушит результат обратно в неё
    • GutHub рассылает уведомления об обновлениях

Merge-схема

  • Хорошо масштабируется на большое сообщество
  • Хорошо работает, когда опыт разработчиков неодинаков
  • Заложена в архитектуру и систему команд git
  • Позволяет взаимодействовать в offline (например, пересылать изменения по почте)

Push-схема

  • Хорошо подходит для маленьких сообществ с одинаково высоким опытом
  • Требует дополнительной дисциплины / online-взаимодействия
  • Не до конца поддерживается в git (например, в git вообще нет понятия «права доступа» — к веткам, коммитам и каким-то «частям кода»)

    • В GitHub есть

ДЗ

Семестровый проект

Семестровый проект — это git-репозиторий с кодом на Python3,

  • который я могу установить (любым предложенным вами кроссплатформенным способом) и запустить

    • предпочтительно wheel

  • в котором есть более одного участника, и я могу посмотреть статистику участия (оба предложенных ниже измерения неидеальны, я это знаю)
    • по количество коммитов
    • по объёму кода
  • в котором flake8 (или pylint) находит не больше 5 ошибок (некоторые требования можно запрещать в config-файле)

  • в котором есть немножко тестов (с использованием любого тест-фреймворка, годится встроенный питоний)
    • должны быть покрыты модульными тестами все функции и классы, не использующие интерактивные возможности (т. е не GUI, не сетевое взаимодействие и т. п.)
    • таких функций/классов должно быть не менее 5
  • в котором есть немножко документации
    • описание проекта в README (в случае GitHub — README.md) и постановка задачи на GH

      • В случае GUI — проект интерфейса
        • не обязательно полностью совпадающий с тем, что получилось
        • достаточно детальный, чтобы было понятно, какой блок виджетов из чего состоит и за что отвечает
        • можно в виде картинки с исходниками из какого-то диаграммера, а можно и просто фоточки нарисованного от руки
    • /!\ (по возможности) программной (с использованием любого фреймворка, годится встроенный питоний, но можно и sphinx)

    • /!\ (по возможности) пользовательской (либо sphinx, либо прямо на GH)

  • в котором есть немножко локализации (с теми же оговорками по части фреймворков)
    • с использованием gettext или babel
    • обратите внимание на то, что, например, -.mo файлы надо сгенерировать и положить в дистрибутив вашего проекта (например, в wheel, как в лекциях)

Немножко — это реально немножко, чтобы я видел, что работа проделана. Например, если вы задумали какое-то приложение из реал лайфа, и в нём довольно много логики, обмазать всю её тестами будет долго. Но пяток должен быть.

Как начать

Для регистрации необходимо оформить issue вот тут, в котором указать ссылку на ваш репозиторий и взаимно-однозначное соответствие ников людям, который будут получать оценки :)

В репозитории уже должен быть файл README.md с постановкой задачи и (в случае GUI) проект интерфейса с коротенькими подписями, какой блок виджетов за то отвечает.

Если вы не знаете, какую задачу вам решать, или с кем скооперироваться, оформляете issue с просьбой выдать вам учебно-тренировочную задачу и/или подобрать товарища по команде.

Внимание!

Выдача задания и особенно подбор партнёра — случайный процесс, который может не привести к появлению команды/решаемой задачи!

LecturesCMC/PythonDevelopment2019/07_TimersAndGhtHub (last edited 2019-04-08 06:19:24 by FrBrGeorge)