Skip to content

Commit 40e06c9

Browse files
authored
Raise minimum python version to 3.8 (esphome#3176)
1 parent ad6c5ff commit 40e06c9

18 files changed

+253
-180
lines changed

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ jobs:
8080
uses: actions/setup-python@v2
8181
id: python
8282
with:
83-
python-version: '3.7'
83+
python-version: '3.8'
8484

8585
- name: Cache virtualenv
8686
uses: actions/cache@v2

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ venv/
7777
ENV/
7878
env.bak/
7979
venv.bak/
80+
venv-*/
8081

8182
# mypy
8283
.mypy_cache/

.pre-commit-config.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,8 @@ repos:
2525
- --branch=dev
2626
- --branch=release
2727
- --branch=beta
28+
- repo: https://github.com/asottile/pyupgrade
29+
rev: v2.31.0
30+
hooks:
31+
- id: pyupgrade
32+
args: [--py38-plus]

esphome/__main__.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -778,10 +778,10 @@ def run_esphome(argv):
778778
_LOGGER.warning("Please instead use:")
779779
_LOGGER.warning(" esphome %s", " ".join(args.deprecated_argv_suggestion))
780780

781-
if sys.version_info < (3, 7, 0):
781+
if sys.version_info < (3, 8, 0):
782782
_LOGGER.error(
783-
"You're running ESPHome with Python <3.7. ESPHome is no longer compatible "
784-
"with this Python version. Please reinstall ESPHome with Python 3.7+"
783+
"You're running ESPHome with Python <3.8. ESPHome is no longer compatible "
784+
"with this Python version. Please reinstall ESPHome with Python 3.8+"
785785
)
786786
return 1
787787

esphome/components/lcd_gpio/display.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ async def to_code(config):
4343
await lcd_base.setup_lcd_display(var, config)
4444
pins_ = []
4545
for conf in config[CONF_DATA_PINS]:
46-
pins_.append((await cg.gpio_pin_expression(conf)))
46+
pins_.append(await cg.gpio_pin_expression(conf))
4747
cg.add(var.set_data_pins(*pins_))
4848
enable = await cg.gpio_pin_expression(config[CONF_ENABLE_PIN])
4949
cg.add(var.set_enable_pin(enable))

esphome/components/remote_base/__init__.py

+14-22
Original file line numberDiff line numberDiff line change
@@ -847,7 +847,7 @@ async def rc_switch_raw_action(var, config, args):
847847
config[CONF_PROTOCOL], args, RCSwitchBase, to_exp=build_rc_switch_protocol
848848
)
849849
cg.add(var.set_protocol(proto))
850-
cg.add(var.set_code((await cg.templatable(config[CONF_CODE], args, cg.std_string))))
850+
cg.add(var.set_code(await cg.templatable(config[CONF_CODE], args, cg.std_string)))
851851

852852

853853
@register_binary_sensor(
@@ -868,13 +868,11 @@ async def rc_switch_type_a_action(var, config, args):
868868
config[CONF_PROTOCOL], args, RCSwitchBase, to_exp=build_rc_switch_protocol
869869
)
870870
cg.add(var.set_protocol(proto))
871+
cg.add(var.set_group(await cg.templatable(config[CONF_GROUP], args, cg.std_string)))
871872
cg.add(
872-
var.set_group((await cg.templatable(config[CONF_GROUP], args, cg.std_string)))
873+
var.set_device(await cg.templatable(config[CONF_DEVICE], args, cg.std_string))
873874
)
874-
cg.add(
875-
var.set_device((await cg.templatable(config[CONF_DEVICE], args, cg.std_string)))
876-
)
877-
cg.add(var.set_state((await cg.templatable(config[CONF_STATE], args, bool))))
875+
cg.add(var.set_state(await cg.templatable(config[CONF_STATE], args, bool)))
878876

879877

880878
@register_binary_sensor(
@@ -897,13 +895,9 @@ async def rc_switch_type_b_action(var, config, args):
897895
config[CONF_PROTOCOL], args, RCSwitchBase, to_exp=build_rc_switch_protocol
898896
)
899897
cg.add(var.set_protocol(proto))
900-
cg.add(
901-
var.set_address((await cg.templatable(config[CONF_ADDRESS], args, cg.uint8)))
902-
)
903-
cg.add(
904-
var.set_channel((await cg.templatable(config[CONF_CHANNEL], args, cg.uint8)))
905-
)
906-
cg.add(var.set_state((await cg.templatable(config[CONF_STATE], args, bool))))
898+
cg.add(var.set_address(await cg.templatable(config[CONF_ADDRESS], args, cg.uint8)))
899+
cg.add(var.set_channel(await cg.templatable(config[CONF_CHANNEL], args, cg.uint8)))
900+
cg.add(var.set_state(await cg.templatable(config[CONF_STATE], args, bool)))
907901

908902

909903
@register_binary_sensor(
@@ -932,11 +926,11 @@ async def rc_switch_type_c_action(var, config, args):
932926
)
933927
cg.add(var.set_protocol(proto))
934928
cg.add(
935-
var.set_family((await cg.templatable(config[CONF_FAMILY], args, cg.std_string)))
929+
var.set_family(await cg.templatable(config[CONF_FAMILY], args, cg.std_string))
936930
)
937-
cg.add(var.set_group((await cg.templatable(config[CONF_GROUP], args, cg.uint8))))
938-
cg.add(var.set_device((await cg.templatable(config[CONF_DEVICE], args, cg.uint8))))
939-
cg.add(var.set_state((await cg.templatable(config[CONF_STATE], args, bool))))
931+
cg.add(var.set_group(await cg.templatable(config[CONF_GROUP], args, cg.uint8)))
932+
cg.add(var.set_device(await cg.templatable(config[CONF_DEVICE], args, cg.uint8)))
933+
cg.add(var.set_state(await cg.templatable(config[CONF_STATE], args, bool)))
940934

941935

942936
@register_binary_sensor(
@@ -959,11 +953,9 @@ async def rc_switch_type_d_action(var, config, args):
959953
config[CONF_PROTOCOL], args, RCSwitchBase, to_exp=build_rc_switch_protocol
960954
)
961955
cg.add(var.set_protocol(proto))
962-
cg.add(
963-
var.set_group((await cg.templatable(config[CONF_GROUP], args, cg.std_string)))
964-
)
965-
cg.add(var.set_device((await cg.templatable(config[CONF_DEVICE], args, cg.uint8))))
966-
cg.add(var.set_state((await cg.templatable(config[CONF_STATE], args, bool))))
956+
cg.add(var.set_group(await cg.templatable(config[CONF_GROUP], args, cg.std_string)))
957+
cg.add(var.set_device(await cg.templatable(config[CONF_DEVICE], args, cg.uint8)))
958+
cg.add(var.set_state(await cg.templatable(config[CONF_STATE], args, bool)))
967959

968960

969961
@register_trigger("rc_switch", RCSwitchTrigger, RCSwitchData)

esphome/components/tuya/climate/__init__.py

+11-21
Original file line numberDiff line numberDiff line change
@@ -36,31 +36,25 @@ def validate_temperature_multipliers(value):
3636
or CONF_TARGET_TEMPERATURE_MULTIPLIER in value
3737
):
3838
raise cv.Invalid(
39-
(
40-
f"Cannot have {CONF_TEMPERATURE_MULTIPLIER} at the same time as "
41-
f"{CONF_CURRENT_TEMPERATURE_MULTIPLIER} and "
42-
f"{CONF_TARGET_TEMPERATURE_MULTIPLIER}"
43-
)
39+
f"Cannot have {CONF_TEMPERATURE_MULTIPLIER} at the same time as "
40+
f"{CONF_CURRENT_TEMPERATURE_MULTIPLIER} and "
41+
f"{CONF_TARGET_TEMPERATURE_MULTIPLIER}"
4442
)
4543
if (
4644
CONF_CURRENT_TEMPERATURE_MULTIPLIER in value
4745
and CONF_TARGET_TEMPERATURE_MULTIPLIER not in value
4846
):
4947
raise cv.Invalid(
50-
(
51-
f"{CONF_TARGET_TEMPERATURE_MULTIPLIER} required if using "
52-
f"{CONF_CURRENT_TEMPERATURE_MULTIPLIER}"
53-
)
48+
f"{CONF_TARGET_TEMPERATURE_MULTIPLIER} required if using "
49+
f"{CONF_CURRENT_TEMPERATURE_MULTIPLIER}"
5450
)
5551
if (
5652
CONF_TARGET_TEMPERATURE_MULTIPLIER in value
5753
and CONF_CURRENT_TEMPERATURE_MULTIPLIER not in value
5854
):
5955
raise cv.Invalid(
60-
(
61-
f"{CONF_CURRENT_TEMPERATURE_MULTIPLIER} required if using "
62-
f"{CONF_TARGET_TEMPERATURE_MULTIPLIER}"
63-
)
56+
f"{CONF_CURRENT_TEMPERATURE_MULTIPLIER} required if using "
57+
f"{CONF_TARGET_TEMPERATURE_MULTIPLIER}"
6458
)
6559
keys = (
6660
CONF_TEMPERATURE_MULTIPLIER,
@@ -76,18 +70,14 @@ def validate_active_state_values(value):
7670
if CONF_ACTIVE_STATE_DATAPOINT not in value:
7771
if CONF_ACTIVE_STATE_COOLING_VALUE in value:
7872
raise cv.Invalid(
79-
(
80-
f"{CONF_ACTIVE_STATE_DATAPOINT} required if using "
81-
f"{CONF_ACTIVE_STATE_COOLING_VALUE}"
82-
)
73+
f"{CONF_ACTIVE_STATE_DATAPOINT} required if using "
74+
f"{CONF_ACTIVE_STATE_COOLING_VALUE}"
8375
)
8476
else:
8577
if value[CONF_SUPPORTS_COOL] and CONF_ACTIVE_STATE_COOLING_VALUE not in value:
8678
raise cv.Invalid(
87-
(
88-
f"{CONF_ACTIVE_STATE_COOLING_VALUE} required if using "
89-
f"{CONF_ACTIVE_STATE_DATAPOINT} and device supports cooling"
90-
)
79+
f"{CONF_ACTIVE_STATE_COOLING_VALUE} required if using "
80+
f"{CONF_ACTIVE_STATE_DATAPOINT} and device supports cooling"
9181
)
9282
return value
9383

esphome/components/web_server/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,11 @@ async def to_code(config):
7777
if CONF_CSS_INCLUDE in config:
7878
cg.add_define("WEBSERVER_CSS_INCLUDE")
7979
path = CORE.relative_config_path(config[CONF_CSS_INCLUDE])
80-
with open(file=path, mode="r", encoding="utf-8") as myfile:
80+
with open(file=path, encoding="utf-8") as myfile:
8181
cg.add(var.set_css_include(myfile.read()))
8282
if CONF_JS_INCLUDE in config:
8383
cg.add_define("WEBSERVER_JS_INCLUDE")
8484
path = CORE.relative_config_path(config[CONF_JS_INCLUDE])
85-
with open(file=path, mode="r", encoding="utf-8") as myfile:
85+
with open(file=path, encoding="utf-8") as myfile:
8686
cg.add(var.set_js_include(myfile.read()))
8787
cg.add(var.set_include_internal(config[CONF_INCLUDE_INTERNAL]))

esphome/components/wifi/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -225,11 +225,11 @@ def _validate(config):
225225
if CONF_MANUAL_IP in config:
226226
use_address = str(config[CONF_MANUAL_IP][CONF_STATIC_IP])
227227
elif CONF_NETWORKS in config:
228-
ips = set(
228+
ips = {
229229
str(net[CONF_MANUAL_IP][CONF_STATIC_IP])
230230
for net in config[CONF_NETWORKS]
231231
if CONF_MANUAL_IP in net
232-
)
232+
}
233233
if len(ips) > 1:
234234
raise cv.Invalid(
235235
"Must specify use_address when using multiple static IP addresses."

esphome/dashboard/dashboard.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,7 @@ def get(self, configuration=None):
733733
content = ""
734734
if os.path.isfile(filename):
735735
# pylint: disable=no-value-for-parameter
736-
with open(file=filename, mode="r", encoding="utf-8") as f:
736+
with open(file=filename, encoding="utf-8") as f:
737737
content = f.read()
738738
self.write(content)
739739

requirements_test.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
pylint==2.12.2
22
flake8==4.0.1
33
black==22.1.0
4+
pyupgrade==2.31.0
45
pre-commit
56

67
# Unit tests

script/build_jsonschema.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ def get_logger_tags():
170170
]
171171
for x in os.walk(CORE_COMPONENTS_PATH):
172172
for y in glob.glob(os.path.join(x[0], "*.cpp")):
173-
with open(y, "r") as file:
173+
with open(y) as file:
174174
data = file.read()
175175
match = pattern.search(data)
176176
if match:

script/ci-custom.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -281,9 +281,7 @@ def highlight(s):
281281
],
282282
)
283283
def lint_no_defines(fname, match):
284-
s = highlight(
285-
"static const uint8_t {} = {};".format(match.group(1), match.group(2))
286-
)
284+
s = highlight(f"static const uint8_t {match.group(1)} = {match.group(2)};")
287285
return (
288286
"#define macros for integer constants are not allowed, please use "
289287
"{} style instead (replace uint8_t with the appropriate "

script/clang-format

+36-25
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ def run_format(args, queue, lock, failed_files):
1717
"""Takes filenames out of queue and runs clang-format on them."""
1818
while True:
1919
path = queue.get()
20-
invocation = ['clang-format-11']
20+
invocation = ["clang-format-11"]
2121
if args.inplace:
22-
invocation.append('-i')
22+
invocation.append("-i")
2323
else:
24-
invocation.extend(['--dry-run', '-Werror'])
24+
invocation.extend(["--dry-run", "-Werror"])
2525
invocation.append(path)
2626

27-
proc = subprocess.run(invocation, capture_output=True, encoding='utf-8')
27+
proc = subprocess.run(invocation, capture_output=True, encoding="utf-8")
2828
if proc.returncode != 0:
2929
with lock:
3030
print_error_for_file(path, proc.stderr)
@@ -33,45 +33,54 @@ def run_format(args, queue, lock, failed_files):
3333

3434

3535
def progress_bar_show(value):
36-
return value if value is not None else ''
36+
return value if value is not None else ""
3737

3838

3939
def main():
4040
colorama.init()
4141

4242
parser = argparse.ArgumentParser()
43-
parser.add_argument('-j', '--jobs', type=int,
44-
default=multiprocessing.cpu_count(),
45-
help='number of format instances to be run in parallel.')
46-
parser.add_argument('files', nargs='*', default=[],
47-
help='files to be processed (regex on path)')
48-
parser.add_argument('-i', '--inplace', action='store_true',
49-
help='reformat files in-place')
50-
parser.add_argument('-c', '--changed', action='store_true',
51-
help='only run on changed files')
43+
parser.add_argument(
44+
"-j",
45+
"--jobs",
46+
type=int,
47+
default=multiprocessing.cpu_count(),
48+
help="number of format instances to be run in parallel.",
49+
)
50+
parser.add_argument(
51+
"files", nargs="*", default=[], help="files to be processed (regex on path)"
52+
)
53+
parser.add_argument(
54+
"-i", "--inplace", action="store_true", help="reformat files in-place"
55+
)
56+
parser.add_argument(
57+
"-c", "--changed", action="store_true", help="only run on changed files"
58+
)
5259
args = parser.parse_args()
5360

5461
try:
55-
get_output('clang-format-11', '-version')
62+
get_output("clang-format-11", "-version")
5663
except:
57-
print("""
64+
print(
65+
"""
5866
Oops. It looks like clang-format is not installed.
5967
6068
Please check you can run "clang-format-11 -version" in your terminal and install
6169
clang-format (v11) if necessary.
6270
6371
Note you can also upload your code as a pull request on GitHub and see the CI check
6472
output to apply clang-format.
65-
""")
73+
"""
74+
)
6675
return 1
6776

6877
files = []
69-
for path in git_ls_files(['*.cpp', '*.h', '*.tcc']):
78+
for path in git_ls_files(["*.cpp", "*.h", "*.tcc"]):
7079
files.append(os.path.relpath(path, os.getcwd()))
7180

7281
if args.files:
7382
# Match against files specified on command-line
74-
file_name_re = re.compile('|'.join(args.files))
83+
file_name_re = re.compile("|".join(args.files))
7584
files = [p for p in files if file_name_re.search(p)]
7685

7786
if args.changed:
@@ -84,14 +93,16 @@ def main():
8493
task_queue = queue.Queue(args.jobs)
8594
lock = threading.Lock()
8695
for _ in range(args.jobs):
87-
t = threading.Thread(target=run_format,
88-
args=(args, task_queue, lock, failed_files))
96+
t = threading.Thread(
97+
target=run_format, args=(args, task_queue, lock, failed_files)
98+
)
8999
t.daemon = True
90100
t.start()
91101

92102
# Fill the queue with files.
93-
with click.progressbar(files, width=30, file=sys.stderr,
94-
item_show_func=progress_bar_show) as bar:
103+
with click.progressbar(
104+
files, width=30, file=sys.stderr, item_show_func=progress_bar_show
105+
) as bar:
95106
for name in bar:
96107
task_queue.put(name)
97108

@@ -100,11 +111,11 @@ def main():
100111

101112
except KeyboardInterrupt:
102113
print()
103-
print('Ctrl-C detected, goodbye.')
114+
print("Ctrl-C detected, goodbye.")
104115
os.kill(0, 9)
105116

106117
sys.exit(len(failed_files))
107118

108119

109-
if __name__ == '__main__':
120+
if __name__ == "__main__":
110121
main()

0 commit comments

Comments
 (0)