Pythonで月末、月初。ついでに月を加減するadd_months

月初はまあいいとしても、月末、月の足し引きは、こんな方法しか思いつかず。

カッコ悪いが使えることは使える、と思う。

2008.3.14追記

  • calendarモジュールを使って月の日数を取得することで、月末計算をシンプルに。
  • add_monthsも見直し。

それほどカッコ悪くはなくなったんじゃないかと思う。修正の経緯

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""月末、月初のdatetime.dateオブジェクトを返す。
Oracleのadd_months互換の月加減。
"""
import datetime
from calendar import monthrange

def first_day(date):
	"""月初を返す"""
	return datetime.date(date.year, date.month, 1)

def is_last_day(date):
	"""月末日付ならTrueを返す"""
	return days_of_month(date.year, date.month) == date.day

def days_of_month(year,month):
	"""年,月の日数を返す"""
	return monthrange(year, month)[1]

def last_day(date):
	"""月末を返す"""
	return datetime.date(year=date.year, month=date.month, day=days_of_month(date.year, date.month))

def add_months(date,months):
	"""月を加減する。
	dateにはdatetime.dateクラスのオブジェクト
	monthsには整数で月数を指定する。
	月末をOracleのadd_months互換の方法で処理する。
	例えば、
	2007年2月28日(月末)に1ヶ月足すと3月31日(月末)。
	2008年2月29日(月末)に1ヶ月足すと2008年3月31日(月末)。
	2008年2月28日(月末ではない)に1ヶ月足すと2008年3月28日(同じ日)。
	"""
	if months==0:
		return date

	year, month = divmod(date.month + months, 12)
	year = year + date.year

	#ちょうど割り切れたら12月で、マイナス1年。
	if month == 0:
		month = 12
		year = year - 1

	#入力日付がその月の月末なら、加算後月の日数を。
	#そうじゃなければ入力日付の日。
	day = date.day
	if date.day > days_of_month(year, month):
		day = days_of_month(year, month)
	return datetime.date(year=year, month=month, day=day)

最新版はGist:227554をどうぞ。

MoinMoinのカスタムユーザ認証スクリプトサンプル

MoinMoinを仕事で使いたい。今すでに使っている社内の認証機構を使ってユーザ管理を楽するためにはどうすればいいか? Pythonのちょっとしたスクリプトを書けばなんとかなるようだ。

ということで調べてみたら、

  1. wikiconfig.pyのConfigクラス内でカスタムスクリプトを使うように設定する。
  2. ログイン用のカスタムスクリプトを書いて、MoinMoin/auth/以下に置く。

の2つの手順でできることがわかった。MoinMoin-1.6で動くことを確認した。

以下、やってみて上手くいった手順を記録しておく。

この例では、

  • カスタムスクリプト内にユーザ情報を保持している。この部分を必要な認証機構を呼び出すようにすれば使えるはず。
  • メールアドレスと別名もMoinMoinのプロファイル外で管理していることにして、カスタムスクリプト内で設定管理している。

wikiconfig.pyの編集

class Config(DefaultConfig):
    """MoinMoinのカスタム認証スクリプトmyauth.loginを使うようにwikiconfig.py
    で認証方法を指定。
    """
    from MoinMoin.auth import moin_session,myauth
    auth = [myauth.login, moin_session]
    #MoinMoin内のPreferenceを自動的に作成する
    user_autocreate = True

Gist:232443

カスタム認証スクリプト MoinMoin/auth/myauth.py

# -*- coding: utf-8 -*-
"""MoinMoin custom user authentication sample
"""
from MoinMoin import user
#User Database
_USER_MAP = {'user1,pass1' : ('user1@example.com',u'user1'),
    'user2,pass2' : ('user2@example.com','user2')}

def login(request, **kw):
	username = kw.get('name')
	password = kw.get('password')
	login = kw.get('login')
	user_obj = kw.get('user_obj')

	if not login:
		return user_obj, True

	u = None
	user_info = _USER_MAP.get("%s,%s" % (username,password),False)

	if user_info:
		u = user.User(request,
		name=username,
		auth_username=username,
		password=password,
		auth_method='myauth',
		auth_attribs=('name', 'auth_username', 'password', 'email', 'aliasname', ))
		u.email = user_info[0]
		u.aliasname = user_info[1]
		u.create_or_update(True)
		request.log("Login OK. user=%s, email=%s, aliasname=%s." % (username,user_info[0],user_info[1]))

	return u, True

Gist:227564

ActiveDirectoryのLDAP認証もどき

python-ldapを使ってみた。

ついでに、以前から試そうと思って手をつけていなかった、ActiveDirectoryのLDAP認証も。試しに、bindしてみるだけ。平文でパスワードが流れるのでこのままではちょっと使えない。

#!/usr/bin/env python
# -*- coding: utf-8-*-
# python-ldapを使ってActiveDirectoryで認証してみる
# http://python-ldap.sourceforge.net/

def ADAuth(username,password,host,port=389):
    """ActiveDirectoryのドメイコントローラにユーザ名とパスワードでbindしてみる。
    bindできれば認証OK。認証NGなら例外が起きる。
    """
    import ldap
    url = "ldap://%s:%d" % (host,port)
    l = ldap.initialize(url)
    l.simple_bind_s(username,password)
    l.unbind_s()

if __name__=='__main__':
    if len(sys.argv)<3:
        print "Usage: %s username password" % (sys.argv[0])
    else:
        try:
            userid = sys.argv[1]
            password = sys.argv[2]
            ADAuth(userid,password,"adserver.example.com")
            print "OK"
        except:
            print "NG"

Gist:227565

Pythonで3桁区切りのカンマ挿入


str.format()でいけるようになりました。locale使うよりこっちがお手軽でよい場合が多いでしょう。
http://docs.python.jp/2/whatsnew/2.7.html#pep-378-format-specifier-for-thousands-separator

PHPでいうところのnumber_formatのように、3桁毎に位取りのカンマを入れる方法はどうするの?ってことで。

いろいろ探してみたところ、これがよさそう。

>>> import locale
>>> locale.setlocale(locale.LC_NUMERIC, 'ja_JP')
'ja_JP'
>>> locale.format('%d', 10000, True)
'10,000'
>>> locale.format('%.2f', 10000.00, True)
'10,000.00'
>>> locale.format('%.2f', 9999.999, True)
'10,000.00'
>>>

割り算

/で整数の割り算をすると切り捨てられるのが、なんか違和感あるって話になって調べてみると、そうだったのかあ。

調べてみるもんだ。

>>> 10/3
3
>>> from __future__ import division
>>> 10/3
3.3333333333333335
>>>

HTMLのタグを取り除く

作るの面倒だな、どこかにあるだろうなあ、と探してみるとこういうのが見つかった。

http://svn.gaplan.org/gaplan/trunk/wepylog/tools.py

この中のstriptagで解決。感謝。

追記:2008.2.7

久しぶりに探してみると、サイト自体がなくなっている。こっちで代用。 http://www.zope.org/Members/chrisw/StripOGram

追記:2009.10.7

最近は、BeautifulSoupとかlxmlを使うのが良さそう。

http://www.ghastlyfop.com/blog/2008/12/strip-html-tags-from-string-python.htmlより

from BeautifulSoup import BeautifulSoup
''.join(BeautifulSoup(page).findAll(text=True))

質問者もコメントしている人もオーバーヘッドが気に入らないっていってるけれど、僕の使い方では問題なし。