[Python] YAPF

Python 2017. 3. 11. 14:59

YAPF

구글에서 제공하는 python Formatter


원래는 기존에 제공하는 autopep8을 사용하려고 했지만, 좀더 효율적인 포멧터를 찾아보려고 찾는 중에, 구글에서 제공하는 yapf 라는 포맷터를 찾았다.


이 포맷터에 대해서 포스팅 해보려고 한다.


지금 현재 잘 알려진 포맷터는 autopep8이랑, pep8ify가 있는데, 기본적으로 lint에서 나오는 Error을 해결하려고 만들어 졌다.


그런데 해당 포맷터들은 제한적일 수 밖에없는데, 어떤 것이냐면, PEP 8의 가이드를 정확히 따르고 있는 코드라면, 해당 코드들은 포맷팅을 하지 않는다.


pep8의 가이드만 준수한다고 해당 코드가 좋다고 볼수 없다.


YAPF는 다른방법으로 포맷팅을 하는데, Daniel Jasper가 개발한 'clang-format'을 기반으로 한다.


이 알고리즘은 코드를 가지고 와서 스타일 가이드를 준수하는 최상의 포맷으로 다시 포맷한다.

즉, PEP8의 가이드를 정확히 따르고 있는 코드더라도 다시 Reformatting 을 할 수 있다는 뜻이다.


Installation


설치방법은 간단하다.


$ pip install yapf

해당 방법으로 설치하면 되지만 YAPF는 계속적으로 바뀔수 있으므로, 가장 최신 버전을 유지하는 가장 좋은 방법은 저장소를 복제하는 방법이다.


Usage

옵션은 아래와 같다.


usage: yapf [-h] [-v] [-d | -i] [-r | -l START-END] [-e PATTERN]
            [--style STYLE] [--style-help] [--no-local-style] [-p]
            [files [files ...]]

Formatter for Python code.

positional arguments:
  files

optional arguments:
  -h, --help            show this help message and exit
  -v, --version         show version number and exit
  -d, --diff            print the diff for the fixed source
  -i, --in-place        make changes to files in place
  -r, --recursive       run recursively over directories
  -l START-END, --lines START-END
                        range of lines to reformat, one-based
  -e PATTERN, --exclude PATTERN
                        patterns for files to exclude from formatting
  --style STYLE         specify formatting style: either a style name (for
                        example "pep8" or "google"), or the name of a file
                        with style settings. The default is pep8 unless a
                        .style.yapf or setup.cfg file located in one of the
                        parent directories of the source file (or current
                        directory for stdin)
  --style-help          show style settings and exit
  --no-local-style      don't search for local style definition (.style.yapf)
  -p, --parallel        Run yapf in parallel when formatting multiple files.
                        Requires concurrent.futures in Python 2.X

Formatting style

YAPF에서 사용하는 STYLE은 얼마든지 설정을 구성할 수 있고, 서식을 지정하는 여러가지 방법들이 있습니다.

코드안에 style.py을 참조하면 전체리스트를 볼수 있습니다.


스타일을 제어하려면 --style 아규먼트를 사용하면 됩니다. 이미 구성되어진 사전 정의된 스타일 ( EX : pep8 또는 google )중 하나를 선택하거나 원하는 구성파일을 직접 지정해도 됩니다.


설정 파일은 [스타일] 표제가 있는 key = value 쌍의 간단한 목록입니다 . 아래를 보시죠.


[style]
based_on_style = pep8
spaces_before_comment = 4
split_before_logical_operator = true

아래와 같은 방법으로 사용가능합니다.


--style='{based_on_style: chromium, indent_width: 4}'

YAPF는 다음과 같은 방식으로 서식 스타일을 검색합니다.


1. 커맨드라인 

2. 현재나, 상위 디렉토리중 하나에 있는 .stype.yapf파일.


2개 찾는법이 있으나 생략 (보통 위2가지를 지정해서 사용할거 같으므로) 없으면


기본적으로 PEP8 방식을 사용함.


Example

어떤식으로 포맷팅 되는지 봅시다.


x = {  'a':37,'b':42,

'c':927}

y = 'hello ''world'
z = 'hello '+'world'
a = 'hello {}'.format('world')
class foo  (     object  ):
  def f    (self   ):
    return       37*-+2
  def g(self, x,y=42):
      return y
def f  (   a ) :
  return      37+-+a[42-x :  y**3]


포멧팅!


x = {'a': 37, 'b': 42, 'c': 927}

y = 'hello ' 'world'
z = 'hello ' + 'world'
a = 'hello {}'.format('world')


class foo(object):
    def f(self):
        return 37 * -+2

    def g(self, x, y=42):
        return y


def f(a):
    return 37 + -+a[42 - x:y**3]


'Python' 카테고리의 다른 글

Pycharm 에서 무조건 세팅해줘야 할것.  (0) 2017.05.18
[Flask] Flask - wsgi - nginx 연동.  (0) 2017.05.15
[Python] python getter setter  (0) 2017.02.16
[Python] 공부해야 할 것.  (0) 2017.02.15
[Python]pywin32 설치기.  (0) 2016.12.15
Posted by C마노
,

다음과 같이 프로그램을 실행한 사용자가 터미널을 종료하면 프로그램도 함께 종료가 된다.

./[실행파일]

이럴 때 nohup을 사용하면 사용자가 터미널을 종료해도 프로그램이 계속 살아있게 된다.

1. nohup
nohup은 리눅스에서 쉘스크립트파일을 데몬형태로 실행시키는 명령어이다.
nohup으로 실행을 시키려면 실행파일 권한이 755이상으로 되어있어야 한다.
뒤에 &를 추가하면 백그라운드로 실행한다.
nohup으로 프로그램을 실행시키면 nohup.log라는 로그 파일이 생성된다.

$nohup [실행파일]
$nohup [실행파일] & // 백그라운드 실행

2. 로그 안 남도록 하는 nohup
nohup으로 프로그램을 실행하면 nohup.log라는 로그가 남게 된다.
로그파일을 안 남게 하려면 다음과 같이 하면 된다

$nohup [실행파일] 1>/dev/null 2>&1 &

1>/dev/null 이 표현은 1의 결과를 /dev/null 이라는 파일 속에 넣는다. /dev/null로 보내버리면 모든 출력을 없애버린다.

2>&1 이 표현은 2번 파일디스크립터를 1번에 지정된 형식과 동일하게 /dev/null로 지정한다.

& 은 프로그램을 백그라운드에서 실행하도록 하는 표현이다.

Posted by C마노
,

함수 기반 View 가아닌 Class 기반 View를 사용해서 API View를 작성할 수도 있습니다.

여러분도 잘 알듯이 클래스기반 View는 일반적인 기능을 재사용 할수있는 강력한 패턴입니다. 그리고 코드의 유지를 훨씬 효율적으로 할수 있습니다.


[ 클래스 기반 View를 사용해서 다시 API를 작성해봅시다.]


먼저 Root View를 클래스 기반 View로 다시 작성해봅시다. views.py를 열어주세요.


from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status


class SnippetList(APIView):
    """
    List all snippets, or create a new snippet.
    """
    def get(self, request, format=None):
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = SnippetSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

이전의 경우와 매우 비슷하게 보이지만 Http메소드를 구분하기에 훨씬 쉽습니다. 


class SnippetDetail(APIView):
    """
    Retrieve, update or delete a snippet instance.
    """
    def get_object(self, pk):
        try:
            return Snippet.objects.get(pk=pk)
        except Snippet.DoesNotExist:
            raise Http404

    def get(self, request, pk, format=None):
        snippet = self.get_object(pk)
        serializer = SnippetSerializer(snippet)
        return Response(serializer.data)

    def put(self, request, pk, format=None):
        snippet = self.get_object(pk)
        serializer = SnippetSerializer(snippet, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk, format=None):
        snippet = self.get_object(pk)
        snippet.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

Detail도 마찬가지로 함수뷰와 비슷하지만 보기에 훨씬 이뻐보입니다. 

클래스 기반 View를 사용하기 때문에 url.py를 살짝 리팩토링해야합니다.


from django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views

urlpatterns = [
    url(r'^snippets/$', views.SnippetList.as_view()),
    url(r'^snippets/(?P<pk>[0-9]+)/$', views.SnippetDetail.as_view()),
]

urlpatterns = format_suffix_patterns(urlpatterns)

이제, 개발서버를 실행하면 모든 것이 이전과 같이 작동해야 합니다.


[ mixins 사용 ]


클래스 기반 뷰를 사용하면서 얻은 가장 큰 장점 중 하나는 재사용을 쉽게 구성할 수 있다는 것입니다.

지금까지 구현되어온것을 보면 create/retrieve/update/delete 는 공통적으로 사용되는데요.

이러한 공통된 동작은 REST FRAMEWORK의 mixin 클래스에서 구현가능합니다.


mixin 클래스를 사용해서 뷰를 구성하는 방법을 살펴보겠습니다. 여기에 views.py 모듈이 있습니다.


from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework import mixins
from rest_framework import generics

class SnippetList(mixins.ListModelMixin,
                  mixins.CreateModelMixin,
                  generics.GenericAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

GenericAPIView를 사용하고 ListModelMixin 및 CreateModelMixin 을 추가해서 뷰를 작성합니다.


베이스클래스는 핵심기능을 제공하고 mixin 클래스는 .list() 및 .create() 를 제공합니다.

그런다음 get및 post 메소드를 명시적으로 적절한 액션에 바인딩합니다. 


이전과 거의 비슷하지만. GenericAPIView 클래스를 사용해서 핵심 기능을 제공하고 .retrieve(), .update(), 및 .destroy() 액션을 제공하기 위해서 mixin 을 추가합니다.


[ 제네릭 클래스 기반 뷰 사용 ]


mixin 클래스를 사용해서 이전보다 적은 코드를 사용하기 위해 뷰를 새로작성했지만 좀더 나아가봅시다.


from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework import generics


class SnippetList(generics.ListCreateAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer


class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer

와.. 이번엔 진짜 간결합니다. 굉장히 코드는 훌륭하고 깨끗하며 관용적인 장고처럼 보입니다.



Posted by C마노
,