zookeeper와 연동하는 kazoo를 python3로 업그레이드하면서 알게된 내용이다.




python2에서는 바이트 문자열(byte string)이라는 것은 무시되었다.



A prefix of 'b' or 'B' is ignored in Python 2; it indicates that the literal should become a bytes literal in Python 3 (e.g. when code is automatically converted with 2to3). A 'u' or 'b' prefix may be followed by an 'r' prefix.



그러나, python3부터는 바이트 문자열을 b또는 B로 쓰이게 되었다.


Bytes literals are always prefixed with 'b' or 'B'; they produce an instance of the bytes type instead of the str type. They may only contain ASCII characters; bytes with a numeric value of 128 or greater must be expressed with escapes.





즉 저장할 때 문자열은 encode()로,


 value.encode()


읽을 때는 decode()로 읽는다.


value.decode()






Posted by 김용환 '김용환'



python3에서 


jinja2.exceptions.UndefinedError: 'len' is undefined 해결하려면


'|length'를 이용한다.


{% node.data|length == 0 %}


Posted by 김용환 '김용환'


flask의 테스트 코드를 실행할 때 사용되는 툴은 다음과 같다.


$ tox -e flake8,py27



tox는 표준 툴이다.

https://tox.readthedocs.io/en/latest/




pyenv를 사용하고 있다면 다음과 같이 설치후 사용할 수 있다.


pip install -r requirements.txt -i http://proxy.google.com/pypi/simple/ --trusted-host proxy.google.com

~/.pyenv/shims/tox -e flake8,py27


Posted by 김용환 '김용환'


아래와 같이 select의 컬럼과 from의 테이블이 서로 다르다.(사실 이게 되기도 한다)


SELECT distinct kibanaauth_esidx.esidx

FROM kibanaauth_role role



이전 쿼리는 kibanaauth_role와 kibanaauth_esidx가 다르기 때문에 조인을 할 수 없다.


sql_alchemy의 query()를 join()과 함께 쓸 때는 

내부적으로 SQL의 select와 from 뒤에 query() 매개 변수에 포함되는 모델의 테이블을 무조건 적용하게 된다.







그래서 아래와 같이 select와 from을 동일한 테이블이 나오도록 쿼리를 수정한 후,, 


SELECT DISTINCT kibanaauth_esidx.esidx AS kibanaauth_esidx_esidx

FROM kibanaauth_esidx 



아래와 같이 sql_alchemy 문을 만들어서 테스트해보니. 조인이 된다.


aaa = session.query(LogAuthServiceTag.esidx).distinct() \

                    .join(LogAuthRoleServiceTag, LogAuthServiceTag.id == LogAuthRoleServiceTag.esidx_id) \

                    .join(LogAuthRole, LogAuthRole.id == LogAuthRoleServiceTag.role_id) \

                    .join(LogAuthRoleUser, LogAuthRoleUser.role_id == LogAuthRole.id) \

                    .join(LogAuthUser, LogAuthUser.id == LogAuthRoleUser.user_id) \

                    .filter(LogAuthUser.userid == userid)



query() 문에 여러 모델을 넣어도 sql_alchemy가 내부적으로 조합하기 때문에 

상황에 따라서는 from이 이상하게 나올 수 있다. 


복잡하게 sql_alchemy 를 사용할 때는 SQL 문장을 디버깅하면서 확인해야 한다.





다시 얘기하면. 



session.query(Post) \

       .join(User, Post.author_id == User.id)



이 문장은 다음과 같이 변환될 것이다.  query()의 매개 변수는 select, from으로 넘어갔다(항상 그런 것은 아니지만, 대개 그렇다.)


select post

from post 

inner join user 

   on post.author_id == user.id




Posted by 김용환 '김용환'



python의 sql_alchemy에서 3개의 테이블을 조인하고 특정 사람의 권한을 보고 싶은 쿼리가 있다.



select role.role

from 

(user join roleuser on user.id = roleuser.user_id)

left join role role on roleuser.role_id = role.id

where user.userid = 'sma'



python의 sql_alchemy는 다음과 같이 코딩한다.



                instance = session.query(Role.role)\

                    .join(RoleUser, User.id == RoleUser.user_id) \

                    .outerjoin(Role, RoleUser.role_id == Role.id) \

                    .filter(User.userid == userid)



조인된 다른 테이블을 보려면 다음과 같다.


                instance = session.query(Role.role)\

                    .join(RoleUser, User.id == RoleUser.user_id) \

                    .outerjoin(Role, RoleUser.role_id == Role.id) \

                    .filter(User.userid == userid) \

                   .add_entity(RoleUser) \

                   .add_entity(User) \

Posted by 김용환 '김용환'



파이썬의 sql_alchemy에서 SQL을 디버깅하려면 다음과 같이 str을 사용해야 한다..



                instance = session.query(...) \

                    .filter(...) \

                    .outerjoin((..))


                print(str(instance))

                

Posted by 김용환 '김용환'


flask 개발 중에 다음과 같은 에러를 발견했다.


  File "/Users/samuel.kim/.pyenv/versions/2.7.12/lib/python2.7/site-packages/flask/app.py", line 1051, in add_url_rule

    'existing endpoint function: %s' % endpoint)

AssertionError: View function mapping is overwriting an existing endpoint function: xxx




이 이유는 서로 다른 URL에서 동일한 Controller 클래스를 사용하면 발생한다.


즉, 다음과 같은 형태로 호출되는 것을 의미한다.



api.add_resource(AuthServiceController,'/authorization') 


api.add_resource(AuthServiceController,'/authentication') 




각 URL 마다 서로 다른 Controller를 수정하면 정상적으로 동작된다. 

Posted by 김용환 '김용환'


python에는 Java의 toString()과 같은 문법이 있다. 




>>> import datetime

>>> today = datetime.datetime.now()

>>> str(today)

'2018-01-23 14:49:37.284361'

>>> repr(today)




>>> f=1.1111111111111111

>>> str(f)

'1.11111111111'

>>> repr(f)

'1.1111111111111112'




str은 사용자가 보기 편하게 "비공식"적으로 쓰는 문자열(반드시) 표현법이고,

repr은 시스템에서 구분하기 위한 공식적연 표현법이며 문자열이 아니어도 된다.



https://docs.python.org/3.7/reference/datamodel.html#object.__repr__


object.__repr__(self)

Called by the repr() built-in function to compute the “official” string representation of an object. If at all possible, this should look like a valid Python expression that could be used to recreate an object with the same value (given an appropriate environment). If this is not possible, a string of the form <...some useful description...> should be returned. The return value must be a string object. If a class defines __repr__() but not __str__(), then __repr__() is also used when an “informal” string representation of instances of that class is required.


This is typically used for debugging, so it is important that the representation is information-rich and unambiguous.


object.__str__(self)

Called by str(object) and the built-in functions format() and print() to compute the “informal” or nicely printable string representation of an object. The return value must be a string object.


This method differs from object.__repr__() in that there is no expectation that __str__() return a valid Python expression: a more convenient or concise representation can be used.


The default implementation defined by the built-in type object calls object.__repr__().



Posted by 김용환 '김용환'

[python] datetime 예제

python 2017.11.20 11:35


파이썬에는 datetime 클래스를 통해 시간을 제어할 수 있다.


현재 시간을 확인하려면 now()를 호출한다.


>>> import datetime

>>> datetime.datetime.now()

datetime.datetime(2017, 11, 20, 11, 27, 46, 820594)



크리스마스까지의 남은 시간을 구하는 예제이다. 현재 시간에서 12월 25일까지의 시간을 


>>> datetime.datetime.now() - datetime.datetime(2017, 12, 25)

datetime.timedelta(-35, 41357, 474997)


사실 이는 정확치 않다. 직접 날짜를 지정하면 된다.


>>> datetime.datetime(2017,12,25)-datetime.datetime(2017,11,20)

datetime.timedelta(35)



timestamp를 구하고 싶다면 timestamp()를 호출한다.


>>> datetime.datetime.now().timestamp()

1511145029.058472




일주일 전 날을 알고 싶다면 datetime.timedelta를 사용한다.


>>> datetime.datetime.now()- datetime.timedelta(days=7)

datetime.datetime(2017, 11, 13, 11, 35, 24, 933742)


Posted by 김용환 '김용환'




SyntaxError: Non-ASCII character '\xec' in file oncall-bot.py on line 50, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details


이 에러는 한글 때문에 발생한 것이다. mac에는 문제 없으나 linux에서 발생했다. 


code에 utf-8 인코딩 설정을 추가하니 더 이상 문제가 발생하지 않는다. 

# -*- coding: utf-8 -*- 


Posted by 김용환 '김용환'