つぶやきテック

日々のつぶやきアウトプット

【Go】つぶやきos.Create()【エラー記録】

os.Create() でpermission errorに遭遇

os.Create()でファイル作成するコードで出会ったパーミッションエラーに関するメモです。

  • エラー起きたコード
package main

import (
    "log"
    "os"
)

func main() {
    fp, err := os.Create("hoge.txt")
    if err != nil {
        log.Println("[os.Create]:", err)
    }
    defer fp.Close()

    fp.WriteString("hogehoge")
}
  • 実行結果
$ go run main.go
2021/09/27 17:27:23 [os.Create]: open hoge.txt: permission denied

ファイルのパーミッションエラーかな?と思ったものの、よくよく調べるとディレクトリのパーミッションが原因のようでした。

package main

import (
    "log"
    "os"
)

func main() {
    /*
        os.Createでのエラー回避のため
        カレントディレクトリのパーミッション変更
        refs: https://stackoverflow.com/questions/58403134/go-permission-denied-when-trying-to-create-a-file-in-a-newly-created-directory
   */
    workDir, _ := os.Getwd()
    os.Chmod(workDir, 0777)

    fp, err := os.Create("hoge.txt")
    if err != nil {
        log.Println("[os.Create]", err)
    }
    defer fp.Close()

    fp.WriteString("hogehoge")
}

【jQuery】つぶやきattr()&prop()

"disabled"属性を制御したい

textareaとbuttonを関係づけるような実装でハマった話です。

  • やりたいこと

    • textareaに何か入力されたらbuttonを有効にする
    • textareaが空ならbuttonを無効にする(=disabled属性を付加する)
  • ぼくがかんがえたさいきょうのソースコード

    <textarea name="hoge" id="hoge" cols="30" rows="10"></textarea>

    <!-- 最初はdisabledにしとくで -->
    <button type="submit" id="huga" disabled>
        ボタンやで
    </button>
    <script>
        $(function() {
            $("#hoge").on('input', function(event) {
                // 入力されてるかどうかで属性を制御したるねん
                if ($(this).val() === "") {
                    $("#huga").attr('disabled')
                } else {
                    $("#huga").removeAttr('disabled')
                }
            })
        })
    </script>
  • 結果

f:id:fugithora812:20210922085926p:plain

うんうん。文字を入れてみる。

f:id:fugithora812:20210922085929p:plain

おお、よしよし。じゃあ一旦消してみよか。

f:id:fugithora812:20210922085943p:plain

あらら?

再度disabledが付かへん。

2種類の挙動をみせる.attr()

よくよく調べてみると、attr()には引数の数によって、2種類の挙動があるようでした。

①.attr(attributeName, value) :属性の追加

Set one or more attributes for the set of matched elements. (jQuery API Documentation より)

引数を2つとると、指定した要素に1つ以上の属性をセットします。imgのsrgなんかを追加するときに便利そうです。

<img id="image">
<script>
$(function(){
    $("#image").attr("src", "http://dummyurl.com/img/hoge.jpg");
});

②.attr(attributeName) :属性値の取得

Get the value of an attribute for the first element in the set of matched elements. (jQuery API Documentation)

引数が1つのとき、attrは与えた属性の値を取ってきます。

<img id="image" src="http://dummyurl.com/img/hoge.jpg">
<script>
$(function(){
    let url = $("#image").attr("src");
    // url の値は "http://dummyurl.com/img/hoge.jpg"
});

要するに、さっきの「さいきょうのソースコード」では、removeAttr()で属性を取り除くことはできたが、属性値を取得する方のattr()を使っているのでdisabledをセットできていないということだったんですね。

論理値にはprops()を

ということで結論を。

disabledのような、trueかfalseのどちらかをとるようなものを論理値といいますが、その制御にはprop()が使えます。

    <textarea name="hoge" id="hoge" cols="10" rows="3"></textarea>
    <button type="submit" id="huga" disabled>
        ボタンやで
    </button>
    <script>
        $(function() {
            $("#hoge").on('input', function(event) {
                if ($(this).val() === "") {
                    $("#huga").prop('disabled', true)
                } else {
                    $("#huga").prop('disabled', false)
                }
            })
        })
    </script>

正確には「属性」をとれるのがattr()、「プロパティ」を操作できるのがprop()ということだそうです。あ、propって"property"の略か!
(→.attr()と.prop()の違いは?

はー、勉強になった。メモメモ。

【Golang】つぶやきstrconv

strconv

strconvはgolangの組み込みパッケージで、数値やbool型をstring型に、もしくはstring型から他の型へコンバージョンする。

基本的な数値⇔文字列の変換

i, err := strconv.Atoi ("-42") // 文字列→数値
if err != nil {
    fmt.Printf("こらあかんで")
}

s := strconv.Itoa (-42) // 数値→文字列

Parse... : 文字列「からの」変換

他にも変換する型に合わせて、Parse...関数が定義されている。

b, err := strconv.ParseBool("true")

// "3.1415"をfloat64の精度で変換
f, err := strconv.ParseFloat("3.1415", 64)

// "-42"を10進数解釈、int64の精度で変換
i, err := strconv.ParseInt("-42", 10, 64)
u, err := strconv.ParseUint("42", 10, 64)

Format... : 文字列「への」変換

文字列への変換には、Format...関数が使える。

s := strconv.FormatBool(true)

// 第2引数'E':-d.ddddE±dd, 10の累乗
// 第3引数'-1':「ParseFloat が正確に f を返すために必要な最小桁数」。今後要学習
s := strconv.FormatFloat(3.1415, 'E', -1, 64)
s := strconv.FormatInt(-42, 16)
s := strconv.FormatUint(42, 16)

コード例は公式ドキュメントよりお借りしました。

つぶやきGo言語【セミコロン】

Golangをある程度触ってきた人にはジョーシキ的な部分かと思いますが、初心者がそれなりにつまづいた箇所のメモ書きです。

「文(Statement)」とセミコロン

Goでは各々の「文」はセミコロンによって区切られます。ただGoでは言語仕様として、「すべてのセミコロンが省略可能」です。

この仕様が、たとえば配列の要素を複数行にわたって定義したときに悪さすることがあります。

strs := [5]string{
    "Tarako",
    "Sake",
    "Konbu",
    "Karubi",
    "Umebosi"  // この行でコンパイルエラーが発生
} 

Goのコンパイラは、行末が「{」や「,」で終わるような場合を除いて、単純に「文の終端」であると判断します。

(『スターティングGo言語』松尾愛賀/SHOEISHA)

上のコードの場合は、末尾の要素に明示的にカンマを置くことで、「行の継続」を示すことができます。

strs := [5]string{
    "Tarako",
    "Sake",
    "Konbu",
    "Karubi",
    "Umebosi",  // カンマを付けるとエラーが消える
} 

つぶやきDatalad【調査メモ公開】

今回Dataladという、巨大なバイナリデータおよびそのメタデータのバージョンを管理する技術をがっつり調べたので、そのメモを公開します。マイナーな技術なので、このメモ書きが最初期の日本語記事かも?

もしDataladに触るよーという方がいらっしゃれば、公式のHandbookの補足的にこちらをご覧ください~。インストール等はHandbookの記述が参考になるかと思います。

では、どうぞ。

※以下、少し文体がかわります※

はじめに、参考サイトを

バージョン情報(7.10.2021現在)

  • python v3.6.9
  • Flask v2.0.1
  • datalad v0.13.7
  • git v2.32.0
  • git-annex v8.20210223-1

Datalad

ローカル環境における見た目は「.gitattributeを配下にもつディレクトリ」。

ちなみに、.gitattributeは「ディレクトリ内のGitの仕様を自分色に着せ替えする」ためのファイル。いうなればバージョン管理のリカちゃん人形だ(うん、わからん笑)。

  • Datalad createで作成されたディレクトリを「プッシュ」するには?
    • Githubのようなリモートのホスティングサービスとして、ginが利用できる

Datalad as a Python Module

install

  1. git-anexの導入
$ sudo apt install git-annex
  1. pipによるdatalad導入
$ python3 -m pip install datalad

※dataladモジュールの利用にはgit2.19.1以上が必要。最新版へのアップデートは以下のコマンドで行える

$ sudo add-apt-repository ppa:git-core/ppa
$ sudo apt update
$ sudo apt install git

また、git-annexについてもバージョン7.20190503以上が必要となる。 gitと同様に以下のコマンドでいけると思ったが、期待するバージョンにアップデートされなかった

git-annex ppa

$ sudo add-apt-repository ppa:kelleyk/git-annex
$ sudo apt update
$ sudo apt install git-annex

$ git-annex version
git-annex version: 6.20180409 ←本当は7.20190503以上にアップデートしたい
(...)

さらに調査をすすめたところ、neuro.debian.netからgit-annex-standaloneという形でstableなバージョンが導入できそうと判明。ページに案内されたコマンドを入力したが、公開鍵の受信でエラーが起きた

$ wget -O- http://neuro.debian.net/lists/bionic.jp.libre | sudo tee /etc/apt/sources.list.d/neurodebian.sources.list
$ sudo apt-key adv --recv-keys --keyserver hkp://pool.sks-keyservers.net:80 0xA5D32F012649A5A9 ←公開鍵と交換するためのフレーズ
Executing: /tmp/apt-key-gpghome.eay7BNfhX7/gpg.1.sh --recv-keys --keyserver hkp://pool.sks-keyservers.net:80 0xA5D32F012649A5A9
gpg: 鍵サーバからの受信に失敗しました: 名前がありません

→Ubuntuを再起動し実行すると導入できた。その後インストール完了

CLIからのメタデータ設定、取得

# 指定したkeyとvalueのメタデータを登録
$ git-annex metadata -s name='John' --force
metadata cn-xxxxx_%.datalad%metadata%objects%9d%.xz 
  name=John
  dmp-lastchanged=2021-06-30@05-41-55
  lastchanged=2021-06-30@05-41-55
ok
(recording state in git...)

# 指定したkeyのvalueを取得
$ git-annex metadata -g name
John

# メタデータ全取得
$ git-annex metadata -A
metadata MD5E-s2693891--e61afe4b3c5d76c849c4e61f6547ed03.pdf 

ok
metadata MD5E-s158--1bcead3da7178553bce385a261df4e47 
  name=John
  dmp-lastchanged=2021-06-30@05-06-55
  lastchanged=2021-06-30@05-06-55
ok
  • 上記と同様の動作をpythonで実現するには?
    • Datalad revolutionにdatalad.api.meta_extract()などが定義されている。これらを使う?

datalad_metalad (Datalad Revolution)

このモジュールはあくまでもDataladの拡張機能のような位置づけ。そのため、インポートもfrom datalad import apiというように、dataladモジュール風に指定する。

pipでモジュールをインストール、api.meta_dump()を試したところ空リストが表示された。

$ pip3 install datalad_metalad
Defaulting to user installation because normal site-packages is not writeable
Collecting datalad_metalad
...
Successfully installed datalad-metalad-0.2.1

$ python3
Python 3.6.9 (default, Jan 26 2021, 15:33:00) 
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from datalad import api
>>> dataset = api.Dataset('./Datalad-102')
>>> api.meta_dump(dataset=dataset, result_renderer='json')
[]

dumpの前に何か「まとめる」処理が必要なようだ。上に示したドキュメントをみると、api.meta_aggregate()という関数がある。ほうほう。

>>> api.meta_aggregate(dataset=dataset)
(aggregateされたJSONが出力される)

>>> api.meta_dump(dataset=dataset, result_renderer='json')
(メタデータのJSONが出力される)

対話型シェルだと少しみづらいが、ビンゴ。リストに入っているから、たぶん参照・表示の際はdatalad_dict[0]とかのように書いてあげれば良さそう。

(つづく・・かも)

つぶやきenum.auto

列挙型で連番を振る

最近になって、Pythonの列挙型で番号を順番に割り当てるときに使えるauto関数を知ったのでまとめてみます。

ちなみにPythonの列挙型(Enum)、公式ドキュメントはこちらです。

enum.auto

autoはpython3.6で追加されたヘルパークラスで、列挙型で定義した変数に連番を振る機能を提供します。

from enum import IntEnum, auto

class Post(IntEnum):
    """
    役職列挙型列挙型
    """
    STAFF = auto()           # 1
    SECTION_CHIEF = auto()  # 2
    GENERAL_MANAGER = auto() # 3

何が嬉しいの?

autoがナイとき…

autoを使わずに列挙型を実装した時、実際のコードは以下のような感じになると思います。

from enum import IntEnum

class Post(metaclass=IEnum):
    """
    役職列挙型列挙型
    """
    STAFF = 1
    SECTION_CHIEF = 2
    GENERAL_MANAGER = 3

上のコードにおいて、「変数STAFFを削除し、連番を"1"から振りなおす」という修正をすることになったとしましょう。

このとき、

  1. 変数STAFFの削除
  2. 変数SECTION_CHIEFの値を"1"に変更
  3. 変数GENERAL_MANAGERの値を"2"に変更

という3つのステップを踏む必要があります。

・・・メンドクサイよう(/ω\)

autoがアルときー!

そんな修正も、autoを使った実装にすると「STAFFを削除する」だけで済むようになります。また、その後「SECTION_CHIEFの前に新しく変数を定義し、"1"から連番を振る」という処理を実装する際にも、その行を加えるだけで修正が終わります。

んー、なかなかイイ感じ。

参考

最後に、参考になりそうなサイトを3つほどご紹介します。

追伸:記事の補足・訂正等ありましたらコメントいただけると幸いです!

【正規表現】漢字・ひらがな・カタカナだけを許可する【Python】

漢字・ひらがな・カタカナだけ

先日、Pythonのプログラムで「正規表現を使って漢字・ひらがな・カタカナだけを許可する」処理を書くにあたって、調べたことをアウトプットしてみます。

文字列全体が正規表現にマッチするか判定する

ある文字列の全体が、あらかじめ定義した正規表現にマッチするか調べるにはre.fullmatch()が使えるそう。

import re

num = r'^[1-9][0-9]{0,4}$'
re_num = re.compile(num)
print(re_num.fullmatch('123'))
# → <re.Match object; span=(0, 3), match='123'>

ちなみに、上のコード例でnumについているrraw文字列と呼ばれるもので、通常エスケープ文字となる\を単なる文字列として扱います。

公式ドキュメントでは、raw文字列を使った正規表現の定義が推奨されているようでした。

文字コードを利用したパターン作成

で、本題の「漢字・ひらがな・カタカナを許可する正規表現」ですが、結論から言うと「文字コードにおけるその範囲を指定する」という方法で実装できるようです。

import re

name = r'^[\u4E00-\u9FFF|\u3040-\u309F|\u30A0-\u30FF]{1,10} [\u4E00-\u9FFF|\u3040-\u309F|\u30A0-\u30FF]{1,10}$'
re_name = re.compile(name)
print(re_name.fullmatch('田中 ピコ太郎'))
# → <re.Match object; span=(0, 7), match='田中\u3000ピコ太郎'>

ぱっと見ではわかりにくいですが、unicodeにおいて漢字が定義されている範囲(\u4E00-\u9FFF)、ひらがなの範囲(\u3040-\u309F)、カタカナの範囲(\u30A0-\u30FF)を区切って記載しています。

ちなみにこのCJK統合漢字と呼ばれるunicodeの漢字のブロックでは、中国の簡体字・台湾の繁体字もまとめたうえで、部首順に並べています。この性質によって、Javaなどでunicodeの順に文字列をソートすると、漢字圏の人間から見て秩序を見出しにくい結果が得られることもあります。

参考

つぶやきgetattr

初見の関数があらわれた

先日、同僚が書いたpythonコードを拝見していて、以下のような実装を見つけました。

class GroupList:
    def __init__(self, item, classifier, modifier) -> None:
    """
    基準に基づいてグループ化されたリストを初期化する

    Args:
        item         グループ化の対象リスト
        classifier   グループ化の基準
        modifier     平均値計算の基準
    """
        (...)

        avg = avg + getattr(employee, modifier)()

        (...)

「従業員」オブジェクトの平均年齢を求める処理の一部にあったこのgetattrという関数、初見だったので調べてみました。

getattrとは

getattr()はprint()などと同様、Pythonの組み込み関数のひとつです。以下のような構文で使用します。

getattr([インスタンス], [メソッド名])([引数...])

この関数を使うと、リスト内のメソッドを順番に呼び出すといった処理が効率的に行えます。

class MyClass:
    def __init__(self):
        print("Test of getattr")
 
    def add(self, x, y):
        return x + y
 
    def sub(self, x, y):
        return x - y
 
    def mult(self, x, y):
        return x * y
 
    def divs(self, x, y):
        return x / y

myclass = MyClass()
x = 6
y = 2
 
calc_list = ['add', 'sub', 'mult', 'divs']
 
# リスト内のメソッドを順に呼び出し
for calc in calc_list:
    result = getattr(myclass, calc)(x, y)
    txt = calc + "の演算結果:"
    print(txt, result)

(コード参照元:【Python】getattrの使い方

冒頭に示したコード例では、引数でメソッド名を指定し、それを実行するというような処理が行われていました。要するに「動的なメソッド実行」をしたいときに真価を発揮しそうな関数です。

その他参考になりそうな記事

つぶやきDjango template

謎のタグ「 {% ... %} 」

Djangoに触れていると、HTMLファイルでみなれない表記を見かけることがあります。

{% load render_bundle from webpack_loader %}

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    {% render_bundle 'base' 'css' %}
    {% block external_header %}
    {% endblock %}
    <title>{% block title %}{% endblock %}</title>
</head>
<body>
    {% block content %}{% endblock %}

    {% render_bundle 'vendor' 'js' %}
    {% render_bundle 'base' 'js' %}

    {% block external_footer %}{% endblock %}
</body>
</html>

この{% ... %}で囲まれたタグは「テンプレートタグ」と呼ばれるもので、ざっくり言うと「この部分で決められた動きをするよ」というものです。

上のコード例だと、django-webpack-loaderが提供するテンプレートタグで、webpackでバンドルしたファイルを読み込んでいます

テンプレートタグを活用すると、繰り返し処理や条件分岐を扱うことはもちろん、フロントエンドで構築したReactのUIをwebpackでバンドルし、Djangoから読み取るといった連携もできるようになります。

参考

つぶやきemmet

emmet とは

  • HTMLやCSSをショートカット的に、簡潔に記述するツールです。
  • VScodeなど、特定エディタ向けのプラグインとして提供されています。
  • VScodeのsetting.jsonでは、タグ展開に関する設定を以下のように追記することができます。
  // Emmetの候補を表示 
  "emmet.showSuggestionsAsSnippets": true, 

  // TAB キーで Emmet を展開できるようにする
  "emmet.triggerExpansionOnTab": true, 

HTMLでのemmet記法

1つの要素の展開

h1
↓
<h1></h1>

ネストした要素の展開

div>a
↓
<div><a href=""></a></div>

同じ要素の繰り返し

ul>li*3
↓
<ul>
    <li></li>
    <li></li>
    <li></li>
</ul>

きょうだい要素の連続展開

h1+p
↓
<h1></h1>
<p></p>

要素へのID付与

div#thisIsId
↓
<div id="thisIsId"></div>

要素へのクラス付与

div.thisIsClass.content
↓
<div class="thisIsClass content"></div>

IDなどを連番にする

p.hoge$*3
↓
<p class="hoge1"></p>
<p class="hoge2"></p>
<p class="hoge3"></p>

要素にテキストを挿入する

a{this is link}
↓
<a href="">this is link</a>

CSSでのemmet記法

w100+h200+m10-0-10-10+tac
↓
width: 100px;
height: 200px;
margin: 10px 0 10px 10px;
text-align: center;

単位を指定しない場合、デフォルトでは「px」が指定されます。明示的に単位を指定すると他の単位にできます。

参考

Emmetで素早くHTML/CSSコーディング!書き方と対応ツールの紹介 | tracpath:Works