Compare commits
7 commits
e8b1330809
...
b6761c2824
Author | SHA1 | Date | |
---|---|---|---|
b6761c2824 | |||
74ccfec742 | |||
426bd118aa | |||
0930d20224 | |||
9687313cb4 | |||
450421ce0d | |||
1728effd97 |
6 changed files with 392 additions and 137 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -1,5 +1,10 @@
|
||||||
files/
|
files/
|
||||||
convert/
|
convert/
|
||||||
tagged/
|
tagged/
|
||||||
.vscode/
|
|
||||||
lyrics.txt
|
lyrics.txt
|
||||||
|
input
|
||||||
|
|
||||||
|
__pycache__/
|
||||||
|
.mypy_cache/
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
|
|
@ -11,14 +11,14 @@ import mimetypes
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from typing import TypedDict
|
from typing import TypedDict
|
||||||
from typing import Optional
|
from typing import Optional, Any
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup # type: ignore
|
||||||
|
|
||||||
from mutagen.id3 import ID3
|
from mutagen.id3 import ID3 # type: ignore
|
||||||
from mutagen.id3 import TPE1, TIT2, TALB
|
from mutagen.id3 import TPE1, TIT2, TALB
|
||||||
from mutagen.id3 import TYER, TRCK
|
from mutagen.id3 import TYER, TRCK
|
||||||
from mutagen.id3 import USLT, APIC
|
from mutagen.id3 import USLT, APIC
|
||||||
|
@ -53,15 +53,30 @@ class ParseResult(TypedDict):
|
||||||
|
|
||||||
class ParseError(Exception):
|
class ParseError(Exception):
|
||||||
|
|
||||||
|
EDIT = 'edit'
|
||||||
|
|
||||||
def __init__(self, parsing_obj: str) -> None:
|
def __init__(self, parsing_obj: str) -> None:
|
||||||
|
|
||||||
super().__init__(
|
super().__init__(
|
||||||
f'Unable to parse {parsing_obj}'
|
f'Unable to parse {parsing_obj}'
|
||||||
)
|
)
|
||||||
|
self.parsing_obj = parsing_obj
|
||||||
|
|
||||||
|
|
||||||
|
parsed = ParseResult(
|
||||||
|
title='', artist='',
|
||||||
|
album='', year=0,
|
||||||
|
track_no=0, tracks=0,
|
||||||
|
lyrics='',
|
||||||
|
cover=None,
|
||||||
|
cover_mime=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
|
|
||||||
|
global parsed
|
||||||
|
|
||||||
copy = int(sys.argv[1]) == 1
|
copy = int(sys.argv[1]) == 1
|
||||||
file = sys.argv[2]
|
file = sys.argv[2]
|
||||||
|
|
||||||
|
@ -76,25 +91,67 @@ def main() -> None:
|
||||||
print('Title:', title)
|
print('Title:', title)
|
||||||
correct = input().strip()
|
correct = input().strip()
|
||||||
|
|
||||||
parsed: Optional[ParseResult] = None
|
|
||||||
|
|
||||||
if correct == '!--':
|
if correct == '!--':
|
||||||
parsed = manual_info_input()
|
manual_info_input()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
if correct != '':
|
if correct != '':
|
||||||
title = correct.lower()
|
title = correct.lower()
|
||||||
url = search_azurl(title)
|
|
||||||
print(url)
|
|
||||||
parsed = parse_azlyrics(url)
|
|
||||||
|
|
||||||
#print(parsed)
|
try:
|
||||||
tagmp3(file, parsed, copy)
|
url = search_azurl(title)
|
||||||
|
print(url)
|
||||||
|
parse_azlyrics(url)
|
||||||
|
|
||||||
|
except Exception as err:
|
||||||
|
|
||||||
|
print(err)
|
||||||
|
|
||||||
|
# pylint: disable=no-member
|
||||||
|
if isinstance(err, ParseError) \
|
||||||
|
and err.parsing_obj == ParseError.EDIT:
|
||||||
|
pass
|
||||||
|
# pylint: enable=no-member
|
||||||
|
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
'In most cases, this error means that '
|
||||||
|
'the script have received some incorrect data, '
|
||||||
|
'so you should enter song info manually.'
|
||||||
|
)
|
||||||
|
|
||||||
|
manual_info_input(False)
|
||||||
|
|
||||||
|
tagmp3(file, copy)
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=redefined-builtin
|
||||||
|
def input(msg: str = '', def_: Any = '') -> str:
|
||||||
|
|
||||||
|
subprocess.call(
|
||||||
|
(
|
||||||
|
f'read -e -r -i "{def_}" -p "{msg}" input; '
|
||||||
|
'echo -n "$input" >./input'
|
||||||
|
),
|
||||||
|
shell=True,
|
||||||
|
executable='bash',
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open('./input', 'rt', encoding='utf-8') as f:
|
||||||
|
return f.read() \
|
||||||
|
.removesuffix('\n') \
|
||||||
|
.removesuffix('\r')
|
||||||
|
except Exception:
|
||||||
|
return def_
|
||||||
|
# pylint: enable=redefined-builtin
|
||||||
|
|
||||||
|
|
||||||
def input_num(msg: str, def_: int = 0) -> int:
|
def input_num(msg: str, def_: int = 0) -> int:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return int(input(msg))
|
return int(input(msg, def_))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return def_
|
return def_
|
||||||
|
|
||||||
|
@ -135,46 +192,37 @@ def conv_title(file: str) -> str:
|
||||||
def search_azurl(title: str) -> str:
|
def search_azurl(title: str) -> str:
|
||||||
|
|
||||||
print('Searching...')
|
print('Searching...')
|
||||||
|
|
||||||
page = session.get(
|
page = session.get(
|
||||||
'https://searx.dc09.ru/search',
|
'https://searx.dc09.ru/search',
|
||||||
params={
|
params={ # type: ignore
|
||||||
'q': f'{title} site:azlyrics.com',
|
'q': f'{title} site:azlyrics.com',
|
||||||
'category_general': 1,
|
|
||||||
'language': 'ru-RU',
|
'language': 'ru-RU',
|
||||||
'time_range': '',
|
|
||||||
'safesearch': 0,
|
'safesearch': 0,
|
||||||
'theme': 'simple',
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
soup = BeautifulSoup(page.text, 'html.parser')
|
soup = BeautifulSoup(page.text, 'html.parser')
|
||||||
link = soup.select_one(
|
link = soup.select_one(
|
||||||
'div#urls>article>h3>a[href*="azlyrics.com/lyrics/"]'
|
'div#urls>article>h3>a'
|
||||||
|
'[href*="azlyrics.com/lyrics/"]'
|
||||||
)
|
)
|
||||||
|
|
||||||
if link is None:
|
if link is None:
|
||||||
raise ParseError('song URL')
|
raise ParseError('song URL')
|
||||||
|
|
||||||
return str(link.get('href'))
|
return str(link.get('href'))
|
||||||
|
|
||||||
|
|
||||||
def parse_azlyrics(link: str) -> ParseResult:
|
def parse_azlyrics(link: str) -> None:
|
||||||
|
|
||||||
result = ParseResult(
|
global parsed
|
||||||
title='', artist='',
|
|
||||||
album='', year=0,
|
|
||||||
track_no=0, tracks=0,
|
|
||||||
lyrics='',
|
|
||||||
cover=None,
|
|
||||||
cover_mime=None,
|
|
||||||
)
|
|
||||||
|
|
||||||
print('Please wait...')
|
print('Please wait...')
|
||||||
|
|
||||||
page = session.get(link)
|
page = session.get(link)
|
||||||
soup = BeautifulSoup(page.text, 'html.parser')
|
soup = BeautifulSoup(page.text, 'html.parser')
|
||||||
|
|
||||||
lyrics = soup.select_one(
|
lyrics = soup.select_one(
|
||||||
f'{LYRICS_ROW}>div'
|
f'{LYRICS_ROW}>div'
|
||||||
':not(.div-share)'
|
':not(.div-share)'
|
||||||
|
@ -183,127 +231,107 @@ def parse_azlyrics(link: str) -> ParseResult:
|
||||||
)
|
)
|
||||||
if lyrics is None:
|
if lyrics is None:
|
||||||
raise ParseError('song lyrics')
|
raise ParseError('song lyrics')
|
||||||
result['lyrics'] = lyrics.get_text().strip()
|
parsed['lyrics'] = lyrics.get_text().strip()
|
||||||
|
|
||||||
artist_elem = soup.select_one(f'{LYRICS_ROW}>.lyricsh>h2')
|
lyrics_file = Path('.') / 'lyrics.txt'
|
||||||
if artist_elem is None:
|
with lyrics_file.open('wt', encoding='utf-8') as f:
|
||||||
print('Unable to parse artist name')
|
f.write(parsed['lyrics'])
|
||||||
result['artist'] = input('Enter the artist name: ')
|
|
||||||
else:
|
|
||||||
result['artist'] = artist_elem.get_text() \
|
|
||||||
.removesuffix(' Lyrics') \
|
|
||||||
.strip()
|
|
||||||
|
|
||||||
title_elem = soup.select_one(f'{LYRICS_ROW}>b')
|
title_elem = soup.select_one(f'{LYRICS_ROW}>b')
|
||||||
if title_elem is None:
|
if title_elem is None:
|
||||||
print('Unable to parse song title')
|
raise ParseError('song title')
|
||||||
result['title'] = input('Enter the title: ')
|
parsed['title'] = title_elem.get_text().strip('" ')
|
||||||
else:
|
|
||||||
result['title'] = title_elem.get_text().strip('" ')
|
artist_elem = soup.select_one(f'{LYRICS_ROW}>.lyricsh>h2')
|
||||||
|
if artist_elem is None:
|
||||||
|
raise ParseError('artist name')
|
||||||
|
parsed['artist'] = artist_elem.get_text() \
|
||||||
|
.removesuffix(' Lyrics') \
|
||||||
|
.strip()
|
||||||
|
|
||||||
album_blocks = soup.select('.songinalbum_title')
|
album_blocks = soup.select('.songinalbum_title')
|
||||||
album = None
|
album = None
|
||||||
|
|
||||||
if len(album_blocks) > 1:
|
if len(album_blocks) > 1:
|
||||||
album = album_blocks[-2]
|
album = album_blocks[-2]
|
||||||
|
|
||||||
elif len(album_blocks) > 0:
|
elif len(album_blocks) > 0:
|
||||||
album = album_blocks[0]
|
album = album_blocks[0]
|
||||||
|
|
||||||
if album is None:
|
|
||||||
album_re = None
|
|
||||||
else:
|
else:
|
||||||
album_re = re.search(
|
raise ParseError('album name')
|
||||||
r'album:\s*"(.+?)"\s*\((\d+)\)',
|
|
||||||
album.get_text()
|
album_re = re.search(
|
||||||
|
r'album:\s*"(.+?)"\s*\((\d+)\)',
|
||||||
|
album.get_text()
|
||||||
|
)
|
||||||
|
if album_re is None:
|
||||||
|
raise ParseError('album name')
|
||||||
|
|
||||||
|
parsed['album'] = album_re[1]
|
||||||
|
parsed['year'] = int(album_re[2])
|
||||||
|
|
||||||
|
cover = album.select_one('img.album-image')
|
||||||
|
|
||||||
|
if cover is not None:
|
||||||
|
|
||||||
|
cover_url = str(cover.get('src'))
|
||||||
|
if cover_url.startswith('/'):
|
||||||
|
cover_url = BASEURL + cover_url
|
||||||
|
|
||||||
|
req = session.get(cover_url)
|
||||||
|
parsed['cover'] = req.content
|
||||||
|
parsed['cover_mime'] = req.headers.get(
|
||||||
|
'Content-Type', 'image/jpeg'
|
||||||
)
|
)
|
||||||
|
|
||||||
if album_re is None:
|
tracklist_elem = soup.select_one('.songlist-panel')
|
||||||
print('Unable to parse album name')
|
if tracklist_elem is not None:
|
||||||
result['album'] = input('Enter the album name: ')
|
|
||||||
result['year'] = input_num('Enter the release year: ')
|
|
||||||
result['track_no'] = input_num('This is the track #')
|
|
||||||
result['tracks'] = input_num('Number of tracks in the album: ')
|
|
||||||
|
|
||||||
cover = input('Insert an album cover? [Y/n] ')
|
tracklist = tracklist_elem.select(
|
||||||
if cover.lower() not in ('n','н'):
|
'.listalbum-item'
|
||||||
try:
|
)
|
||||||
print(
|
parsed['tracks'] = len(tracklist)
|
||||||
'Download the cover and enter its path:',
|
|
||||||
'(relative path is not recommended)',
|
|
||||||
sep='\n',
|
|
||||||
)
|
|
||||||
cover_file = Path(input().strip())
|
|
||||||
|
|
||||||
with cover_file.open('rb') as f:
|
current_url = re.search(
|
||||||
result['cover'] = f.read()
|
r'/(lyrics/.+?\.html)',
|
||||||
|
link,
|
||||||
|
)
|
||||||
|
|
||||||
result['cover_mime'] = (
|
parsed['track_no'] = 0
|
||||||
mimetypes.guess_type(cover_file)[0]
|
if current_url is not None:
|
||||||
or 'image/jpeg'
|
for i, track in enumerate(tracklist):
|
||||||
)
|
|
||||||
except Exception as err:
|
|
||||||
logging.exception(err)
|
|
||||||
|
|
||||||
else:
|
track_url = track.select_one('a')
|
||||||
result['album'] = album_re[1]
|
if track_url is None:
|
||||||
result['year'] = int(album_re[2])
|
continue
|
||||||
|
|
||||||
assert album is not None
|
track_href = str(track_url.get('href'))
|
||||||
cover = album.select_one('img.album-image')
|
if current_url[0] in track_href:
|
||||||
|
parsed['track_no'] = (i + 1)
|
||||||
|
break
|
||||||
|
|
||||||
if cover is not None:
|
print('Succesfully parsed')
|
||||||
|
print('Title:', parsed['title'])
|
||||||
|
print('Artist:', parsed['artist'])
|
||||||
|
print('Album:', parsed['album'])
|
||||||
|
print('Track:', parsed['track_no'], '/', parsed['tracks'])
|
||||||
|
print('Correct something?')
|
||||||
|
|
||||||
cover_url = str(cover.get('src'))
|
if input('[y/N] ').lower == 'y':
|
||||||
if cover_url.startswith('/'):
|
raise ParseError(ParseError.EDIT)
|
||||||
cover_url = BASEURL + cover_url
|
|
||||||
|
|
||||||
req = session.get(cover_url)
|
print()
|
||||||
result['cover'] = req.content
|
|
||||||
result['cover_mime'] = req.headers.get(
|
|
||||||
'Content-Type', 'image/jpeg'
|
|
||||||
)
|
|
||||||
|
|
||||||
tracklist_elem = soup.select_one('.songlist-panel')
|
|
||||||
if tracklist_elem is not None:
|
|
||||||
|
|
||||||
tracklist = tracklist_elem.select(
|
|
||||||
'.listalbum-item'
|
|
||||||
)
|
|
||||||
result['tracks'] = len(tracklist)
|
|
||||||
|
|
||||||
current_url = re.search(
|
|
||||||
r'/(lyrics/.+?\.html)',
|
|
||||||
link,
|
|
||||||
)
|
|
||||||
|
|
||||||
result['track_no'] = 0
|
|
||||||
if current_url is not None:
|
|
||||||
for i, track in enumerate(tracklist):
|
|
||||||
|
|
||||||
track_url = track.select_one('a')
|
|
||||||
if track_url is None:
|
|
||||||
continue
|
|
||||||
|
|
||||||
track_href = str(track_url.get('href'))
|
|
||||||
if current_url[0] in track_href:
|
|
||||||
result['track_no'] = (i + 1)
|
|
||||||
break
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def manual_info_input() -> ParseResult:
|
def manual_info_input(overwrite_lyrics: bool = True) -> None:
|
||||||
|
|
||||||
result = ParseResult(
|
global parsed
|
||||||
title=input('Song title: '),
|
|
||||||
artist=input('Artist name: '),
|
parsed['title'] = input('Song title: ', parsed['title'])
|
||||||
album=input('Album name: '),
|
parsed['artist'] = input('Artist name: ', parsed['artist'])
|
||||||
year=input_num('Release year: '),
|
parsed['album'] = input('Album name: ', parsed['album'])
|
||||||
track_no=input_num('Track #'),
|
parsed['year'] = input_num('Release year: ', parsed['year'])
|
||||||
tracks=input_num('Tracks in album: '),
|
parsed['track_no'] = input_num('Track #', parsed['track_no'])
|
||||||
lyrics='', cover=None, cover_mime=None,
|
parsed['tracks'] = input_num('Tracks in album: ', parsed['tracks'])
|
||||||
)
|
|
||||||
|
|
||||||
editor = os.getenv('EDITOR', 'nano')
|
editor = os.getenv('EDITOR', 'nano')
|
||||||
print('Now, paste the lyrics into a text editor')
|
print('Now, paste the lyrics into a text editor')
|
||||||
|
@ -316,8 +344,10 @@ def manual_info_input() -> ParseResult:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
lyrics_file = Path('.') / 'lyrics.txt'
|
lyrics_file = Path('.') / 'lyrics.txt'
|
||||||
with lyrics_file.open('wt') as f:
|
|
||||||
f.write('\n')
|
if overwrite_lyrics or not lyrics_file.exists():
|
||||||
|
with lyrics_file.open('wt') as f:
|
||||||
|
f.write('\n')
|
||||||
|
|
||||||
subprocess.call([
|
subprocess.call([
|
||||||
editor,
|
editor,
|
||||||
|
@ -326,14 +356,14 @@ def manual_info_input() -> ParseResult:
|
||||||
|
|
||||||
print('Reading file...')
|
print('Reading file...')
|
||||||
with open('lyrics.txt', 'rt', encoding='utf-8') as f:
|
with open('lyrics.txt', 'rt', encoding='utf-8') as f:
|
||||||
result['lyrics'] = f.read().strip()
|
parsed['lyrics'] = f.read().strip()
|
||||||
print('Done')
|
print('Done')
|
||||||
|
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
logging.exception(err)
|
logging.exception(err)
|
||||||
|
|
||||||
cover = input('Insert an album cover? [Y/n] ')
|
cover = input('Insert an album cover? [Y/n] ')
|
||||||
if cover.lower() not in ('n','н'):
|
if cover.lower() != 'n':
|
||||||
try:
|
try:
|
||||||
print(
|
print(
|
||||||
'Download the cover and enter its path:',
|
'Download the cover and enter its path:',
|
||||||
|
@ -343,26 +373,27 @@ def manual_info_input() -> ParseResult:
|
||||||
cover_file = Path(input().strip())
|
cover_file = Path(input().strip())
|
||||||
|
|
||||||
with cover_file.open('rb') as f:
|
with cover_file.open('rb') as f:
|
||||||
result['cover'] = f.read()
|
parsed['cover'] = f.read()
|
||||||
|
|
||||||
result['cover_mime'] = (
|
parsed['cover_mime'] = (
|
||||||
mimetypes.guess_type(cover_file)[0]
|
mimetypes.guess_type(cover_file)[0]
|
||||||
or 'image/jpeg'
|
or 'image/jpeg'
|
||||||
)
|
)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logging.exception(err)
|
logging.exception(err)
|
||||||
|
|
||||||
return result
|
print()
|
||||||
|
|
||||||
|
|
||||||
def tagmp3(
|
def tagmp3(
|
||||||
file: str,
|
file: str,
|
||||||
parsed: ParseResult,
|
|
||||||
copy: bool) -> None:
|
copy: bool) -> None:
|
||||||
|
|
||||||
|
global parsed
|
||||||
|
|
||||||
oldpath = Path(file)
|
oldpath = Path(file)
|
||||||
newpath = oldpath
|
newpath = oldpath
|
||||||
|
|
||||||
if copy:
|
if copy:
|
||||||
|
|
||||||
newdir = (
|
newdir = (
|
||||||
|
@ -387,7 +418,7 @@ def tagmp3(
|
||||||
cover = newdir / f'cover{ext}'
|
cover = newdir / f'cover{ext}'
|
||||||
with cover.open('wb') as f:
|
with cover.open('wb') as f:
|
||||||
f.write(parsed['cover'])
|
f.write(parsed['cover'])
|
||||||
|
|
||||||
id3 = ID3(str(newpath))
|
id3 = ID3(str(newpath))
|
||||||
id3['TPE1'] = TPE1(text=parsed['artist'])
|
id3['TPE1'] = TPE1(text=parsed['artist'])
|
||||||
id3['TIT2'] = TIT2(text=parsed['title'])
|
id3['TIT2'] = TIT2(text=parsed['title'])
|
||||||
|
|
26
Makefile
Normal file
26
Makefile
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
clean:
|
||||||
|
rm -rf __pycache__/
|
||||||
|
rm -rf .mypy_cache/
|
||||||
|
rm -f lyrics.txt input
|
||||||
|
|
||||||
|
deps:
|
||||||
|
python3 -m pip install -r requirements.txt
|
||||||
|
|
||||||
|
run:
|
||||||
|
chmod +x ./autoytdlp.sh
|
||||||
|
./autoytdlp.sh
|
||||||
|
|
||||||
|
conv:
|
||||||
|
chmod +x ./convert.sh
|
||||||
|
./convert.sh
|
||||||
|
|
||||||
|
tags:
|
||||||
|
chmod +x ./id3tag.sh
|
||||||
|
./id3tag.sh
|
||||||
|
|
||||||
|
pyformat:
|
||||||
|
python3 -m autopep8 --in-place .*.py
|
||||||
|
|
||||||
|
pycheck:
|
||||||
|
python3 -m mypy .*.py
|
||||||
|
python3 -m pylint -j4 .*.py
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
debug=1
|
debug=0
|
||||||
watching=1
|
watching=1
|
||||||
links=()
|
links=()
|
||||||
success=0
|
success=0
|
||||||
|
|
|
@ -20,3 +20,5 @@ echo
|
||||||
|
|
||||||
find "$directory" -type f -name "*.mp3" -exec \
|
find "$directory" -type f -name "*.mp3" -exec \
|
||||||
python3 ./.id3tag_helper.py "$copy_arg" {} \;
|
python3 ./.id3tag_helper.py "$copy_arg" {} \;
|
||||||
|
|
||||||
|
rm -f ./input
|
||||||
|
|
191
pylintrc
Normal file
191
pylintrc
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
[MAIN]
|
||||||
|
analyse-fallback-blocks=no
|
||||||
|
extension-pkg-allow-list=
|
||||||
|
extension-pkg-whitelist=
|
||||||
|
fail-on=
|
||||||
|
fail-under=10
|
||||||
|
ignore=CVS
|
||||||
|
ignore-paths=
|
||||||
|
ignore-patterns=^\.#
|
||||||
|
ignored-modules=
|
||||||
|
jobs=4
|
||||||
|
limit-inference-results=100
|
||||||
|
load-plugins=
|
||||||
|
persistent=yes
|
||||||
|
py-version=3.10
|
||||||
|
recursive=no
|
||||||
|
suggestion-mode=yes
|
||||||
|
unsafe-load-any-extension=no
|
||||||
|
|
||||||
|
[REPORTS]
|
||||||
|
evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10))
|
||||||
|
msg-template=
|
||||||
|
reports=no
|
||||||
|
score=yes
|
||||||
|
|
||||||
|
[MESSAGES CONTROL]
|
||||||
|
confidence=HIGH,
|
||||||
|
CONTROL_FLOW,
|
||||||
|
INFERENCE,
|
||||||
|
INFERENCE_FAILURE,
|
||||||
|
UNDEFINED
|
||||||
|
disable=raw-checker-failed,
|
||||||
|
bad-inline-option,
|
||||||
|
locally-disabled,
|
||||||
|
file-ignored,
|
||||||
|
suppressed-message,
|
||||||
|
useless-suppression,
|
||||||
|
deprecated-pragma,
|
||||||
|
use-symbolic-message-instead,
|
||||||
|
too-many-branches,
|
||||||
|
too-many-statements,
|
||||||
|
too-many-locals,
|
||||||
|
broad-except,
|
||||||
|
global-variable-not-assigned
|
||||||
|
enable=c-extension-no-member
|
||||||
|
|
||||||
|
[SIMILARITIES]
|
||||||
|
ignore-comments=yes
|
||||||
|
ignore-docstrings=yes
|
||||||
|
ignore-imports=yes
|
||||||
|
ignore-signatures=yes
|
||||||
|
min-similarity-lines=4
|
||||||
|
|
||||||
|
[MISCELLANEOUS]
|
||||||
|
notes=FIXME,
|
||||||
|
XXX,
|
||||||
|
TODO
|
||||||
|
notes-rgx=
|
||||||
|
|
||||||
|
[DESIGN]
|
||||||
|
exclude-too-few-public-methods=
|
||||||
|
ignored-parents=
|
||||||
|
max-args=5
|
||||||
|
max-attributes=7
|
||||||
|
max-bool-expr=5
|
||||||
|
max-branches=12
|
||||||
|
max-locals=15
|
||||||
|
max-parents=7
|
||||||
|
max-public-methods=20
|
||||||
|
max-returns=6
|
||||||
|
max-statements=50
|
||||||
|
min-public-methods=2
|
||||||
|
|
||||||
|
[STRING]
|
||||||
|
check-quote-consistency=no
|
||||||
|
check-str-concat-over-line-jumps=no
|
||||||
|
|
||||||
|
[CLASSES]
|
||||||
|
check-protected-access-in-special-methods=no
|
||||||
|
defining-attr-methods=__init__,
|
||||||
|
__new__,
|
||||||
|
setUp,
|
||||||
|
__post_init__
|
||||||
|
exclude-protected=_asdict,
|
||||||
|
_fields,
|
||||||
|
_replace,
|
||||||
|
_source,
|
||||||
|
_make
|
||||||
|
valid-classmethod-first-arg=cls
|
||||||
|
valid-metaclass-classmethod-first-arg=cls
|
||||||
|
|
||||||
|
[FORMAT]
|
||||||
|
expected-line-ending-format=
|
||||||
|
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
|
||||||
|
indent-after-paren=4
|
||||||
|
indent-string=' '
|
||||||
|
max-line-length=100
|
||||||
|
max-module-lines=1000
|
||||||
|
single-line-class-stmt=no
|
||||||
|
single-line-if-stmt=no
|
||||||
|
|
||||||
|
[IMPORTS]
|
||||||
|
allow-any-import-level=
|
||||||
|
allow-wildcard-with-all=no
|
||||||
|
deprecated-modules=
|
||||||
|
ext-import-graph=
|
||||||
|
import-graph=
|
||||||
|
int-import-graph=
|
||||||
|
known-standard-library=
|
||||||
|
known-third-party=enchant
|
||||||
|
preferred-modules=
|
||||||
|
|
||||||
|
[VARIABLES]
|
||||||
|
additional-builtins=
|
||||||
|
allow-global-unused-variables=yes
|
||||||
|
allowed-redefined-builtins=
|
||||||
|
callbacks=cb_,
|
||||||
|
_cb
|
||||||
|
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
|
||||||
|
ignored-argument-names=_.*|^ignored_|^unused_
|
||||||
|
init-import=no
|
||||||
|
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
|
||||||
|
|
||||||
|
[LOGGING]
|
||||||
|
logging-format-style=old
|
||||||
|
logging-modules=logging
|
||||||
|
|
||||||
|
[EXCEPTIONS]
|
||||||
|
overgeneral-exceptions=BaseException,
|
||||||
|
Exception
|
||||||
|
|
||||||
|
[BASIC]
|
||||||
|
argument-naming-style=snake_case
|
||||||
|
attr-naming-style=snake_case
|
||||||
|
bad-names=foo,
|
||||||
|
bar,
|
||||||
|
baz,
|
||||||
|
toto,
|
||||||
|
tutu,
|
||||||
|
tata
|
||||||
|
bad-names-rgxs=
|
||||||
|
class-attribute-naming-style=any
|
||||||
|
class-const-naming-style=UPPER_CASE
|
||||||
|
class-naming-style=PascalCase
|
||||||
|
const-naming-style=any
|
||||||
|
docstring-min-length=-1
|
||||||
|
function-naming-style=snake_case
|
||||||
|
good-names=i,
|
||||||
|
j,
|
||||||
|
k,
|
||||||
|
f,
|
||||||
|
ex,
|
||||||
|
Run,
|
||||||
|
_
|
||||||
|
good-names-rgxs=
|
||||||
|
include-naming-hint=no
|
||||||
|
inlinevar-naming-style=any
|
||||||
|
method-naming-style=snake_case
|
||||||
|
module-naming-style=snake_case
|
||||||
|
name-group=
|
||||||
|
no-docstring-rgx=^_
|
||||||
|
property-classes=abc.abstractproperty
|
||||||
|
variable-naming-style=snake_case
|
||||||
|
|
||||||
|
[SPELLING]
|
||||||
|
max-spelling-suggestions=4
|
||||||
|
spelling-dict=
|
||||||
|
spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy:
|
||||||
|
spelling-ignore-words=
|
||||||
|
spelling-private-dict-file=
|
||||||
|
spelling-store-unknown-words=no
|
||||||
|
|
||||||
|
[TYPECHECK]
|
||||||
|
contextmanager-decorators=contextlib.contextmanager
|
||||||
|
generated-members=
|
||||||
|
ignore-none=yes
|
||||||
|
ignore-on-opaque-inference=yes
|
||||||
|
ignored-checks-for-mixins=no-member,
|
||||||
|
not-async-context-manager,
|
||||||
|
not-context-manager,
|
||||||
|
attribute-defined-outside-init
|
||||||
|
ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace
|
||||||
|
missing-member-hint=yes
|
||||||
|
missing-member-hint-distance=1
|
||||||
|
missing-member-max-choices=1
|
||||||
|
mixin-class-rgx=.*[Mm]ixin
|
||||||
|
signature-mutators=
|
||||||
|
|
||||||
|
[REFACTORING]
|
||||||
|
max-nested-blocks=5
|
||||||
|
never-returning-functions=sys.exit,argparse.parse_error
|
Reference in a new issue