ファイルのパーミッションを変更するコードを書く

Unix系ならばコマンドchmodを使ってファイルのパーミッションを変更する。
Pythonもos.chmodでできるが、指定できるmodeはint型だけを許容し、u+xのように指定できない。
Pythonでも文字列によりパーミッションを変更したい…
できるだけUnix系のchmodの機能に近づけたい欲とコードをシンプルに保ちたい欲との葛藤を経て、コードを書く。
import os

def get_delta(mode, delim):
	mode_shift = {'u': 6, 'g': 3, 'o': 0}
	mode_delta = {'r': 0b100, 'w': 0b010, 'x': 0b001}
	(owner, mode) = mode.split(delim, 1)
	if len(owner) == 0: owner = 'ugo'
	owner = owner.replace('a', 'ugo')
	owner = ''.join(set(owner))
	if len(mode) == 0: mode = 'rwx'
	mode = ''.join(set(mode))
	for o in owner:
		if not o in mode_shift: raise ValueError
	for m in mode:
		if not m in mode_delta: raise ValueError
	delta = 0b0
	delta0 = 0b0
	for m in mode: delta0 |= mode_delta[m]
	for o, shift_bit in mode_shift.items():
		if o in owner: delta |= delta0 << shift_bit
	return delta

def get_mode(path, mask=0o777):
	return os.stat(path).st_mode & mask

def set_mode(path, mode):
	if type(mode) is str and mode[:2] in ('0o', '0x'): mode = int(mode[2:], 8)
	if type(mode) is int: os.chmod(path, mode)
	if type(mode) is str:
		for mode in mode.split(','):
			mode = mode.strip()
			mask = 0o777
			delta = 0o0
			if '-' in mode: mask &= ~ get_delta(mode, '-')
			elif '+' in mode:
				delta = get_delta(mode, '+')
				mask &= ~ delta
			os.chmod(path, get_mode(path) & mask | delta)

# 試験
path = './sqlite.py'
for mode in (0o753, '0o753', '0x753', 'a+wr', 'u-wr', 'g+,o+r,u+w', 'ugo-,ug+x,g-x', 'a+,a-x'):
	set_mode(path, mode)
	print(oct(get_mode(path)))
2021/11/27 22:06
タグ