import math, sys;
def example1():
####This is a long comment. This should be wrapped to fit within 72 characters.
some_tuple=( 1,2, 3,'a' );
some_variable={'long':'Long code lines should be wrapped within 79 characters.',
'other':[math.pi, 100,200,300,9876543210,'This is a long string that goes on'],
'more':{'inner':'This whole logical line should be wrapped.',some_tuple:[1,
20,300,40000,500000000,60000000000000000]}}
return (some_tuple, some_variable)
def example2(): return {'has_key() is deprecated':True}.has_key({'f':2}.has_key(''));
class Example3( object ):
def __init__ ( self, bar ):
#Comments should have a space after the hash.
if bar : bar+=1; bar=bar* bar ; return bar
else:
some_string = """
Indentation in multiline strings should not be touched.
Only actual code should be reindented.
"""
return (sys.path, some_string)
(pyconjp2014)$ pep8 example1.py
example1.py:1:12: E401 multiple imports on one line
example1.py:1:17: E703 statement ends with a semicolon
example1.py:3:1: E302 expected 2 blank lines, found 1
example1.py:4:5: E265 block comment should start with '# '
example1.py:4:80: E501 line too long (83 > 79 characters)
example1.py:5:15: E225 missing whitespace around operator
example1.py:5:17: E201 whitespace after '('
example1.py:5:21: E231 missing whitespace after ','
example1.py:5:26: E231 missing whitespace after ','
example1.py:5:31: E202 whitespace before ')'
example1.py:5:33: E703 statement ends with a semicolon
example1.py:6:18: E225 missing whitespace around operator
example1.py:6:26: E231 missing whitespace after ':'
example1.py:6:80: E501 line too long (84 > 79 characters)
example1.py:7:5: E128 continuation line under-indented for visual indent
""" Here are some examples.
This module docstring should be dedented."""
def launch_rocket():
"""Launch
the
rocket. Go colonize space."""
def factorial(x):
'''
Return x factorial.
This uses math.factorial.
'''
import math
return math.factorial(x)
def print_factorial(x):
"""Print x factorial"""
print(factorial(x))
def main():
"""Main
function"""
print_factorial(5)
if factorial(10):
launch_rocket()
(pyconjp2014) $ pep257 example2.py
example2.py:1 at module level:
D209: Put multi-line docstring closing quotes on separate line
example2.py:1 at module level:
D208: Docstring is over-indented
example2.py:5 in public function `launch_rocket`:
D209: Put multi-line docstring closing quotes on separate line
example2.py:5 in public function `launch_rocket`:
D400: First line should end with '.', not 'h'
example2.py:5 in public function `launch_rocket`:
D205: Blank line missing between one-line summary and description
example2.py:5 in public function `launch_rocket`:
D207: Docstring is under-indented
example2.py:11 in public function `factorial`:
D300: Expected """-quotes, got '''-quotes
example2.py:23 in public function `print_factorial`:
D400: First line should end with '.', not 'l'
example2.py:28 in public function `main`:
D209: Put multi-line docstring closing quotes on separate line
example2.py:28 in public function `main`:
D400: First line should end with '.', not 'n'
example2.py:28 in public function `main`:
D205: Blank line missing between one-line summary and description
import math
import re
import os
import random
import multiprocessing
import grp, pwd, platform
import subprocess, sys
def foo():
from abc import ABCMeta, WeakSet
try:
import multiprocessing
print(multiprocessing.cpu_count())
except ImportError as exception:
print(sys.version)
return math.pi
example3.py:2: 're' imported but unused
example3.py:3: 'os' imported but unused
example3.py:4: 'random' imported but unused
example3.py:5: 'multiprocessing' imported but unused
example3.py:6: 'grp' imported but unused
example3.py:6: 'platform' imported but unused
example3.py:6: 'pwd' imported but unused
example3.py:7: 'subprocess' imported but unused
example3.py:11: 'ABCMeta' imported but unused
example3.py:11: 'WeakSet' imported but unused
example3.py:13: redefinition of unused 'multiprocessing' from line 5
example3.py:15: local variable 'exception' is assigned to but never used
訳) 最低flake8に通してからレビューに出そうや。な?
[flake8]
max-line-length = 120
exclude = /apps/*/migrations/*
from settings.base import * # NOQA
.hgがあるディレクトリで以下のコマンドを叩く
$ flake8 --install-hook
.hg/hgrcに勝手に追記してくれる
[hooks]
commit = python:flake8.hooks.hg_hook
qrefresh = python:flake8.hooks.hg_hook
[flake8]
complexity = 10
strict = False
ignore = None
lazy = False
$ pip install flake8_docstrings
やる事はこれだけ
$ flake8 example3.py
example3.py:1:1: D100 Docstring missing
example3.py:2:1: F401 're' imported but unused
example3.py:3:1: F401 'os' imported but unused
example3.py:4:1: F401 'random' imported but unused
example3.py:5:1: F401 'multiprocessing' imported but unused
example3.py:6:1: F401 'grp' imported but unused
example3.py:6:1: F401 'platform' imported but unused
example3.py:6:1: F401 'pwd' imported but unused
example3.py:6:11: E401 multiple imports on one line
example3.py:7:1: F401 'subprocess' imported but unused
example3.py:7:18: E401 multiple imports on one line
example3.py:10:1: D103 Docstring missing
Dで始まるメッセージが表示されるようになる。
Before
import math, sys;
def example1():
####This is a long comment. This should be wrapped to fit within 72 characters.
some_tuple=( 1,2, 3,'a' );
some_variable={'long':'Long code lines should be wrapped within 79 characters.',
'other':[math.pi, 100,200,300,9876543210,'This is a long string that goes on'],
'more':{'inner':'This whole logical line should be wrapped.',some_tuple:[1,
20,300,40000,500000000,60000000000000000]}}
return (some_tuple, some_variable)
def example2(): return {'has_key() is deprecated':True}.has_key({'f':2}.has_key(''));
class Example3( object ):
def __init__ ( self, bar ):
#Comments should have a space after the hash.
if bar : bar+=1; bar=bar* bar ; return bar
else:
some_string = """
Indentation in multiline strings should not be touched.
Only actual code should be reindented.
"""
return (sys.path, some_string)
コマンド
$ autopep8 --in-place --aggressive --aggressive exmaple1.py
After
import math
import sys
def example1():
# This is a long comment. This should be wrapped to fit within 72
# characters.
some_tuple = (1, 2, 3, 'a')
some_variable = {
'long': 'Long code lines should be wrapped within 79 characters.',
'other': [
math.pi,
100,
200,
300,
9876543210,
'This is a long string that goes on'],
'more': {
'inner': 'This whole logical line should be wrapped.',
some_tuple: [
1,
20,
300,
40000,
500000000,
60000000000000000]}}
return (some_tuple, some_variable)
def example2():
return ('' in {'f': 2}) in {'has_key() is deprecated': True}
class Example3(object):
def __init__(self, bar):
# Comments should have a space after the hash.
if bar:
bar += 1
bar = bar * bar
return bar
else:
some_string = """
Indentation in multiline strings should not be touched.
Only actual code should be reindented.
"""
return (sys.path, some_string)
Before
import math
import re
import os
import random
import multiprocessing
import grp, pwd, platform
import subprocess, sys
hoge = "hoge"
def foo():
from abc import ABCMeta, WeakSet
fuga = "fuga"
try:
import multiprocessing
print(multiprocessing.cpu_count())
except ImportError as exception:
print(sys.version)
return math.pi
コマンド
$ autoflake --in-place --remove-unused-variables example3-autoflake.py
After
import math
import sys
hoge = "hoge" # <= モジュールスコープの変数は消さないでくれる
def foo():
try:
import multiprocessing
print(multiprocessing.cpu_count())
except ImportError:
print(sys.version)
return math.pi
関数の括弧にきたら勝手にでる
.ropeproject/config.py
# プロジェクトのソースのパスを指定する
# 'src/my_source_folder' for instance.
prefs.add('source_folders', 'django_apps')
# Virtualenvにパスを通す
# You can extend python path for looking up modules
prefs.add('python_path', '/Users/hoge/.virtualenvs/pyconjp2014/lib/python2.7/site-packages')
spam.py
def get_spam(num=1):
return "spam x {}".format(num)
main.py
from spam import get_spam
print get_spam() # => "spam x 1"
main.py の「get_spam()」にカーソルを置いて「:RopeRename」
新しい名前を聞かれる
1を入力してプレビューを確認する。
spam.py
def get_spam(num=1):
return "spam x {}".format(num)
main.py
from spam import get_spam
print get_spam() # => "spam x 1"
丸っと移動される。不要なimportも削除
spam.py
def get_spam(num=1):
return "spam x {}".format(num)
main.py
print get_spam() # => "spam x 1"
spam.py
# BaseSpamという抽象クラスを用意
from abc import ABCMeta
class BaseSpam:
__metaclass__ = ABCMeta
@abstractmethod
def get_spam(self):
""" must implement. """
main.py
from spam import BaseSpam
class MySpam(BaseSpam):
def get_spam(self, num=1):
return "my spam x {}".format(num)
class YourSpam(BaseSpam):
def get_spam(self, num=1):
return "your spam x {}".format(num)
spam.py
def get_spam(num=1):
return "spam x {}".format(num)
main.py
from spam import get_spam
print get_spam() # => "spam x 1"
引数にpriceを追加
# 〜 省略 〜
class Customer(object):
def statement(self):
total_amount = 0
frequent_renter_points = 0
rentals = self._rentals
result = "Rental Record for {name}\n".format(name=self.name)
for each in rentals:
this_amount = 0
# ここのif文全体を丸っとメソッドにする
if each.movie.price_code == Movie.REGULAR:
this_amount += 2
if each.days_rented > 2:
this_amount += (each.days_rented - 2) * 1.5
elif each.movie.price_code == Movie.NEW_RELEASE:
this_amount += each.days_rented * 3
elif each.movie.price_code == Movie.CHILDRENS:
this_amount += 1.5
if each.days_rented > 3:
this_amount += (each.days_rented - 3) * 1.5
# 〜 省略 〜
RopeUndo
RopeRedo
def fizzbuzz(max_number):
ret = []
for i in range(1, max_number + 1): # <= +1
if i % 15 == 0: # <= +1
ret.append('FizzBuzz')
elif i % 5 == 0: # <= +1
ret.append('Buzz')
elif i % 3 == 0: # <= +1
ret.append('Fizz')
else:
ret.append(i)
return ret
print fizzbuzz(max_number=15)
# => [1, 2, 'Fizz', 4, 'Buzz', 'Fizz', 7, 8, 'Fizz',
# 'Buzz', 11, 'Fizz', 13, 14, 'FizzBuzz']
わざと複雑度をあげてみる
def fizzbuzz(max_number):
ret = []
for i in range(1, max_number + 1):
if i % 15 == 0:
ret.append('FizzBuzz')
elif i % 5 == 0:
ret.append('Buzz')
elif i % 3 == 0:
ret.append('Fizz')
elif i % 2 == 0: # <= 追加 +1
pass # do nothing
else:
ret.append(i)
return ret
複雑度が6になるので「B」になる
radon ccコマンドのオプションは色々ある
class ProjectAdmin(admin.ModelAdmin):
list_display = ('full_slug', 'owner', 'platform', 'status', 'date_added')
list_filter = ('status', 'platform', 'public')
search_fields = ('name', 'owner__username', 'owner__email', 'team__slug',
'team__name', 'slug')
raw_id_fields = ('owner', 'team')
def full_slug(self, instance):
if not instance.team:
slug = instance.slug
else:
slug = '%s/%s' % (instance.team.slug, instance.slug)
例えばDjango
coverage run manage.py runserver --noreload
アプリ動作テストみたいなのを一通りする
coverage report -m
カバレッジを見る
[run]
omit = *migrations*,*.virtualenvs*
除外対象を .coveragercに書くと良い
Name Stmts Miss Cover Missing
----------------------------------------------------------------------
apps/__init__ 0 0 100%
apps/account/__init__ 0 0 100%
apps/account/api 68 56 18% 23, 31-84, 91-111, 120-129, 133-141
apps/account/forms 11 0 100%
apps/account/models 63 20 68% 94, 100-102, 108-113, 118-127
apps/account/urls 5 0 100%
apps/account/validators 5 0 100%
apps/account/views 128 67 48% 38-65, 70-96, 107-114, 123-124, 129, 142-143, 146-149, 152, 155, 17
apps/comment/__init__ 0 0 100%
apps/comment/admin 3 0 100%
apps/comment/api 18 11 39% 15, 26-28, 34-40
apps/comment/cache 5 2 60% 8, 16
apps/comment/forms 5 0 100%
apps/comment/models 28 7 75% 15-16, 35, 38-41, 53
apps/comment/sitemaps 26 12 54% 35-38, 41, 47-62
ビープラウド広告
この記事はビープラウド勤務中に書かれたかもしれない。
ここから採用された場合は、社長およびCTOから特茶のバックマージンが発生するじゃないかなって妄想してる。
ビープラウドは本物のPythonプログラマーを募集しています。
CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0