Skip to content

Commit a60c57a

Browse files
committed
Initial support for Python 3.5+ // Resolve platformio#895 Resolve platformio#1365
1 parent fabaade commit a60c57a

35 files changed

+265
-198
lines changed

.appveyor.yml

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ platform:
77
environment:
88
matrix:
99
- TOXENV: "py27"
10+
- TOXENV: "py35"
11+
- TOXENV: "py36"
1012

1113
install:
1214
- cmd: git submodule update --init --recursive

.pylintrc

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ confidence=
2020
# --disable=W"
2121
# disable=import-star-module-level,old-octal-literal,oct-method,print-statement,unpacking-in-except,parameter-unpacking,backtick,old-raise-syntax,old-ne-operator,long-suffix,dict-view-method,dict-iter-method,metaclass-assignment,next-method-called,raising-string,indexing-exception,raw_input-builtin,long-builtin,file-builtin,execfile-builtin,coerce-builtin,cmp-builtin,buffer-builtin,basestring-builtin,apply-builtin,filter-builtin-not-iterating,using-cmp-argument,useless-suppression,range-builtin-not-iterating,suppressed-message,no-absolute-import,old-division,cmp-method,reload-builtin,zip-builtin-not-iterating,intern-builtin,unichr-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,input-builtin,round-builtin,hex-method,nonzero-method,map-builtin-not-iterating
2222

23-
disable=locally-disabled,missing-docstring,invalid-name,too-few-public-methods,redefined-variable-type,import-error,similarities,unsupported-membership-test,unsubscriptable-object,ungrouped-imports,cyclic-import,superfluous-parens
23+
disable=locally-disabled,missing-docstring,invalid-name,too-few-public-methods,redefined-variable-type,import-error,similarities,unsupported-membership-test,unsubscriptable-object,ungrouped-imports,cyclic-import,superfluous-parens,useless-object-inheritance,useless-import-alias

.travis.yml

+9-5
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,18 @@ matrix:
66
sudo: false
77
python: 2.7
88
env: TOX_ENV=docs
9-
- os: linux
10-
sudo: false
11-
python: 2.7
12-
env: TOX_ENV=lint
139
- os: linux
1410
sudo: required
1511
python: 2.7
1612
env: TOX_ENV=py27
13+
- os: linux
14+
sudo: required
15+
python: 3.5
16+
env: TOX_ENV=py35
17+
- os: linux
18+
sudo: required
19+
python: 3.6
20+
env: TOX_ENV=py36
1721
- os: osx
1822
language: generic
1923
env: TOX_ENV=skipexamples
@@ -24,7 +28,7 @@ install:
2428
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sudo pip install "tox==3.0.0"; else pip install -U tox; fi
2529

2630
# ChipKIT issue: install 32-bit support for GCC PIC32
27-
- if [[ "$TOX_ENV" == "py27" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install libc6-i386; fi
31+
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install libc6-i386; fi
2832

2933
script:
3034
- tox -e $TOX_ENV

HISTORY.rst

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
Release Notes
22
=============
33

4+
PlatformIO 4.0
5+
--------------
6+
7+
4.0.0 (2019-??-??)
8+
~~~~~~~~~~~~~~~~~~
9+
10+
* Added Python 3.5+ support
11+
(`issue #895 <https://github.com/platformio/platformio-core/issues/895>`_)
12+
413
PlatformIO 3.0
514
--------------
615

7-
3.6.4 (2018-??-??)
16+
3.6.4 (2019-??-??)
817
~~~~~~~~~~~~~~~~~~
918

1019
* Improved Project Generator for IDEs:

platformio/__init__.py

+1-10
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
import sys
16-
17-
VERSION = (3, 6, "4b1")
15+
VERSION = (4, 0, "0a1")
1816
__version__ = ".".join([str(s) for s in VERSION])
1917

2018
__title__ = "platformio"
@@ -33,10 +31,3 @@
3331
__copyright__ = "Copyright 2014-present PlatformIO"
3432

3533
__apiurl__ = "https://api.platformio.org"
36-
37-
if sys.version_info < (2, 7, 0) or sys.version_info >= (3, 0, 0):
38-
msg = ("PlatformIO Core v%s does not run under Python version %s.\n"
39-
"Minimum supported version is 2.7, please upgrade Python.\n"
40-
"Python 3 is not yet supported.\n")
41-
sys.stderr.write(msg % (__version__, sys.version))
42-
sys.exit(1)

platformio/__main__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def _handle_obsolate_command(name):
5353
if name == "platforms":
5454
from platformio.commands import platform
5555
return platform.cli
56-
elif name == "serialports":
56+
if name == "serialports":
5757
from platformio.commands import device
5858
return device.cli
5959
raise AttributeError()

platformio/app.py

+24-20
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,11 @@ def get_cache_path(self, key):
169169
@staticmethod
170170
def key_from_args(*args):
171171
h = hashlib.md5()
172-
for data in args:
173-
h.update(str(data))
172+
for arg in args:
173+
if not arg:
174+
continue
175+
arg = str(arg)
176+
h.update(arg if util.PY2 else arg.encode())
174177
return h.hexdigest()
175178

176179
def get(self, key):
@@ -191,7 +194,7 @@ def set(self, key, data, valid):
191194
if not isdir(self.cache_dir):
192195
os.makedirs(self.cache_dir)
193196
tdmap = {"s": 1, "m": 60, "h": 3600, "d": 86400}
194-
assert valid.endswith(tuple(tdmap.keys()))
197+
assert valid.endswith(tuple(tdmap))
195198
expire_time = int(time() + tdmap[valid[-1]] * int(valid[:-1]))
196199

197200
if not self._lock_dbindex():
@@ -339,21 +342,22 @@ def is_disabled_progressbar():
339342

340343
def get_cid():
341344
cid = get_state_item("cid")
342-
if not cid:
343-
_uid = None
344-
if getenv("C9_UID"):
345-
_uid = getenv("C9_UID")
346-
elif getenv("CHE_API", getenv("CHE_API_ENDPOINT")):
347-
try:
348-
_uid = requests.get("{api}/user?token={token}".format(
349-
api=getenv("CHE_API", getenv("CHE_API_ENDPOINT")),
350-
token=getenv("USER_TOKEN"))).json().get("id")
351-
except: # pylint: disable=bare-except
352-
pass
353-
cid = str(
354-
uuid.UUID(
355-
bytes=hashlib.md5(str(_uid if _uid else uuid.getnode())).
356-
digest()))
357-
if "windows" in util.get_systype() or os.getuid() > 0:
358-
set_state_item("cid", cid)
345+
if cid:
346+
return cid
347+
uid = None
348+
if getenv("C9_UID"):
349+
uid = getenv("C9_UID")
350+
elif getenv("CHE_API", getenv("CHE_API_ENDPOINT")):
351+
try:
352+
uid = requests.get("{api}/user?token={token}".format(
353+
api=getenv("CHE_API", getenv("CHE_API_ENDPOINT")),
354+
token=getenv("USER_TOKEN"))).json().get("id")
355+
except: # pylint: disable=bare-except
356+
pass
357+
if not uid:
358+
uid = uuid.getnode()
359+
cid = uuid.UUID(bytes=hashlib.md5(str(uid).encode()).digest())
360+
cid = str(cid)
361+
if "windows" in util.get_systype() or os.getuid() > 0:
362+
set_state_item("cid", cid)
359363
return cid

platformio/builder/main.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@
9292
variables=commonvars,
9393

9494
# Propagating External Environment
95-
PIOVARIABLES=commonvars.keys(),
95+
PIOVARIABLES=list(commonvars.keys()),
9696
ENV=environ,
9797
UNIX_TIME=int(time()),
9898
PIOHOME_DIR=util.get_home_dir(),
@@ -125,9 +125,11 @@
125125
env = DefaultEnvironment(**DEFAULT_ENV_OPTIONS)
126126

127127
# decode common variables
128-
for k in commonvars.keys():
128+
for k in list(commonvars.keys()):
129129
if k in env:
130130
env[k] = base64.b64decode(env[k])
131+
if isinstance(env[k], bytes):
132+
env[k] = env[k].decode()
131133
if k in MULTILINE_VARS:
132134
env[k] = util.parse_conf_multi_values(env[k])
133135

@@ -161,7 +163,9 @@
161163
env.LoadPioPlatform(commonvars)
162164

163165
env.SConscriptChdir(0)
164-
env.SConsignFile(join("$PROJECTBUILD_DIR", ".sconsign.dblite"))
166+
env.SConsignFile(
167+
join("$PROJECTBUILD_DIR",
168+
".sconsign.dblite" if util.PY2 else ".sconsign3.dblite"))
165169

166170
for item in env.GetExtraScripts("pre"):
167171
env.SConscript(item, exports="env")

platformio/builder/tools/piolib.py

+20-13
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,19 @@ def get_used_frameworks(env, path):
7474
if not env.IsFileWithExt(
7575
fname, piotool.SRC_BUILD_EXT + piotool.SRC_HEADER_EXT):
7676
continue
77-
with open(join(root, fname)) as f:
78-
content = f.read()
79-
if "Arduino.h" in content and include_re.search(content):
80-
return ["arduino"]
81-
elif "mbed.h" in content and include_re.search(content):
82-
return ["mbed"]
77+
content = ""
78+
try:
79+
with open(join(root, fname)) as f:
80+
content = f.read()
81+
except UnicodeDecodeError:
82+
with open(join(root, fname), encoding="latin-1") as f:
83+
content = f.read()
84+
if not content:
85+
continue
86+
if "Arduino.h" in content and include_re.search(content):
87+
return ["arduino"]
88+
if "mbed.h" in content and include_re.search(content):
89+
return ["mbed"]
8390
return []
8491

8592

@@ -183,9 +190,9 @@ def get_include_dirs(self):
183190

184191
@property
185192
def build_dir(self):
186-
return join("$BUILD_DIR",
187-
"lib%s" % hashlib.sha1(self.path).hexdigest()[:3],
188-
basename(self.path))
193+
lib_hash = hashlib.sha1(self.path if util.PY2 else self.path.
194+
encode()).hexdigest()[:3]
195+
return join("$BUILD_DIR", "lib%s" % lib_hash, basename(self.path))
189196

190197
@property
191198
def build_flags(self):
@@ -227,7 +234,7 @@ def is_built(self):
227234

228235
@staticmethod
229236
def validate_ldf_mode(mode):
230-
if isinstance(mode, basestring):
237+
if isinstance(mode, util.string_types):
231238
mode = mode.strip().lower()
232239
if mode in LibBuilderBase.LDF_MODES:
233240
return mode
@@ -239,7 +246,7 @@ def validate_ldf_mode(mode):
239246

240247
@staticmethod
241248
def validate_compat_mode(mode):
242-
if isinstance(mode, basestring):
249+
if isinstance(mode, util.string_types):
243250
mode = mode.strip().lower()
244251
if mode in LibBuilderBase.COMPAT_MODES:
245252
return mode
@@ -612,9 +619,9 @@ def _is_arduino_manifest(self):
612619
def src_filter(self):
613620
if "srcFilter" in self._manifest.get("build", {}):
614621
return self._manifest.get("build").get("srcFilter")
615-
elif self.env['SRC_FILTER']:
622+
if self.env['SRC_FILTER']:
616623
return self.env['SRC_FILTER']
617-
elif self._is_arduino_manifest():
624+
if self._is_arduino_manifest():
618625
return ArduinoLibBuilder.src_filter.fget(self)
619626
return LibBuilderBase.src_filter.fget(self)
620627

platformio/builder/tools/piomisc.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ def append_prototypes(self, contents):
162162
if not prototypes:
163163
return contents
164164

165-
prototype_names = set([m.group(3).strip() for m in prototypes])
165+
prototype_names = set(m.group(3).strip() for m in prototypes)
166166
split_pos = prototypes[0].start()
167167
match_ptrs = re.search(
168168
self.PROTOPTRS_TPLRE % ("|".join(prototype_names)),
@@ -212,7 +212,7 @@ def _get_compiler_type(env):
212212
output = "".join([result['out'], result['err']]).lower()
213213
if "clang" in output and "LLVM" in output:
214214
return "clang"
215-
elif "gcc" in output:
215+
if "gcc" in output:
216216
return "gcc"
217217
return None
218218

platformio/builder/tools/pioplatform.py

+9-4
Original file line numberDiff line numberDiff line change
@@ -95,19 +95,24 @@ def LoadPioPlatform(env, variables):
9595
for key, value in variables.UnknownVariables().items():
9696
if not key.startswith("BOARD_"):
9797
continue
98-
env.Replace(
99-
**{key.upper().replace("BUILD.", ""): base64.b64decode(value)})
98+
value = base64.b64decode(value)
99+
if isinstance(value, bytes):
100+
value = value.decode()
101+
env.Replace(**{key.upper().replace("BUILD.", ""): value})
100102
return
101103

102104
# update board manifest with a custom data
103105
board_config = env.BoardConfig()
104106
for key, value in variables.UnknownVariables().items():
105107
if not key.startswith("BOARD_"):
106108
continue
107-
board_config.update(key.lower()[6:], base64.b64decode(value))
109+
value = base64.b64decode(value)
110+
if isinstance(value, bytes):
111+
value = value.decode()
112+
board_config.update(key.lower()[6:], value)
108113

109114
# update default environment variables
110-
for key in variables.keys():
115+
for key in list(variables.keys()):
111116
if key in env or \
112117
not any([key.startswith("BOARD_"), key.startswith("UPLOAD_")]):
113118
continue

platformio/builder/tools/piowinhooks.py

+8-3
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,13 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
from __future__ import absolute_import
16+
1517
from hashlib import md5
1618
from os import makedirs
1719
from os.path import isdir, isfile, join
18-
from platform import system
20+
21+
from platformio import util
1922

2023
# Windows CLI has limit with command length to 8192
2124
# Leave 2000 chars for flags and other options
@@ -58,7 +61,9 @@ def _file_long_data(env, data):
5861
build_dir = env.subst("$BUILD_DIR")
5962
if not isdir(build_dir):
6063
makedirs(build_dir)
61-
tmp_file = join(build_dir, "longcmd-%s" % md5(data).hexdigest())
64+
tmp_file = join(
65+
build_dir,
66+
"longcmd-%s" % md5(data if util.PY2 else data.encode()).hexdigest())
6267
if isfile(tmp_file):
6368
return tmp_file
6469
with open(tmp_file, "w") as fp:
@@ -71,7 +76,7 @@ def exists(_):
7176

7277

7378
def generate(env):
74-
if system() != "Windows":
79+
if "windows" not in util.get_systype():
7580
return None
7681

7782
env.Replace(_long_sources_hook=long_sources_hook)

platformio/builder/tools/platformio.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild,
2525
DefaultEnvironment, Export, SConscript)
2626

27-
from platformio.util import glob_escape, pioversion_to_intstr
27+
from platformio.util import glob_escape, pioversion_to_intstr, string_types
2828

2929
SRC_HEADER_EXT = ["h", "hpp"]
3030
SRC_C_EXT = ["c", "cc", "cpp"]
@@ -189,7 +189,7 @@ def ProcessFlags(env, flags): # pylint: disable=too-many-branches
189189
# provided with a -U option // Issue #191
190190
undefines = [
191191
u for u in env.get("CCFLAGS", [])
192-
if isinstance(u, basestring) and u.startswith("-U")
192+
if isinstance(u, string_types) and u.startswith("-U")
193193
]
194194
if undefines:
195195
for undef in undefines:

platformio/commands/device.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def device_list( # pylint: disable=too-many-branches
4444
if mdns:
4545
data['mdns'] = util.get_mdns_services()
4646

47-
single_key = data.keys()[0] if len(data.keys()) == 1 else None
47+
single_key = list(data)[0] if len(list(data)) == 1 else None
4848

4949
if json_output:
5050
return click.echo(json.dumps(data[single_key] if single_key else data))

0 commit comments

Comments
 (0)