mirror of
https://github.com/home-assistant/core.git
synced 2025-12-24 21:06:19 +00:00
Black
This commit is contained in:
@@ -10,174 +10,175 @@ import sys
|
||||
from script.hassfest.model import Integration
|
||||
|
||||
COMMENT_REQUIREMENTS = (
|
||||
'Adafruit-DHT',
|
||||
'Adafruit_BBIO',
|
||||
'avion',
|
||||
'beacontools',
|
||||
'blinkt',
|
||||
'bluepy',
|
||||
'bme680',
|
||||
'credstash',
|
||||
'decora',
|
||||
'envirophat',
|
||||
'evdev',
|
||||
'face_recognition',
|
||||
'fritzconnection',
|
||||
'i2csense',
|
||||
'opencv-python-headless',
|
||||
'py_noaa',
|
||||
'VL53L1X2',
|
||||
'pybluez',
|
||||
'pycups',
|
||||
'PySwitchbot',
|
||||
'pySwitchmate',
|
||||
'python-eq3bt',
|
||||
'python-lirc',
|
||||
'pyuserinput',
|
||||
'raspihats',
|
||||
'rpi-rf',
|
||||
'RPi.GPIO',
|
||||
'smbus-cffi',
|
||||
"Adafruit-DHT",
|
||||
"Adafruit_BBIO",
|
||||
"avion",
|
||||
"beacontools",
|
||||
"blinkt",
|
||||
"bluepy",
|
||||
"bme680",
|
||||
"credstash",
|
||||
"decora",
|
||||
"envirophat",
|
||||
"evdev",
|
||||
"face_recognition",
|
||||
"fritzconnection",
|
||||
"i2csense",
|
||||
"opencv-python-headless",
|
||||
"py_noaa",
|
||||
"VL53L1X2",
|
||||
"pybluez",
|
||||
"pycups",
|
||||
"PySwitchbot",
|
||||
"pySwitchmate",
|
||||
"python-eq3bt",
|
||||
"python-lirc",
|
||||
"pyuserinput",
|
||||
"raspihats",
|
||||
"rpi-rf",
|
||||
"RPi.GPIO",
|
||||
"smbus-cffi",
|
||||
)
|
||||
|
||||
TEST_REQUIREMENTS = (
|
||||
'adguardhome',
|
||||
'ambiclimate',
|
||||
'aioambient',
|
||||
'aioautomatic',
|
||||
'aiobotocore',
|
||||
'aioesphomeapi',
|
||||
'aiohttp_cors',
|
||||
'aiohue',
|
||||
'aionotion',
|
||||
'aiounifi',
|
||||
'aioswitcher',
|
||||
'aiowwlln',
|
||||
'apns2',
|
||||
'aprslib',
|
||||
'av',
|
||||
'axis',
|
||||
'caldav',
|
||||
'coinmarketcap',
|
||||
'defusedxml',
|
||||
'dsmr_parser',
|
||||
'eebrightbox',
|
||||
'emulated_roku',
|
||||
'enocean',
|
||||
'ephem',
|
||||
'evohomeclient',
|
||||
'feedparser-homeassistant',
|
||||
'foobot_async',
|
||||
'geojson_client',
|
||||
'geopy',
|
||||
'georss_generic_client',
|
||||
'georss_ign_sismologia_client',
|
||||
'georss_qld_bushfire_alert_client',
|
||||
'google-api-python-client',
|
||||
'gTTS-token',
|
||||
'ha-ffmpeg',
|
||||
'hangups',
|
||||
'HAP-python',
|
||||
'hass-nabucasa',
|
||||
'haversine',
|
||||
'hbmqtt',
|
||||
'hdate',
|
||||
'holidays',
|
||||
'home-assistant-frontend',
|
||||
'homekit[IP]',
|
||||
'homematicip',
|
||||
'httplib2',
|
||||
'huawei-lte-api',
|
||||
'influxdb',
|
||||
'jsonpath',
|
||||
'libpurecool',
|
||||
'libsoundtouch',
|
||||
'luftdaten',
|
||||
'pyMetno',
|
||||
'mbddns',
|
||||
'mficlient',
|
||||
'netdisco',
|
||||
'numpy',
|
||||
'oauth2client',
|
||||
'paho-mqtt',
|
||||
'pexpect',
|
||||
'pilight',
|
||||
'pmsensor',
|
||||
'prometheus_client',
|
||||
'ptvsd',
|
||||
'pushbullet.py',
|
||||
'py-canary',
|
||||
'pyblackbird',
|
||||
'pydeconz',
|
||||
'pydispatcher',
|
||||
'pyheos',
|
||||
'pyhomematic',
|
||||
'pyiqvia',
|
||||
'pylitejet',
|
||||
'pymfy',
|
||||
'pymonoprice',
|
||||
'pynx584',
|
||||
'pyopenuv',
|
||||
'pyotp',
|
||||
'pyps4-homeassistant',
|
||||
'pysmartapp',
|
||||
'pysmartthings',
|
||||
'pysonos',
|
||||
'pyqwikswitch',
|
||||
'PyRMVtransport',
|
||||
'PyTransportNSW',
|
||||
'pyspcwebgw',
|
||||
'python-forecastio',
|
||||
'python-nest',
|
||||
'python_awair',
|
||||
'python-velbus',
|
||||
'pytradfri[async]',
|
||||
'pyunifi',
|
||||
'pyupnp-async',
|
||||
'pyvesync',
|
||||
'pywebpush',
|
||||
'pyHS100',
|
||||
'PyNaCl',
|
||||
'regenmaschine',
|
||||
'restrictedpython',
|
||||
'rflink',
|
||||
'ring_doorbell',
|
||||
'rxv',
|
||||
'simplisafe-python',
|
||||
'sleepyq',
|
||||
'smhi-pkg',
|
||||
'somecomfort',
|
||||
'sqlalchemy',
|
||||
'srpenergy',
|
||||
'statsd',
|
||||
'toonapilib',
|
||||
'twentemilieu',
|
||||
'uvcclient',
|
||||
'vsure',
|
||||
'warrant',
|
||||
'pythonwhois',
|
||||
'wakeonlan',
|
||||
'vultr',
|
||||
'YesssSMS',
|
||||
'ruamel.yaml',
|
||||
'zeroconf',
|
||||
'zigpy-homeassistant',
|
||||
'bellows-homeassistant',
|
||||
'py17track',
|
||||
"adguardhome",
|
||||
"ambiclimate",
|
||||
"aioambient",
|
||||
"aioautomatic",
|
||||
"aiobotocore",
|
||||
"aioesphomeapi",
|
||||
"aiohttp_cors",
|
||||
"aiohue",
|
||||
"aionotion",
|
||||
"aiounifi",
|
||||
"aioswitcher",
|
||||
"aiowwlln",
|
||||
"apns2",
|
||||
"aprslib",
|
||||
"av",
|
||||
"axis",
|
||||
"caldav",
|
||||
"coinmarketcap",
|
||||
"defusedxml",
|
||||
"dsmr_parser",
|
||||
"eebrightbox",
|
||||
"emulated_roku",
|
||||
"enocean",
|
||||
"ephem",
|
||||
"evohomeclient",
|
||||
"feedparser-homeassistant",
|
||||
"foobot_async",
|
||||
"geojson_client",
|
||||
"geopy",
|
||||
"georss_generic_client",
|
||||
"georss_ign_sismologia_client",
|
||||
"georss_qld_bushfire_alert_client",
|
||||
"google-api-python-client",
|
||||
"gTTS-token",
|
||||
"ha-ffmpeg",
|
||||
"hangups",
|
||||
"HAP-python",
|
||||
"hass-nabucasa",
|
||||
"haversine",
|
||||
"hbmqtt",
|
||||
"hdate",
|
||||
"holidays",
|
||||
"home-assistant-frontend",
|
||||
"homekit[IP]",
|
||||
"homematicip",
|
||||
"httplib2",
|
||||
"huawei-lte-api",
|
||||
"influxdb",
|
||||
"jsonpath",
|
||||
"libpurecool",
|
||||
"libsoundtouch",
|
||||
"luftdaten",
|
||||
"pyMetno",
|
||||
"mbddns",
|
||||
"mficlient",
|
||||
"netdisco",
|
||||
"numpy",
|
||||
"oauth2client",
|
||||
"paho-mqtt",
|
||||
"pexpect",
|
||||
"pilight",
|
||||
"pmsensor",
|
||||
"prometheus_client",
|
||||
"ptvsd",
|
||||
"pushbullet.py",
|
||||
"py-canary",
|
||||
"pyblackbird",
|
||||
"pydeconz",
|
||||
"pydispatcher",
|
||||
"pyheos",
|
||||
"pyhomematic",
|
||||
"pyiqvia",
|
||||
"pylitejet",
|
||||
"pymfy",
|
||||
"pymonoprice",
|
||||
"pynx584",
|
||||
"pyopenuv",
|
||||
"pyotp",
|
||||
"pyps4-homeassistant",
|
||||
"pysmartapp",
|
||||
"pysmartthings",
|
||||
"pysonos",
|
||||
"pyqwikswitch",
|
||||
"PyRMVtransport",
|
||||
"PyTransportNSW",
|
||||
"pyspcwebgw",
|
||||
"python-forecastio",
|
||||
"python-nest",
|
||||
"python_awair",
|
||||
"python-velbus",
|
||||
"pytradfri[async]",
|
||||
"pyunifi",
|
||||
"pyupnp-async",
|
||||
"pyvesync",
|
||||
"pywebpush",
|
||||
"pyHS100",
|
||||
"PyNaCl",
|
||||
"regenmaschine",
|
||||
"restrictedpython",
|
||||
"rflink",
|
||||
"ring_doorbell",
|
||||
"rxv",
|
||||
"simplisafe-python",
|
||||
"sleepyq",
|
||||
"smhi-pkg",
|
||||
"somecomfort",
|
||||
"sqlalchemy",
|
||||
"srpenergy",
|
||||
"statsd",
|
||||
"toonapilib",
|
||||
"twentemilieu",
|
||||
"uvcclient",
|
||||
"vsure",
|
||||
"warrant",
|
||||
"pythonwhois",
|
||||
"wakeonlan",
|
||||
"vultr",
|
||||
"YesssSMS",
|
||||
"ruamel.yaml",
|
||||
"zeroconf",
|
||||
"zigpy-homeassistant",
|
||||
"bellows-homeassistant",
|
||||
"py17track",
|
||||
)
|
||||
|
||||
IGNORE_PIN = ('colorlog>2.1,<3', 'keyring>=9.3,<10.0', 'urllib3')
|
||||
IGNORE_PIN = ("colorlog>2.1,<3", "keyring>=9.3,<10.0", "urllib3")
|
||||
|
||||
IGNORE_REQ = (
|
||||
'colorama<=1', # Windows only requirement in check_config
|
||||
IGNORE_REQ = ("colorama<=1",) # Windows only requirement in check_config
|
||||
|
||||
URL_PIN = (
|
||||
"https://developers.home-assistant.io/docs/"
|
||||
"creating_platform_code_review.html#1-requirements"
|
||||
)
|
||||
|
||||
URL_PIN = ('https://developers.home-assistant.io/docs/'
|
||||
'creating_platform_code_review.html#1-requirements')
|
||||
|
||||
|
||||
CONSTRAINT_PATH = os.path.join(os.path.dirname(__file__),
|
||||
'../homeassistant/package_constraints.txt')
|
||||
CONSTRAINT_PATH = os.path.join(
|
||||
os.path.dirname(__file__), "../homeassistant/package_constraints.txt"
|
||||
)
|
||||
CONSTRAINT_BASE = """
|
||||
pycryptodome>=3.6.6
|
||||
|
||||
@@ -198,10 +199,10 @@ def explore_module(package, explore_children):
|
||||
|
||||
found = []
|
||||
|
||||
if not hasattr(module, '__path__'):
|
||||
if not hasattr(module, "__path__"):
|
||||
return found
|
||||
|
||||
for _, name, _ in pkgutil.iter_modules(module.__path__, package + '.'):
|
||||
for _, name, _ in pkgutil.iter_modules(module.__path__, package + "."):
|
||||
found.append(name)
|
||||
|
||||
if explore_children:
|
||||
@@ -212,9 +213,8 @@ def explore_module(package, explore_children):
|
||||
|
||||
def core_requirements():
|
||||
"""Gather core requirements out of setup.py."""
|
||||
with open('setup.py') as inp:
|
||||
reqs_raw = re.search(
|
||||
r'REQUIRES = \[(.*?)\]', inp.read(), re.S).group(1)
|
||||
with open("setup.py") as inp:
|
||||
reqs_raw = re.search(r"REQUIRES = \[(.*?)\]", inp.read(), re.S).group(1)
|
||||
return re.findall(r"'(.*?)'", reqs_raw)
|
||||
|
||||
|
||||
@@ -224,12 +224,12 @@ def gather_recursive_requirements(domain, seen=None):
|
||||
seen = set()
|
||||
|
||||
seen.add(domain)
|
||||
integration = Integration(pathlib.Path(
|
||||
'homeassistant/components/{}'.format(domain)
|
||||
))
|
||||
integration = Integration(
|
||||
pathlib.Path("homeassistant/components/{}".format(domain))
|
||||
)
|
||||
integration.load_manifest()
|
||||
reqs = set(integration.manifest['requirements'])
|
||||
for dep_domain in integration.manifest['dependencies']:
|
||||
reqs = set(integration.manifest["requirements"])
|
||||
for dep_domain in integration.manifest["dependencies"]:
|
||||
reqs.update(gather_recursive_requirements(dep_domain, seen))
|
||||
return reqs
|
||||
|
||||
@@ -249,12 +249,11 @@ def gather_modules():
|
||||
gather_requirements_from_modules(errors, reqs)
|
||||
|
||||
for key in reqs:
|
||||
reqs[key] = sorted(reqs[key],
|
||||
key=lambda name: (len(name.split('.')), name))
|
||||
reqs[key] = sorted(reqs[key], key=lambda name: (len(name.split(".")), name))
|
||||
|
||||
if errors:
|
||||
print("******* ERROR")
|
||||
print("Errors while importing: ", ', '.join(errors))
|
||||
print("Errors while importing: ", ", ".join(errors))
|
||||
return None
|
||||
|
||||
return reqs
|
||||
@@ -262,39 +261,36 @@ def gather_modules():
|
||||
|
||||
def gather_requirements_from_manifests(errors, reqs):
|
||||
"""Gather all of the requirements from manifests."""
|
||||
integrations = Integration.load_dir(pathlib.Path(
|
||||
'homeassistant/components'
|
||||
))
|
||||
integrations = Integration.load_dir(pathlib.Path("homeassistant/components"))
|
||||
for domain in sorted(integrations):
|
||||
integration = integrations[domain]
|
||||
|
||||
if not integration.manifest:
|
||||
errors.append(
|
||||
'The manifest for integration {} is invalid.'.format(domain)
|
||||
)
|
||||
errors.append("The manifest for integration {} is invalid.".format(domain))
|
||||
continue
|
||||
|
||||
process_requirements(
|
||||
errors,
|
||||
integration.manifest['requirements'],
|
||||
'homeassistant.components.{}'.format(domain),
|
||||
reqs
|
||||
integration.manifest["requirements"],
|
||||
"homeassistant.components.{}".format(domain),
|
||||
reqs,
|
||||
)
|
||||
|
||||
|
||||
def gather_requirements_from_modules(errors, reqs):
|
||||
"""Collect the requirements from the modules directly."""
|
||||
for package in sorted(
|
||||
explore_module('homeassistant.scripts', True) +
|
||||
explore_module('homeassistant.auth', True)):
|
||||
explore_module("homeassistant.scripts", True)
|
||||
+ explore_module("homeassistant.auth", True)
|
||||
):
|
||||
try:
|
||||
module = importlib.import_module(package)
|
||||
except ImportError as err:
|
||||
print("{}: {}".format(package.replace('.', '/') + '.py', err))
|
||||
print("{}: {}".format(package.replace(".", "/") + ".py", err))
|
||||
errors.append(package)
|
||||
continue
|
||||
|
||||
if getattr(module, 'REQUIREMENTS', None):
|
||||
if getattr(module, "REQUIREMENTS", None):
|
||||
process_requirements(errors, module.REQUIREMENTS, package, reqs)
|
||||
|
||||
|
||||
@@ -303,14 +299,14 @@ def process_requirements(errors, module_requirements, package, reqs):
|
||||
for req in module_requirements:
|
||||
if req in IGNORE_REQ:
|
||||
continue
|
||||
if '://' in req:
|
||||
if "://" in req:
|
||||
errors.append(
|
||||
"{}[Only pypi dependencies are allowed: {}]".format(
|
||||
package, req))
|
||||
if req.partition('==')[1] == '' and req not in IGNORE_PIN:
|
||||
"{}[Only pypi dependencies are allowed: {}]".format(package, req)
|
||||
)
|
||||
if req.partition("==")[1] == "" and req not in IGNORE_PIN:
|
||||
errors.append(
|
||||
"{}[Please pin requirement {}, see {}]".format(
|
||||
package, req, URL_PIN))
|
||||
"{}[Please pin requirement {}, see {}]".format(package, req, URL_PIN)
|
||||
)
|
||||
reqs.setdefault(req, []).append(package)
|
||||
|
||||
|
||||
@@ -319,90 +315,98 @@ def generate_requirements_list(reqs):
|
||||
output = []
|
||||
for pkg, requirements in sorted(reqs.items(), key=lambda item: item[0]):
|
||||
for req in sorted(requirements):
|
||||
output.append('\n# {}'.format(req))
|
||||
output.append("\n# {}".format(req))
|
||||
|
||||
if comment_requirement(pkg):
|
||||
output.append('\n# {}\n'.format(pkg))
|
||||
output.append("\n# {}\n".format(pkg))
|
||||
else:
|
||||
output.append('\n{}\n'.format(pkg))
|
||||
return ''.join(output)
|
||||
output.append("\n{}\n".format(pkg))
|
||||
return "".join(output)
|
||||
|
||||
|
||||
def requirements_all_output(reqs):
|
||||
"""Generate output for requirements_all."""
|
||||
output = []
|
||||
output.append('# Home Assistant core')
|
||||
output.append('\n')
|
||||
output.append('\n'.join(core_requirements()))
|
||||
output.append('\n')
|
||||
output.append("# Home Assistant core")
|
||||
output.append("\n")
|
||||
output.append("\n".join(core_requirements()))
|
||||
output.append("\n")
|
||||
output.append(generate_requirements_list(reqs))
|
||||
|
||||
return ''.join(output)
|
||||
return "".join(output)
|
||||
|
||||
|
||||
def requirements_test_output(reqs):
|
||||
"""Generate output for test_requirements."""
|
||||
output = []
|
||||
output.append('# Home Assistant test')
|
||||
output.append('\n')
|
||||
with open('requirements_test.txt') as test_file:
|
||||
output.append("# Home Assistant test")
|
||||
output.append("\n")
|
||||
with open("requirements_test.txt") as test_file:
|
||||
output.append(test_file.read())
|
||||
output.append('\n')
|
||||
filtered = {key: value for key, value in reqs.items()
|
||||
if any(
|
||||
re.search(r'(^|#){}($|[=><])'.format(re.escape(ign)),
|
||||
key) is not None for ign in TEST_REQUIREMENTS)}
|
||||
output.append("\n")
|
||||
filtered = {
|
||||
key: value
|
||||
for key, value in reqs.items()
|
||||
if any(
|
||||
re.search(r"(^|#){}($|[=><])".format(re.escape(ign)), key) is not None
|
||||
for ign in TEST_REQUIREMENTS
|
||||
)
|
||||
}
|
||||
output.append(generate_requirements_list(filtered))
|
||||
|
||||
return ''.join(output)
|
||||
return "".join(output)
|
||||
|
||||
|
||||
def gather_constraints():
|
||||
"""Construct output for constraint file."""
|
||||
return '\n'.join(sorted(core_requirements() + list(
|
||||
gather_recursive_requirements('default_config'))) + [''])
|
||||
return "\n".join(
|
||||
sorted(
|
||||
core_requirements() + list(gather_recursive_requirements("default_config"))
|
||||
)
|
||||
+ [""]
|
||||
)
|
||||
|
||||
|
||||
def write_requirements_file(data):
|
||||
"""Write the modules to the requirements_all.txt."""
|
||||
with open('requirements_all.txt', 'w+', newline="\n") as req_file:
|
||||
with open("requirements_all.txt", "w+", newline="\n") as req_file:
|
||||
req_file.write(data)
|
||||
|
||||
|
||||
def write_test_requirements_file(data):
|
||||
"""Write the modules to the requirements_test_all.txt."""
|
||||
with open('requirements_test_all.txt', 'w+', newline="\n") as req_file:
|
||||
with open("requirements_test_all.txt", "w+", newline="\n") as req_file:
|
||||
req_file.write(data)
|
||||
|
||||
|
||||
def write_constraints_file(data):
|
||||
"""Write constraints to a file."""
|
||||
with open(CONSTRAINT_PATH, 'w+', newline="\n") as req_file:
|
||||
with open(CONSTRAINT_PATH, "w+", newline="\n") as req_file:
|
||||
req_file.write(data + CONSTRAINT_BASE)
|
||||
|
||||
|
||||
def validate_requirements_file(data):
|
||||
"""Validate if requirements_all.txt is up to date."""
|
||||
with open('requirements_all.txt', 'r') as req_file:
|
||||
with open("requirements_all.txt", "r") as req_file:
|
||||
return data == req_file.read()
|
||||
|
||||
|
||||
def validate_requirements_test_file(data):
|
||||
"""Validate if requirements_test_all.txt is up to date."""
|
||||
with open('requirements_test_all.txt', 'r') as req_file:
|
||||
with open("requirements_test_all.txt", "r") as req_file:
|
||||
return data == req_file.read()
|
||||
|
||||
|
||||
def validate_constraints_file(data):
|
||||
"""Validate if constraints is up to date."""
|
||||
with open(CONSTRAINT_PATH, 'r') as req_file:
|
||||
with open(CONSTRAINT_PATH, "r") as req_file:
|
||||
return data + CONSTRAINT_BASE == req_file.read()
|
||||
|
||||
|
||||
def main(validate):
|
||||
"""Run the script."""
|
||||
if not os.path.isfile('requirements_all.txt'):
|
||||
print('Run this from HA root dir')
|
||||
if not os.path.isfile("requirements_all.txt"):
|
||||
print("Run this from HA root dir")
|
||||
return 1
|
||||
|
||||
data = gather_modules()
|
||||
@@ -424,12 +428,11 @@ def main(validate):
|
||||
errors.append("requirements_test_all.txt is not up to date")
|
||||
|
||||
if not validate_constraints_file(constraints):
|
||||
errors.append(
|
||||
"home-assistant/package_constraints.txt is not up to date")
|
||||
errors.append("home-assistant/package_constraints.txt is not up to date")
|
||||
|
||||
if errors:
|
||||
print("******* ERROR")
|
||||
print('\n'.join(errors))
|
||||
print("\n".join(errors))
|
||||
print("Please run script/gen_requirements_all.py")
|
||||
return 1
|
||||
|
||||
@@ -441,6 +444,6 @@ def main(validate):
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
_VAL = sys.argv[-1] == 'validate'
|
||||
if __name__ == "__main__":
|
||||
_VAL = sys.argv[-1] == "validate"
|
||||
sys.exit(main(_VAL))
|
||||
|
||||
Reference in New Issue
Block a user