Windowsでのpipのアップデート(10.0.1⇒18.0)

PyCharmを入れてみたときにpip upgradeできなかったので備忘録

■現象
 ・PyCharmのterminalからpip upgradeを実行すると以下のエラー。
  pip listで見ると10.0.1のままだがpip upgradeすると最新バージョンとなっている。
 ・参考先と同じく強制再インストールすれば入る。
  

エラーログ + デバッグログ

(venv) D:\prog\work\deepleaning>pip list
Package    Version
---------- -------
pip        10.0.1
setuptools 39.1.0
You are using pip version 10.0.1, however version 18.0 is available.
You should consider upgrading via the 'python -m pip install --upgrade pip' command.

(venv) D:\prog\work\deepleaning>python -m pip install --upgrade pip
Collecting pip
  Using cached https://files.pythonhosted.org/packages/5f/25/e52d3f31441505a5f3af41213346e5b6c221c9e086a166f3703
d2ddaf940/pip-18.0-py2.py3-none-any.whl
Installing collected packages: pip
  Found existing installation: pip 10.0.1
    Uninstalling pip-10.0.1:
      Successfully uninstalled pip-10.0.1

  Rolling back uninstall of pip
Exception:
Traceback (most recent call last):
  File "D:\prog\work\deepleaning\venv\lib\site-packages\pip-10.0.1-py3.6.egg\pip\_internal\basecommand.py", line
 228, in main
    status = self.run(options, args)
  File "D:\prog\work\deepleaning\venv\lib\site-packages\pip-10.0.1-py3.6.egg\pip\_internal\commands\install.py",
 line 335, in run
    use_user_site=options.use_user_site,
  File "D:\prog\work\deepleaning\venv\lib\site-packages\pip-10.0.1-py3.6.egg\pip\_internal\req\__init__.py", lin
e 49, in install_given_reqs
    **kwargs
  File "D:\prog\work\deepleaning\venv\lib\site-packages\pip-10.0.1-py3.6.egg\pip\_internal\req\req_install.py",
line 748, in install
    use_user_site=use_user_site, pycompile=pycompile,
  File "D:\prog\work\deepleaning\venv\lib\site-packages\pip-10.0.1-py3.6.egg\pip\_internal\req\req_install.py",
line 961, in move_wheel_files
    warn_script_location=warn_script_location,
  File "D:\prog\work\deepleaning\venv\lib\site-packages\pip-10.0.1-py3.6.egg\pip\_internal\wheel.py", line 431,
in move_wheel_files
    generated.extend(maker.make(spec))
  File "D:\prog\work\deepleaning\venv\lib\site-packages\pip-10.0.1-py3.6.egg\pip\_vendor\distlib\scripts.py", li
ne 407, in make
    self._make_script(entry, filenames, options=options)
  File "D:\prog\work\deepleaning\venv\lib\site-packages\pip-10.0.1-py3.6.egg\pip\_vendor\distlib\scripts.py", li
ne 307, in _make_script
    self._write_script(scriptnames, shebang, script, filenames, ext)
  File "D:\prog\work\deepleaning\venv\lib\site-packages\pip-10.0.1-py3.6.egg\pip\_vendor\distlib\scripts.py", li
ne 243, in _write_script
    launcher = self._get_launcher('t')
  File "D:\prog\work\deepleaning\venv\lib\site-packages\pip-10.0.1-py3.6.egg\pip\_vendor\distlib\scripts.py", li
ne 386, in _get_launcher
    result = finder(distlib_package).find(name).bytes
AttributeError: 'NoneType' object has no attribute 'bytes'

■原因
 ・t64.exeを探しに行くが見つからないためNoneが戻され、Noneのbytesメンバーに
  アクセスしようとしている。
 ・PyCharmで作成したVirtualEnvを見ると、

初回は、D:\prog\work\base\venv\Lib\site-packages\pip-10.0.1-py3.6.egg\pip  
失敗後は、D:\prog\work\base\venv\Lib\site-packages\pip  

  とフォルダ構成が違うため、ただしフォルダパスを検索できていないようだ。
  違う原因はpip-10.0.1をeasy-installで展開したしただけになっているから?
  ※未確認、フォルダ名からの予想
 ・2回目の強制再インストールは、失敗後のpipから実行しているため
  正しく動作しているようだ。

■対策
 ・一応今のところ下記のどちらかで問題なく動いている。
  ①参考先と同じく強制再インストールすれば入る。
  ②VirtualEnvでProject作成後に、
   [PJFolder]\venv\Lib\site-packages\pip-10.0.1-py3.6.egg\pipフォルダを
   一つ上の階層([PJFolder]\venv\Lib\site-packages\pipフォルダ)に移動させる。

tomcat+springでindex.jspが表示される仕組み

理由が全然わからなかったが、ググったら見つかったのでメモ。

eclipseでspring legacy projectを作成した際に、なんでindex.jspが表示されるのかずっと分からなかったが、
以下のページに記載があった。

単純にtomcat先生がwelcome-pageの設定でindex.jspを読みだしているというオチだった。
※こういう時は動かすんじゃなくてエラーにしてくれるほうが、ありがたかった。。。


Spring - Springの超初歩、なぜindex.jspが表示されるのかが分かりません(74941)|teratail

tomcatのアーキテクチャ整理

eclipseでspringを使うことが増えそうなので、基礎を抑えるために
tomcatの構成を整理する。


f:id:osaka_taro:20170811214929p:plain

クライアントからの要求はConnectorを通して行われ、Serviceが対応するただ一つの
Engineへと結びつける。
Engineは要求を処理し、Connectorに返す動作となっている。
この図の中でWebアプリケーションはContextが該当する。

ドキュメントから、上記のアーキテクチャを元にxml(server.xml)を構成しており、
基本的にwebアプリを載せるだけなら以下の部分だけ触ればローカルでは問題ないはず。

1.Connectorタグはクライアントからの要求を待ち受けるportとprotocolの設定を行う。
2.Engineタグはdefaulthostの設定を行う。※Hostタグが存在している必要あり。
3.HostタグはappBaseの設定を行う。ここにはアプリの含まれる場所を記載する。
4.Contextタグはwebアプリの設定を行う。ここでは、docBaseにappBaseからの
  相対パスでアプリの格納場所を設定する。pathにはwebでアクセスしたときの
  別名を設定できる。


※ webアプリの開発については別ページ(参考元)を見てくれと書いてるので軽く見て
  みたが、量が多いので、webアプリの構成だけ目を通してあとは、飛ばした。
  springのdocumentに書いていると信じて・・・。


■参考元
アーキテクチャ概要
Apache Tomcat 8 Architecture (8.5.20) - Architecture Overview

コンフィグの概要
Apache Tomcat 8 Configuration Reference (8.5.20) - Overview

Webアプリケーション開発ガイド
Application Developer's Guide (8.5.20) - Table of Contents

sendMsg時にエンコードエラー(※追記あり)

skpyでメッセージを送るときに下記のエラー発生。

Traceback (most recent call last):
  File "main.py", line 32, in 
    sk.chats[sk.contacts[user].chat.id].sendMsg("Hello")
  File "build/bdist.linux-x86_64/egg/skpy/chat.py", line 142, in sendMsg
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)


ソースを見てると下記の部分で相手の名前を引っ張ってくるときにエンコードエラーが発生しているようだ。

        def __str__(self):
            return " ".join(filter(None, (self.first, self.last)))


というわけで以下のように修正すれば動く。

diff --git a/skpy/user.py b/skpy/user.py
index 46ae450..c68d926 100644
--- a/skpy/user.py
+++ b/skpy/user.py
@@ -47,7 +47,7 @@ class SkypeUser(SkypeObj):
         attrs = ("first", "last")
 
         def __str__(self):
-            return " ".join(filter(None, (self.first, self.last)))
+            return u" ".join(filter(None, (self.first, self.last))).encode('utf-8')
 
     @SkypeUtils.initAttrs
     @SkypeUtils.truthyAttrs


追記 別の個所でも同じ現象が発生。対応する。※grepして修正するのめんどい。

Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner
    self.run()
  File "main.py", line 53, in run
    print(v)
  File "build/bdist.linux-x86_64/egg/skpy/core.py", line 90, in __str__
    valStr = ("\n".join(str(i) for i in value) if isinstance(value, list) else str(value))
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)


diff --git a/skpy/core.py b/skpy/core.py
index a202b2a..10e9dcb 100644
--- a/skpy/core.py
+++ b/skpy/core.py
@@ -84,11 +84,11 @@ class SkypeObj(object):
 
         Nested objects are indented as needed.
         """
-        out = "[{0}]".format(self.__class__.__name__)
+        out = u"[{0}]".format(self.__class__.__name__).encode("utf-8")
         for attr in self.attrs:
             value = getattr(self, attr)
-            valStr = ("\n".join(str(i) for i in value) if isinstance(value, list) else str(value))
-            out += "\n{0}{1}: {2}".format(attr[0].upper(), attr[1:], valStr.replace("\n", "\n  " + (" " * len(attr))))
+            valStr = ("\n".join(unicode(i) for i in value) if isinstance(value, list) else unicode(value))
+            out += u"\n{0}{1}: {2}".format(attr[0].upper(), attr[1:], valStr.replace("\n", "\n  " + (" " * len(attr)))).encode("utf-8")
         return out

Couldn't retrieve t field from login response(追記あり)

便利そうだったので使ってみたが、エラーが出ていたので、gitからソースを落としてみて原因を調査してみた。

 

Traceback (most recent call last):
  File "D:\Users\corei7\Anaconda3\lib\site-packages\skpy\main.py", line 67, in __init__
    self.conn.readToken()
  File "D:\Users\corei7\Anaconda3\lib\site-packages\skpy\conn.py", line 286, in readToken
    raise SkypeAuthException("No token file specified")
skpy.core.SkypeAuthException: No token file specified

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "skypebot.py", line 4, in 
    Skype('xxxxxxxx', 'xxxxxxxx')
  File "D:\Users\corei7\Anaconda3\lib\site-packages\skpy\main.py", line 69, in __init__
    self.conn.getSkypeToken()
  File "D:\Users\corei7\Anaconda3\lib\site-packages\skpy\conn.py", line 264, in getSkypeToken
    self.liveLogin(user, pwd)
  File "D:\Users\corei7\Anaconda3\lib\site-packages\skpy\conn.py", line 361, in liveLogin
    self.tokens["skype"], self.tokenExpiry["skype"] = SkypeLiveAuthProvider(self).auth(user, pwd)
  File "D:\Users\corei7\Anaconda3\lib\site-packages\skpy\conn.py", line 535, in auth
    t = self.sendCreds(user, pwd, params)
  File "D:\Users\corei7\Anaconda3\lib\site-packages\skpy\conn.py", line 568, in sendCreds
    raise SkypeAuthException(errMsg, loginResp)
skpy.core.SkypeAuthException: ("Couldn't retrieve t field from login response", )

 

skpyのサイトの下記とソースを見てみたがおかしいところはなかったので、
SKype ログイン画面Chromeのdevtoolで見るとCkTstの頭文字にGがついていた。

なので、connn.pyの568行目を
"CkTst": "G"+str(int(time.time() * 1000))},
とするとエラーは出なくなった。
このあとチャットができるかは明日以降に確認する。

追記(2017/08/25 15:00)
下記のissuesを見てみるとロシアは修正なしでログイン可能。アメリカと日本はログイン失敗となっている。
国によって成否が変わるってどういうことだ。。。

https://github.com/OllieTerrance/SkPy/issues/66

 

さらに追記(2017/08/25 20:00)
パケットの中を見てると最初のログインページのGetに対してレスポンスでCkTstが入っているので以下のように修正すれよいが値が取れなかった時の挙動が決めきれない。
日本国内だとGを追加すればよいが他の国ではダメなところがあるのでいい修正ではなさそう。

 

diff --git a/skpy/conn.py b/skpy/conn.py
index 885d643..92887ec 100644
--- a/skpy/conn.py
+++ b/skpy/conn.py
@@ -545,9 +545,13 @@ class SkypeLiveAuthProvider(SkypeAuthProvider):
             raise SkypeApiException("Couldn't retrieve PPFT from login form", loginResp)
         if "MSPRequ" not in loginResp.cookies or "MSPOK" not in loginResp.cookies:
             raise SkypeApiException("Couldn't retrieve MSPRequ/MSPOK cookies", loginResp)
+        CkTst = "G"+str(int(time.time() * 1000))
+        if "CkTst" in loginResp.cookies:
+            CkTst = loginResp.cookies.get("CkTst")
         return {"MSPRequ": loginResp.cookies.get("MSPRequ"),
                 "MSPOK": loginResp.cookies.get("MSPOK"),
-                "PPFT": ppftReg.group(1)}
+                "PPFT": ppftReg.group(1),
+                "CkTst": CkTst}
 
     def sendCreds(self, user, pwd, params):
         # Now pass the login credentials over.
@@ -557,7 +561,7 @@ class SkypeLiveAuthProvider(SkypeAuthProvider):
                                                 "lw.skype.com&redirect_uri=https%3A%2F%2Fweb.skype.com%2F"},
                               cookies={"MSPRequ": params["MSPRequ"],
                                        "MSPOK": params["MSPOK"],
-                                       "CkTst": str(int(time.time() * 1000))},
+                                       "CkTst": params["CkTst"]},
                               data={"login": user, "passwd": pwd, "PPFT": params["PPFT"]})
         tField = BeautifulSoup(loginResp.text, "html.parser").find(id="t")
         if tField is None:

azure-c-shared-utility

azure-edgeのソース見てると、マクロ関連がいろいろ使われていたので、その定義先を調べてみた。

基本的にはazure-c-shared-utilityに定義が固まっているようだ。

 

github.com

 

一つ例を取り上げると、Lock_Init()だと、

azure_c_shared_utility/lock.hに以下の定義がある。

/**
 * @brief	This API creates and returns a valid lock handle.
 *
 * @return	A valid @c LOCK_HANDLE when successful or @c NULL otherwise.
 */
MOCKABLE_FUNCTION(, LOCK_HANDLE, Lock_Init);

また、新しいマクロか。。。ということで、結論だけでいくと、MOCKABLE_FUNCTIONの動作は置いておいて(マクロが長すぎて、読むのがつらい)

LOCK_HANDLE Lock_Init()に展開されています。※正確にはUnitテストができるように値を外から流し込めるように実装が展開されますが割愛。

2017/8/12追記 マクロで展開してみましたが、行数が多いため解析を断念。時間あるときに試すことにする。

ENABLE_MOCKSが無効な時は単に、プロトタイプ宣言として、マクロを展開するだけのようです。

また、Lock_Init()の説明は、azure-c-shared-utility/porting_guide.md at master · Azure/azure-c-shared-utility · GitHubにある。

C言語でテストを書いたことがないので、これ以降は、勉強のために追跡する。※修正予定

テスト関連はmock_cというライブラリを使っている。※目で追うのはさすがにつらいので、-Eオプションでプリプロセッサを展開させようかな。

#ifdef ENABLE_MOCKS

/* Codes_SRS_UMOCK_C_LIB_01_001: [MOCKABLE_FUNCTION shall be used to wrap function definition allowing the user to declare a function that can be mocked.]*/
#define MOCKABLE_FUNCTION(modifiers, result, function, ...) \
    MOCKABLE_FUNCTION_UMOCK_INTERNAL_WITH_MOCK(modifiers, result, function, __VA_ARGS__)

#include "umock_c.h"

#else

#include "azure_c_shared_utility/macro_utils.h"

#define UMOCK_C_PROD_ARG_IN_SIGNATURE(count, arg_type, arg_name) arg_type arg_name IFCOMMA(count)

/* Codes_SRS_UMOCK_C_LIB_01_002: [The macro shall generate a function signature in case ENABLE_MOCKS is not defined.] */
/* Codes_SRS_UMOCK_C_LIB_01_005: [**If ENABLE_MOCKS is not defined, MOCKABLE_FUNCTION shall only generate a declaration for the function.] */
/* Codes_SRS_UMOCK_C_LIB_01_001: [MOCKABLE_FUNCTION shall be used to wrap function definition allowing the user to declare a function that can be mocked.]*/
#define MOCKABLE_FUNCTION(modifiers, result, function, ...) \
    result modifiers function(IF(COUNT_ARG(__VA_ARGS__),,void) FOR_EACH_2_COUNTED(UMOCK_C_PROD_ARG_IN_SIGNATURE, __VA_ARGS__));

#endif

ENABLE_MOCKSが有効だと、MOCKABLE_FUNCTION_UMOCK_INTERNAL_WITH_MOCKが呼ばれ、無効だと FOR_EACH_2_COUNTEDが呼ばれる。

MOCKABLE_FUNCTION_UMOCK_INTERNAL_WITH_MOCKは以下のソースに定義がある。
 
github.com


FOR_EACH_2_COUNTEDは以下のソースに定義がある。

github.com

トランジスタ技術 2016年11月号 Part1

暇ができたので、RasberryPi3で遊べないかなーと日本橋をぶらぶらしてると遊び道具を見つけたので、購入。

とりあえず動かしてみて記事と違うことをしたらメモをしていく。

 

0.環境

作業PC:Windows10

 

1.Windosw10からRaspberryPi3へのリモートアクセスができない

 xrdpをインストールするだけではWindows⇒RaspberryPi3へのアクセスに失敗するので、下記のサイトを参考に環境構築を実施。

 

Raspberry Pi に RDP で接続できないときの対処 - Qiita

raspbian - error - problem connecting to Raspberry Pi 3 with xrdp - Raspberry Pi Stack Exchange

 

$sudo apt-get remove xrdp
$sudo apt-get install tightvncserver
$sudo apt-get install xrdp

 

2.リモートデスクトップ時のキーボード設定

これも記事通りではできなかったので、以下のサイトを参考に設定する。

 

Raspberry Pi でリモートデスクトップ - Qiita

 

#cd /etc/xrdp/
$sudo wget http://w.vmeta.jp/temp/km-0411.ini
$sudo ln -s km-0411.ini km-e0010411.ini
$sudo ln -s km-0411.ini km-e0200411.ini
$sudo ln -s km-0411.ini km-e0210411.ini

 

3.スクリーンショット取得用のソフトの導入

 ブログの記事を書くようにスクリーンショットを取得するソフトを導する。下記のサイトの「ksnapshot」を使用する。

 

Raspberry Piのスクリーンショット | S2

 

#cd /etc/xrdp/
$sudo apt-get install ksnapshot

 

4.デフォルトエディタの変更

 デフォルトのエディタがnanoになっているので、vimをインストールして

vimが起動するように変更した。

 

$sudo apt-get install vim
$sudo update-alternatives --congif editor