Make compatible with python 3 (#281)

* Make compatible with python 3

* Update travis

* Env

* Fix typo

* Fix install correct platformio

* Lint

* Fix build flags

* Lint

* Upgrade pylint

* Lint
This commit is contained in:
Otto Winter 2019-01-02 14:11:11 +01:00 committed by GitHub
parent 5db70bea3c
commit 22fd4ec722
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 249 additions and 181 deletions

View File

@ -1,20 +1,30 @@
sudo: false
language: python
python:
- "2.7"
jobs:
matrix:
fast_finish: true
include:
- name: "Lint"
install:
- pip install -r requirements.txt
- pip install flake8==3.5.0 pylint==1.9.3 tzlocal pillow
- python: "2.7"
env: TARGET=Lint2.7
install: pip install -e . && pip install flake8==3.6.0 pylint==1.9.4 tzlocal pillow
script:
- flake8 esphomeyaml
- pylint esphomeyaml
- name: "Test"
install:
- pip install -e .
- pip install tzlocal pillow
- python: "3.5.3"
env: TARGET=Lint3.5
install: pip install -U https://github.com/platformio/platformio-core/archive/develop.zip && pip install -e . && pip install flake8==3.6.0 pylint==2.2.2 tzlocal pillow
script:
- flake8 esphomeyaml
- pylint esphomeyaml
- python: "2.7"
env: TARGET=Test2.7
install: pip install -e . && pip install flake8==3.6.0 pylint==1.9.4 tzlocal pillow
script:
- esphomeyaml tests/test1.yaml compile
- esphomeyaml tests/test2.yaml compile
- python: "3.5.3"
env: TARGET=Test3.5
install: pip install -U https://github.com/platformio/platformio-core/archive/develop.zip && pip install -e . && pip install flake8==3.6.0 pylint==2.2.2 tzlocal pillow
script:
- esphomeyaml tests/test1.yaml compile
- esphomeyaml tests/test2.yaml compile

View File

@ -3,4 +3,4 @@ FROM python:2.7
COPY requirements.txt /requirements.txt
RUN pip install -r /requirements.txt && \
pip install flake8==3.5.0 pylint==1.9.3 tzlocal pillow
pip install flake8==3.6.0 pylint==1.9.4 tzlocal pillow

View File

@ -16,8 +16,9 @@ from esphomeyaml.const import CONF_BAUD_RATE, CONF_ESPHOMEYAML, CONF_LOGGER, CON
from esphomeyaml.core import CORE, EsphomeyamlError
from esphomeyaml.cpp_generator import Expression, RawStatement, add, statement
from esphomeyaml.helpers import color, indent
from esphomeyaml.storage_json import StorageJSON, storage_path, start_update_check_thread, \
esphomeyaml_storage_path
from esphomeyaml.py_compat import safe_input, text_type
from esphomeyaml.storage_json import StorageJSON, esphomeyaml_storage_path, \
start_update_check_thread, storage_path
from esphomeyaml.util import run_external_command, safe_print
_LOGGER = logging.getLogger(__name__)
@ -50,7 +51,7 @@ def choose_prompt(options):
safe_print(u" [{}] {}".format(i + 1, desc))
while True:
opt = raw_input('(number): ')
opt = safe_input('(number): ')
if opt in options:
opt = options.index(opt)
break
@ -140,7 +141,7 @@ def write_cpp(config):
if not config[CONF_ESPHOMEYAML][CONF_USE_CUSTOM_CODE]:
if isinstance(exp, Expression) and not exp.required:
continue
all_code.append(unicode(statement(exp)))
all_code.append(text_type(statement(exp)))
writer.write_platformio_project()
@ -199,7 +200,7 @@ def upload_program(config, args, host):
if storage is not None and not storage.use_legacy_ota:
return res
_LOGGER.warn("OTA v2 method failed. Trying with legacy OTA...")
_LOGGER.warning("OTA v2 method failed. Trying with legacy OTA...")
return espota2.run_legacy_ota(verbose, host_port, host, remote_port, password,
CORE.firmware_bin)
@ -208,9 +209,9 @@ def show_logs(config, args, port):
if get_port_type(port) == 'SERIAL':
run_miniterm(config, port)
return 0
elif get_port_type(port) == 'NETWORK':
if get_port_type(port) == 'NETWORK':
return run_logs(config, port)
elif get_port_type(port) == 'MQTT':
if get_port_type(port) == 'MQTT':
return mqtt.show_logs(config, args.topic, args.username, args.password, args.client_id)
raise ValueError

View File

@ -14,6 +14,7 @@ import esphomeyaml.api.api_pb2 as pb
from esphomeyaml.const import CONF_PASSWORD, CONF_PORT
from esphomeyaml.core import EsphomeyamlError
from esphomeyaml.helpers import resolve_ip_address, indent, color
from esphomeyaml.py_compat import text_type
from esphomeyaml.util import safe_print
_LOGGER = logging.getLogger(__name__)
@ -254,14 +255,14 @@ class APIClient(threading.Thread):
def _send_message(self, msg):
# type: (message.Message) -> None
for message_type, klass in MESSAGE_TYPE_TO_PROTO.iteritems():
for message_type, klass in MESSAGE_TYPE_TO_PROTO.items():
if isinstance(msg, klass):
break
else:
raise ValueError
encoded = msg.SerializeToString()
_LOGGER.debug("Sending %s:\n%s", type(msg), indent(unicode(msg)))
_LOGGER.debug("Sending %s:\n%s", type(msg), indent(text_type(msg)))
req = chr(0x00)
req += _varuint_to_bytes(len(encoded))
req += _varuint_to_bytes(message_type)
@ -435,12 +436,14 @@ def run_logs(config, address):
while retry_timer:
retry_timer.pop(0).cancel()
error = None
try:
cli.connect()
cli.login()
except APIConnectionError as error:
pass
else:
except APIConnectionError as err: # noqa
error = err
if error is None:
_LOGGER.info("Successfully connected to %s", address)
return

View File

@ -41,7 +41,7 @@ def validate_recursive_condition(value):
raise vol.Invalid(u"Unable to find condition with the name '{}', is the "
u"component loaded?".format(key), path + [key])
item.setdefault(CONF_CONDITION_ID, None)
key2 = next((x for x in item if x != CONF_CONDITION_ID and x != key), None)
key2 = next((x for x in item if x not in (CONF_CONDITION_ID, key)), None)
if key2 is not None:
raise vol.Invalid(u"Cannot have two conditions in one item. Key '{}' overrides '{}'! "
u"Did you forget to indent the block inside the condition?"
@ -76,7 +76,7 @@ def validate_recursive_action(value):
raise vol.Invalid(u"Unable to find action with the name '{}', is the component loaded?"
u"".format(key), path + [key])
item.setdefault(CONF_ACTION_ID, None)
key2 = next((x for x in item if x != CONF_ACTION_ID and x != key), None)
key2 = next((x for x in item if x not in (CONF_ACTION_ID, key)), None)
if key2 is not None:
raise vol.Invalid(u"Cannot have two actions in one item. Key '{}' overrides '{}'! "
u"Did you forget to indent the block inside the action?"

View File

@ -43,7 +43,7 @@ BUILD_FLAGS = '-DUSE_API'
def lib_deps(config):
if CORE.is_esp32:
return 'AsyncTCP@1.0.1'
elif CORE.is_esp8266:
if CORE.is_esp8266:
return 'ESPAsyncTCP@1.1.3'
raise NotImplementedError

View File

@ -14,6 +14,7 @@ from esphomeyaml.core import CORE
from esphomeyaml.cpp_generator import process_lambda, ArrayInitializer, add, Pvariable, \
StructInitializer, get_variable
from esphomeyaml.cpp_types import esphomelib_ns, Nameable, Trigger, NoArg, Component, App, bool_
from esphomeyaml.py_compat import string_types
DEVICE_CLASSES = [
'', 'battery', 'cold', 'connectivity', 'door', 'garage_door', 'gas',
@ -70,7 +71,7 @@ MULTI_CLICK_TIMING_SCHEMA = vol.Schema({
def parse_multi_click_timing_str(value):
if not isinstance(value, basestring):
if not isinstance(value, string_types):
return value
parts = value.lower().split(' ')

View File

@ -73,40 +73,40 @@ def receiver_base(full_config):
key, config = next((k, v) for k, v in full_config.items() if k in REMOTE_KEYS)
if key == CONF_LG:
return LGReceiver.new(name, config[CONF_DATA], config[CONF_NBITS])
elif key == CONF_NEC:
if key == CONF_NEC:
return NECReceiver.new(name, config[CONF_ADDRESS], config[CONF_COMMAND])
elif key == CONF_PANASONIC:
if key == CONF_PANASONIC:
return PanasonicReceiver.new(name, config[CONF_ADDRESS], config[CONF_COMMAND])
elif key == CONF_SAMSUNG:
if key == CONF_SAMSUNG:
return SamsungReceiver.new(name, config[CONF_DATA])
elif key == CONF_SONY:
if key == CONF_SONY:
return SonyReceiver.new(name, config[CONF_DATA], config[CONF_NBITS])
elif key == CONF_RAW:
if key == CONF_RAW:
data = ArrayInitializer(*config, multiline=False)
return RawReceiver.new(name, data)
elif key == CONF_RC_SWITCH_RAW:
if key == CONF_RC_SWITCH_RAW:
return RCSwitchRawReceiver.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]),
binary_code(config[CONF_CODE]), len(config[CONF_CODE]))
elif key == CONF_RC_SWITCH_TYPE_A:
if key == CONF_RC_SWITCH_TYPE_A:
return RCSwitchTypeAReceiver.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]),
binary_code(config[CONF_GROUP]),
binary_code(config[CONF_DEVICE]),
config[CONF_STATE])
elif key == CONF_RC_SWITCH_TYPE_B:
if key == CONF_RC_SWITCH_TYPE_B:
return RCSwitchTypeBReceiver.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]),
config[CONF_ADDRESS], config[CONF_CHANNEL],
config[CONF_STATE])
elif key == CONF_RC_SWITCH_TYPE_C:
if key == CONF_RC_SWITCH_TYPE_C:
return RCSwitchTypeCReceiver.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]),
ord(config[CONF_FAMILY][0]) - ord('a'),
config[CONF_GROUP], config[CONF_DEVICE],
config[CONF_STATE])
elif key == CONF_RC_SWITCH_TYPE_D:
if key == CONF_RC_SWITCH_TYPE_D:
return RCSwitchTypeDReceiver.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]),
ord(config[CONF_GROUP][0]) - ord('a'),
config[CONF_DEVICE], config[CONF_STATE])
else:
raise NotImplementedError("Unknown receiver type {}".format(config))
raise NotImplementedError("Unknown receiver type {}".format(config))
def to_code(config):

View File

@ -33,10 +33,9 @@ def validate_glyphs(value):
if len(x_) < len(y_):
return -1
elif len(x_) > len(y_):
if len(x_) > len(y_):
return 1
else:
raise vol.Invalid(u"Found duplicate glyph {}".format(x))
raise vol.Invalid(u"Found duplicate glyph {}".format(x))
value.sort(cmp=comparator)
return value
@ -47,11 +46,11 @@ def validate_pillow_installed(value):
import PIL
except ImportError:
raise vol.Invalid("Please install the pillow python package to use this feature. "
"(pip2 install pillow)")
"(pip install pillow)")
if PIL.__version__[0] < '4':
raise vol.Invalid("Please update your pillow installation to at least 4.0.x. "
"(pip2 install -U pillow)")
"(pip install -U pillow)")
return value

View File

@ -10,6 +10,8 @@ from esphomeyaml.core import EsphomeyamlError, Lambda, CORE
from esphomeyaml.cpp_generator import Pvariable, RawExpression, add, process_lambda, statement
from esphomeyaml.cpp_types import App, Component, esphomelib_ns, global_ns
from esphomeyaml.py_compat import text_type
LOG_LEVELS = {
'NONE': global_ns.ESPHOMELIB_LOG_LEVEL_NONE,
'ERROR': global_ns.ESPHOMELIB_LOG_LEVEL_ERROR,
@ -37,7 +39,7 @@ is_log_level = cv.one_of(*LOG_LEVELS, upper=True)
def validate_local_no_higher_than_global(value):
global_level = value.get(CONF_LEVEL, 'DEBUG')
for tag, level in value.get(CONF_LOGS, {}).iteritems():
for tag, level in value.get(CONF_LOGS, {}).items():
if LOG_LEVEL_SEVERITY.index(level) > LOG_LEVEL_SEVERITY.index(global_level):
raise EsphomeyamlError(u"The local log level {} for {} must be less severe than the "
u"global log level {}.".format(level, tag, global_level))
@ -64,7 +66,7 @@ def to_code(config):
add(log.set_tx_buffer_size(config[CONF_TX_BUFFER_SIZE]))
if CONF_LEVEL in config:
add(log.set_global_log_level(LOG_LEVELS[config[CONF_LEVEL]]))
for tag, level in config.get(CONF_LOGS, {}).iteritems():
for tag, level in config.get(CONF_LOGS, {}).items():
add(log.set_log_level(tag, LOG_LEVELS[level]))
@ -120,7 +122,7 @@ def validate_printf(value):
[cCdiouxXeEfgGaAnpsSZ] # type
) | # OR
%%) # literal "%%"
"""
""" # noqa
matches = re.findall(cfmt, value[CONF_FORMAT], flags=re.X)
if len(matches) != len(value[CONF_ARGS]):
raise vol.Invalid(u"Found {} printf-patterns ({}), but {} args were given!"
@ -140,9 +142,9 @@ LOGGER_LOG_ACTION_SCHEMA = vol.All(maybe_simple_message({
@ACTION_REGISTRY.register(CONF_LOGGER_LOG, LOGGER_LOG_ACTION_SCHEMA)
def logger_log_action_to_code(config, action_id, arg_type, template_arg):
esp_log = LOG_LEVEL_TO_ESP_LOG[config[CONF_LEVEL]]
args = [RawExpression(unicode(x)) for x in config[CONF_ARGS]]
args = [RawExpression(text_type(x)) for x in config[CONF_ARGS]]
text = unicode(statement(esp_log(config[CONF_TAG], config[CONF_FORMAT], *args)))
text = text_type(statement(esp_log(config[CONF_TAG], config[CONF_FORMAT], *args)))
for lambda_ in process_lambda(Lambda(text), [(arg_type, 'x')]):
yield None

View File

@ -36,7 +36,7 @@ def get_port(config):
return config[CONF_OTA][CONF_PORT]
if CORE.is_esp32:
return 3232
elif CORE.is_esp8266:
if CORE.is_esp8266:
return 8266
raise NotImplementedError
@ -52,6 +52,6 @@ REQUIRED_BUILD_FLAGS = '-DUSE_NEW_OTA'
def lib_deps(config):
if CORE.is_esp32:
return ['Update', 'ESPmDNS']
elif CORE.is_esp8266:
if CORE.is_esp8266:
return ['Hash', 'ESP8266mDNS']
raise NotImplementedError

View File

@ -37,7 +37,7 @@ def validate_custom_output(value):
value[CONF_TYPE] = type
if type == 'binary':
return BINARY_SCHEMA(value)
elif type == 'float':
if type == 'float':
return FLOAT_SCHEMA(value)
raise vol.Invalid("type must either be binary or float, not {}!".format(type))

View File

@ -7,6 +7,7 @@ from esphomeyaml.const import CONF_BUFFER_SIZE, CONF_DUMP, CONF_FILTER, CONF_ID,
from esphomeyaml.cpp_generator import Pvariable, add
from esphomeyaml.cpp_helpers import gpio_input_pin_expression, setup_component
from esphomeyaml.cpp_types import App, Component, esphomelib_ns
from esphomeyaml.py_compat import string_types
remote_ns = esphomelib_ns.namespace('remote')
MULTI_CONF = True
@ -30,7 +31,7 @@ DUMPERS = {
def validate_dumpers_all(value):
if not isinstance(value, (str, unicode)):
if not isinstance(value, string_types):
raise vol.Invalid("Not valid dumpers")
if value.upper() == "ALL":
return list(sorted(list(DUMPERS)))

View File

@ -10,6 +10,7 @@ from esphomeyaml.core import HexInt
from esphomeyaml.cpp_generator import Pvariable, add
from esphomeyaml.cpp_helpers import gpio_output_pin_expression, setup_component
from esphomeyaml.cpp_types import App, Component
from esphomeyaml.py_compat import text_type
RemoteTransmitterComponent = remote_ns.class_('RemoteTransmitterComponent',
RemoteControlComponentBase, Component)
@ -20,7 +21,7 @@ MULTI_CONF = True
def validate_rc_switch_code(value):
if not isinstance(value, (str, unicode)):
if not isinstance(value, (str, text_type)):
raise vol.Invalid("All RCSwitch codes must be in quotes ('')")
for c in value:
if c not in ('0', '1'):

View File

@ -6,6 +6,7 @@ import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_ADS1115_ID, CONF_GAIN, CONF_MULTIPLEXER, CONF_NAME, \
CONF_UPDATE_INTERVAL
from esphomeyaml.cpp_generator import get_variable
from esphomeyaml.py_compat import string_types
DEPENDENCIES = ['ads1115']
@ -35,7 +36,7 @@ GAIN = {
def validate_gain(value):
if isinstance(value, float):
value = u'{:0.03f}'.format(value)
elif not isinstance(value, (str, unicode)):
elif not isinstance(value, string_types):
raise vol.Invalid('invalid gain "{}"'.format(value))
return cv.one_of(*GAIN)(value)

View File

@ -36,7 +36,7 @@ SENSORS_TO_TYPE = {
def validate_pmsx003_sensors(value):
for key, types in SENSORS_TO_TYPE.iteritems():
for key, types in SENSORS_TO_TYPE.items():
if key in value and value[CONF_TYPE] not in types:
raise vol.Invalid(u"{} does not have {} sensor!".format(value[CONF_TYPE], key))
return value

View File

@ -35,8 +35,8 @@ def validate_internal_filter(value):
if value.total_microseconds > 13:
raise vol.Invalid("Maximum internal filter value for ESP32 is 13us")
return value
else:
return cv.positive_time_period_microseconds(value)
return cv.positive_time_period_microseconds(value)
PLATFORM_SCHEMA = cv.nameable(sensor.SENSOR_PLATFORM_SCHEMA.extend({

View File

@ -61,8 +61,8 @@ def _expand_substitutions(substitutions, value, path):
if name.startswith(u'{') and name.endswith(u'}'):
name = name[1:-1]
if name not in substitutions:
_LOGGER.warn(u"Found '%s' (see %s) which looks like a substitution, but '%s' was not "
u"declared", orig_value, u'->'.join(str(x) for x in path), name)
_LOGGER.warning(u"Found '%s' (see %s) which looks like a substitution, but '%s' was "
u"not declared", orig_value, u'->'.join(str(x) for x in path), name)
i = j
continue
@ -82,7 +82,7 @@ def _substitute_item(substitutions, item, path):
item[i] = sub
elif isinstance(item, dict):
replace_keys = []
for k, v in item.iteritems():
for k, v in item.items():
if path or k != CONF_SUBSTITUTIONS:
sub = _substitute_item(substitutions, k, path + [k])
if sub is not None:
@ -116,7 +116,7 @@ def do_substitution_pass(config):
key = ''
try:
replace_keys = []
for key, value in substitutions.iteritems():
for key, value in substitutions.items():
sub = validate_substitution_key(key)
if sub != key:
replace_keys.append((key, sub))

View File

@ -85,15 +85,15 @@ def transmitter_base(full_config):
if key == CONF_LG:
return LGTransmitter.new(name, config[CONF_DATA], config[CONF_NBITS])
elif key == CONF_NEC:
if key == CONF_NEC:
return NECTransmitter.new(name, config[CONF_ADDRESS], config[CONF_COMMAND])
elif key == CONF_PANASONIC:
if key == CONF_PANASONIC:
return PanasonicTransmitter.new(name, config[CONF_ADDRESS], config[CONF_COMMAND])
elif key == CONF_SAMSUNG:
if key == CONF_SAMSUNG:
return SamsungTransmitter.new(name, config[CONF_DATA])
elif key == CONF_SONY:
if key == CONF_SONY:
return SonyTransmitter.new(name, config[CONF_DATA], config[CONF_NBITS])
elif key == CONF_RAW:
if key == CONF_RAW:
if isinstance(config, dict):
data = config[CONF_DATA]
carrier_frequency = config.get(CONF_CARRIER_FREQUENCY)
@ -102,29 +102,29 @@ def transmitter_base(full_config):
carrier_frequency = None
return RawTransmitter.new(name, ArrayInitializer(*data, multiline=False),
carrier_frequency)
elif key == CONF_RC_SWITCH_RAW:
if key == CONF_RC_SWITCH_RAW:
return RCSwitchRawTransmitter.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]),
binary_code(config[CONF_CODE]), len(config[CONF_CODE]))
elif key == CONF_RC_SWITCH_TYPE_A:
if key == CONF_RC_SWITCH_TYPE_A:
return RCSwitchTypeATransmitter.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]),
binary_code(config[CONF_GROUP]),
binary_code(config[CONF_DEVICE]),
config[CONF_STATE])
elif key == CONF_RC_SWITCH_TYPE_B:
if key == CONF_RC_SWITCH_TYPE_B:
return RCSwitchTypeBTransmitter.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]),
config[CONF_ADDRESS], config[CONF_CHANNEL],
config[CONF_STATE])
elif key == CONF_RC_SWITCH_TYPE_C:
if key == CONF_RC_SWITCH_TYPE_C:
return RCSwitchTypeCTransmitter.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]),
ord(config[CONF_FAMILY][0]) - ord('a'),
config[CONF_GROUP], config[CONF_DEVICE],
config[CONF_STATE])
elif key == CONF_RC_SWITCH_TYPE_D:
if key == CONF_RC_SWITCH_TYPE_D:
return RCSwitchTypeDTransmitter.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]),
ord(config[CONF_GROUP][0]) - ord('a'),
config[CONF_DEVICE], config[CONF_STATE])
else:
raise NotImplementedError("Unknown transmitter type {}".format(config))
raise NotImplementedError("Unknown transmitter type {}".format(config))
def to_code(config):

View File

@ -7,6 +7,7 @@ from esphomeyaml.const import CONF_DATA, CONF_INVERTED, CONF_MAKE_ID, CONF_NAME,
from esphomeyaml.core import HexInt
from esphomeyaml.cpp_generator import ArrayInitializer, get_variable, variable
from esphomeyaml.cpp_types import App, Application
from esphomeyaml.py_compat import text_type
DEPENDENCIES = ['uart']
@ -15,11 +16,11 @@ UARTSwitch = switch.switch_ns.class_('UARTSwitch', switch.Switch, uart.UARTDevic
def validate_data(value):
if isinstance(value, unicode):
if isinstance(value, text_type):
return value.encode('utf-8')
elif isinstance(value, str):
if isinstance(value, str):
return value
elif isinstance(value, list):
if isinstance(value, list):
return vol.Schema([cv.hex_uint8_t])(value)
raise vol.Invalid("data must either be a string wrapped in quotes or a list of bytes")

View File

@ -11,6 +11,7 @@ from esphomeyaml.const import CONF_CRON, CONF_DAYS_OF_MONTH, CONF_DAYS_OF_WEEK,
from esphomeyaml.core import CORE
from esphomeyaml.cpp_generator import add, Pvariable, ArrayInitializer
from esphomeyaml.cpp_types import esphomelib_ns, Component, NoArg, Trigger, App
from esphomeyaml.py_compat import string_types
_LOGGER = logging.getLogger(__name__)
@ -30,9 +31,9 @@ def _tz_timedelta(td):
offset_second = int(abs(td.total_seconds())) % 60
if offset_hour == 0 and offset_minute == 0 and offset_second == 0:
return '0'
elif offset_minute == 0 and offset_second == 0:
if offset_minute == 0 and offset_second == 0:
return '{}'.format(offset_hour)
elif offset_second == 0:
if offset_second == 0:
return '{}:{}'.format(offset_hour, offset_minute)
return '{}:{}:{}'.format(offset_hour, offset_minute, offset_second)
@ -119,7 +120,7 @@ def detect_tz():
import pytz
except ImportError:
raise vol.Invalid("No timezone specified and 'tzlocal' not installed. To automatically "
"detect the timezone please install tzlocal (pip2 install tzlocal)")
"detect the timezone please install tzlocal (pip install tzlocal)")
try:
tz = tzlocal.get_localzone()
except pytz.exceptions.UnknownTimeZoneError:
@ -131,7 +132,7 @@ def detect_tz():
def _parse_cron_int(value, special_mapping, message):
special_mapping = special_mapping or {}
if isinstance(value, (str, unicode)) and value in special_mapping:
if isinstance(value, string_types) and value in special_mapping:
return special_mapping[value]
try:
return int(value)
@ -140,7 +141,7 @@ def _parse_cron_int(value, special_mapping, message):
def _parse_cron_part(part, min_value, max_value, special_mapping):
if part == '*' or part == '?':
if part in ('*', '?'):
return set(x for x in range(min_value, max_value + 1))
if '/' in part:
data = part.split('/')

View File

@ -171,6 +171,6 @@ def to_code(config):
def lib_deps(config):
if CORE.is_esp8266:
return 'ESP8266WiFi'
elif CORE.is_esp32:
if CORE.is_esp32:
return None
raise NotImplementedError

View File

@ -13,6 +13,7 @@ from esphomeyaml.components import substitutions
from esphomeyaml.const import CONF_ESPHOMEYAML, CONF_PLATFORM, ESP_PLATFORMS
from esphomeyaml.core import CORE, EsphomeyamlError
from esphomeyaml.helpers import color, indent
from esphomeyaml.py_compat import text_type
from esphomeyaml.util import safe_print
# pylint: disable=unused-import, wrong-import-order
@ -50,7 +51,7 @@ def is_platform_component(component):
def iter_components(config):
for domain, conf in config.iteritems():
for domain, conf in config.items():
if domain == CONF_ESPHOMEYAML:
yield CONF_ESPHOMEYAML, core_config, conf
continue
@ -67,7 +68,7 @@ def iter_components(config):
yield p_name, platform, p_config
ConfigPath = List[Union[basestring, int]]
ConfigPath = List[Union[str, int]]
def _path_begins_with_(path, other): # type: (ConfigPath, ConfigPath) -> bool
@ -90,8 +91,8 @@ class Config(OrderedDict):
def add_error(self, message, path):
# type: (basestring, ConfigPath) -> None
if not isinstance(message, unicode):
message = unicode(message)
if not isinstance(message, text_type):
message = text_type(message)
self.errors.append((message, path))
def add_domain(self, path, name):
@ -158,7 +159,7 @@ def iter_ids(config, path=None):
for result in iter_ids(item, path + [i]):
yield result
elif isinstance(config, dict):
for key, value in config.iteritems():
for key, value in config.items():
for result in iter_ids(value, path + [key]):
yield result
@ -229,7 +230,7 @@ def validate_config(config):
result.add_domain([CONF_ESPHOMEYAML], CONF_ESPHOMEYAML)
result[CONF_ESPHOMEYAML] = config[CONF_ESPHOMEYAML]
for domain, conf in config.iteritems():
for domain, conf in config.items():
domain = str(domain)
if domain == CONF_ESPHOMEYAML or domain.startswith(u'.'):
skip_paths.append([domain])
@ -337,7 +338,7 @@ def validate_config(config):
except vol.Invalid as ex:
_comp_error(ex, [CONF_ESPHOMEYAML])
for domain, conf in result.iteritems():
for domain, conf in result.items():
domain = str(domain)
if [domain] in skip_paths:
continue
@ -401,7 +402,7 @@ def humanize_error(config, validation_error):
offending_item_summary = json.dumps(offending_item_summary)
except (TypeError, ValueError):
pass
validation_error = unicode(validation_error)
validation_error = text_type(validation_error)
m = re.match(r'^(.*?)\s*(?:for dictionary value )?@ data\[.*$', validation_error)
if m is not None:
validation_error = m.group(1)
@ -514,7 +515,7 @@ def dump_dict(config, path, at_root=True):
ret += u'{}'
multiline = False
for k in conf.iterkeys():
for k in conf.keys():
path_ = path + [k]
error = config.get_error_for_path(path_)
if error is not None:
@ -543,9 +544,9 @@ def dump_dict(config, path, at_root=True):
conf = u'|-\n' + indent(conf)
error = config.get_error_for_path(path)
col = 'bold_red' if error else 'white'
ret += color(col, unicode(conf))
ret += color(col, text_type(conf))
elif isinstance(conf, core.Lambda):
conf = u'!lambda |-\n' + indent(unicode(conf.value))
conf = u'!lambda |-\n' + indent(text_type(conf.value))
error = config.get_error_for_path(path)
col = 'bold_red' if error else 'white'
ret += color(col, conf)
@ -554,7 +555,7 @@ def dump_dict(config, path, at_root=True):
else:
error = config.get_error_for_path(path)
col = 'bold_red' if error else 'white'
ret += color(col, unicode(conf))
ret += color(col, text_type(conf))
multiline = u'\n' in ret
return ret, multiline
@ -571,7 +572,7 @@ def strip_default_ids(config):
config.remove(x)
elif isinstance(config, dict):
to_remove = []
for k, v in config.iteritems():
for k, v in config.items():
v = config[k] = strip_default_ids(v)
if isinstance(v, core.ID) and not v.is_manual:
to_remove.append(k)

View File

@ -16,6 +16,7 @@ from esphomeyaml.const import CONF_AVAILABILITY, CONF_COMMAND_TOPIC, CONF_DISCOV
ESP_PLATFORM_ESP8266
from esphomeyaml.core import CORE, HexInt, IPAddress, Lambda, TimePeriod, TimePeriodMicroseconds, \
TimePeriodMilliseconds, TimePeriodSeconds
from esphomeyaml.py_compat import text_type, string_types, integer_types
_LOGGER = logging.getLogger(__name__)
@ -51,7 +52,7 @@ RESERVED_IDS = [
def alphanumeric(value):
if value is None:
raise vol.Invalid("string value is None")
value = unicode(value)
value = text_type(value)
if not value.isalnum():
raise vol.Invalid("string value is not alphanumeric")
return value
@ -70,13 +71,13 @@ def string(value):
if isinstance(value, (dict, list)):
raise vol.Invalid("string value cannot be dictionary or list.")
if value is not None:
return unicode(value)
return text_type(value)
raise vol.Invalid("string value is None")
def string_strict(value):
"""Strictly only allow strings."""
if isinstance(value, (str, unicode)):
if isinstance(value, string_types):
return value
raise vol.Invalid("Must be string, got {}. did you forget putting quotes "
"around the value?".format(type(value)))
@ -138,7 +139,7 @@ def ensure_dict(value):
def hex_int_(value):
if isinstance(value, (int, long)):
if isinstance(value, integer_types):
return HexInt(value)
value = string_strict(value).lower()
if value.startswith('0x'):
@ -147,7 +148,7 @@ def hex_int_(value):
def int_(value):
if isinstance(value, (int, long)):
if isinstance(value, integer_types):
return value
value = string_strict(value).lower()
if value.startswith('0x'):
@ -310,9 +311,9 @@ def time_period_str_colon(value):
def time_period_str_unit(value):
"""Validate and transform time period with time unit and integer value."""
if isinstance(value, int):
raise vol.Invalid("Don't know what '{}' means as it has no time *unit*! Did you mean "
"'{}s'?".format(value, value))
elif not isinstance(value, (str, unicode)):
raise vol.Invalid("Don't know what '{0}' means as it has no time *unit*! Did you mean "
"'{0}s'?".format(value))
elif not isinstance(value, string_types):
raise vol.Invalid("Expected string for time period with unit.")
unit_to_kwarg = {
@ -489,7 +490,7 @@ def ssid(value):
def ipv4(value):
if isinstance(value, list):
parts = value
elif isinstance(value, basestring):
elif isinstance(value, string_types):
parts = value.split('.')
elif isinstance(value, IPAddress):
return value
@ -579,7 +580,7 @@ i2c_address = hex_uint8_t
def percentage(value):
has_percent_sign = isinstance(value, (str, unicode)) and value.endswith('%')
has_percent_sign = isinstance(value, string_types) and value.endswith('%')
if has_percent_sign:
value = float(value[:-1].rstrip()) / 100.0
if value > 1:
@ -591,7 +592,7 @@ def percentage(value):
def percentage_int(value):
if isinstance(value, (str, unicode)) and value.endswith('%'):
if isinstance(value, string_types) and value.endswith('%'):
value = int(value[:-1].rstrip())
return value

View File

@ -13,15 +13,22 @@ from esphomeyaml.helpers import ensure_unique_string
# pylint: disable=unused-import, wrong-import-order
from typing import Any, Dict, List # noqa
from esphomeyaml.py_compat import integer_types, IS_PY2
_LOGGER = logging.getLogger(__name__)
class EsphomeyamlError(Exception):
"""General esphomeyaml exception occurred."""
pass
class HexInt(long):
if IS_PY2:
base_int = long
else:
base_int = int
class HexInt(base_int):
def __str__(self):
if 0 <= self <= 255:
return "0x{:02X}".format(self)
@ -55,7 +62,7 @@ class MACAddress(object):
def is_approximately_integer(value):
if isinstance(value, (int, long)):
if isinstance(value, integer_types):
return True
return abs(value - round(value)) < 0.001
@ -379,7 +386,7 @@ class EsphomeyamlCore(object):
task, domain = self.pending_tasks.popleft()
_LOGGER.debug("Executing task for domain=%s", domain)
try:
task.next()
next(task)
self.pending_tasks.append((task, domain))
except StopIteration:
_LOGGER.debug(" -> %s finished", domain)
@ -404,7 +411,7 @@ class EsphomeyamlCore(object):
def get_variable_with_full_id(self, id):
while True:
if id in self.variables:
for k, v in self.variables.iteritems():
for k, v in self.variables.items():
if k == id:
yield (k, v)
return

View File

@ -15,6 +15,7 @@ from esphomeyaml.const import ARDUINO_VERSION_ESP32_DEV, ARDUINO_VERSION_ESP8266
from esphomeyaml.core import CORE, EsphomeyamlError
from esphomeyaml.cpp_generator import Pvariable, RawExpression, add
from esphomeyaml.cpp_types import App, NoArg, const_char_ptr, esphomelib_ns
from esphomeyaml.py_compat import text_type
_LOGGER = logging.getLogger(__name__)
@ -52,12 +53,12 @@ def validate_simple_esphomelib_version(value):
CONF_REPOSITORY: LIBRARY_URI_REPO,
CONF_TAG: 'v' + ESPHOMELIB_VERSION,
}
elif value.upper() == 'DEV':
if value.upper() == 'DEV':
return {
CONF_REPOSITORY: LIBRARY_URI_REPO,
CONF_BRANCH: 'dev'
}
elif VERSION_REGEX.match(value) is not None:
if VERSION_REGEX.match(value) is not None:
return {
CONF_REPOSITORY: LIBRARY_URI_REPO,
CONF_TAG: 'v' + value,
@ -139,7 +140,7 @@ def validate_arduino_version(value):
if value_ in PLATFORMIO_ESP8266_LUT:
return PLATFORMIO_ESP8266_LUT[value_]
return value
elif CORE.is_esp32:
if CORE.is_esp32:
if VERSION_REGEX.match(value) is not None and value_ not in PLATFORMIO_ESP32_LUT:
raise vol.Invalid("Unfortunately the arduino framework version '{}' is unsupported "
"at this time. You can override this by manually using "
@ -206,7 +207,7 @@ def preload_core_config(config):
CORE.build_path = CORE.relative_path(
cv.string(core_conf.get(CONF_BUILD_PATH, default_build_path())))
except vol.Invalid as e:
raise EsphomeyamlError(unicode(e))
raise EsphomeyamlError(text_type(e))
def to_code(config):

View File

@ -7,6 +7,7 @@ from esphomeyaml.helpers import cpp_string_escape, indent_all_but_first_and_last
# pylint: disable=unused-import, wrong-import-order
from typing import Any, Generator, List, Optional, Tuple, Union # noqa
from esphomeyaml.core import ID # noqa
from esphomeyaml.py_compat import text_type, string_types, integer_types
class Expression(object):
@ -28,7 +29,7 @@ class Expression(object):
return self.required
SafeExpType = Union[Expression, bool, str, unicode, int, long, float, TimePeriod]
SafeExpType = Union[Expression, bool, str, text_type, int, float, TimePeriod]
class RawExpression(Expression):
@ -73,7 +74,7 @@ class ExpressionList(Expression):
self.args.append(exp)
def __str__(self):
text = u", ".join(unicode(x) for x in self.args)
text = u", ".join(text_type(x) for x in self.args)
return indent_all_but_first_and_last(text)
@ -115,7 +116,7 @@ class StructInitializer(Expression):
if not isinstance(args, OrderedDict):
args = OrderedDict(args)
self.args = OrderedDict()
for key, value in args.iteritems():
for key, value in args.items():
if value is None:
continue
exp = safe_exp(value)
@ -124,7 +125,7 @@ class StructInitializer(Expression):
def __str__(self):
cpp = u'{}{{\n'.format(self.base)
for key, value in self.args.iteritems():
for key, value in self.args.items():
cpp += u' .{} = {},\n'.format(key, value)
cpp += u'}'
return cpp
@ -176,7 +177,7 @@ class ParameterListExpression(Expression):
self.requires.append(parameter)
def __str__(self):
return u", ".join(unicode(x) for x in self.parameters)
return u", ".join(text_type(x) for x in self.parameters)
class LambdaExpression(Expression):
@ -203,7 +204,7 @@ class LambdaExpression(Expression):
@property
def content(self):
return u''.join(unicode(part) for part in self.parts)
return u''.join(text_type(part) for part in self.parts)
class Literal(Expression):
@ -232,7 +233,7 @@ class IntLiteral(Literal):
return u'{}UL'.format(self.i)
if self.i < -2147483648:
return u'{}LL'.format(self.i)
return unicode(self.i)
return text_type(self.i)
class BoolLiteral(Literal):
@ -268,21 +269,21 @@ def safe_exp(obj # type: Union[Expression, bool, str, unicode, int, long, float
# type: (...) -> Expression
if isinstance(obj, Expression):
return obj
elif isinstance(obj, bool):
if isinstance(obj, bool):
return BoolLiteral(obj)
elif isinstance(obj, (str, unicode)):
if isinstance(obj, string_types):
return StringLiteral(obj)
elif isinstance(obj, HexInt):
if isinstance(obj, HexInt):
return HexIntLiteral(obj)
elif isinstance(obj, (int, long)):
if isinstance(obj, integer_types):
return IntLiteral(obj)
elif isinstance(obj, float):
if isinstance(obj, float):
return FloatLiteral(obj)
elif isinstance(obj, TimePeriodMicroseconds):
if isinstance(obj, TimePeriodMicroseconds):
return IntLiteral(int(obj.total_microseconds))
elif isinstance(obj, TimePeriodMilliseconds):
if isinstance(obj, TimePeriodMilliseconds):
return IntLiteral(int(obj.total_milliseconds))
elif isinstance(obj, TimePeriodSeconds):
if isinstance(obj, TimePeriodSeconds):
return IntLiteral(int(obj.total_seconds))
raise ValueError(u"Object is not an expression", obj)
@ -441,7 +442,7 @@ class MockObj(Expression):
return obj
def __str__(self): # type: () -> unicode
return unicode(self.base)
return text_type(self.base)
def require(self): # type: () -> None
self.required = True

View File

@ -20,11 +20,11 @@ def generic_gpio_pin_expression_(conf, mock_obj, default_mode):
mode = pcf8574.PCF8675_GPIO_MODES[conf.get(CONF_MODE, u'INPUT')]
yield hub.make_input_pin(number, mode, inverted)
return
elif default_mode == u'OUTPUT':
if default_mode == u'OUTPUT':
yield hub.make_output_pin(number, inverted)
return
else:
raise EsphomeyamlError(u"Unknown default mode {}".format(default_mode))
raise EsphomeyamlError(u"Unknown default mode {}".format(default_mode))
if len(conf) == 1:
yield IntLiteral(number)
return

View File

@ -176,7 +176,7 @@ class WizardRequestHandler(BaseHandler):
if not self.is_authenticated():
self.redirect('/login')
return
kwargs = {k: ''.join(v) for k, v in self.request.arguments.iteritems()}
kwargs = {k: ''.join(v) for k, v in self.request.arguments.items()}
destination = os.path.join(CONFIG_DIR, kwargs['name'] + '.yaml')
wizard.wizard_write(path=destination, **kwargs)
self.redirect('/?begin=True')
@ -436,7 +436,7 @@ class LoginHandler(BaseHandler):
self.redirect('/')
return
except Exception as err: # pylint: disable=broad-except
_LOGGER.warn("Error during Hass.io auth request: %s", err)
_LOGGER.warning("Error during Hass.io auth request: %s", err)
self.set_status(500)
self.render_hassio_login(error="Internal server error")
return

View File

@ -37,6 +37,7 @@
import hashlib
import logging
# pylint: disable=deprecated-module
import optparse
import os
import random

View File

@ -6,6 +6,8 @@ import os
import socket
import subprocess
from esphomeyaml.py_compat import text_type, IS_PY2
_LOGGER = logging.getLogger(__name__)
@ -39,14 +41,16 @@ def indent(text, padding=u' '):
# From https://stackoverflow.com/a/14945195/8924614
def cpp_string_escape(string, encoding='utf-8'):
if isinstance(string, unicode):
if isinstance(string, text_type):
string = string.encode(encoding)
result = ''
for character in string:
if not (32 <= ord(character) < 127) or character in ('\\', '"'):
result += '\\%03o' % ord(character)
if IS_PY2:
character = ord(character)
if not (32 <= character < 127) or character in ('\\', '"'):
result += '\\%03o' % character
else:
result += character
result += chr(character)
return '"' + result + '"'

View File

@ -246,7 +246,7 @@ def validate_gpio_pin(value):
_LOGGER.warning(u"ESP32: Pin %s (20, 24, 28-31) can usually not be used. "
u"Be warned.", value)
return value
elif CORE.is_esp8266:
if CORE.is_esp8266:
if 6 <= value <= 11:
_LOGGER.warning(u"ESP8266: Pin %s (6-11) might already be used by the "
u"flash interface. Be warned.", value)
@ -264,7 +264,7 @@ def input_pullup_pin(value):
value = input_pin(value)
if CORE.is_esp32:
return output_pin(value)
elif CORE.is_esp8266:
if CORE.is_esp8266:
if value == 0:
raise vol.Invalid("GPIO Pin 0 does not support pullup pin mode. "
"Please choose another pin.")
@ -279,7 +279,7 @@ def output_pin(value):
raise vol.Invalid(u"ESP32: GPIO{} (34-39) can only be used as an "
u"input pin.".format(value))
return value
elif CORE.is_esp8266:
if CORE.is_esp8266:
return value
raise NotImplementedError
@ -316,7 +316,7 @@ PIN_MODES_ESP32 = [
def pin_mode(value):
if CORE.is_esp32:
return cv.one_of(*PIN_MODES_ESP32, upper=True)(value)
elif CORE.is_esp8266:
if CORE.is_esp8266:
return cv.one_of(*PIN_MODES_ESP8266, upper=True)(value)
raise NotImplementedError

25
esphomeyaml/py_compat.py Normal file
View File

@ -0,0 +1,25 @@
import sys
PYTHON_MAJOR = sys.version_info[0]
IS_PY2 = PYTHON_MAJOR == 2
IS_PY3 = PYTHON_MAJOR == 3
# pylint: disable=no-else-return
def safe_input(line):
if IS_PY2:
return raw_input(line)
else:
return input(line)
if IS_PY2:
text_type = unicode
string_types = (str, unicode)
integer_types = (int, long)
binary_type = str
else:
text_type = str
string_types = (str,)
integer_types = (int,)
binary_type = bytes

View File

@ -272,13 +272,13 @@ class CheckForUpdateThread(threading.Thread):
remote_version = StrictVersion(storage.remote_version)
self_version = StrictVersion(const.__version__)
if remote_version > self_version:
_LOGGER.warn("*" * 80)
_LOGGER.warn("A new version of esphomeyaml is available: %s (this is %s)",
self.format_version(remote_version), self.format_version(self_version))
_LOGGER.warn("Changelog: %s/esphomeyaml/changelog/index.html", self.docs_base)
_LOGGER.warn("Update Instructions: %s/esphomeyaml/guides/faq.html"
"#how-do-i-update-to-the-latest-version", self.docs_base)
_LOGGER.warn("*" * 80)
_LOGGER.warning("*" * 80)
_LOGGER.warning("A new version of esphomeyaml is available: %s (this is %s)",
self.format_version(remote_version), self.format_version(self_version))
_LOGGER.warning("Changelog: %s/esphomeyaml/changelog/index.html", self.docs_base)
_LOGGER.warning("Update Instructions: %s/esphomeyaml/guides/faq.html"
"#how-do-i-update-to-the-latest-version", self.docs_base)
_LOGGER.warning("*" * 80)
def run(self):
try:

View File

@ -11,31 +11,32 @@ from esphomeyaml.const import ESP_PLATFORMS, ESP_PLATFORM_ESP32, ESP_PLATFORM_ES
from esphomeyaml.helpers import color
# pylint: disable=anomalous-backslash-in-string
from esphomeyaml.pins import ESP32_BOARD_PINS, ESP8266_BOARD_PINS
from esphomeyaml.py_compat import safe_input, text_type
from esphomeyaml.storage_json import StorageJSON, ext_storage_path
from esphomeyaml.util import safe_print
CORE_BIG = """ _____ ____ _____ ______
CORE_BIG = r""" _____ ____ _____ ______
/ ____/ __ \| __ \| ____|
| | | | | | |__) | |__
| | | | | | _ /| __|
| |___| |__| | | \ \| |____
\_____\____/|_| \_\______|
"""
ESP_BIG = """ ______ _____ _____
ESP_BIG = r""" ______ _____ _____
| ____|/ ____| __ \\
| |__ | (___ | |__) |
| __| \___ \| ___/
| |____ ____) | |
|______|_____/|_|
"""
WIFI_BIG = """ __ ___ ______ _
WIFI_BIG = r""" __ ___ ______ _
\ \ / (_) ____(_)
\ \ /\ / / _| |__ _
\ \/ \/ / | | __| | |
\ /\ / | | | | |
\/ \/ |_|_| |_|
"""
OTA_BIG = """ ____ _______
OTA_BIG = r""" ____ _______
/ __ \__ __|/\\
| | | | | | / \\
| | | | | | / /\ \\
@ -85,7 +86,7 @@ def wizard_write(path, **kwargs):
storage.save(storage_path)
if os.getenv('ESPHOMEYAML_QUICKWIZARD', False):
if os.getenv('ESPHOMEYAML_QUICKWIZARD', ''):
def sleep(time):
pass
else:
@ -104,12 +105,12 @@ def safe_print_step(step, big):
def default_input(text, default):
safe_print()
safe_print(u"Press ENTER for default ({})".format(default))
return raw_input(text.format(default)) or default
return safe_input(text.format(default)) or default
# From https://stackoverflow.com/a/518232/8924614
def strip_accents(string):
return u''.join(c for c in unicodedata.normalize('NFD', unicode(string))
return u''.join(c for c in unicodedata.normalize('NFD', text_type(string))
if unicodedata.category(c) != 'Mn')
@ -140,7 +141,7 @@ def wizard(path):
color('bold_white', "livingroom")))
safe_print()
sleep(1)
name = raw_input(color("bold_white", "(name): "))
name = safe_input(color("bold_white", "(name): "))
while True:
try:
name = cv.valid_name(name)
@ -165,7 +166,7 @@ def wizard(path):
sleep(0.5)
safe_print()
safe_print("Please enter either ESP32 or ESP8266.")
platform = raw_input(color("bold_white", "(ESP32/ESP8266): "))
platform = safe_input(color("bold_white", "(ESP32/ESP8266): "))
try:
platform = vol.All(vol.Upper, vol.Any(*ESP_PLATFORMS))(platform)
break
@ -197,7 +198,7 @@ def wizard(path):
safe_print("Options: {}".format(', '.join(boards)))
while True:
board = raw_input(color("bold_white", "(board): "))
board = safe_input(color("bold_white", "(board): "))
try:
board = vol.All(vol.Lower, vol.Any(*boards))(board)
break
@ -221,7 +222,7 @@ def wizard(path):
sleep(1.5)
safe_print("For example \"{}\".".format(color('bold_white', "Abraham Linksys")))
while True:
ssid = raw_input(color('bold_white', "(ssid): "))
ssid = safe_input(color('bold_white', "(ssid): "))
try:
ssid = cv.ssid(ssid)
break
@ -241,7 +242,7 @@ def wizard(path):
safe_print()
safe_print("For example \"{}\"".format(color('bold_white', 'PASSWORD42')))
sleep(0.5)
psk = raw_input(color('bold_white', '(PSK): '))
psk = safe_input(color('bold_white', '(PSK): '))
safe_print("Perfect! WiFi is now set up (you can create static IPs and so on later).")
sleep(1.5)
@ -253,7 +254,7 @@ def wizard(path):
safe_print()
sleep(0.25)
safe_print("Press ENTER for no password")
password = raw_input(color('bold_white', '(password): '))
password = safe_input(color('bold_white', '(password): '))
wizard_write(path=path, name=name, platform=platform, board=board,
ssid=ssid, psk=psk, password=password)

View File

@ -16,6 +16,7 @@ from esphomeyaml.core import CORE, EsphomeyamlError
from esphomeyaml.core_config import VERSION_REGEX, LIBRARY_URI_REPO, GITHUB_ARCHIVE_ZIP
from esphomeyaml.helpers import mkdir_p, run_system_command
from esphomeyaml.pins import ESP8266_LD_SCRIPTS, ESP8266_FLASH_SIZES
from esphomeyaml.py_compat import IS_PY3, string_types
from esphomeyaml.storage_json import StorageJSON, storage_path
from esphomeyaml.util import safe_print
@ -71,7 +72,7 @@ def get_build_flags(key):
flags = flags(conf)
if flags is None:
continue
if isinstance(flags, (str, unicode)):
if isinstance(flags, string_types):
flags = [flags]
build_flags |= set(flags)
return build_flags
@ -114,14 +115,19 @@ def update_esphomelib_repo():
'--')
if rc != 0:
# local changes, cannot update
_LOGGER.warn("Local changes in esphomelib copy from git. Will not auto-update.")
_LOGGER.warning("Local changes in esphomelib copy from git. Will not auto-update.")
return
_LOGGER.info("Updating esphomelib copy from git (%s)", esphomelib_path)
rc, stdout, _ = run_system_command('git', '-c', 'color.ui=always', '-C', esphomelib_path,
'pull', '--stat')
if rc != 0:
_LOGGER.warn("Couldn't auto-update local git copy of esphomelib.")
_LOGGER.warning("Couldn't auto-update local git copy of esphomelib.")
return
if IS_PY3:
try:
stdout = stdout.encode('utf-8')
except Exception: # pylint: disable=broad-except
pass
safe_print(stdout.strip())

View File

@ -12,6 +12,7 @@ import yaml.constructor
from esphomeyaml import core
from esphomeyaml.core import EsphomeyamlError, HexInt, IPAddress, Lambda, MACAddress, TimePeriod
from esphomeyaml.py_compat import text_type, string_types
_LOGGER = logging.getLogger(__name__)
@ -24,14 +25,10 @@ SECRET_YAML = u'secrets.yaml'
class NodeListClass(list):
"""Wrapper class to be able to add attributes on a list."""
pass
class NodeStrClass(unicode):
class NodeStrClass(text_type):
"""Wrapper class to be able to add attributes on a string."""
pass
class SafeLineLoader(yaml.SafeLoader): # pylint: disable=too-many-ancestors
"""Loader class that keeps track of line numbers."""
@ -72,7 +69,7 @@ def custom_construct_pairs(loader, node):
if not isinstance(obj, dict):
raise EsphomeyamlError(
"Expected mapping for anchored include tag, got {}".format(type(obj)))
for key, value in obj.iteritems():
for key, value in obj.items():
pairs.append((key, value))
else:
key_node, value_node = kv
@ -168,7 +165,7 @@ def _construct_seq(loader, node):
def _add_reference(obj, loader, node):
"""Add file reference information to an object."""
if isinstance(obj, (str, unicode)):
if isinstance(obj, string_types):
obj = NodeStrClass(obj)
if isinstance(obj, list):
obj = NodeListClass(obj)
@ -184,7 +181,7 @@ def _env_var_yaml(_, node):
# Check for a default value
if len(args) > 1:
return os.getenv(args[0], u' '.join(args[1:]))
elif args[0] in os.environ:
if args[0] in os.environ:
return os.environ[args[0]]
raise EsphomeyamlError(u"Environment variable {} not defined.".format(node.value))
@ -268,7 +265,7 @@ def _secret_yaml(loader, node):
def _lambda(loader, node):
return Lambda(unicode(node.value))
return Lambda(text_type(node.value))
yaml.SafeLoader.add_constructor(yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, _ordered_dict)
@ -295,7 +292,7 @@ def represent_odict(dump, tag, mapping, flow_style=None):
dump.represented_objects[dump.alias_key] = node
best_style = True
if hasattr(mapping, 'items'):
mapping = mapping.items()
mapping = list(mapping.items())
for item_key, item_value in mapping:
node_key = dump.represent_data(item_key)
node_value = dump.represent_data(item_value)
@ -372,7 +369,7 @@ yaml.SafeDumper.add_representer(
dumper.represent_sequence('tag:yaml.org,2002:seq', value)
)
yaml.SafeDumper.add_representer(unicode, unicode_representer)
yaml.SafeDumper.add_representer(text_type, unicode_representer)
yaml.SafeDumper.add_representer(HexInt, hex_int_representer)
yaml.SafeDumper.add_representer(IPAddress, stringify_representer)
yaml.SafeDumper.add_representer(MACAddress, stringify_representer)

View File

@ -19,6 +19,8 @@ disable=
cyclic-import,
redefined-builtin,
undefined-loop-variable,
useless-object-inheritance,
stop-iteration-return,
additional-builtins=

View File

@ -56,7 +56,7 @@ setup(
zip_safe=False,
platforms='any',
test_suite='tests',
python_requires='>=2.7,<3',
python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,<4.0',
install_requires=REQUIRES,
keywords=['home', 'automation'],
entry_points={