diff --git a/.gitignore b/.gitignore
index d0cafa3d..54a15d6e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@ __pycache__
*.swp
*.swo
.vscode/
+.mypy_cache/
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 00000000..5f583325
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,59 @@
+repos:
+ - repo: https://github.com/asottile/pyupgrade
+ rev: v2.3.0
+ hooks:
+ - id: pyupgrade
+ args: [--py37-plus]
+ - repo: https://github.com/psf/black
+ rev: 19.10b0
+ hooks:
+ - id: black
+ args:
+ - --safe
+ - --quiet
+ files: ^((homeassistant|script|tests)/.+)?[^/]+\.py$
+ - repo: https://github.com/codespell-project/codespell
+ rev: v1.16.0
+ hooks:
+ - id: codespell
+ args:
+ - --ignore-words-list=hass,alot,datas,dof,dur,farenheit,hist,iff,ines,ist,lightsensor,mut,nd,pres,referer,ser,serie,te,technik,ue,uint,visability,wan,wanna,withing
+ - --skip="./.*,*.csv,*.json"
+ - --quiet-level=2
+ exclude_types: [csv, json]
+ - repo: https://gitlab.com/pycqa/flake8
+ rev: 3.8.1
+ hooks:
+ - id: flake8
+ additional_dependencies:
+ - flake8-docstrings==1.5.0
+ - pydocstyle==5.0.2
+ files: ^(homeassistant|script|tests)/.+\.py$
+ - repo: https://github.com/PyCQA/bandit
+ rev: 1.6.2
+ hooks:
+ - id: bandit
+ args:
+ - --quiet
+ - --format=custom
+ - --configfile=tests/bandit.yaml
+ files: ^(homeassistant|script|tests)/.+\.py$
+ - repo: https://github.com/pre-commit/mirrors-isort
+ rev: v4.3.21
+ hooks:
+ - id: isort
+ - repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v2.4.0
+ hooks:
+ - id: check-executables-have-shebangs
+ stages: [manual]
+ - id: check-json
+ - repo: https://github.com/pre-commit/mirrors-mypy
+ rev: v0.770
+ hooks:
+ - id: mypy
+ args:
+ - --pretty
+ - --show-error-codes
+ - --show-error-context
+ - --ignore-missing-imports
diff --git a/README.md b/README.md
index 2f53a462..07d98dbb 100644
--- a/README.md
+++ b/README.md
@@ -43,7 +43,7 @@ Currently the following service providers are supported:
The configuration consists of 2 entries in configuration.yaml.
1. Source configuration
- A source is a used to retrieve the data from a web service. Multiple source can be created at the same time. Even a single source can be created multiple times (with different arguments), e.g. if you want to see the waste collection schedule for multple districts.
+ A source is a used to retrieve the data from a web service. Multiple source can be created at the same time. Even a single source can be created multiple times (with different arguments), e.g. if you want to see the waste collection schedule for multiple districts.
2. Sensor configuration
For every Source, one or more sensors can be defined to visualize the retrieved data. For each sensor, the entity state format, date format, details view and other properties can be customized.
diff --git a/custom_components/waste_collection_schedule/__init__.py b/custom_components/waste_collection_schedule/__init__.py
index 14c66116..6c585f6d 100644
--- a/custom_components/waste_collection_schedule/__init__.py
+++ b/custom_components/waste_collection_schedule/__init__.py
@@ -3,16 +3,16 @@ import asyncio
import logging
from random import randrange
-import voluptuous as vol
-
-from homeassistant.core import HomeAssistant, callback
import homeassistant.helpers.config_validation as cv
-from homeassistant.helpers.event import async_call_later, async_track_time_change
import homeassistant.util.dt as dt_util
+import voluptuous as vol
+from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import dispatcher_send
+from homeassistant.helpers.event import (async_call_later,
+ async_track_time_change)
from .const import DOMAIN, UPDATE_SENSORS_SIGNAL
-from .package.scraper import Scraper, Customize
+from .package.scraper import Customize, Scraper
_LOGGER = logging.getLogger(__name__)
diff --git a/custom_components/waste_collection_schedule/package/scraper.py b/custom_components/waste_collection_schedule/package/scraper.py
index 25fc9dc3..79d4c60c 100644
--- a/custom_components/waste_collection_schedule/package/scraper.py
+++ b/custom_components/waste_collection_schedule/package/scraper.py
@@ -1,12 +1,12 @@
#!/usr/bin/python3
-from itertools import islice
-import logging
import collections
-import os
import datetime
import importlib
import itertools
+import logging
+import os
+from itertools import islice
from .helpers import CollectionAppointment, CollectionAppointmentGroup
@@ -154,7 +154,7 @@ class Scraper:
# remove unwanted waste types
if types is not None:
# generate set
- types_set = set(t for t in types)
+ types_set = {t for t in types}
entries = list(filter(lambda e: e.type in types_set, self._entries))
# remove expired entries
diff --git a/custom_components/waste_collection_schedule/package/service/AbfallnaviDe.py b/custom_components/waste_collection_schedule/package/service/AbfallnaviDe.py
index 711ad584..b384ebfc 100644
--- a/custom_components/waste_collection_schedule/package/service/AbfallnaviDe.py
+++ b/custom_components/waste_collection_schedule/package/service/AbfallnaviDe.py
@@ -1,8 +1,9 @@
#!/usr/bin/env python3
-import requests
-import json
import datetime
+import json
+
+import requests
SERVICE_DOMAINS = {
"aachen": "Aachen",
@@ -25,7 +26,7 @@ SERVICE_DOMAINS = {
"wml2": "EGW Westmünsterland",
}
-class AbfallnaviDe(object):
+class AbfallnaviDe:
def __init__(self, service_domain):
self._service_domain = service_domain
self._service_url = f"https://{service_domain}-abfallapp.regioit.de/abfall-app-{service_domain}/rest"
@@ -152,4 +153,3 @@ def main():
if __name__ == "__main__":
main()
-
diff --git a/custom_components/waste_collection_schedule/package/service/ICS.py b/custom_components/waste_collection_schedule/package/service/ICS.py
index 5a45ddd4..033fa029 100644
--- a/custom_components/waste_collection_schedule/package/service/ICS.py
+++ b/custom_components/waste_collection_schedule/package/service/ICS.py
@@ -1,5 +1,6 @@
-import re
import datetime
+import re
+
import icalendar
import recurring_ical_events
diff --git a/custom_components/waste_collection_schedule/package/source/abfall_io.py b/custom_components/waste_collection_schedule/package/source/abfall_io.py
index 0246724b..383e3786 100644
--- a/custom_components/waste_collection_schedule/package/source/abfall_io.py
+++ b/custom_components/waste_collection_schedule/package/source/abfall_io.py
@@ -1,10 +1,10 @@
-import requests
import csv
import datetime
from collections import OrderedDict
-from ..helpers import CollectionAppointment
+import requests
+from ..helpers import CollectionAppointment
DESCRIPTION = "Source for AbfallPlus.de based services. Service is hosted on abfall.io"
URL = "https://www.abfallplus.de"
diff --git a/custom_components/waste_collection_schedule/package/source/abfall_kreis_tuebingen_de.py b/custom_components/waste_collection_schedule/package/source/abfall_kreis_tuebingen_de.py
index 7b279855..41e3a665 100644
--- a/custom_components/waste_collection_schedule/package/source/abfall_kreis_tuebingen_de.py
+++ b/custom_components/waste_collection_schedule/package/source/abfall_kreis_tuebingen_de.py
@@ -1,9 +1,10 @@
import datetime
-import requests
-from ..helpers import CollectionAppointment
from collections import OrderedDict
-from ..service.ICS import ICS
+import requests
+
+from ..helpers import CollectionAppointment
+from ..service.ICS import ICS
DESCRIPTION = "Source for Abfall Landkreis Tuebingen"
URL = "https://www.abfall-kreis-tuebingen.de"
diff --git a/custom_components/waste_collection_schedule/package/source/abfall_zollernalbkreis_de.py b/custom_components/waste_collection_schedule/package/source/abfall_zollernalbkreis_de.py
index e037bb0d..01c3b0f4 100644
--- a/custom_components/waste_collection_schedule/package/source/abfall_zollernalbkreis_de.py
+++ b/custom_components/waste_collection_schedule/package/source/abfall_zollernalbkreis_de.py
@@ -1,11 +1,11 @@
-import requests
-from datetime import date, datetime
from collections import OrderedDict
+from datetime import date, datetime
+
+import requests
from ..helpers import CollectionAppointment
from ..service.ICS import ICS
-
DESCRIPTION = "Source for Abfallwirtschaft Zollernalbkreis based services"
URL = "https://www.abfallkalender-zak.de"
TEST_CASES = OrderedDict(
diff --git a/custom_components/waste_collection_schedule/package/source/abfallnavi_de.py b/custom_components/waste_collection_schedule/package/source/abfallnavi_de.py
index 6f3c689f..6b56650c 100644
--- a/custom_components/waste_collection_schedule/package/source/abfallnavi_de.py
+++ b/custom_components/waste_collection_schedule/package/source/abfallnavi_de.py
@@ -3,7 +3,6 @@ from collections import OrderedDict
from ..helpers import CollectionAppointment
from ..service.AbfallnaviDe import AbfallnaviDe
-
DESCRIPTION = "Source for AbfallNavi (= regioit.de) based services"
URL = "https://www.regioit.de"
TEST_CASES = OrderedDict(
diff --git a/custom_components/waste_collection_schedule/package/source/awbkoeln_de.py b/custom_components/waste_collection_schedule/package/source/awbkoeln_de.py
index 217911ec..7b240618 100644
--- a/custom_components/waste_collection_schedule/package/source/awbkoeln_de.py
+++ b/custom_components/waste_collection_schedule/package/source/awbkoeln_de.py
@@ -1,10 +1,10 @@
-import requests
-import json
import datetime
+import json
from collections import OrderedDict
-from ..helpers import CollectionAppointment
+import requests
+from ..helpers import CollectionAppointment
DESCRIPTION = "Source for AWB Koeln."
URL = "https://www.awbkoeln.de"
diff --git a/custom_components/waste_collection_schedule/package/source/bsr_de.py b/custom_components/waste_collection_schedule/package/source/bsr_de.py
index 186d4818..ced143b5 100644
--- a/custom_components/waste_collection_schedule/package/source/bsr_de.py
+++ b/custom_components/waste_collection_schedule/package/source/bsr_de.py
@@ -1,7 +1,8 @@
-import requests
import datetime
-from collections import OrderedDict
import urllib.parse
+from collections import OrderedDict
+
+import requests
from ..helpers import CollectionAppointment
from ..service.ICS import ICS
diff --git a/custom_components/waste_collection_schedule/package/source/example.py b/custom_components/waste_collection_schedule/package/source/example.py
index f4ddc31c..5095e4f4 100644
--- a/custom_components/waste_collection_schedule/package/source/example.py
+++ b/custom_components/waste_collection_schedule/package/source/example.py
@@ -1,7 +1,7 @@
import datetime
-from ..helpers import CollectionAppointment
from collections import OrderedDict
+from ..helpers import CollectionAppointment
DESCRIPTION = "Example scraper"
URL = ""
diff --git a/custom_components/waste_collection_schedule/package/source/ics.py b/custom_components/waste_collection_schedule/package/source/ics.py
index f82f2907..084abf2d 100644
--- a/custom_components/waste_collection_schedule/package/source/ics.py
+++ b/custom_components/waste_collection_schedule/package/source/ics.py
@@ -1,12 +1,12 @@
-import requests
import datetime
from collections import OrderedDict
from pathlib import Path
+import requests
+
from ..helpers import CollectionAppointment
from ..service.ICS import ICS
-
DESCRIPTION = "Source for ICS based services"
URL = ""
TEST_CASES = OrderedDict(
@@ -113,7 +113,7 @@ class Source:
return self._convert(r.text)
def fetch_file(self, file):
- f = open(file, "r")
+ f = open(file)
return self._convert(f.read())
def _convert(self, data):
diff --git a/custom_components/waste_collection_schedule/package/source/jumomind_de.py b/custom_components/waste_collection_schedule/package/source/jumomind_de.py
index deb74401..f630c264 100644
--- a/custom_components/waste_collection_schedule/package/source/jumomind_de.py
+++ b/custom_components/waste_collection_schedule/package/source/jumomind_de.py
@@ -1,10 +1,10 @@
-import requests
import datetime
import json
from collections import OrderedDict
-from ..helpers import CollectionAppointment
+import requests
+from ..helpers import CollectionAppointment
DESCRIPTION = "Source for Jumomind.de based services."
URL = "https://www.jumomind.de"
diff --git a/custom_components/waste_collection_schedule/package/source/muellmax_de.py b/custom_components/waste_collection_schedule/package/source/muellmax_de.py
index e924e3b4..1f98cfa5 100644
--- a/custom_components/waste_collection_schedule/package/source/muellmax_de.py
+++ b/custom_components/waste_collection_schedule/package/source/muellmax_de.py
@@ -1,8 +1,9 @@
-import requests
import datetime
from collections import OrderedDict
from html.parser import HTMLParser
+import requests
+
from ..helpers import CollectionAppointment
from ..service.ICS import ICS
diff --git a/custom_components/waste_collection_schedule/package/source/stadtreinigung_hamburg.py b/custom_components/waste_collection_schedule/package/source/stadtreinigung_hamburg.py
index 12e475b3..8cf7fdc0 100644
--- a/custom_components/waste_collection_schedule/package/source/stadtreinigung_hamburg.py
+++ b/custom_components/waste_collection_schedule/package/source/stadtreinigung_hamburg.py
@@ -1,10 +1,10 @@
-import requests
from collections import OrderedDict
+import requests
+
from ..helpers import CollectionAppointment
from ..service.ICS import ICS
-
DESCRIPTION = "Source for Stadtreinigung.Hamburg based services."
URL = "https://www.stadtreinigung.hamburg"
TEST_CASES = OrderedDict([("Hamburg", {"asId": 5087, "hnId": 113084})])
diff --git a/custom_components/waste_collection_schedule/package/source/stuttgart_de.py b/custom_components/waste_collection_schedule/package/source/stuttgart_de.py
index 3011045c..68ba5a9c 100644
--- a/custom_components/waste_collection_schedule/package/source/stuttgart_de.py
+++ b/custom_components/waste_collection_schedule/package/source/stuttgart_de.py
@@ -1,8 +1,8 @@
-import requests
import datetime
from collections import OrderedDict
from html.parser import HTMLParser
+import requests
from ..helpers import CollectionAppointment
diff --git a/custom_components/waste_collection_schedule/package/wizard/abfall_io.py b/custom_components/waste_collection_schedule/package/wizard/abfall_io.py
index b3905ef1..1583306e 100755
--- a/custom_components/waste_collection_schedule/package/wizard/abfall_io.py
+++ b/custom_components/waste_collection_schedule/package/wizard/abfall_io.py
@@ -1,8 +1,9 @@
#!/usr/bin/python3
+from html.parser import HTMLParser
+
import inquirer
import requests
-from html.parser import HTMLParser
MODUS_KEY = "d6c5855a62cf32a4dadbc2831f0f295f"
HEADERS = {"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
diff --git a/custom_components/waste_collection_schedule/package/wizard/abfall_kreis_tuebingen_de.py b/custom_components/waste_collection_schedule/package/wizard/abfall_kreis_tuebingen_de.py
index a60ede82..88307323 100755
--- a/custom_components/waste_collection_schedule/package/wizard/abfall_kreis_tuebingen_de.py
+++ b/custom_components/waste_collection_schedule/package/wizard/abfall_kreis_tuebingen_de.py
@@ -1,8 +1,10 @@
#!/usr/bin/python3
+from html.parser import HTMLParser
+
import inquirer
import requests
-from html.parser import HTMLParser
+
# Parser for HTML option list
class OptionParser(HTMLParser):
diff --git a/custom_components/waste_collection_schedule/package/wizard/abfallnavi_de.py b/custom_components/waste_collection_schedule/package/wizard/abfallnavi_de.py
index d340a1ba..bb738778 100755
--- a/custom_components/waste_collection_schedule/package/wizard/abfallnavi_de.py
+++ b/custom_components/waste_collection_schedule/package/wizard/abfallnavi_de.py
@@ -1,17 +1,18 @@
#!/usr/bin/python3
+import json
+import os
+import sys
+
import inquirer
import requests
-import json
-
-import sys
-import os
PACKAGE_PARENT = '..'
SCRIPT_DIR = os.path.dirname(os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__))))
sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT)))
-from service.AbfallnaviDe import AbfallnaviDe, SERVICE_DOMAINS
+from service.AbfallnaviDe import SERVICE_DOMAINS, AbfallnaviDe # isort:skip
+
def convert_dict_to_array(d):
a = []
diff --git a/custom_components/waste_collection_schedule/package/wizard/awbkoeln_de.py b/custom_components/waste_collection_schedule/package/wizard/awbkoeln_de.py
index e0e65f25..cb1c8125 100755
--- a/custom_components/waste_collection_schedule/package/wizard/awbkoeln_de.py
+++ b/custom_components/waste_collection_schedule/package/wizard/awbkoeln_de.py
@@ -1,8 +1,9 @@
#!/usr/bin/python3
+import json
+
import inquirer
import requests
-import json
def main():
diff --git a/custom_components/waste_collection_schedule/package/wizard/bsr_de.py b/custom_components/waste_collection_schedule/package/wizard/bsr_de.py
index ad9ae86f..68b4504c 100755
--- a/custom_components/waste_collection_schedule/package/wizard/bsr_de.py
+++ b/custom_components/waste_collection_schedule/package/wizard/bsr_de.py
@@ -1,8 +1,9 @@
#!/usr/bin/python3
+import json
+
import inquirer
import requests
-import json
def main():
diff --git a/custom_components/waste_collection_schedule/package/wizard/jumomind_de.py b/custom_components/waste_collection_schedule/package/wizard/jumomind_de.py
index 49eb97ce..4cb6df98 100755
--- a/custom_components/waste_collection_schedule/package/wizard/jumomind_de.py
+++ b/custom_components/waste_collection_schedule/package/wizard/jumomind_de.py
@@ -1,8 +1,9 @@
#!/usr/bin/python3
+import json
+
import inquirer
import requests
-import json
def main():
diff --git a/custom_components/waste_collection_schedule/package/wizard/muellmax_de.py b/custom_components/waste_collection_schedule/package/wizard/muellmax_de.py
index feef96c9..725fe71a 100755
--- a/custom_components/waste_collection_schedule/package/wizard/muellmax_de.py
+++ b/custom_components/waste_collection_schedule/package/wizard/muellmax_de.py
@@ -1,9 +1,10 @@
#!/usr/bin/python3
+import json
+from html.parser import HTMLParser
+
import inquirer
import requests
-import json
-from html.parser import HTMLParser
# Parser for HTML input (hidden) text
diff --git a/custom_components/waste_collection_schedule/package/wizard/stadtreinigung_hamburg.py b/custom_components/waste_collection_schedule/package/wizard/stadtreinigung_hamburg.py
index b797b9df..183d1f21 100755
--- a/custom_components/waste_collection_schedule/package/wizard/stadtreinigung_hamburg.py
+++ b/custom_components/waste_collection_schedule/package/wizard/stadtreinigung_hamburg.py
@@ -1,9 +1,11 @@
#!/usr/bin/python3
+import json
+from html.parser import HTMLParser
+
import inquirer
import requests
-import json
-from html.parser import HTMLParser
+
# Parser for HTML input
class InputParser(HTMLParser):
diff --git a/custom_components/waste_collection_schedule/package/wizard/stuttgart_de.py b/custom_components/waste_collection_schedule/package/wizard/stuttgart_de.py
index 6bd11963..072cc741 100755
--- a/custom_components/waste_collection_schedule/package/wizard/stuttgart_de.py
+++ b/custom_components/waste_collection_schedule/package/wizard/stuttgart_de.py
@@ -1,9 +1,10 @@
#!/usr/bin/python3
+import json
+from html.parser import HTMLParser
+
import inquirer
import requests
-import json
-from html.parser import HTMLParser
def main():
diff --git a/custom_components/waste_collection_schedule/sensor.py b/custom_components/waste_collection_schedule/sensor.py
index ac63c6f1..3384d5e4 100644
--- a/custom_components/waste_collection_schedule/sensor.py
+++ b/custom_components/waste_collection_schedule/sensor.py
@@ -3,15 +3,15 @@
import collections
import datetime
import logging
-import voluptuous as vol
from enum import Enum
-from homeassistant.core import callback
-from homeassistant.components.sensor import PLATFORM_SCHEMA
-from homeassistant.helpers.entity import Entity
-from homeassistant.helpers.dispatcher import async_dispatcher_connect
import homeassistant.helpers.config_validation as cv
+import voluptuous as vol
+from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import CONF_NAME, CONF_VALUE_TEMPLATE, STATE_UNKNOWN
+from homeassistant.core import callback
+from homeassistant.helpers.dispatcher import async_dispatcher_connect
+from homeassistant.helpers.entity import Entity
from .const import DOMAIN, UPDATE_SENSORS_SIGNAL
diff --git a/custom_components/waste_collection_schedule/test_sources.py b/custom_components/waste_collection_schedule/test_sources.py
index ad88984d..99befa37 100755
--- a/custom_components/waste_collection_schedule/test_sources.py
+++ b/custom_components/waste_collection_schedule/test_sources.py
@@ -1,9 +1,9 @@
#!/usr/bin/python3
import argparse
+import importlib
import os
import pathlib
-import importlib
def main():