作成されたpython scriptをpyinstallerを用いてMacOSのアプリを作れます。
最初僕はpy2appを使用しましたが結果ファイルサイズが以下のように違いました。
- Py2appの結果:35MB
- Pyinstallerの結果:25MB
 Pyinstallerを使わないわけがないでしょう。
 インストールはPIPで可能になりまして。(昨年はできませんでした)
pip install pyinstaller
それで完了
pyinstallerの駆動は*.specファイルを通じてするのがお勧めです。
specファイルの基本構造は下のようです。
# -*- mode: python -*-
# filename = Main.spec
a = Analysis(['Main.py'],
             pathex=['/Users/.../ProgramNameDir'],
             hiddenimports=[],
             hookspath=None,
             runtime_hooks=None)
pyz = PYZ(a.pure)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='Main',
          debug=False,
          strip=None,
          upx=True,
          console=False , icon='mainIcon.ico')
app = BUNDLE(exe,
             name='Main.app',
             icon='mainIcon.ico')
この場合はmain.pyを読んでMain.appを作ります。iconはmainIcon.icoをかぶります。
Main.pyは ”/Users/.../ProgramNameDir”に存在し、その下の "./lib"のlibファイルを参考しています。なので *.specファイルが"./lib"を認識できるように少し修正します。
# -*- mode: python -*-
# filename = Main.spec
### 個人の./libsを認識するためのコード ###
import sys 
myLibPath = './libs'
sys.path.append(myLibPath)
############################
a = Analysis(['Main.py'],
             pathex=['/Users/.../ProgramNameDir'],
             hiddenimports=[],
             hookspath=None,
             runtime_hooks=None)
pyz = PYZ(a.pure)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='Main',
          debug=False,
          strip=None,
          upx=True,
          console=False , icon='mainIcon.ico')
app = BUNDLE(exe,
             name='Main.app',
             icon='mainIcon.ico')
もう一つの問題があります。Main.pyでは /Users/.../ProgramNameDir/img内のイメージ・ファイルをつかいます。これはsys.path.appendで追加しても最終のアプリでは読めません。イメージ・ファイルをハンドリング仕組みが違うからです。
pyinstallerで作られたアプリが駆動する際、必要なファイル(イメージ・ファイルなど)は臨時フォルダ(temp folder)内「_MEIPASS」という場所でコピーします。だから*.pyコード内に「_MEIPASS」を認識させる必要があります。
Main.pyでこの関数を追加します。
def resource_path(relative):
  if hasattr(sys, "_MEIPASS"):
      return os.path.join(sys._MEIPASS, relative)
  return os.path.join(relative)
そしてコード内のイメージ参照こどを変換します。
例え:
"./img/Title.png" --> resource_path("./img/Title.png")
*.specファイルにはTree()を追加します。
# -*- mode: python -*-
# filename = Main.spec
import sys 
myLibPath = './libs'
sys.path.append(myLibPath)
a = Analysis(['Main.py'],
             pathex=['/Users/.../ProgramNameDir'],
             hiddenimports=[],
             hookspath=None,
             runtime_hooks=None)
pyz = PYZ(a.pure)
exe = EXE(pyz,
Tree('img',prefix='img'), #<--追加するイメージがあるフォルダ名
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='Main',
          debug=False,
          strip=None,
          upx=True,
          console=False , icon='mainIcon.ico')
app = BUNDLE(exe,
             name='Main.app',
             icon='mainIcon.ico')
僕はMacBook proを使っています。即ちRetina Displayを使っています。pyinstallerで作られたアプリをそのまま作るとRetina Displayの上にはメッセージ・ボックスとかダイアログが滲んで見えるので醜いです。
それを解決するためBUNDLEにinfo_plistを追加します。
# -*- mode: python -*-
# filename = Main.spec
import sys 
myLibPath = './libs'
sys.path.append(myLibPath)
a = Analysis(['Main.py'],
             pathex=['/Users/.../ProgramNameDir'],
             hiddenimports=[],
             hookspath=None,
             runtime_hooks=None)
pyz = PYZ(a.pure)
exe = EXE(pyz,
Tree('img',prefix='img'), 
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='Main',
          debug=False,
          strip=None,
          upx=True,
          console=False , icon='mainIcon.ico')
app = BUNDLE(exe,
             name='Main.app',
        info_plist={ 'NSHighResolutionCapable': 'True'}, #<-- Option for High Resolution
             icon='mainIcon.ico')
これで大体におわりです。
pyinstaller Main.spec
でアプリができます。
py2exeとかpy2appの場合は事例がずいぶんあるけどpyinstallerの場合はあんまりないので整理のため記録しました。