みおもん倶楽部 技術雑記 (original) (raw)
いつも恒例のn番煎じシリーズいきます。
やること
pythonスクリプト(docstring付き)をhtmlファイルのドキュメントに変換します。 docstring自体の記法はここでは触れません。
事前準備
pipでパッケージを入れておきます。
pip install sphinx
あとで使うので、テーマファイルも入れます。
pip install sphinx_rtd_theme
ソースコードを用意
. └── src ├── entry.py ├── mod1.py └── mod2.py
上記のような感じでpythonファイルをいくつか用意します。とりあえずdocstringがちょっと書かれていれば中身はなんでもいいです。 ここでは以下のような感じでざっくり書いてみました。
entry.py
from mod1 import split_basename, compute_awesome_value, check_list_has_even_length from mod2 import DownCounter
def main(): """ エントリーポイント
以下の関数を順に実行する
- split_basename
- compute_awesome_value
- check_list_has_even_length
- DownCounterのインスタンス作成
- DownCounterのtickメソッドを5回実行
"""
rev1 = split_basename("hello/world.txt")
rev2 = compute_awesome_value(2, 3.4, True)
rev3 = check_list_has_even_length([1, 2, 3])
print(rev1)
print(rev2)
print(rev3)
counter = DownCounter(5, 1)
for _ in range(5):
counter.tick()
if name == "main": main()
mod1.py
def split_basename(filepath: str) -> str: """ファイルパスからベース名を取得する
Args:
filepath (str): ベース名を取得するファイルパス
Returns:
str: ファイルパスのベース名
"""
return filepath.split('/')[-1]
def compute_awesome_value(i: int, f: float, multiple: bool) -> float: """条件に基づいて素晴らしい値を計算する
Args:
i (int): 整数値
f (float): 浮動小数点数
multiple (bool): 掛け算または足し算を行うかを示すブール値
Returns:
float: 算術演算の結果
"""
if multiple:
return i * f
else:
return i + f
def check_list_has_even_length(numlist: list[int]) -> bool: """リストの長さが偶数かどうかを確認する
Args:
numlist (list[int]): 整数のリスト
Returns:
bool: リストの長さが偶数の場合はTrue、そうでない場合はFalse
"""
if type(numlist) is not list:
return False
return len(numlist) % 2 == 0
mod2.py
class DownCounter: """ カウンタ機能を持ったクラス
Attributes:
count: カウンタの値
Methods:
- increment: カウンタを1増やす
- decrement: カウンタを1減らす
- set: カウンタの値を設定する
- get: カウンタの値を取得する
"""
initial_count: int
count: int
step: int
def __init__(self, count: int = 100, step: int = 1):
"""
カウンタ値とstepを初期化する
Args:
count: カウンタの初期値、デフォルトは100
step: カウンタを増減させる値、デフォルトは1
"""
if type(count) is not int:
raise ValueError("count must be an integer")
if type(step) is not int:
raise ValueError("step must be an integer")
if count < 0:
raise ValueError("count must be a non-negative integer")
if step < 0:
raise ValueError("step must be a non-negative integer")
self.initial_count = count
self.count = count
self.step = step
def tick(self):
"""
カウンタ値を1減らし、0未満になった場合は警告を出力する
"""
self.count -= self.step
if self.count <= 0:
print("beep beep beep!!")
def reset(self):
"""
カウンタ値を初期値にリセットする
"""
self.count = self.initial_count
ドキュメントの雛形生成
sphinx-apidoc
で作っていきます。
sphinx-apidoc ./src -a -F -o docs
いろいろファイルが生成されますが、ビルドに関わる設定はconf.py
に対して行います。
説明
-a
:conf.py
に./src
を追加、ただし絶対パスなので、複数人で持ち回る場合は相対パスに書き換えた方がよいと思います-F
: ビルドに必要なあれこれ(Makefileとか)も同時に作成します-o docs
: 出力先を指定します
-a
についてはこんな感じです。
import os import sys sys.path.insert(0, '../src')
他にもオプションがありますが、詳しく以下からご確認ください。
https://www.sphinx-doc.org/ja/master/man/sphinx-apidoc.html
ファイル構成は以下のようになります。
. ├── docs │ ├── Makefile │ ├── _build │ ├── _static │ ├── _templates │ ├── conf.py │ ├── entry.rst │ ├── index.rst │ ├── make.bat │ ├── mod1.rst │ └── mod2.rst └── src ├── entry.py ├── mod1.py └── mod2.py
ドキュメントのビルド
docsに移動してビルドしていきます。
Makefileの確認
以下のような内容になっています。
Minimal makefile for Sphinx documentation
You can set these variables from the command line, and also
from the environment for the first two.
SPHINXOPTS ?= SPHINXBUILD ?= sphinx-build SOURCEDIR = . BUILDDIR = _build
Put it first so that "make" without argument is like "make help".
help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" (SPHINXOPTS)(SPHINXOPTS) (SPHINXOPTS)(O)
.PHONY: help Makefile
Catch-all target: route all unknown targets to Sphinx using the new
"make mode" option. (O)ismeantasashortcutfor(O) is meant as a shortcut for (O)ismeantasashortcutfor(SPHINXOPTS).
%: Makefile @$(SPHINXBUILD) -M @"@ "@"(SOURCEDIR)" "$(BUILDDIR)" (SPHINXOPTS)(SPHINXOPTS) (SPHINXOPTS)(O)
sphinx-build
のラッパとして動作するようです。
単にmakeするとhelpが表示されるようなので、試してみます。
Sphinx v7.2.6 Please use `make target' where target is one of html to make standalone HTML files dirhtml to make HTML files named index.html in directories singlehtml to make a single large HTML file pickle to make pickle files json to make JSON files htmlhelp to make HTML files and an HTML help project qthelp to make HTML files and a qthelp project devhelp to make HTML files and a Devhelp project epub to make an epub latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter latexpdf to make LaTeX and PDF files (default pdflatex) latexpdfja to make LaTeX files and run them through platex/dvipdfmx text to make text files man to make manual pages texinfo to make Texinfo files info to make Texinfo files and run them through makeinfo gettext to make PO message catalogs changes to make an overview of all changed/added/deprecated items xml to make Docutils-native XML files pseudoxml to make pseudoxml-XML files for display purposes linkcheck to check all external links for integrity doctest to run all doctests embedded in the documentation (if enabled) coverage to run coverage check of the documentation (if enabled) clean to remove everything in the build directory
いざビルド
htmlターゲットがあるので、それを実行してみましょう。
make html
ビルドできたようです。
. ├── docs │ ├── Makefile │ ├── _build │ │ ├── doctrees │ │ │ ├── entry.doctree │ │ │ ├── environment.pickle │ │ │ ├── index.doctree │ │ │ ├── mod1.doctree │ │ │ └── mod2.doctree │ │ └── html │ │ ├── _modules │ │ │ ├── entry.html │ │ │ ├── index.html │ │ │ └── mod1.html │ │ ├── _sources │ │ │ ├── entry.rst.txt │ │ │ ├── index.rst.txt │ │ │ ├── mod1.rst.txt │ │ │ └── mod2.rst.txt │ │ ├── _static │ │ │ ├── alabaster.css │ │ │ ├── basic.css │ │ │ ├── custom.css │ │ │ ├── doctools.js │ │ │ ├── documentation_options.js │ │ │ ├── file.png │ │ │ ├── language_data.js │ │ │ ├── minus.png │ │ │ ├── plus.png │ │ │ ├── pygments.css │ │ │ ├── searchtools.js │ │ │ └── sphinx_highlight.js │ │ ├── entry.html │ │ ├── genindex.html │ │ ├── index.html │ │ ├── mod1.html │ │ ├── mod2.html │ │ ├── objects.inv │ │ ├── py-modindex.html │ │ ├── search.html │ │ └── searchindex.js │ ├── _static │ ├── _templates │ ├── conf.py │ ├── entry.rst │ ├── index.rst │ ├── make.bat │ ├── mod1.rst │ └── mod2.rst └── src ├── pycache │ ├── entry.cpython-312.pyc │ ├── mod1.cpython-312.pyc │ └── mod2.cpython-312.pyc ├── entry.py ├── mod1.py └── mod2.py
ビルド結果
alabaster entry
alabaster mod1
alabaster mod2
とりあえず情報は出揃っているようです。
テーマを変える
少しテーマが味気ないように感じるので、よく見る感じのテーマに変えてみます。
conf.py
を少しいじります。
- html_theme = 'alabaster'
- html_theme = 'sphinx_rtd_theme'
Makefileのあるディレクトリに移動してもう一度ビルドします。
make html
rtd entry
rtd mod1
rtd mod2
いい感じです。
ソースを更新したら
./src/
配下のpythonスクリプトを編集した場合は、もう一度 make html
を実行すればhtmlファイルに変更が反映されます。
dockerで立てたコンテナにsshでアクセスして開発を行いたいなと思いました。
N番煎じもいいところですが、ちょっとハマったので記録を残しておきます。
目指すもの
- イメージはubuntu
- 認証方式は公開鍵認証、パスワード認証はしない。
~/.ssh/terminal
、~/.ssh/terminal.pub
というキーペアを作成する- アクセス方法は
ssh localhost -p 2222 -i ~/.ssh/terminal
- rootではなく作成したユーザでログインする(macやlinuxでは
$USER
で現在のユーザを参照できますが、その値でユーザを作成します) - ポートは2222
ファイル構成
. ├── Dockerfile ├── docker-compose.yaml └── setup.sh
Dockerfile
FROM ubuntu:latest
ビルド時、new_userという引数を受け取る
ARG new_user
ユーザを作成
RUN useradd -ms /bin/bash ${new_user}
sshディレクトリを作成
RUN mkdir /home/${new_user}/.ssh
公開鍵をコピー(terminal.pubが存在している必要がある)
COPY terminal.pub /home/${new_user}/.ssh/authorized_keys
sshサーバとsudoコマンドをインストール
RUN apt update && apt install -y openssh-server sudo && apt clean
ひとまずパスワードを設定、あとで変えたほうがいい
RUN echo "${new_user}:password" | chpasswd
sudoに追加
RUN gpasswd -a ${new_user} sudo
ssh用のディレクトリを作成
RUN mkdir /var/run/sshd
パスワードを使用したログインを許可しない
RUN sed -i -r 's/^#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
公開鍵認証を許可
RUN sed -i -r 's/#AuthorizedKeysFile/AuthorizedKeysFile/' /etc/ssh/sshd_config
ポートを22から2222に変更
RUN sed -i -r 's/^#Port 22/Port 2222/' /etc/ssh/sshd_config
RUN /usr/sbin/sshd
EXPOSE 2222
ENTRYPOINT [ "/usr/sbin/sshd", "-D" ]
docker-compose.yaml
version: "3" services: terminal: build: args: - new_user=${USER} context: . dockerfile: Dockerfile container_name: terminal privileged: true tty: true ports: - "2222:2222"
new_user=${USER}
の部分では、ホスト側の環境変数を使用しています。 別の名前を使用したい場合はここを変更します。
ボリュームをマウントしたい場合、dnsを設定したい場合、他のコンテナを付け足したい場合、適宜改造してください。
setup.sh
手元ではコンテナが起動していたら止めるとか、キーペアが存在してたら中止するとかを付け加えていますが、その部分は省略して、エッセンスだけ抜粋します。
ssh-keygen -t ed25519 -C "" -f ~/.ssh/terminal -N ""
cp ~/.ssh/terminal.pub .
docker compose up -d --build
ssh localhost -p 2222 -i ~/.ssh/terminal
実行手順
上記記載済みですが、terminal.pub
を用意してdocker compose up
を実行すればOKです。
xxxxxxxx@yyyyyyyy zzzzzzzz % ./setup.sh
[+] Building 0.0s (15/15) FINISHED docker:desktop-linux
=> [terminal internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 880B 0.0s
=> [terminal internal] load metadata for docker.io/library/ubuntu:latest 0.0s
=> [terminal internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [terminal 1/10] FROM docker.io/library/ubuntu:latest 0.0s
=> [terminal internal] load build context 0.0s
=> => transferring context: 595B 0.0s
=> CACHED [terminal 2/10] RUN useradd -ms /bin/bash xxxxxxxx 0.0s
=> CACHED [terminal 3/10] RUN mkdir /home/xxxxxxxx/.ssh 0.0s
=> CACHED [terminal 4/10] COPY terminal.pub /home/xxxxxxxx/.ssh/authorized_keys 0.0s
=> CACHED [terminal 5/10] RUN apt update && apt install -y openssh-server && apt clean 0.0s
=> CACHED [terminal 6/10] RUN mkdir /var/run/sshd 0.0s
=> CACHED [terminal 7/10] RUN sed -i -r 's/^#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config 0.0s
=> CACHED [terminal 8/10] RUN sed -i -r 's/#AuthorizedKeysFile/AuthorizedKeysFile/' /etc/ssh/sshd_config 0.0s
=> CACHED [terminal 9/10] RUN sed -i -r 's/^#Port 22/Port 2222/' /etc/ssh/sshd_config 0.0s
=> CACHED [terminal 10/10] RUN /usr/sbin/sshd 0.0s
=> [terminal] exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:fbe41ddbf46c8601b2709640c58c66f311c66628c5cc53b0429877270bf0bad2 0.0s
=> => naming to docker.io/library/zzzzzzzz-terminal 0.0s
[+] Running 1/2
⠙ Network zzzzzzzz_default Created 0.1s
✔ Container terminal Started 0.1s
xxxxxxxx@yyyyyyyy zzzzzzzz % ssh localhost -p 2222 -i ~/.ssh/terminal Welcome to Ubuntu 22.04.1 LTS (GNU/Linux 6.6.16-linuxkit aarch64)
- Documentation: https://help.ubuntu.com
- Management: https://landscape.canonical.com
- Support: https://ubuntu.com/advantage
This system has been minimized by removing packages and content that are not required on a system that users do not log into.
To restore this content, you can run the 'unminimize' command.
The programs included with the Ubuntu system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright.
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law.
xxxxxxxx@c264796d36c0:~$
以下の情報は置き換えています。
- ログインユーザ名:
xxxxxxxx
- ホストPCのホスト名:
yyyyyyyy
- 作業ディレクトリ名:
zzzzzzzz
Dockerfile
とかdocker-compose.yaml
は雰囲気で書いていますので、変な部分あるかもしれません。
serdeはserializeとdeserializeを行うクレートです。
関数を呼んで機能を実現する「わかりやすいライブラリ」ではなく、インターフェースというか、プロトコルというか、1段メタな機能を実現するツールであるように思います。attributeで目印をつけ、たとえばserde_jsonという別クレートで実際のシリアライズ・デシリアライズを行うと理解しています。
以下、jsonとstructの相互変換を行う例を雑にまとめてみます。
必要クレート
serde = { version = "1.0.130", features = ["derive"] } serde_json = "1.0.68"
準備
use serde::{Deserialize, Serialize}; use std::fs;
#[derive(Serialize, Deserialize, Debug)] struct Person { name: String, age: u8, }
structからJSON
serde_json::to_writer(&mut file, &p)
JSONからstruct
serde_json::from_reader::<std::fs::File, Person>
もしくは
serde_json::from_str::(&content)
全体
use serde::{Deserialize, Serialize}; use std::fs;
const JSON_FILE_NAME: &str = "person.json";
#[derive(Serialize, Deserialize, Debug)] struct Person { name: String, age: u8, }
fn gen_json() { let json = r#" { "name": "John Doe", "age": 43 } "#;
let p: Person = serde_json::from_str(json).unwrap();
let mut file = std::fs::File::create(JSON_FILE_NAME).unwrap();
serde_json::to_writer(&mut file, &p).unwrap();
println!("{:?}", p);
}
fn read_json_fs() { let file = std::fs::File::open(JSON_FILE_NAME).unwrap();
match serde_json::from_reader::<std::fs::File, Person>(file) {
Ok(p) => println!("{:?}", p),
Err(e) => println!("error: {}", e),
}
}
fn read_json_str() { let content = fs::read_to_string(JSON_FILE_NAME).unwrap();
match serde_json::from_str::<Person>(&content) {
Ok(p) => println!("{:?}", p),
Err(e) => println!("error: {}", e),
}
}
fn main() {
read_json_fs();
read_json_str();
}
結果のJSON
{"name":"John Doe","age":43}
JSONの値を不正にしてみる
{"name":"John Doe","age":1000}
注:Personのageはu8
fn main() {
read_json_fs();
read_json_str();
}
結果
error: invalid value: integer 1000
, expected u8 at line 1 column 30
error: invalid value: integer 1000
, expected u8 at line 1 column 29
上記、jsonとstructの例でしたが、例えばHashMapとstructではこうもいかないと思います。 なぜかというと、HashMapはkeyとvalueが静的に決まっている必要があり、nameを取得したらStringだけど、ageを取得したらu8、というような表現力がHashMapにはないからです。(というかそういうことをしたいならstruct)
あるいはHashMapに全部stringで入れて(u8も"20"などのようにStringで入れる)、structと相互変換する、も方法としてはアリかもしれませんが、まあだったらJSONでいいのでは、と思っています。
何を思ってこんなことを書いているかというと、なんらかのデータをデータベースから取得し、一時的にHashMapに入れ、structに変換するのはアリなのか?と思ったのですが、HashMapよりはjsonなどの方が取り回ししやすそうだね、と思った次第です。
無論、データベースから値を取るならそれ用のクレートを使うべきです。(serde_dynamodbなど)
注意:Linux or macユーザを想定しています。windowsユーザも、細部は異なると思いますが、適用可能なはずです。
キーペアの作成
キーペアのディレクトリへ移動します
cd ~/.ssh
キーペアを生成します。ED25519にしますが、RSAとかでもいいと思います。
ssh-keygen -t ed25519
以下のような画面になるはずです。
username@hostname .ssh % ssh-keygen -t ed25519 Generating public/private ed25519 key pair. Enter file in which to save the key (/Users/username/.ssh/id_ed25519): github⭐️1 Enter passphrase (empty for no passphrase):⭐️2 Enter same passphrase again:⭐️2 Your identification has been saved in github Your public key has been saved in github.pub The key fingerprint is: SHA256:xa/hogehogehogehogehogehogehoge/w username@hostname.local
⭐️1 キー名を入力します。github、gitlab、codecommitなど使い分けるならそれがわかるように、もしくはデフォルトのままにして使い回してもOKです。ここではgithubと入力することにします。
⭐️2 パスフレーズを入力しますが私は普段空欄です。現場のルールに従ってください。
キーの登録
以下のURLを開いてください。
https://github.com/settings/keys
以下のような画面になるはずです。
sshkeyの登録画面
ここでNew SSH Keyをクリックします。以下のような画面になるはずです。
キーペアの登録画面
- Titleは識別しやすい名前ならなんでもいいですが、私はmacにつけたホスト名をつけてます。他の端末からもアクセスすることがあるのですが、それが識別できればOKかと思います。
- Keyにはキーペアのうち公開鍵の情報を登録します。秘密鍵は登録しないように。
なお、公開鍵は以下のコマンドで取得できます。
cat ~/.ssh/github.pub
キーを登録
github側の作業はこれでOKですが、もうちょっと続きます。
~/.ssh/configの設定
~/.ssh/configファイルを設定します。
編集コマンドはviでもcatでもなんでもいいですが、macではopenコマンドを使えば、多少不慣れな人でも操作可能かと思います。
open ~/.ssh/config
以下の内容を追加します。キー名は適宜置き換えてください。
Host github github.com Hostname github.com IdentityFile ~/.ssh/github User git
接続確認のために、以下を実行します。
ssh -T git@github.com
以下のように表示されれば成功です。
username@hostname .ssh % ssh -T git@github.com Hi Username! You've successfully authenticated, but GitHub does not provide shell access.
追記:sshとは
そもそもsshとはSecure SHellの略で、ネットワーク経由で他のPCにアクセス・操作するための、クライアントとサーバ構成のプロトコルです。ごく簡単に言えば、sshクライアントがLinuxコマンドをネットワーク経由で送り付け、sshサーバがそれを解釈して実行し、その結果をネットワーク経由で送り返す、という挙動になります。(さらにいうと、Linuxコマンドを送るだけがsshではない)
種々のコマンドの実行を許可するので認証が当然必要になるのですが、大雑把にIDパスワードを使う方法とキーペアを使う方法があり、特に後者は公開鍵認証と呼ばれます。キーペアのうち公開して良い方(公開鍵)をsshサーバにあらかじめ登録しておき、認証時にはsshクライアントのみが持っているはずの秘密鍵を使って認証をするというものですが、詳しい挙動は適宜ググってください。
さて本題ですが、githubではローカル環境と接続する際に、httpとsshの2種類の方法で認証をすることが可能です。httpではIDとパスワード、sshではキーペアを用いた認証をするようです。ただ、githubへのアクセスにあたりsshを使ってLinuxコマンドを送りつけるのかというと、少なくともユーザがsshで接続し、Linuxコマンドを送りつけるということはありません。内部で何らかの形で使っていると思われますが、詳細を知らなくてもgithubは使えるので、気にしないことにします。
ViteでSvelteをざっくり動かしてみる
create-viteパッケージをインストール
npm install -g create-vite
svelteプロジェクトを作成する
create-vite my-svelte-app --template svelte
ディレクトリに移動
cd my-svelte-app
依存をインストール
npm install
開発サーバを起動
npm run dev
以下のアドレスとポートでWebサーバプログラムが起動するので、アクセスしてみる。 ポートは環境によって変わるかもしれないので、ターミナルのメッセージを確認。
npm run devの結果
表示されたアドレスにアクセス。"Count is XXX"をクリックすると値が増える。
コンポーネントを作成
./my-svelte-app/src/lib/Hello.svelte
を以下のように作成。
Hello.svelteを追加してみる
5行目と23〜25行目を追加
もう一度以下にアクセスすると、画面が少し変わる
Click meが増えている
Click meをクリックしてみると
予想通り、alert関数が実行される
今回はdockerを使って、postgresサーバの環境を準備する方法について書いてみます。
dockerの環境が構築済みであることが前提です。 未構築の方はこちらもどうぞ。
Postgresサーバ
dockerを使ってサーバをたてます。
オフィシャルイメージはこちらから確認できます。
起動方法はシンプルで、以下のコマンドでpostgresサーバの起動を行います。
docker run -p 5432:5432 -e POSTGRES_PASSWORD=mysecretpassword -d postgres
ちょっとだけ補足を入れておくと
-p 5432:5432
を指定することで、localhost:5432
に対するパケットを受けると、POSTGRESコンテナの5432へポートフォワードされます。よくわからない場合は、dockerでTCPとかUDPをしたい時のおまじないであると考えてください。-e POSTGRES_PASSWORD=mysecretpassword
を指定することで、環境変数POSTGRES_PASSWORD
に値mysecretpassword
をセットします。POSTGRESコンテナは、これをユーザpostgres
のパスワードであると解釈します。-d
を指定することで、バックグラウンドで起動させておきます。
Postgresクライアント
次に、このサーバに接続して、動作確認をするために、クライアントソフトpsql
をローカル環境にインストールします。 いつものごとく、homebrewを使ってインストールを行いますが、入れるパッケージはlibpq
です。libpqの詳細はこちらを参照していただければと思いますが、大事な箇所だけ抜き出すと
libpq is the C application programmer's interface to PostgreSQL. libpq is a set of library functions that allow client programs to pass queries to the PostgreSQL backend server and to receive the results of these queries.
あとは
libpq is also the underlying engine for several other PostgreSQL application interfaces, including those written for C++, Perl, Python, Tcl and ECPG.
あたりでしょうか。要するに、Cで書かれたクライアントソフトであり、他の言語からも使用されることがある、くらいの理解を私はしています。
ということで、インストールを以下のコマンドで行います。
brew install libpq
バイナリの置かれるパスを、環境変数PATHに追加しろ、と指示がありますので、これも実行します。 環境によってはzshrcではなくzprofileが良いかもしれませんので、適宜置き換えてください。
echo 'export PATH="/opt/homebrew/opt/libpq/bin:$PATH"' >> ~/.zshrc
注意:homebrewでインストールしたバイナリがどこに置かれるかは環境によって異なりそうです。画面に表示されたコマンドを実行してください。
その後シェルの再起動、もしくは設定ファイルの再読み込みを行って、ようやくpsqlが実行できるようになるはずです。
なお、設定ファイルの再読み込みは以下です。
source ~/.zshrc
以下のコマンドでインストールされていることを確認します。
psql --version
以下のようなメッセージが出れば成功です。
psql (PostgreSQL) 15.2
接続確認
では、満を持してサーバへの接続確認を行いましょう
まずは、以下のコマンドで接続をします。
psql -h localhost -p 5432 -U postgres
続いて、パスワードを尋ねられるので、環境変数にセットしたmysecretpassword
を入力します。
以下の画面が表示されたら成功です。あとはお好きなSQLを書いて楽しみましょう。
postgres=#
GUIをインストールする
おまけで、GUIのインストール方法も書いておきます。 (実のところ、私はあまり使ったことがありません)
homebrewで以下のツールをインストールしましょう
brew install --cask pgadmin4
参考までに、homebrewのformulaeはこちら、本家のサイトはこちら。
起動するとこんな感じになります。
なお、マスタパスワードの作成を求められると思いますので、適当に作成しておきましょう。
Serversを右クリック -> Register -> Serverを選んで
サーバを識別するための任意の名前と
ホスト名もしくはアドレス、そしてパスワード(上の例ではmysecretpassword
)をいれます。
接続成功したのち、右クリックメニューなどでテーブルを作成できます。
その後、Create ScriptでSQLスクリプトを作成し、お好きなSQLを書いて楽しみましょう。
Pythonスクリプトを実行してみる
おまけその2として、PythonからPostgresに接続してみます。
Pythonはインストールされている前提です。
psycopg2のインストール
以下を実行して、Pythonから接続するためのツールをインストールします。
pip3 install psycopg2-binary
なお、以下のコマンドでもソースのダウンロード -> clangでビルド -> インストールできるようです。
pip3 install psycopg2
が、私の環境ではssl関連のライブラリが参照できない?などの理由でビルドに失敗しているようでした。 調べれば解決できそうでしたが、面倒だったのでビルド済みのバイナリだけを取ってくることにしました。
データを書き込む
「ポケモン csv」などで検索し、ヒットしたデータを使用させていただき、データベースに格納してみたいと思います。
import psycopg2 import csv
connection = psycopg2.connect(host='localhost', user='postgres', password='mysecretpassword', database='pokemon')
with connection: with connection.cursor() as cursor:
sql = "DROP TABLE IF EXISTS monsters;"
cursor.execute(sql)
sql = "CREATE TABLE monsters (\
id serial PRIMARY KEY, \
pokedex_number smallint, \
name varchar(255), \
base_total smallint, \
attack smallint, \
defense smallint, \
sp_attack smallint, \
sp_defense smallint, \
speed smallint, \
hp smallint \
);"
cursor.execute(sql)
sql = "DROP TABLE IF EXISTS types;"
cursor.execute(sql)
sql = "CREATE TABLE types (\
id serial PRIMARY KEY, \
pokedex_number smallint, \
type varchar(255) \
);"
cursor.execute(sql)
with open('pokemon.csv') as f:
for row in csv.reader(f):
monsterinfo = row[:9]
typeinfo = row[-2:]
if monsterinfo[0] == 'pokedex_number':
continue
sql = "INSERT INTO monsters (pokedex_number, name, base_total, attack, defense, sp_attack, sp_defense, speed, hp) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)"
cursor.execute(sql, monsterinfo)
for t in typeinfo:
if t == '':
continue
sql = "INSERT INTO types (pokedex_number, type) VALUES (%s, %s)"
cursor.execute(sql, (monsterinfo[0], t))
sql = "DROP TABLE IF EXISTS affinities;"
cursor.execute(sql)
sql = "CREATE TABLE affinities (\
id serial PRIMARY KEY, \
attacker varchar(255), \
defender varchar(255), \
magnifier real \
);"
cursor.execute(sql)
with open('affinity.csv') as f:
header = []
for i, row in enumerate(csv.reader(f)):
if i == 0:
header = [r.strip() for r in row]
continue
t0 = row[0].strip()
for t1 in header[1:]:
t1 = t1.strip()
mag = float(row[header.index(t1)])
sql = "INSERT INTO affinities (attacker, defender, magnifier) VALUES (%s, %s, %s)"
cursor.execute(sql, (t0, t1, mag))
connection.commit()
pokemon.csv
はこんな感じ。
pokedex_number,name,base_total,attack,defense,sp_attack,sp_defense,speed,hp,type1,type2 1,フシギダネ,318,49,49,65,65,45,45,grass,poison 2,フシギソウ,405,62,63,80,80,60,60,grass,poison 3,フシギバナ,625,100,123,122,120,80,80,grass,poison 4,ヒトカゲ,309,52,43,60,50,65,39,fire, 5,リザード,405,64,58,80,65,80,58,fire, 6,リザードン,634,104,78,159,115,100,78,fire,flying
以下を参考にさせていたきました。ありがとうございます。
https://gist.github.com/leoyuholo/b12f882a92a25d43cf90e29812639eb3
affinity.csv
はこんな感じ。
" ",normal, fire, water, electric, grass,ice, fighting, poison, ground, flying,psychic, bug, rock,ghost, dragon,dark, steel, fairy normal,1,1,1,1,1,1,1,1,1,1,1,1,0.5,0,1,1,0.5,1 fire,1,0.5,0.5,1,2,2,1,1,1,1,1,2,0.5,1,0.5,1,2,1 water,1,2,0.5,1,0.5,1,1,1,2,1,1,1,2,1,0.5,1,1,1 electric,1,1,2,0.5,0.5,1,1,1,0,2,1,1,0.5,1,0.5,1,1,1 grass,1,0.5,2,1,0.5,1,1,0.5,2,0.5,1,0.5,2,1,0.5,1,0.5,1 ice,1,0.5,0.5,1,2,0.5,1,1,2,2,1,1,1,1,2,1,0.5,1 fighting,2,1,1,1,1,2,1,0.5,1,0.5,0.5,1,2,1,1,2,2,0.5 poison,1,1,1,1,2,1,1,0.5,0.5,1,1,1,0.5,0.5,1,1,0,2 ground,1,2,1,2,0.5,1,1,2,1,1,1,0.5,2,1,1,1,2,1 flying,1,1,1,0.5,2,1,2,1,1,1,1,2,0.5,1,1,1,0.5,1 psychic,1,1,1,1,1,1,2,2,1,1,0.5,1,1,1,1,1,0.5,1 bug,1,0.5,1,1,2,1,0.5,0.5,1,0.5,2,1,1,0.5,1,2,0.5,0.5 rock,1,2,1,1,1,2,0.5,1,0.5,2,1,2,1,1,1,1,0.5,1 ghost,0,1,1,1,1,1,1,1,1,1,2,1,1,2,1,0.5,1,1 dragon,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,0.5,0 dark,1,1,1,1,1,1,0.5,1,1,1,2,1,1,2,1,0.5,1,0.5 steel,1,0.5,0.5,0.5,1,2,1,1,1,1,1,1,2,1,1,1,0.5,2 fairy,1,0.5,1,1,1,1,2,0.5,1,1,1,1,1,1,2,2,0.5,1
こちらを使用させていただきました、ありがとうございます。
https://sironekolab.com/archives/6012
ちょっと遊んでみる
ポケモンのリストをとりあえず表示してみます。
種族値の合計が600を超えるポケモンで、ほのおタイプを持つものを表示してみたいと思います。SQL的に正しいかはよくわかりません。
ポケモンのタイプを横持ちに変換
dockerをMacに入れる方法について書いてみたいと思います。
方法は色々あるかと思いますが、私はもっぱらhomebrewしか使っていません。 これはdockerに限らず、何かソフトウェアを入れたいときはhomebrewにパッケージがあるかどうかをまずは確認し、なければ渋々dmgを探してインストールしています。
まず、homebrewが入っているかの確認をするには、ターミナルから以下を実行してください。
brew --version
入っていれば、以下のような結果が返ってくるはずです。
Homebrew 4.0.15 Homebrew/homebrew-core (git revision 830070c393f; last commit 2023-02-18) Homebrew/homebrew-cask (git revision 1a8cad145c; last commit 2023-02-18)
もし入っていなかったら以下を実行してください。
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
なお、こちらが公式サイトです。気になる方はこちらも参考にしてください。
ちなみに、パッケージの検索はこちらからできます。
Dockerのインストール
以下のコマンドをターミナルから実行してください。
brew install --cask docker
Dockerのエンジン管理にGUIを使うので、--caskオプションをつけています。
Dockerアカウントの作成
こちらからアカウントの作成をしてください。支払い情報などの入力は不要です。
Dockerエンジンの起動
dockerではエンジンとなるプロセスがまずは起動します。これを起動しておかないとdockerコマンドを実行しても成功しません。
spotlightなどからdockerを起動すると良いでしょう。
docker spolight
正常に起動していれば、以下のようなアイコンがメニューバーに出ているはずです。
docker icon in menubar
最後に動作確認をしてみます。docker
コマンドの詳細な使い方は置いておくとして、以下のコマンドで動作確認ができます。
docker run hello-world
以下の結果が出力されていれば、正常に動作しています。 また、最初の5行は手元にコンテナイメージがない場合、つまり初回などに出力されるメッセージです。
Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world 7050e35b49f5: Pull complete Digest: sha256:4e83453afed1b4fa1a3500525091dbfca6ce1e66903fd4c01ff015dbcb1ba33e Status: Downloaded newer image for hello-world:latest
Hello from Docker! This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
- The Docker client contacted the Docker daemon.
- The Docker daemon pulled the "hello-world" image from the Docker Hub. (arm64v8)
- The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading.
- The Docker daemon streamed that output to the Docker client, which sent it to your terminal.
To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/
For more examples and ideas, visit: https://docs.docker.com/get-started/
ひとまず、ここまで完了すれば、dockerのインストールは完了です。