PythonでIMAPメール操作なら、IMAPClientが便利だった件

PythonIMAPでメール受信したくなった。標準のimaplibで基本的に可能なわけですが、実は結構めんどくさい。まずフォルダ名の取得からして、結果文字列がエンコードされたままで日本語だとそのままでは読めない...。読める文字列にするには何かと面倒...。メール読みたいだけなのに、正直辛い...。
で、手元にあった本、

退屈なことはPythonにやらせよう ―ノンプログラマーにもできる自動化処理プログラミング

を改めて読んでみたら、IMAPには「IMAPClient」というのを使っている。こっちの方がよかった。

pip install imapclient

してインストール。
違いは下のよう。

# 標準のimaplibの場合
import imaplib
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login('foo@gmail.com', 'password')
mail.list()
#取得結果のままでは日本語文字列エンコードされてて読めない...
> ('OK',
 [b'(\\HasNoChildren) "/" "INBOX"',
  b'(\\HasChildren \\Noselect) "/" "[Gmail]"',
  b'(\\All \\HasNoChildren) "/" "[Gmail]/&MFkweTBmMG4w4TD8MOs-"',
  b'(\\HasNoChildren \\Trash) "/" "[Gmail]/&MLQw33ux-"',
  b'(\\HasNoChildren \\Sent) "/" "[Gmail]/&kAFP4W4IMH8w4TD8MOs-"'])
# IMAPClientの場合
import imapclient
server = imapclient.IMAPClient("imap.gmail.com", ssl=True)
server.login(foo@gmail.com', 'password')
server.list_folders()
#取得結果がすでにデコード済みの文字列、日本語も読める!!
> 
[((b'\\HasNoChildren',), b'/', 'INBOX'),
 ((b'\\HasChildren', b'\\Noselect'), b'/', '[Gmail]'),
 ((b'\\All', b'\\HasNoChildren'), b'/', '[Gmail]/すべてのメール'),
 ((b'\\HasNoChildren', b'\\Trash'), b'/', '[Gmail]/ゴミ箱'),
 ((b'\\HasNoChildren', b'\\Sent'), b'/', '[Gmail]/送信済みメール')]

これなら嬉しい。
IMAPメール本文を読むにはさらにひと工夫いるのですが、その辺は 上述の本退屈なことはPythonにやらせよう ―ノンプログラマーにもできる自動化処理プログラミングでは、pyzmailを使っていて、確かに便利だ。pyzmailについてはまたいつか。

ラズパイのOSをRaspbian Busterにしたら、Ansibleでpip3がエラーになった件

Raspbian BusterはPython3がデフォルトで3.7系とのことで、それなら自前でビルドしなくていいから嬉しい。さっそく使おう。
公式サイトからRaspbian Buster Liteのイメージをダウンロードして、Macな私は
balenaEtcher - Home を使って、SDカードにイメージを書き込みします。(SDカードの控えもないので、今まで使ってたやつにそのまま上書き。バックアップとかしない。(キリッ!))

で、以前Stretch時代に自分で色々入れてたものの環境の復元は、Ansibleで。Infrastructure as Codeバンザイ。こういう時に便利ですね。
と思ったら、pipモジュールでエラー。
"Failed to import the required Python library (setuptools) on raspberrypi's Python /usr/bin/python. Please read module documentation and install in the appropriate location"

#一部抜粋
pip:
      name: [色々と]
      executable: pip3

こんな感じでやってるところが、なぜか上のエラー。

いろいろググったら、私はPython3とpip3でAnsibleしたいのですが、ラズパイ側がPython2で実行されているためっぽい。
対策として、ansibleのインベントリでホスト指定の時、下のようにansible_python_interpreterを指定すると良い。

raspberrypi.local ansible_python_interpreter=/usr/bin/python3

これって、別にBusterにしたからじゃなかったかも...。でもまあいいや。
無事、Busterに移行できました!!

PowerShell DSC で Active Directory のグループ管理がしたかったら ActiveDirectoryDsc

最近ちょくちょくPowerShellを使う機会があって、で、ちょっと思い立って PowerShell DSC で Active Directory のグループ設定とかしたらどうなのかなと。DSCほぼ初めて使ったのですが。
で、Active Directoryのグループ設定をするDSCリソースとかあるのかなと思って公式見に行ったら、DSC グループ リソースは、ローカルグループだな。ADのグループ管理は?と思ってググったけど、なんか見つからない。もしかしてまさかAD管理するリソースって謹製のは無いのか、と思いかけたら、ちゃんとありました。これ、ActiveDirectoryDsc

github.com

でも、NTFSACL管理するのは無いな...。

[Edit 2019.8.24] 名前がxActiveDirectoryからActiveDirectoryDscにかわってました。 ActiveDirectoryDsc: Rename module from xActiveDirectory · Issue #312 · PowerShell/ActiveDirectoryDsc · GitHub

Node.jsが令和に対応して、homebrewでのインストールでは--with-full-icuオプションもいらなくたっていた件

以前はhomebrewでNode.jsをインストールするとき、--with-full-icuオプションをつけていたのですが、いつの間にかその必要は無くなっていたようです。 普通にインストールして、和暦も使える。しかも、令和も対応されてますよ!

var date = new Date(Date.UTC(2019, 4, 1, 3, 0, 0));
new Intl.DateTimeFormat('ja-JP-u-ca-japanese', { era: 'long' }).format(date);
'令和元年5月1日'

HomebewでのNode.jsのインストールは、--with-intl=system-icu がデフォルトになっているようです。

Elmガイドの例Timeで、初期化時に現在時間をModelにセットする

Time · An Introduction to Elmの例では、初期化時のModelのtimeがゼロだったので、現在時間で初期化したかった。やる前は瞬殺と思っていたのだが、いやいやどうにも苦戦した。どうやるのか理解するのに結構苦労してしまった。関数脳への道は遠い...。
結果こうなった。

module Main exposing (Model, Msg(..), init, main, subscriptions, update, view)

import Browser
import Html exposing (..)
import Task
import Time



-- MAIN


main =
    Browser.element
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }



-- MODEL


type alias Model =
    { zone : Time.Zone
    , time : Time.Posix
    }


init : () -> ( Model, Cmd Msg )
init _ =
    ( Model Time.utc (Time.millisToPosix 0)
    , Task.perform SetSystemTime Time.now
    )



-- UPDATE


type Msg
    = Tick Time.Posix
    | SetSystemTime Time.Posix


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        Tick newTime ->
            ( { model | time = newTime }
            , Cmd.none
            )

        SetSystemTime newTime ->
            ( { model | time = newTime }, Cmd.none )



-- SUBSCRIPTIONS


subscriptions : Model -> Sub Msg
subscriptions model =
    Time.every 1000 Tick



-- VIEW


view : Model -> Html Msg
view model =
    let
        hour =
            Time.toHour model.zone model.time |> String.fromInt |> String.pad 2 '0'

        minute =
            Time.toMinute model.zone model.time |> String.fromInt |> String.pad 2 '0'

        second =
            Time.toSecond model.zone model.time |> String.fromInt |> String.pad 2 '0'
    in
    h1 [] [ text ("時間" ++ hour ++ ":" ++ minute ++ ":" ++ second) ]

Web NTLM認証、Pythonとrequests 対 PowerShell

とあるIISのWebアプリでログインにNTLM認証を使っているサイトをスクレイピングしたかった。 まずは所望のページをgetしたいぞと。

Pythonとrequestsでやってみた。最終的にこんな感じ。

import requests
from requests_negotiate_sspi import HttpNegotiateAuth

session = requests.session() # ログインした後クッキーとかのため
session.auth = HttpNegotiateAuth() # Windowsのカレントユーザで認証
res = session.get('どこかのURL')

ポイントは、requests-negotiate-sspi · PyPI これを使うとこで、Windowsのカレントユーザで認証してくれる。なんとスマートなコードではないか。(実はここにたどり着くまでに散々苦労したのだが...、結果よければ全てよし、ですね)

ここまでできたところで、ふと思った。どうせWindowsだけで使うモノなので、毒を食らわば皿まで郷に入っては郷に従え、ということで、PowerShellでやったらどうだろうか。結果こうなった。

$res = Invoke-WebRequest -Uri "どこかのURL" -SessionVariable session -UseDefaultCredentials

おおぅ、簡単にできるではないか。PowerShellならWindows環境のまんまで特に追加インストールもいらないしね。うれしい。

Ansibleで Raspberry Pi に Python 3.7 をインストールしてみる

急に思い立って、Ansibleを使ってみることにした。

こんなかんじになった。

### raspberry pi に Python3.7.2をインストール
---
- hosts: all
  vars:
    apt_for_python_build_names: [build-essential,zlib1g-dev,zlib1g-dev,libncurses5-dev,libgdbm-dev,libnss3-dev,libssl-dev,libreadline-dev,libffi-dev,wget]
    python_build_version: "3.7.2"
  tasks:
  - name: apt Update and Upgrade
    become: true
    apt:
      update_cache: "yes"
      force_apt_get: "yes"
      autoclean: "yes"
      autoremove: "yes"
      upgrade: "dist"
  - name: Python3.7のダウンロードと展開
    unarchive:
      src: "https://www.python.org/ftp/python/{{python_build_version}}/Python-{{python_build_version}}.tar.xz"
      dest: .
      remote_src: yes
  - name: apt for Python build.
    become: true
    apt:
      autoclean: "yes"
      autoremove: "yes"
      name: "{{apt_for_python_build_names}}"
  - name: Running ./configure for Python build.
    # command: ./configure --enable-optimizations
    command: ./configure #上はビルドにすごく時間がかかる testも全て実行されてしまう
    args:
      chdir: "./Python-{{python_build_version}}/"
  - name: make Python
    make:   # makeモジュールはmakeの引数が渡せない。make -j -l 4
      chdir: "./Python-{{python_build_version}}"
  - name: install Python
    become: true
    make:
      chdir: "./Python-{{python_build_version}}/"
      target: altinstall  #既存を上書きしないインストール
  - name: pip3をpip3.7に
    become: true
    command: python3.7 -m pip install --upgrade pip 
  # ビルドのためのaptインストールを削除
  - name: apt Remove for Python build.
    become: true
    apt:
      state: "absent"
      name: "{{apt_for_python_build_names}}"
      force_apt_get: "yes"
      purge: "yes"
      autoclean: "yes"
      autoremove: "yes"

Ansibleをほぼ初めて使ったら、なんかひどく苦労してしまった。インベントリって何だ?から始まって、YAMLもよく知らなかったのでインデントとハイフンの位置ですったもんだ。あと、unarchiveモジュールがremote_src: yesでネット上のsrcを指定できるの知らなかったのであれこれ遠回りした、などなど。ふぅ。疲れた。