Blank line at end of file как исправить python

W391 says that there should be one (and only one) blank line at the end of file. However, flake8 reports the error when there is at least one newline at the end of the file: $ cat /tmp/test.py def...

W391 says that there should be one (and only one) blank line at the end of file. However, flake8 reports the error when there is at least one newline at the end of the file:

$ cat /tmp/test.py
def hello():
    print('hello')


hello()


$ hexdump -C /tmp/test.py
00000000  64 65 66 20 68 65 6c 6c  6f 28 29 3a 0a 20 20 20  |def hello():.   |
00000010  20 70 72 69 6e 74 28 27  68 65 6c 6c 6f 27 29 0a  | print('hello').|
00000020  0a 0a 68 65 6c 6c 6f 28  29 0a 0a                 |..hello()..|
0000002b

You can see above there is in fact one and only one blank line at the end of the file (0a is n). However, when I run flake8, I get the W391 error:

$ flake8 /tmp/test.py
/tmp/test.py:6:1: W391 blank line at end of file

Why is that?

asked Nov 10, 2019 at 2:59

Ben Davis's user avatar

12

Apparently vim automatically adds a newline to every file, which fools me into thinking that last blank line isn’t there. Over time this implicit newline confused me into thinking two newline characters at the end created one blank line.

So, the warning is correct. There should be one and only one n at the end of the file.

answered Nov 10, 2019 at 19:12

Ben Davis's user avatar

Ben DavisBen Davis

12.6k10 gold badges48 silver badges58 bronze badges

@sigmavirus24

A newline at the end of a file does not mean that there needs to be an empty line. Your editor may not show this to you but the raw bytes would look like:

# your python code
def foo():n
    return barn

If you don’t have the last n there then you will see W391. You seem to be doing

Edited to fix the last example.

@IanLee1521

@davidaames —

Could you provide some sample code where this is an issue? Thanks.

@jkterry1

Hey, I seem to be having this issue as well, with this sample code:

        raise Exception('Error: Incorrect new dag flows on line '
                        + str(i))

@FichteFoll

Since this error is highly whitespace-sensitive, I don’t think it can be reproduced with simple code blocks as those are stripped. Please upload files.

That said, I suspect that the initial problem was that the end of the file looked as follows:

# your python code
def foo():n
    return barn
    n

Note that the last line here is not empty but has 4 spaces. This should raise W391. It was then attempted to fix the error by removing the last newline, but that left the four spaces in the now last line, which caused W292 to be raised.

@hoylemd

As a workaround in the meantime, I have a bit in my editor(vim) config(.vimrc) that strips trailing whitespace whenever a buffer is saved. That might help you (@justinkterry) in the short term, if you use vim and are ok with your editor cleaning whitespace up for you:

function! TrimTrailingWhitespace()
  :%s/s+$//e
endfunction
autocmd BufWritePre *.py :call TrimTrailingWhitespace()

or more concisely:

autocmd BufWritePre *.py :%s/s+$//e  " Trim trailing whitespace

@bsmoliak

W391 appears to supercede W292.

$ echo -n "a = 1" > file.py | pycodestyle file.py
file.py:1:1: W391 blank line at end of file

Seems like W292 should be raised first.

@codypiersall

Hmmm, for what it’s worth, it seems like Vim inserts the newline at the end of the file, but it doesn’t look like there is a newline. I wonder if this is what was happening with the OP?

It took me quite a while to believe that I actually deserved to get W391, but when I hexdump -C /the/file | tail, it was true! The last two bytes were 0a 0a.

@kierun

This is the file I use:

# -*- coding: utf-8 -*-
"""Function to sanitise paths."""

from pathvalidate import sanitize_filename
import os


def sanitise(*paths):
    return os.path.join(*[sanitize_filename(x) for x in paths])

The last line does have a [W292] warning on it. Flake8 passes fine.

Running hexdump, get:

hexdump -C sanitise.py | tail
00000040  70 61 74 68 76 61 6c 69  64 61 74 65 20 69 6d 70  |pathvalidate imp|
00000050  6f 72 74 20 73 61 6e 69  74 69 7a 65 5f 66 69 6c  |ort sanitize_fil|
00000060  65 6e 61 6d 65 0a 69 6d  70 6f 72 74 20 6f 73 0a  |ename.import os.|
00000070  0a 0a 64 65 66 20 73 61  6e 69 74 69 73 65 28 2a  |..def sanitise(*|
00000080  70 61 74 68 73 29 3a 0a  20 20 20 20 72 65 74 75  |paths):.    retu|
00000090  72 6e 20 6f 73 2e 70 61  74 68 2e 6a 6f 69 6e 28  |rn os.path.join(|
000000a0  2a 5b 73 61 6e 69 74 69  7a 65 5f 66 69 6c 65 6e  |*[sanitize_filen|
000000b0  61 6d 65 28 78 29 20 66  6f 72 20 78 20 69 6e 20  |ame(x) for x in |
000000c0  70 61 74 68 73 5d 29 0a                           |paths]).|
000000c8

This is what I see on screen:

screenshot

OS: Centos (7.6.1810), neovim (0.3.2), and neovim-qt (master)…

@FichteFoll

What happens when you run pycodestyle sanitise.py from the command line? This could be a problem in the vim intergation.

@kierun

What happens when you run pycodestyle sanitise.py from the command line? This could be a problem in the vim intergation.

HA! the one thing I did not try. It returns 0, no output whatsoever.

@asottile

I can’t reproduce this (nor @bsmoliak’s example) on the latest version:

$ pycodestyle --version
2.5.0
$ echo -n "a = 1" > file.py | pycodestyle file.py
file.py:1:6: W292 no newline at end of file

I’m having trouble understanding what «No newline at end of file» means exactly.

The error is pointing to the last line

Can someone help explain to me why I’m getting this invalid error and offer a solution to solve it. Thanks

user avatar

user avatar

1 Answer 1

It means exactly what it says. There is no recognizable newline at the end of the file. The last character is the ) . or maybe a TAB , or SPACE , or a line terminator for a different platform.

Solution: open the file in an editor, add a newline at the end, save and close the file.

I’ve tried that, I had a new line after it and I get «blank line contains whitespace» error.

So what you had was a line consisting of white space (SPACE or TAB characters) followed by a newline. Use your editor to get rid of that line.

The style checker wants the last line of the file to end with the newline character, and to have no trailing whitespace on that line.

Почему важно всегда ставить символ переноса строки в конце текстовых файлов?

Иногда при просмотре диффов коммитов через git log или git diff можно заметить следующий вывод:

Или на GitHub в интерфейсе для просмотра диффов:

GitHub "now newline at end of file" warning

Почему это так важно, что Git и GitHub предупреждают нас об этом? Давайте разберемся.

Что такое символ переноса строки?

Что может быть проще, чем текстовый файл? Просто текстовые данные — как хранятся на диске, так и отображаются. На самом деле правительство нам врёт всё немного сложнее.

Оффтопик про управляющие символы ASCII

Не все символы, которые содержатся в текстовых файлах, имеют визуальное представление. Такие символы ещё называют «управляющими», и к ним относятся, например:

  • нулевой символ ( x00 , ) — часто используется для кодирования конца строки в памяти; т.е. программа считывает символы из памяти по одному до тех пор, пока не встретит нулевой символ, и тогда строка считается завершённой;
  • табуляция ( x09 , t ) — используется для выравнивания данных по границе столбца, так что это выглядит как таблица;
  • перевод строки ( x0a , n ) — используется для разделения текстовых данных на отдельные строки;
  • возврат каретки ( x0d , r ) — переместить курсор в начало строки;
  • возврат на один символ ( x08 , b ) — переместить курсор на один символ назад;
  • звонок ( x07 , a ) — если набрать этот символ в терминале, то будет бибикающий символ; именно так консольные программы, типа vim , бибикают на пользователей; .

Многие эти символы пришли к нам из эпохи печатных машинок, поэтому у них такие странные названия. И действительно, в контексте печатной машинки или принтера такие операции, как перевод строки (сместить лист бумаги вверх так, чтобы печатающая головка попала на следующую строку), возврат каретки (переместить печатающую головку в крайнее левое положение) и возврат на один символ назад, обретают смысл. При помощи возврата на один символ назад создавались жирные символы (печатаешь символ, возвращаешься назад и печатаешь его ещё раз) и буквы с диакритическими знаками, такие как à или ã (печатаешь символ, возвращаешься назад и печатаешь апостроф или тильду). Но зачем печатной машинке бибикалка?

Сегодня многие из этих символов потеряли смысл, но некоторые до сих пор выполняют функцию, схожую с исходной.

Текстовые редакторы отображают текстовые файлы в некоем адаптированном виде, преобразуя непечатаемые символы, например, переносы строк и табуляции преобразуются в настоящие отдельные строки или выравнивающие отступы.

Для набора символа переноса строки достаточно нажать клавишу «Enter», но на разных платформах этот символ закодируется по-разному:

  • в Unix-совместимых системах (включая современные версии macOS) используется один символ перевода строки ( LF );
  • в Windows используется сразу два символа — возврат каретки ( CR ) и перевод строки ( LF );
  • в очень старых версиях Mac OS (до 2001 года) использовался один символ CR .

Как видите, Windows точнее всего эмулирует поведение печатной машинки.

В языках программирования символ новой строки часто кодируют при помощи бэкслэш-последовательностей, таких как n или rn . Нужно понимать разницу между такой последовательностью и настоящим символом переноса строки. Если в редакторе в файле *.txt просто набрать n и сохранить, то вы получите ровно то, что написали. Символом переноса строки оно не станет. Нужно что-то, что заменит эти бэкслэш-последовательности на настоящие символы переноса строки (например, компилятор или интерпретатор языка программирования).

Почему перенос строки в конце файла важен?

Согласно определению из стандарта POSIX, который тоже пришёл к нам из эпохи печатных машинок:

Строка — это последовательность из нуля или более символов, не являющихся символом новой строки, и терминирующего символа новой строки.

Почему важен этот стандарт? Возможен миллиард способов реализовать одно и то же, и только благодаря стандартам, таким как POSIX, мы имеем сейчас огромное количество качественного ПО, которое не конфликтует друг с другом.

Т.е. если вы не ставите символ переноса строки в конце строки, то формально по стандарту такая строка не является валидной. Множество утилит из Unix, которыми я пользуюсь каждый день, написано в согласии с этим стандартом, и они просто не могут правильно обрабатывать такие «сломанные» строки.

Давайте, например, через Python создадим такой файл со сломанными строками:

Сколько по-вашему в этом файле строк? Три? Давайте посмотрим, что об этом файле думает утилита wc , которая с флагом -l умеет считать количество строк в файле:

Упс! wc нашла только 2 строки!

Давайте создадим еще один файл:

И попробуем теперь склеить два созданных файла при помощи утилиты cat :

Название cat — это сокращение от «конкатенация», и никак не связано с котиками. А жаль.

И опять какой-то странный результат! В большинстве случаев это не то, чего вы бы ожидали, но вполне возможны ситуации, когда вам нужен именно такой результат. Именно поэтому утилита cat не может самостоятельно вставлять отсутствующие символы переноса строки, иначе это сделало бы её поведение неконсистентным.

Это только пара примеров, но многие другие утилиты, которые работают с текстом (например, diff , grep , sed ), имеют такие же проблемы. Собственно говоря, это даже не проблемы, а их задокументированное поведение.

Ещё доводы:

  • при дозаписи содержимого в конец файла без переноса строки получится некрасивый дифф — будет изменена последняя строка (хотя на ней всего лишь добавился символ переноса);
  • файл с переносом строки и без переноса строки — это два разных файла; для diff и git diff единственный способ отобразить разницу между ними — это напечатать сообщение об отсутствии символа переноса строки;
  • согласно стандарту языка C (до 2014 года), непустые файлы с исходным кодом должны заканчиваться символом переноса строки.

Настраиваем редактор

Самый простой способ перестать думать о пустых строках и начать жить — это настроить свой текстовый редактор или IDE на автоматическое добавление символа переноса строки в конец файлов:

  • PyCharm и другие IDE JetBrains: Settings > Editor > General > Ensure an empty line at the end of a file on Save ;
  • VS Code: «files.insertFinalNewline»: true .

Для других редакторов смотрите настройку здесь.

Кстати, если вы пользуетесь форматтером black , то у меня хорошие новости — он всегда добавляет перенос строки в конец всех файлов *.py .

Заключение

Возможно, такая маленькая деталь, как перенос строки в конце файла и не кажется очень важной, а тема вообще кажется спорной, но боюсь, что у нас нет другого выбора, кроме как принять это правило за данность и просто выработать привычку (или настроить инструментарий) всегда ставить символ новой строки в любых текстовых файлах, даже если этого не требуется явно. Это считается распространённой хорошей практикой, и как минимум убережёт вас и ваших коллег от всяких неожиданных эффектов при работе с утилитами Unix.

В текстовом редакторе это выглядит как лишняя пустая строка в конце файла:

W391 blank line at end of file introduces —> W292 no newline at end of file #365

The text was updated successfully, but these errors were encountered:

IanLee1521 commented Jan 3, 2015

Could you provide some sample code where this is an issue? Thanks.

jkterry1 commented Mar 15, 2018

Hey, I seem to be having this issue as well, with this sample code:

FichteFoll commented Mar 15, 2018 •

Since this error is highly whitespace-sensitive, I don’t think it can be reproduced with simple code blocks as those are stripped. Please upload files.

That said, I suspect that the initial problem was that the end of the file looked as follows:

Note that the last line here is not empty but has 4 spaces. This should raise W391. It was then attempted to fix the error by removing the last newline, but that left the four spaces in the now last line, which caused W292 to be raised.

hoylemd commented Mar 16, 2018 •

As a workaround in the meantime, I have a bit in my editor(vim) config(.vimrc) that strips trailing whitespace whenever a buffer is saved. That might help you (@justinkterry) in the short term, if you use vim and are ok with your editor cleaning whitespace up for you:

or more concisely:

bsmoliak commented Jan 4, 2019

W391 appears to supercede W292.

Seems like W292 should be raised first.

codypiersall commented Jan 16, 2019

Hmmm, for what it’s worth, it seems like Vim inserts the newline at the end of the file, but it doesn’t look like there is a newline. I wonder if this is what was happening with the OP?

It took me quite a while to believe that I actually deserved to get W391, but when I hexdump -C /the/file | tail , it was true! The last two bytes were 0a 0a .

When saving the data to csv, data.to_csv('csv_data', sep=',', encoding='utf-8', header= False, index = False), it creates a blank line at the end of csv file.

How do you avoid that?

It’s got to do with the line_terminator and it’s default value is n, for new line.

Is there a way to specify the line_terminator to avoid creating a blank line at the end, or do i need to read the csv file, remove the blank line and save it?

Not familiar with pandas. Your help will be appreciated, thanks in advance!

asked Aug 30, 2016 at 22:00

medev21's user avatar

medev21medev21

2,3597 gold badges29 silver badges41 bronze badges

9

One way would be to save data except the last entry,with default line_terminator(n) and append the last line with line_terminator="" .

data1 = data.iloc[0:len(data)-1]
data2 = data.iloc[[len(data)-1]]
data1.to_csv('csv_data', sep=',', encoding='utf-8', header= False, index = False)
data2.to_csv('csv_data', sep=',', encoding='utf-8', header= False, index = False,mode='a',line_terminator="")

answered Aug 31, 2016 at 7:47

kanatti's user avatar

kanattikanatti

7557 silver badges10 bronze badges

1

For some reason, the line terminator did not work when I tried it. (It gave an error, saying line_terminator is an unrecognized keyword argument.)

However, this will do the trick:

    df.to_csv(path)
    with open(path) as f:
        lines = f.readlines()
        last = len(lines) - 1
        lines[last] = lines[last].replace('r','').replace('n','')
    with open(path, 'w') as wr:
        wr.writelines(lines)

answered Feb 17, 2017 at 18:09

Jared's user avatar

JaredJared

312 bronze badges

1

file_out = r'c:your_output_file_pathfile_name.csv'
df.to_csv(file_out)
file_data = open(file_out, 'rb').read()
open(file_out, 'wb').write(file_data[:-2])

df.to_csv() function has a parameter called line_terminator with a default value of ‘n’. This new line character is the issue at hand.

The code above:
1) writes the dataframe to file as normal
2) opens the file and reads in the bytes data to the file_data variable
3) writes the file_data variable back out to the same file but trims off the ‘n’ with the splice: file_data[:-2]

answered Jun 17, 2019 at 14:21

DonkeyKong's user avatar

DonkeyKongDonkeyKong

96513 silver badges18 bronze badges

One solution is to not use pandas to export the data to a file. The example below will not include an empty row at the end of the file. However, it’s probably a lot slower than pandas’ «to_csv» method.

import pandas as pd

def export_dataframe_to_file( 
        df: pd.DataFrame, file_name: str, 
        header=True, index=True, delimiter=',',
        line_terminator='n', encoding='utf-8' 
        ) -> None:
    '''
    This function exports a Pandas DataFrame to a file without
    including an empty row at the very end of the file.
    '''
    number_of_rows, current_row = len(df), 1
    with open(file_name, 'w', encoding=encoding) as file :
        if header:
            file.write( 
                delimiter*index + delimiter.join(df.columns) 
                + line_terminator 
                )
        for df_index, series in df.iterrows():
            file.write( 
                (str(df_index) + delimiter)*index 
                + delimiter.join(series.astype( str )) 
                + line_terminator*(not not number_of_rows - current_row)
                )
            current_row += 1
    return

answered Apr 21, 2021 at 0:41

Zachary Chiodini's user avatar

None of the solutions above worked because as the original question asked he was trying to send the file to another script/REST API that wouldn’t accept carriage return. This is likely caused by the requests library he is using to send the csv file to the REST API. I was able to use the requests library to send a file which had a carriage return via REST API:

import requests
import pandas as pd
import settings


file_name = Hierarchy.csv'
df = pd.read_csv(file_name)
df.to_csv(file_name, sep=',', encoding='utf-8', index=False)
headers = {
  'x-api-key': settings.MONITOR_REST_API_KEY,
  'x-api-token': settings.MONITOR_REST_API_TOKEN,
  'accept': 'application/json'
}

files = {'file': (file_name, open(file_name, 'rb'), 'text/csv')}
monitor_rest_url = "https://api.yourcloud.com"
response = requests.post(monitor_rest_url +'/api/v2/your_endpoint',
                        files=files, verify=False, headers=headers)
print(response.text)

answered Jan 12, 2022 at 11:52

Carlos Ferreira's user avatar

Carlos FerreiraCarlos Ferreira

1,8642 gold badges13 silver badges18 bronze badges

A more efficient way is to open the file first, write to that stream, then remove the last newline:

import os
with open('csv_data', 'wb') as dst:
    data.to_csv(wb, sep=',', encoding='utf-8', header= False, index = False)
    dst.seek(-1, os.SEEK_END) # <---- 1 : len('n')
    dst.truncate()

answered Jan 31, 2018 at 22:10

Luke Corrigall's user avatar

When saving the data to csv, data.to_csv('csv_data', sep=',', encoding='utf-8', header= False, index = False), it creates a blank line at the end of csv file.

How do you avoid that?

It’s got to do with the line_terminator and it’s default value is n, for new line.

Is there a way to specify the line_terminator to avoid creating a blank line at the end, or do i need to read the csv file, remove the blank line and save it?

Not familiar with pandas. Your help will be appreciated, thanks in advance!

asked Aug 30, 2016 at 22:00

medev21's user avatar

medev21medev21

2,3597 gold badges29 silver badges41 bronze badges

9

One way would be to save data except the last entry,with default line_terminator(n) and append the last line with line_terminator="" .

data1 = data.iloc[0:len(data)-1]
data2 = data.iloc[[len(data)-1]]
data1.to_csv('csv_data', sep=',', encoding='utf-8', header= False, index = False)
data2.to_csv('csv_data', sep=',', encoding='utf-8', header= False, index = False,mode='a',line_terminator="")

answered Aug 31, 2016 at 7:47

kanatti's user avatar

kanattikanatti

7557 silver badges10 bronze badges

1

For some reason, the line terminator did not work when I tried it. (It gave an error, saying line_terminator is an unrecognized keyword argument.)

However, this will do the trick:

    df.to_csv(path)
    with open(path) as f:
        lines = f.readlines()
        last = len(lines) - 1
        lines[last] = lines[last].replace('r','').replace('n','')
    with open(path, 'w') as wr:
        wr.writelines(lines)

answered Feb 17, 2017 at 18:09

Jared's user avatar

JaredJared

312 bronze badges

1

file_out = r'c:your_output_file_pathfile_name.csv'
df.to_csv(file_out)
file_data = open(file_out, 'rb').read()
open(file_out, 'wb').write(file_data[:-2])

df.to_csv() function has a parameter called line_terminator with a default value of ‘n’. This new line character is the issue at hand.

The code above:
1) writes the dataframe to file as normal
2) opens the file and reads in the bytes data to the file_data variable
3) writes the file_data variable back out to the same file but trims off the ‘n’ with the splice: file_data[:-2]

answered Jun 17, 2019 at 14:21

DonkeyKong's user avatar

DonkeyKongDonkeyKong

96513 silver badges18 bronze badges

One solution is to not use pandas to export the data to a file. The example below will not include an empty row at the end of the file. However, it’s probably a lot slower than pandas’ «to_csv» method.

import pandas as pd

def export_dataframe_to_file( 
        df: pd.DataFrame, file_name: str, 
        header=True, index=True, delimiter=',',
        line_terminator='n', encoding='utf-8' 
        ) -> None:
    '''
    This function exports a Pandas DataFrame to a file without
    including an empty row at the very end of the file.
    '''
    number_of_rows, current_row = len(df), 1
    with open(file_name, 'w', encoding=encoding) as file :
        if header:
            file.write( 
                delimiter*index + delimiter.join(df.columns) 
                + line_terminator 
                )
        for df_index, series in df.iterrows():
            file.write( 
                (str(df_index) + delimiter)*index 
                + delimiter.join(series.astype( str )) 
                + line_terminator*(not not number_of_rows - current_row)
                )
            current_row += 1
    return

answered Apr 21, 2021 at 0:41

Zachary Chiodini's user avatar

None of the solutions above worked because as the original question asked he was trying to send the file to another script/REST API that wouldn’t accept carriage return. This is likely caused by the requests library he is using to send the csv file to the REST API. I was able to use the requests library to send a file which had a carriage return via REST API:

import requests
import pandas as pd
import settings


file_name = Hierarchy.csv'
df = pd.read_csv(file_name)
df.to_csv(file_name, sep=',', encoding='utf-8', index=False)
headers = {
  'x-api-key': settings.MONITOR_REST_API_KEY,
  'x-api-token': settings.MONITOR_REST_API_TOKEN,
  'accept': 'application/json'
}

files = {'file': (file_name, open(file_name, 'rb'), 'text/csv')}
monitor_rest_url = "https://api.yourcloud.com"
response = requests.post(monitor_rest_url +'/api/v2/your_endpoint',
                        files=files, verify=False, headers=headers)
print(response.text)

answered Jan 12, 2022 at 11:52

Carlos Ferreira's user avatar

Carlos FerreiraCarlos Ferreira

1,8642 gold badges13 silver badges18 bronze badges

A more efficient way is to open the file first, write to that stream, then remove the last newline:

import os
with open('csv_data', 'wb') as dst:
    data.to_csv(wb, sep=',', encoding='utf-8', header= False, index = False)
    dst.seek(-1, os.SEEK_END) # <---- 1 : len('n')
    dst.truncate()

answered Jan 31, 2018 at 22:10

Luke Corrigall's user avatar

By Szymon Lipiński

May 21, 2013

When you develop a program in a group of programmers, it is really important to have some standards. Especially helpful are standards of naming things and formatting code. If all team members format the code in the same way and use consistent names, then it is much easier to read the code. This also means that the team works faster.

The same rules apply when you develop software in Python.

For Python there is a document which describes some of the most desirable style features for Python code Style Guide for Python Code. However there are some problems with that, as even the standard Python library has some libraries which are not consistent. This shouldn’t be an excuse for your team to be inconsistent as well. Ensuring that the code is nice and readable is worth working for a moment on that.

In Python there are two tools which I use for writing code in Python—​Python style guide checker and Python code static checker.

pep8

Program pep8 is a simple tool checking Python code against some of the style conventions in PEP 8 document.

Installation

You can install it within your virtual environment with simple:

pip install pep8

Usage

Let’s test the pep8 command on such an ugly Python file named test.py:

"this is a very long comment line this is a very long comment line this is a very long comment line"
def sth  (  a ):
    return  "x"+a
def sth1 ( a,b,c):
    a+b+c

The basic usage of the program is:

pep8 test.py

The above command prints:

test.py:1:80: E501 line too long (100 > 79 characters)
test.py:2:1: E302 expected 2 blank lines, found 0
test.py:2:11: E201 whitespace after '('
test.py:2:14: E202 whitespace before ')'
test.py:2:8: E211 whitespace before '('
test.py:3:16: E225 missing whitespace around operator
test.py:4:1: E302 expected 2 blank lines, found 0
test.py:4:11: E201 whitespace after '('
test.py:4:13: E231 missing whitespace after ','
test.py:4:15: E231 missing whitespace after ','
test.py:4:9: E211 whitespace before '('
test.py:5:6: E225 missing whitespace around operator
test.py:5:8: E225 missing whitespace around operator
test.py:6:1: W391 blank line at end of file

Configuration

Pep8 is highly configurable. The most important options allow to choose which errors should be ignored. For this there is an argument –ignore. There is also one thing in PEP8 document, which I don’t agree with. This document states that the length of the line shouldn’t be bigger than 80 characters. Usually terminals and editors I use are much wider and having 100 characters doesn’t make your program unreadable. You can set the allowed length of your line with –max-line-length.

So if I want to ignore the errors about empty lines at the end of file and set maximum line length to 100, then the whole customized command is:

pep8 --ignore=W391 --max-line-length=100  test.py

The output is different now:

test.py:2:1: E302 expected 2 blank lines, found 0
test.py:2:11: E201 whitespace after '('
test.py:2:14: E202 whitespace before ')'
test.py:2:8: E211 whitespace before '('
test.py:3:16: E225 missing whitespace around operator
test.py:4:1: E302 expected 2 blank lines, found 0
test.py:4:11: E201 whitespace after '('
test.py:4:13: E231 missing whitespace after ','
test.py:4:15: E231 missing whitespace after ','
test.py:4:9: E211 whitespace before '('
test.py:5:6: E225 missing whitespace around operator
test.py:5:8: E225 missing whitespace around operator
Config file

The same effect can be achieved using a config file. PEP8 searches for this file at the project level, the file must be named .pep8 or setup.cfg. If such a file is not found, then it looks for a file ~/.config/pep8. Only the first file is taken into consideration. After finding a file, it looks for a pep8 section in, if there is no such section, then no custom settings are used.

To have the same settings as in the above example, you can create a file .pep8 in the project directory with the following content:

[pep8]
ignore = W391
max-line-length = 100

The list of all all possible errors you can find at PEP8 documentation page.

Statistics

Another nice option which I use for checking the code is –statistics. It prints information about the type and number of problems found. I use it along with -qq option which causes pep8 to hide all other informations. The sort -n 1 -k -r part sorts the pep8 output in reverse order (biggest numbers come first) by first column treating that as numbers:

pep8 --statistics -qq django | sort -k 1 -n -r

The first 10 lines of the above command run against Django 1.5.1 code look like:

4685    E501 line too long (80 > 79 characters)
1718    E302 expected 2 blank lines, found 1
1092    E128 continuation line under-indented for visual indent
559     E203 whitespace before ':'
414     E231 missing whitespace after ','
364     E261 at least two spaces before inline comment
310     E251 no spaces around keyword / parameter equals
303     E701 multiple statements on one line (colon)
296     W291 trailing whitespace
221     E225 missing whitespace around operator

pylint

Pylint is a program very similar to pep8, it just checks different things. The pylint’s goal is to look for common errors in programs and find potential code smells.

Installation

You can install pylint in a similar way as pep8:

pip install pylint

Usage

Usage is similar as well:

pylint --reports=n test.py

Notice there is –reports argument. Without it, the output is much longer and quiet messy.

The output of the above command is:

No config file found, using default configuration
************* Module test
C:  1,0: Line too long (100/80)
C:  2,0:sth: Invalid name "a" for type argument (should match [a-z_][a-z0-9_]{2,30}$)
C:  2,0:sth: Missing docstring
C:  2,12:sth: Invalid name "a" for type variable (should match [a-z_][a-z0-9_]{2,30}$)
C:  4,0:sth1: Comma not followed by a space
def sth1 ( a,b,c):
            ^^
C:  4,0:sth1: Invalid name "a" for type argument (should match [a-z_][a-z0-9_]{2,30}$)
C:  4,0:sth1: Invalid name "b" for type argument (should match [a-z_][a-z0-9_]{2,30}$)
C:  4,0:sth1: Invalid name "c" for type argument (should match [a-z_][a-z0-9_]{2,30}$)
C:  4,0:sth1: Missing docstring
C:  4,11:sth1: Invalid name "a" for type variable (should match [a-z_][a-z0-9_]{2,30}$)
C:  4,13:sth1: Invalid name "b" for type variable (should match [a-z_][a-z0-9_]{2,30}$)
C:  4,15:sth1: Invalid name "c" for type variable (should match [a-z_][a-z0-9_]{2,30}$)
W:  5,4:sth1: Statement seems to have no effect

Configuration

For pylint you can decide which problems should be ignored as well. If I want to ignore some errors, you have to know its number first. You can get the number in two ways, you can check at pylint errors list or add the message number with argument –include-ids=y:

pylint --reports=n --include-ids=y test.py
No config file found, using default configuration
************* Module test
C0301:  1,0: Line too long (100/80)
C0103:  2,0:sth: Invalid name "a" for type argument (should match [a-z_][a-z0-9_]{2,30}$)
C0111:  2,0:sth: Missing docstring
C0103:  2,12:sth: Invalid name "a" for type variable (should match [a-z_][a-z0-9_]{2,30}$)
C0324:  4,0:sth1: Comma not followed by a space
def sth1 ( a,b,c):
            ^^
C0103:  4,0:sth1: Invalid name "a" for type argument (should match [a-z_][a-z0-9_]{2,30}$)
C0103:  4,0:sth1: Invalid name "b" for type argument (should match [a-z_][a-z0-9_]{2,30}$)
C0103:  4,0:sth1: Invalid name "c" for type argument (should match [a-z_][a-z0-9_]{2,30}$)
C0111:  4,0:sth1: Missing docstring
C0103:  4,11:sth1: Invalid name "a" for type variable (should match [a-z_][a-z0-9_]{2,30}$)
C0103:  4,13:sth1: Invalid name "b" for type variable (should match [a-z_][a-z0-9_]{2,30}$)
C0103:  4,15:sth1: Invalid name "c" for type variable (should match [a-z_][a-z0-9_]{2,30}$)
W0104:  5,4:sth1: Statement seems to have no effect

Now I know the number of the problem I want to ignore, let’s assume it is C0103, then I can ignore it with:

pylint --reports=n --include-ids=y --disable=C0103 test.py
No config file found, using default configuration
************* Module test
C0301:  1,0: Line too long (100/80)
C0111:  2,0:sth: Missing docstring
C0324:  4,0:sth1: Comma not followed by a space
def sth1 ( a,b,c):
            ^^
C0111:  4,0:sth1: Missing docstring
W0104:  5,4:sth1: Statement seems to have no effect
Config file

Pylint also supports setting the options in a config file. This config file can be a little bit complicated, and I think the best way is to let pylint generate the file, this can be done with the –generate-rcfile argument:

pylint --reports=n --include-ids=y --disable=C0103 --generate-rcfile > .pylint

This will create config file with all default settings and the changes from the command line.

To use the new config file, you should use the –rcfile argument:

pylint --rcfile=.pylint test.py

Pylint is great—​sometimes even too great.

I usually ignore many of the errors, as too often the changes needed to satisfy pylint are not worth time spending on them. One of common problems found by pylint is that the variable name is too short. It has a rule that all the names should have between 2 and 30 characters. There is nothing bad with one letter variable, especially when it is something like Point(x, y) or it is a small local variable, something like for i in xrange(1,1000).

However on the other hand when a variable has much broader usage, or it should have some meaningful name to have code easier to read, it is a good idea to change the code.

For me it is good to have pylint checking such errors, so I don’t want pylint to ignore them. Sometimes it is OK to have code which violates those rules, so I just ignore them after ensuring that it is on purpose.

python


Понравилась статья? Поделить с друзьями:
  • Blade and soul system error 100 неверный пароль
  • Blackvue ошибка 1 gps
  • Blackvue dashcam module error
  • Blackvue dashcam model error
  • Blacksprut com error code 1020 blacksprutl1 com