Road to first pull request for OSS

# 前回のあらすじ

https://qiita.com/chihiro-yabuta/items/72e4a1869e9196ca9a67

### こんな人におすすめの記事

- 基礎文法は覚えたけど0からコードを書けない
- vscodeを有効に使いたい
- 他人の書いたコードを読み解けない
- githubで共同開発をしてみたい

# 知るべきこと

### どのように出力されているか

![スクリーンショット 2022-10-02 11.21.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883424/734734a9-d6d5-392f-e7b9-21b8b8339ca1.png)
とりあえず静的出力から調べる
tqdm_notebookの中身を見ていく
![スクリーンショット 2022-10-06 9.57.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883424/855c10d4-ac1f-9a36-089b-774f1c3afdbc.png)
2本指(右)クリックから *定義へ移動* とするとすぐ行ける

```notebook.py
try:  # IPython 4.x / 3.x
    if IPY == 32:
        from IPython.html.widgets import HTML
        from IPython.html.widgets import FloatProgress as IProgress
        from IPython.html.widgets import HBox
        IPY = 3
    else:
        from ipywidgets import HTML
        from ipywidgets import FloatProgress as IProgress # <-
        from ipywidgets import HBox
```

dependenciesによってimportを分けている
![スクリーンショット 2022-10-06 9.32.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883424/a8505cc7-3a2a-1760-1b7e-af8f66b1d025.png)
condaの最新環境では矢印のところになる

```notebook.py
class tqdm_notebook(std_tqdm):
   #~~~~~~~~~~~~~~~~~~~~
    @staticmethod
    def status_printer(_, total=None, desc=None, ncols=None):
       #~~~~~~~~~~~~~~~~~~~~
        if IProgress is None:  # #187 #451 #558 #872
            raise ImportError(WARN_NOIPYW)
        if total:
            pbar = IProgress(min=0, max=total)
        else:  # No total? Show info style bar with no progress tqdm status
            pbar = IProgress(min=0, max=1)
            pbar.value = 1
            pbar.bar_style = 'info'
            if ncols is None:
                pbar.layout.width = "20px"

        ltext = HTML()
        rtext = HTML()
        if desc:
            ltext.value = desc
        container = TqdmHBox(children=[ltext, pbar, rtext])
       #~~~~~~~~~~~~~~~~~~~~
        return container
   #~~~~~~~~~~~~~~~~~~~~
    @property
   #~~~~~~~~~~~~~~~~~~~~
    def __init__(self, *args, **kwargs):
       #~~~~~~~~~~~~~~~~~~~~
        # Replace with IPython progress bar display (with correct total)
        unit_scale = 1 if self.unit_scale is True else self.unit_scale or 1
        total = self.total * unit_scale if self.total else self.total
        self.container = self.status_printer(self.fp, total, self.desc, self.ncols)
   #~~~~~~~~~~~~~~~~~~~~
    def update(self, n=1):
        try:
            return super(tqdm_notebook, self).update(n=n)
```

widget を作るために *FloatProgress as IProgress* の constructor を呼び出す
静的に初期化した要素達を *TqdmBox* に渡している
*TqdmBox* はただ文字コードの見てるだけ
それを tqdm_notebook の constructor で宣言
update をよぶ出すことで self を更新
という処理のようだ
updateは親クラスである *std_tqdm* のメンバーで、これは

```std.py
class tqdm(Comparable):
#~~~~~~~~~~~~~~~~~~~~
    @property
   #~~~~~~~~~~~~~~~~~~~~
    def update(self, n=1):
       #~~~~~~~~~~~~~~~~~~~~
        if self.disable:
            return

        if n < 0:
            self.last_print_n += n  # for auto-refresh logic to work
        self.n += n

        if self.n - self.last_print_n >= self.miniters:
            cur_t = self._time()
            dt = cur_t - self.last_print_t
            if dt >= self.mininterval and cur_t >= self.start_t + self.delay:
               #~~~~~~~~~~~~~~~~~~~~
                # Store old values for next call
                self.last_print_n = self.n
                self.last_print_t = cur_t
```
このような処理　内部の値を更新している
つまりは *from ipywidgets import FloatProgress* を出力しているだけ

### どのように動的に行われているか

ここがキモとなる部分
一般的に tqdm はこのように使われる
![タイトルなし.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883424/b9e004d2-23e3-db4b-3137-a4e5e9e93562.gif)
このように標準出力の履歴が残らない　普通こうなるはず
![タイトルなし2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883424/379d4bdf-5993-8da2-d9f6-62f5163cb8d2.gif)
この謎を調べるべく私はコードの奥深くへ赴いた。。。

```std.py
class tqdm(Comparable):
#~~~~~~~~~~~~~~~~~~~~
    def __init__(self, iterable=None, desc=None, total=None, leave=True, file=None,
                 ncols=None, mininterval=0.1, maxinterval=10.0, miniters=None,
                 ascii=None, disable=False, unit='it', unit_scale=False,
                 dynamic_ncols=False, smoothing=0.3, bar_format=None, initial=0,
                 position=None, postfix=None, unit_divisor=1000, write_bytes=None,
                 lock_args=None, nrows=None, colour=None, delay=0, gui=False,
                 **kwargs):
       #~~~~~~~~~~~~~~~~~~~~
        if not gui:
            # Initialize the screen printer
            self.sp = self.status_printer(self.fp)
            if delay <= 0:
                self.refresh(lock_args=self.lock_args)
```

この辺りが臭そう

```std.py
class tqdm(Comparable):
#~~~~~~~~~~~~~~~~~~~~
    @staticmethod
    def status_printer(file):
        """
        Manage the printing and in-place updating of a line of characters.
        Note that if the string is longer than a line, then in-place
        updating may not work (it will print a new line at each refresh).
        """
        fp = file
        fp_flush = getattr(fp, 'flush', lambda: None)  # pragma: no cover
        if fp in (sys.stderr, sys.stdout):
            getattr(sys.stderr, 'flush', lambda: None)()
            getattr(sys.stdout, 'flush', lambda: None)()

        def fp_write(s):
            fp.write(_unicode(s))
            fp_flush()

        last_len = [0]

        def print_status(s):
            len_s = disp_len(s)
            fp_write('\r' + s + (' ' * max(last_len[0] - len_s, 0)))
            last_len[0] = len_s

        return print_status
```

https://qiita.com/nabenabe0928/items/255b571c62c1b1d69ad4

getattrはここから知った　うーーーんどうも見当違いのところを見てそう

### 仕方ないので__init__以外も見よう

```std.py
class tqdm(Comparable):
#~~~~~~~~~~~~~~~~~~~~
    @staticmethod
    def format_meter(n, total, elapsed, ncols=None, prefix='', ascii=False, unit='it',
                     unit_scale=False, rate=None, bar_format=None, postfix=None,
                     unit_divisor=1000, initial=0, colour=None, **extra_kwargs):
       #~~~~~~~~~~~~~~~~~~~~
        # total is known: we can predict some stats
        if total:
            # fractional and percentage progress
            frac = n / total
            percentage = frac * 100

            l_bar += '{0:3.0f}%|'.format(percentage)

            if ncols == 0:
                return l_bar[:-1] + r_bar[1:]

            format_dict.update(l_bar=l_bar)
            if bar_format:
                format_dict.update(percentage=percentage)

                # auto-remove colon for empty `desc`
                if not prefix:
                    bar_format = bar_format.replace("{desc}: ", '')
            else:
                bar_format = "{l_bar}{bar}{r_bar}"

            full_bar = FormatReplace()
            try:
                nobar = bar_format.format(bar=full_bar, **format_dict)
            except UnicodeEncodeError:
                bar_format = _unicode(bar_format)
                nobar = bar_format.format(bar=full_bar, **format_dict)
            if not full_bar.format_called:
                # no {bar}, we can just format and return
                return nobar
       #~~~~~~~~~~~~~~~~~~~~
```

この関数が怪しいなあ。。。

```std.py
class tqdm(Comparable):
#~~~~~~~~~~~~~~~~~~~~
    def __str__(self):
        return self.format_meter(**self.format_dict)
```

正直に言います　ここまで私は **アンダーバーの意義を知らずに生きていました**

https://qiita.com/kiii142/items/6879cb065ad4c5f0b901

素晴らしい記事を発見
**magic method** という機能で、予約語に機能を付け加えることができるみたいです

### 結論

```std.py
class tqdm(Comparable):
#~~~~~~~~~~~~~~~~~~~~
    def __iter__(self):
       #~~~~~~~~~~~~~~~~~~~~
        finally:
            self.n = n
            self.close()
#~~~~~~~~~~~~~~~~~~~~
    def close(self):
        """Cleanup and (if leave=False) close the progressbar."""
       #~~~~~~~~~~~~~~~~~~~~
        with self._lock:
            if leave:
                # stats for overall rate (no weighted average)
                self._ema_dt = lambda: None
                self.display(pos=0)
                fp_write('\n')
            else:
                # clear previous display
                if self.display(msg='', pos=pos) and not pos:
                    fp_write('\r')
```

。。。ん？　これだけ？

https://dot-blog.jp/news/python-print-overwrite-output/

あ。。。

![タイトルなし3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883424/87742e07-7be2-0565-f8f7-f89627da909e.gif)

ま、まあコードは読み解けたということで。。。
**\r** を付けると上書きできるようです　pythonすごい。

# やりたいこと

### stdのサイズを画面サイズに動的に合わせたい

少女祈祷中...