Initial support for Python 3.5+ // Resolve #895 Resolve #1365

This commit is contained in:
Ivan Kravets
2018-12-26 20:54:29 +02:00
parent fabaadec60
commit a60c57ac58
35 changed files with 265 additions and 198 deletions

View File

@ -7,6 +7,8 @@ platform:
environment: environment:
matrix: matrix:
- TOXENV: "py27" - TOXENV: "py27"
- TOXENV: "py35"
- TOXENV: "py36"
install: install:
- cmd: git submodule update --init --recursive - cmd: git submodule update --init --recursive

View File

@ -20,4 +20,4 @@ confidence=
# --disable=W" # --disable=W"
# 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 # 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
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 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

View File

@ -6,14 +6,18 @@ matrix:
sudo: false sudo: false
python: 2.7 python: 2.7
env: TOX_ENV=docs env: TOX_ENV=docs
- os: linux
sudo: false
python: 2.7
env: TOX_ENV=lint
- os: linux - os: linux
sudo: required sudo: required
python: 2.7 python: 2.7
env: TOX_ENV=py27 env: TOX_ENV=py27
- os: linux
sudo: required
python: 3.5
env: TOX_ENV=py35
- os: linux
sudo: required
python: 3.6
env: TOX_ENV=py36
- os: osx - os: osx
language: generic language: generic
env: TOX_ENV=skipexamples env: TOX_ENV=skipexamples
@ -24,7 +28,7 @@ install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sudo pip install "tox==3.0.0"; else pip install -U tox; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sudo pip install "tox==3.0.0"; else pip install -U tox; fi
# ChipKIT issue: install 32-bit support for GCC PIC32 # ChipKIT issue: install 32-bit support for GCC PIC32
- if [[ "$TOX_ENV" == "py27" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install libc6-i386; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install libc6-i386; fi
script: script:
- tox -e $TOX_ENV - tox -e $TOX_ENV

View File

@ -1,10 +1,19 @@
Release Notes Release Notes
============= =============
PlatformIO 4.0
--------------
4.0.0 (2019-??-??)
~~~~~~~~~~~~~~~~~~
* Added Python 3.5+ support
(`issue #895 <https://github.com/platformio/platformio-core/issues/895>`_)
PlatformIO 3.0 PlatformIO 3.0
-------------- --------------
3.6.4 (2018-??-??) 3.6.4 (2019-??-??)
~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~
* Improved Project Generator for IDEs: * Improved Project Generator for IDEs:

View File

@ -12,9 +12,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import sys VERSION = (4, 0, "0a1")
VERSION = (3, 6, "4b1")
__version__ = ".".join([str(s) for s in VERSION]) __version__ = ".".join([str(s) for s in VERSION])
__title__ = "platformio" __title__ = "platformio"
@ -33,10 +31,3 @@ __license__ = "Apache Software License"
__copyright__ = "Copyright 2014-present PlatformIO" __copyright__ = "Copyright 2014-present PlatformIO"
__apiurl__ = "https://api.platformio.org" __apiurl__ = "https://api.platformio.org"
if sys.version_info < (2, 7, 0) or sys.version_info >= (3, 0, 0):
msg = ("PlatformIO Core v%s does not run under Python version %s.\n"
"Minimum supported version is 2.7, please upgrade Python.\n"
"Python 3 is not yet supported.\n")
sys.stderr.write(msg % (__version__, sys.version))
sys.exit(1)

View File

@ -53,7 +53,7 @@ class PlatformioCLI(click.MultiCommand): # pylint: disable=R0904
if name == "platforms": if name == "platforms":
from platformio.commands import platform from platformio.commands import platform
return platform.cli return platform.cli
elif name == "serialports": if name == "serialports":
from platformio.commands import device from platformio.commands import device
return device.cli return device.cli
raise AttributeError() raise AttributeError()

View File

@ -169,8 +169,11 @@ class ContentCache(object):
@staticmethod @staticmethod
def key_from_args(*args): def key_from_args(*args):
h = hashlib.md5() h = hashlib.md5()
for data in args: for arg in args:
h.update(str(data)) if not arg:
continue
arg = str(arg)
h.update(arg if util.PY2 else arg.encode())
return h.hexdigest() return h.hexdigest()
def get(self, key): def get(self, key):
@ -191,7 +194,7 @@ class ContentCache(object):
if not isdir(self.cache_dir): if not isdir(self.cache_dir):
os.makedirs(self.cache_dir) os.makedirs(self.cache_dir)
tdmap = {"s": 1, "m": 60, "h": 3600, "d": 86400} tdmap = {"s": 1, "m": 60, "h": 3600, "d": 86400}
assert valid.endswith(tuple(tdmap.keys())) assert valid.endswith(tuple(tdmap))
expire_time = int(time() + tdmap[valid[-1]] * int(valid[:-1])) expire_time = int(time() + tdmap[valid[-1]] * int(valid[:-1]))
if not self._lock_dbindex(): if not self._lock_dbindex():
@ -339,21 +342,22 @@ def is_disabled_progressbar():
def get_cid(): def get_cid():
cid = get_state_item("cid") cid = get_state_item("cid")
if not cid: if cid:
_uid = None return cid
if getenv("C9_UID"): uid = None
_uid = getenv("C9_UID") if getenv("C9_UID"):
elif getenv("CHE_API", getenv("CHE_API_ENDPOINT")): uid = getenv("C9_UID")
try: elif getenv("CHE_API", getenv("CHE_API_ENDPOINT")):
_uid = requests.get("{api}/user?token={token}".format( try:
api=getenv("CHE_API", getenv("CHE_API_ENDPOINT")), uid = requests.get("{api}/user?token={token}".format(
token=getenv("USER_TOKEN"))).json().get("id") api=getenv("CHE_API", getenv("CHE_API_ENDPOINT")),
except: # pylint: disable=bare-except token=getenv("USER_TOKEN"))).json().get("id")
pass except: # pylint: disable=bare-except
cid = str( pass
uuid.UUID( if not uid:
bytes=hashlib.md5(str(_uid if _uid else uuid.getnode())). uid = uuid.getnode()
digest())) cid = uuid.UUID(bytes=hashlib.md5(str(uid).encode()).digest())
if "windows" in util.get_systype() or os.getuid() > 0: cid = str(cid)
set_state_item("cid", cid) if "windows" in util.get_systype() or os.getuid() > 0:
set_state_item("cid", cid)
return cid return cid

View File

@ -92,7 +92,7 @@ DEFAULT_ENV_OPTIONS = dict(
variables=commonvars, variables=commonvars,
# Propagating External Environment # Propagating External Environment
PIOVARIABLES=commonvars.keys(), PIOVARIABLES=list(commonvars.keys()),
ENV=environ, ENV=environ,
UNIX_TIME=int(time()), UNIX_TIME=int(time()),
PIOHOME_DIR=util.get_home_dir(), PIOHOME_DIR=util.get_home_dir(),
@ -125,9 +125,11 @@ if not int(ARGUMENTS.get("PIOVERBOSE", 0)):
env = DefaultEnvironment(**DEFAULT_ENV_OPTIONS) env = DefaultEnvironment(**DEFAULT_ENV_OPTIONS)
# decode common variables # decode common variables
for k in commonvars.keys(): for k in list(commonvars.keys()):
if k in env: if k in env:
env[k] = base64.b64decode(env[k]) env[k] = base64.b64decode(env[k])
if isinstance(env[k], bytes):
env[k] = env[k].decode()
if k in MULTILINE_VARS: if k in MULTILINE_VARS:
env[k] = util.parse_conf_multi_values(env[k]) env[k] = util.parse_conf_multi_values(env[k])
@ -161,7 +163,9 @@ env['LIBSOURCE_DIRS'] = [
env.LoadPioPlatform(commonvars) env.LoadPioPlatform(commonvars)
env.SConscriptChdir(0) env.SConscriptChdir(0)
env.SConsignFile(join("$PROJECTBUILD_DIR", ".sconsign.dblite")) env.SConsignFile(
join("$PROJECTBUILD_DIR",
".sconsign.dblite" if util.PY2 else ".sconsign3.dblite"))
for item in env.GetExtraScripts("pre"): for item in env.GetExtraScripts("pre"):
env.SConscript(item, exports="env") env.SConscript(item, exports="env")

View File

@ -74,12 +74,19 @@ class LibBuilderFactory(object):
if not env.IsFileWithExt( if not env.IsFileWithExt(
fname, piotool.SRC_BUILD_EXT + piotool.SRC_HEADER_EXT): fname, piotool.SRC_BUILD_EXT + piotool.SRC_HEADER_EXT):
continue continue
with open(join(root, fname)) as f: content = ""
content = f.read() try:
if "Arduino.h" in content and include_re.search(content): with open(join(root, fname)) as f:
return ["arduino"] content = f.read()
elif "mbed.h" in content and include_re.search(content): except UnicodeDecodeError:
return ["mbed"] with open(join(root, fname), encoding="latin-1") as f:
content = f.read()
if not content:
continue
if "Arduino.h" in content and include_re.search(content):
return ["arduino"]
if "mbed.h" in content and include_re.search(content):
return ["mbed"]
return [] return []
@ -183,9 +190,9 @@ class LibBuilderBase(object):
@property @property
def build_dir(self): def build_dir(self):
return join("$BUILD_DIR", lib_hash = hashlib.sha1(self.path if util.PY2 else self.path.
"lib%s" % hashlib.sha1(self.path).hexdigest()[:3], encode()).hexdigest()[:3]
basename(self.path)) return join("$BUILD_DIR", "lib%s" % lib_hash, basename(self.path))
@property @property
def build_flags(self): def build_flags(self):
@ -227,7 +234,7 @@ class LibBuilderBase(object):
@staticmethod @staticmethod
def validate_ldf_mode(mode): def validate_ldf_mode(mode):
if isinstance(mode, basestring): if isinstance(mode, util.string_types):
mode = mode.strip().lower() mode = mode.strip().lower()
if mode in LibBuilderBase.LDF_MODES: if mode in LibBuilderBase.LDF_MODES:
return mode return mode
@ -239,7 +246,7 @@ class LibBuilderBase(object):
@staticmethod @staticmethod
def validate_compat_mode(mode): def validate_compat_mode(mode):
if isinstance(mode, basestring): if isinstance(mode, util.string_types):
mode = mode.strip().lower() mode = mode.strip().lower()
if mode in LibBuilderBase.COMPAT_MODES: if mode in LibBuilderBase.COMPAT_MODES:
return mode return mode
@ -612,9 +619,9 @@ class PlatformIOLibBuilder(LibBuilderBase):
def src_filter(self): def src_filter(self):
if "srcFilter" in self._manifest.get("build", {}): if "srcFilter" in self._manifest.get("build", {}):
return self._manifest.get("build").get("srcFilter") return self._manifest.get("build").get("srcFilter")
elif self.env['SRC_FILTER']: if self.env['SRC_FILTER']:
return self.env['SRC_FILTER'] return self.env['SRC_FILTER']
elif self._is_arduino_manifest(): if self._is_arduino_manifest():
return ArduinoLibBuilder.src_filter.fget(self) return ArduinoLibBuilder.src_filter.fget(self)
return LibBuilderBase.src_filter.fget(self) return LibBuilderBase.src_filter.fget(self)

View File

@ -162,7 +162,7 @@ class InoToCPPConverter(object):
if not prototypes: if not prototypes:
return contents return contents
prototype_names = set([m.group(3).strip() for m in prototypes]) prototype_names = set(m.group(3).strip() for m in prototypes)
split_pos = prototypes[0].start() split_pos = prototypes[0].start()
match_ptrs = re.search( match_ptrs = re.search(
self.PROTOPTRS_TPLRE % ("|".join(prototype_names)), self.PROTOPTRS_TPLRE % ("|".join(prototype_names)),
@ -212,7 +212,7 @@ def _get_compiler_type(env):
output = "".join([result['out'], result['err']]).lower() output = "".join([result['out'], result['err']]).lower()
if "clang" in output and "LLVM" in output: if "clang" in output and "LLVM" in output:
return "clang" return "clang"
elif "gcc" in output: if "gcc" in output:
return "gcc" return "gcc"
return None return None

View File

@ -95,8 +95,10 @@ def LoadPioPlatform(env, variables):
for key, value in variables.UnknownVariables().items(): for key, value in variables.UnknownVariables().items():
if not key.startswith("BOARD_"): if not key.startswith("BOARD_"):
continue continue
env.Replace( value = base64.b64decode(value)
**{key.upper().replace("BUILD.", ""): base64.b64decode(value)}) if isinstance(value, bytes):
value = value.decode()
env.Replace(**{key.upper().replace("BUILD.", ""): value})
return return
# update board manifest with a custom data # update board manifest with a custom data
@ -104,10 +106,13 @@ def LoadPioPlatform(env, variables):
for key, value in variables.UnknownVariables().items(): for key, value in variables.UnknownVariables().items():
if not key.startswith("BOARD_"): if not key.startswith("BOARD_"):
continue continue
board_config.update(key.lower()[6:], base64.b64decode(value)) value = base64.b64decode(value)
if isinstance(value, bytes):
value = value.decode()
board_config.update(key.lower()[6:], value)
# update default environment variables # update default environment variables
for key in variables.keys(): for key in list(variables.keys()):
if key in env or \ if key in env or \
not any([key.startswith("BOARD_"), key.startswith("UPLOAD_")]): not any([key.startswith("BOARD_"), key.startswith("UPLOAD_")]):
continue continue

View File

@ -12,10 +12,13 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from __future__ import absolute_import
from hashlib import md5 from hashlib import md5
from os import makedirs from os import makedirs
from os.path import isdir, isfile, join from os.path import isdir, isfile, join
from platform import system
from platformio import util
# Windows CLI has limit with command length to 8192 # Windows CLI has limit with command length to 8192
# Leave 2000 chars for flags and other options # Leave 2000 chars for flags and other options
@ -58,7 +61,9 @@ def _file_long_data(env, data):
build_dir = env.subst("$BUILD_DIR") build_dir = env.subst("$BUILD_DIR")
if not isdir(build_dir): if not isdir(build_dir):
makedirs(build_dir) makedirs(build_dir)
tmp_file = join(build_dir, "longcmd-%s" % md5(data).hexdigest()) tmp_file = join(
build_dir,
"longcmd-%s" % md5(data if util.PY2 else data.encode()).hexdigest())
if isfile(tmp_file): if isfile(tmp_file):
return tmp_file return tmp_file
with open(tmp_file, "w") as fp: with open(tmp_file, "w") as fp:
@ -71,7 +76,7 @@ def exists(_):
def generate(env): def generate(env):
if system() != "Windows": if "windows" not in util.get_systype():
return None return None
env.Replace(_long_sources_hook=long_sources_hook) env.Replace(_long_sources_hook=long_sources_hook)

View File

@ -24,7 +24,7 @@ from SCons import Builder, Util
from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild, from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild,
DefaultEnvironment, Export, SConscript) DefaultEnvironment, Export, SConscript)
from platformio.util import glob_escape, pioversion_to_intstr from platformio.util import glob_escape, pioversion_to_intstr, string_types
SRC_HEADER_EXT = ["h", "hpp"] SRC_HEADER_EXT = ["h", "hpp"]
SRC_C_EXT = ["c", "cc", "cpp"] SRC_C_EXT = ["c", "cc", "cpp"]
@ -189,7 +189,7 @@ def ProcessFlags(env, flags): # pylint: disable=too-many-branches
# provided with a -U option // Issue #191 # provided with a -U option // Issue #191
undefines = [ undefines = [
u for u in env.get("CCFLAGS", []) u for u in env.get("CCFLAGS", [])
if isinstance(u, basestring) and u.startswith("-U") if isinstance(u, string_types) and u.startswith("-U")
] ]
if undefines: if undefines:
for undef in undefines: for undef in undefines:

View File

@ -44,7 +44,7 @@ def device_list( # pylint: disable=too-many-branches
if mdns: if mdns:
data['mdns'] = util.get_mdns_services() data['mdns'] = util.get_mdns_services()
single_key = data.keys()[0] if len(data.keys()) == 1 else None single_key = list(data)[0] if len(list(data)) == 1 else None
if json_output: if json_output:
return click.echo(json.dumps(data[single_key] if single_key else data)) return click.echo(json.dumps(data[single_key] if single_key else data))

View File

@ -17,7 +17,6 @@
import json import json
import time import time
from os.path import isdir, join from os.path import isdir, join
from urllib import quote
import click import click
@ -25,6 +24,11 @@ from platformio import exception, util
from platformio.managers.lib import LibraryManager, get_builtin_libs from platformio.managers.lib import LibraryManager, get_builtin_libs
from platformio.util import get_api_result from platformio.util import get_api_result
try:
from urllib.parse import quote
except ImportError:
from urllib import quote
@click.group(short_help="Library Manager") @click.group(short_help="Library Manager")
@click.option( @click.option(
@ -142,9 +146,9 @@ def lib_update(lm, libraries, only_check, json_output):
manifest['versionLatest'] = latest manifest['versionLatest'] = latest
result.append(manifest) result.append(manifest)
return click.echo(json.dumps(result)) return click.echo(json.dumps(result))
else:
for library in libraries: for library in libraries:
lm.update(library, only_check=only_check) lm.update(library, only_check=only_check)
return True return True

View File

@ -62,7 +62,7 @@ def _original_version(version):
return None return None
if len(y) % 2 != 0: if len(y) % 2 != 0:
y = "0" + y y = "0" + y
parts = [str(int(y[i * 2:i * 2 + 2])) for i in range(len(y) / 2)] parts = [str(int(y[i * 2:i * 2 + 2])) for i in range(int(len(y) / 2))]
return ".".join(parts) return ".".join(parts)
@ -88,8 +88,8 @@ def _get_installed_platform_data(platform,
docs=p.docs_url, docs=p.docs_url,
license=p.license, license=p.license,
forDesktop=not p.is_embedded(), forDesktop=not p.is_embedded(),
frameworks=sorted(p.frameworks.keys() if p.frameworks else []), frameworks=sorted(list(p.frameworks) if p.frameworks else []),
packages=p.packages.keys() if p.packages else []) packages=list(p.packages) if p.packages else [])
# if dump to API # if dump to API
# del data['version'] # del data['version']
@ -374,15 +374,14 @@ def platform_update(platforms, only_packages, only_check, json_output):
data['versionLatest'] = latest data['versionLatest'] = latest
result.append(data) result.append(data)
return click.echo(json.dumps(result)) return click.echo(json.dumps(result))
else:
# cleanup cached board and platform lists # cleanup cached board and platform lists
app.clean_cache() app.clean_cache()
for platform in platforms: for platform in platforms:
click.echo("Platform %s" % click.style( click.echo("Platform %s" % click.style(
pkg_dir_to_name.get(platform, platform), fg="cyan")) pkg_dir_to_name.get(platform, platform), fg="cyan"))
click.echo("--------") click.echo("--------")
pm.update( pm.update(platform, only_packages=only_packages, only_check=only_check)
platform, only_packages=only_packages, only_check=only_check) click.echo()
click.echo()
return True return True

View File

@ -357,7 +357,7 @@ def _clean_build_dir(build_dir):
def print_header(label, is_error=False): def print_header(label, is_error=False):
terminal_width, _ = click.get_terminal_size() terminal_width, _ = click.get_terminal_size()
width = len(click.unstyle(label)) width = len(click.unstyle(label))
half_line = "=" * ((terminal_width - width - 2) / 2) half_line = "=" * int((terminal_width - width - 2) / 2)
click.echo("%s %s %s" % (half_line, label, half_line), err=is_error) click.echo("%s %s %s" % (half_line, label, half_line), err=is_error)
@ -394,7 +394,7 @@ def print_summary(results, start_time):
def check_project_defopts(config): def check_project_defopts(config):
if not config.has_section("platformio"): if not config.has_section("platformio"):
return True return True
unknown = set([k for k, _ in config.items("platformio")]) - set( unknown = set(k for k, _ in config.items("platformio")) - set(
EnvironmentProcessor.KNOWN_PLATFORMIO_OPTIONS) EnvironmentProcessor.KNOWN_PLATFORMIO_OPTIONS)
if not unknown: if not unknown:
return True return True
@ -409,7 +409,7 @@ def check_project_envs(config, environments=None):
if not config.sections(): if not config.sections():
raise exception.ProjectEnvsNotAvailable() raise exception.ProjectEnvsNotAvailable()
known = set([s[4:] for s in config.sections() if s.startswith("env:")]) known = set(s[4:] for s in config.sections() if s.startswith("env:"))
unknown = set(environments or []) - known unknown = set(environments or []) - known
if unknown: if unknown:
raise exception.UnknownEnvNames(", ".join(unknown), ", ".join(known)) raise exception.UnknownEnvNames(", ".join(unknown), ", ".join(known))
@ -432,4 +432,5 @@ def calculate_project_hash():
# Fix issue with useless project rebuilding for case insensitive FS. # Fix issue with useless project rebuilding for case insensitive FS.
# A case of disk drive can differ... # A case of disk drive can differ...
chunks_to_str = chunks_to_str.lower() chunks_to_str = chunks_to_str.lower()
return sha1(chunks_to_str).hexdigest() return sha1(chunks_to_str if util.PY2 else chunks_to_str.
encode()).hexdigest()

View File

@ -45,14 +45,16 @@ class FileDownloader(object):
if disposition and "filename=" in disposition: if disposition and "filename=" in disposition:
self._fname = disposition[disposition.index("filename=") + self._fname = disposition[disposition.index("filename=") +
9:].replace('"', "").replace("'", "") 9:].replace('"', "").replace("'", "")
self._fname = self._fname.encode("utf8") if util.PY2:
self._fname = self._fname.encode("utf8")
else: else:
self._fname = [p for p in url.split("/") if p][-1] self._fname = [p for p in url.split("/") if p][-1]
self._destination = self._fname self._destination = self._fname
if dest_dir: if dest_dir:
self.set_destination( if util.PY2:
join(dest_dir.decode(getfilesystemencoding()), self._fname)) dest_dir = dest_dir.decode(getfilesystemencoding())
self.set_destination(join(dest_dir, self._fname))
def set_destination(self, destination): def set_destination(self, destination):
self._destination = destination self._destination = destination

View File

@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# pylint: disable=not-an-iterable
class PlatformioException(Exception): class PlatformioException(Exception):
@ -20,7 +22,7 @@ class PlatformioException(Exception):
def __str__(self): # pragma: no cover def __str__(self): # pragma: no cover
if self.MESSAGE: if self.MESSAGE:
return self.MESSAGE.format(*self.args) return self.MESSAGE.format(*self.args)
return Exception.__str__(self) return super(PlatformioException, self).__str__()
class ReturnErrorCode(PlatformioException): class ReturnErrorCode(PlatformioException):

View File

@ -116,9 +116,10 @@ class ProjectGenerator(object):
os.makedirs(dst_dir) os.makedirs(dst_dir)
file_name = basename(tpl_path)[:-4] file_name = basename(tpl_path)[:-4]
contents = self._render_tpl(tpl_path)
self._merge_contents( self._merge_contents(
join(dst_dir, file_name), join(dst_dir, file_name),
self._render_tpl(tpl_path).encode("utf8")) contents.encode("utf8") if util.PY2 else contents)
def _render_tpl(self, tpl_path): def _render_tpl(self, tpl_path):
content = "" content = ""

View File

@ -127,7 +127,7 @@ class Upgrader(object):
if not item.endswith(".json"): if not item.endswith(".json"):
continue continue
data = util.load_json(join(boards_dir, item)) data = util.load_json(join(boards_dir, item))
if set(["name", "url", "vendor"]) <= set(data.keys()): if set(["name", "url", "vendor"]) <= set(data):
continue continue
os.remove(join(boards_dir, item)) os.remove(join(boards_dir, item))
for key, value in data.items(): for key, value in data.items():

View File

@ -26,9 +26,9 @@ from platformio.managers.package import PackageManager
CORE_PACKAGES = { CORE_PACKAGES = {
"contrib-piohome": "^2.0.0", "contrib-piohome": "^2.0.0",
"contrib-pysite": "~2.%d%d.0" % (sys.version_info[0], sys.version_info[1]), "contrib-pysite": "~2.%d%d.0" % (sys.version_info[0], sys.version_info[1]),
"tool-pioplus": "^2.0.0", "tool-pioplus": "^2.0.2",
"tool-unity": "~1.20403.0", "tool-unity": "~1.20403.0",
"tool-scons": "~2.20501.7" "tool-scons": "~2.20501.7" if util.PY2 else "~3.30100.0"
} }
PIOPLUS_AUTO_UPDATES_MAX = 100 PIOPLUS_AUTO_UPDATES_MAX = 100

View File

@ -120,7 +120,7 @@ class LibraryManager(BasePkgManager):
# convert listed items via comma to array # convert listed items via comma to array
for key in ("keywords", "frameworks", "platforms"): for key in ("keywords", "frameworks", "platforms"):
if key not in manifest or \ if key not in manifest or \
not isinstance(manifest[key], basestring): not isinstance(manifest[key], util.string_types):
continue continue
manifest[key] = [ manifest[key] = [
i.strip() for i in manifest[key].split(",") if i.strip() i.strip() for i in manifest[key].split(",") if i.strip()
@ -147,7 +147,7 @@ class LibraryManager(BasePkgManager):
continue continue
if item[k] == "*": if item[k] == "*":
del item[k] del item[k]
elif isinstance(item[k], basestring): elif isinstance(item[k], util.string_types):
item[k] = [ item[k] = [
i.strip() for i in item[k].split(",") if i.strip() i.strip() for i in item[k].split(",") if i.strip()
] ]
@ -275,7 +275,7 @@ class LibraryManager(BasePkgManager):
break break
if not lib_info: if not lib_info:
if filters.keys() == ["name"]: if list(filters) == ["name"]:
raise exception.LibNotFound(filters['name']) raise exception.LibNotFound(filters['name'])
else: else:
raise exception.LibNotFound(str(filters)) raise exception.LibNotFound(str(filters))

View File

@ -71,7 +71,7 @@ class PackageRepoIterator(object):
if self.package in manifest: if self.package in manifest:
return manifest[self.package] return manifest[self.package]
return self.next() return next(self)
class PkgRepoMixin(object): class PkgRepoMixin(object):
@ -544,7 +544,7 @@ class PkgInstallerMixin(object):
def _install_from_tmp_dir( # pylint: disable=too-many-branches def _install_from_tmp_dir( # pylint: disable=too-many-branches
self, tmp_dir, requirements=None): self, tmp_dir, requirements=None):
tmp_manifest = self.load_manifest(tmp_dir) tmp_manifest = self.load_manifest(tmp_dir)
assert set(["name", "version"]) <= set(tmp_manifest.keys()) assert set(["name", "version"]) <= set(tmp_manifest)
pkg_dirname = self.get_install_dirname(tmp_manifest) pkg_dirname = self.get_install_dirname(tmp_manifest)
pkg_dir = join(self.package_dir, pkg_dirname) pkg_dir = join(self.package_dir, pkg_dirname)
@ -587,8 +587,10 @@ class PkgInstallerMixin(object):
cur_manifest['version']) cur_manifest['version'])
if "__src_url" in cur_manifest: if "__src_url" in cur_manifest:
target_dirname = "%s@src-%s" % ( target_dirname = "%s@src-%s" % (
pkg_dirname, hashlib.md5( pkg_dirname,
cur_manifest['__src_url']).hexdigest()) hashlib.md5(cur_manifest['__src_url'] if util.
PY2 else cur_manifest['__src_url'].
encode()).hexdigest())
shutil.move(pkg_dir, join(self.package_dir, target_dirname)) shutil.move(pkg_dir, join(self.package_dir, target_dirname))
# fix to a version # fix to a version
elif action == 2: elif action == 2:
@ -596,8 +598,10 @@ class PkgInstallerMixin(object):
tmp_manifest['version']) tmp_manifest['version'])
if "__src_url" in tmp_manifest: if "__src_url" in tmp_manifest:
target_dirname = "%s@src-%s" % ( target_dirname = "%s@src-%s" % (
pkg_dirname, hashlib.md5( pkg_dirname,
tmp_manifest['__src_url']).hexdigest()) hashlib.md5(tmp_manifest['__src_url'] if util.
PY2 else tmp_manifest['__src_url'].
encode()).hexdigest())
pkg_dir = join(self.package_dir, target_dirname) pkg_dir = join(self.package_dir, target_dirname)
# remove previous/not-satisfied package # remove previous/not-satisfied package

View File

@ -18,7 +18,6 @@ import re
from imp import load_source from imp import load_source
from multiprocessing import cpu_count from multiprocessing import cpu_count
from os.path import basename, dirname, isdir, isfile, join from os.path import basename, dirname, isdir, isfile, join
from urllib import quote
import click import click
import semantic_version import semantic_version
@ -27,6 +26,11 @@ from platformio import __version__, app, exception, util
from platformio.managers.core import get_core_package_dir from platformio.managers.core import get_core_package_dir
from platformio.managers.package import BasePkgManager, PackageManager from platformio.managers.package import BasePkgManager, PackageManager
try:
from urllib.parse import quote
except ImportError:
from urllib import quote
class PlatformManager(BasePkgManager): class PlatformManager(BasePkgManager):
@ -81,7 +85,7 @@ class PlatformManager(BasePkgManager):
skip_default_package, skip_default_package,
silent=silent, silent=silent,
force=force) force=force)
return self.cleanup_packages(p.packages.keys()) return self.cleanup_packages(list(p.packages))
def uninstall(self, package, requirements=None, after_update=False): def uninstall(self, package, requirements=None, after_update=False):
if isdir(package): if isdir(package):
@ -101,7 +105,7 @@ class PlatformManager(BasePkgManager):
if after_update: if after_update:
return True return True
return self.cleanup_packages(p.packages.keys()) return self.cleanup_packages(list(p.packages))
def update( # pylint: disable=arguments-differ def update( # pylint: disable=arguments-differ
self, self,
@ -119,17 +123,17 @@ class PlatformManager(BasePkgManager):
raise exception.UnknownPlatform(package) raise exception.UnknownPlatform(package)
p = PlatformFactory.newPlatform(pkg_dir) p = PlatformFactory.newPlatform(pkg_dir)
pkgs_before = p.get_installed_packages().keys() pkgs_before = list(p.get_installed_packages())
missed_pkgs = set() missed_pkgs = set()
if not only_packages: if not only_packages:
BasePkgManager.update(self, pkg_dir, requirements, only_check) BasePkgManager.update(self, pkg_dir, requirements, only_check)
p = PlatformFactory.newPlatform(pkg_dir) p = PlatformFactory.newPlatform(pkg_dir)
missed_pkgs = set(pkgs_before) & set(p.packages.keys()) missed_pkgs = set(pkgs_before) & set(p.packages)
missed_pkgs -= set(p.get_installed_packages().keys()) missed_pkgs -= set(p.get_installed_packages())
p.update_packages(only_check) p.update_packages(only_check)
self.cleanup_packages(p.packages.keys()) self.cleanup_packages(list(p.packages))
if missed_pkgs: if missed_pkgs:
p.install_packages( p.install_packages(
@ -265,7 +269,7 @@ class PlatformPackagesMixin(object):
without_packages = set(self.find_pkg_names(without_packages or [])) without_packages = set(self.find_pkg_names(without_packages or []))
upkgs = with_packages | without_packages upkgs = with_packages | without_packages
ppkgs = set(self.packages.keys()) ppkgs = set(self.packages)
if not upkgs.issubset(ppkgs): if not upkgs.issubset(ppkgs):
raise exception.UnknownPackage(", ".join(upkgs - ppkgs)) raise exception.UnknownPackage(", ".join(upkgs - ppkgs))
@ -384,7 +388,12 @@ class PlatformRunMixin(object):
# encode and append variables # encode and append variables
for key, value in variables.items(): for key, value in variables.items():
cmd.append("%s=%s" % (key.upper(), base64.b64encode(value))) if util.PY2:
cmd.append("%s=%s" % (key.upper(), base64.b64encode(value)))
else:
cmd.append(
"%s=%s" % (key.upper(), base64.b64encode(
value.encode()).decode()))
util.copy_pythonpath_to_osenv() util.copy_pythonpath_to_osenv()
result = util.exec_command( result = util.exec_command(
@ -550,7 +559,7 @@ class PlatformBase( # pylint: disable=too-many-public-methods
config = PlatformBoardConfig(manifest_path) config = PlatformBoardConfig(manifest_path)
if "platform" in config and config.get("platform") != self.name: if "platform" in config and config.get("platform") != self.name:
return return
elif "platforms" in config \ if "platforms" in config \
and self.name not in config.get("platforms"): and self.name not in config.get("platforms"):
return return
config.manifest['platform'] = self.name config.manifest['platform'] = self.name
@ -652,7 +661,7 @@ class PlatformBoardConfig(object):
self._manifest = util.load_json(manifest_path) self._manifest = util.load_json(manifest_path)
except ValueError: except ValueError:
raise exception.InvalidBoardManifest(manifest_path) raise exception.InvalidBoardManifest(manifest_path)
if not set(["name", "url", "vendor"]) <= set(self._manifest.keys()): if not set(["name", "url", "vendor"]) <= set(self._manifest):
raise exception.PlatformioException( raise exception.PlatformioException(
"Please specify name, url and vendor fields for " + "Please specify name, url and vendor fields for " +
manifest_path) manifest_path)
@ -666,8 +675,7 @@ class PlatformBoardConfig(object):
except KeyError: except KeyError:
if default is not None: if default is not None:
return default return default
else: raise KeyError("Invalid board option '%s'" % path)
raise KeyError("Invalid board option '%s'" % path)
def update(self, path, value): def update(self, path, value):
newdict = None newdict = None
@ -752,7 +760,7 @@ class PlatformBoardConfig(object):
return tool_name return tool_name
raise exception.DebugInvalidOptions( raise exception.DebugInvalidOptions(
"Unknown debug tool `%s`. Please use one of `%s` or `custom`" % "Unknown debug tool `%s`. Please use one of `%s` or `custom`" %
(tool_name, ", ".join(sorted(debug_tools.keys())))) (tool_name, ", ".join(sorted(list(debug_tools)))))
# automatically select best tool # automatically select best tool
data = {"default": [], "onboard": [], "external": []} data = {"default": [], "onboard": [], "external": []}

View File

@ -14,7 +14,6 @@
import atexit import atexit
import platform import platform
import Queue
import re import re
import sys import sys
import threading import threading
@ -29,6 +28,11 @@ import requests
from platformio import __version__, app, exception, util from platformio import __version__, app, exception, util
try:
import queue
except ImportError:
import Queue as queue
class TelemetryBase(object): class TelemetryBase(object):
@ -74,12 +78,12 @@ class MeasurementProtocol(TelemetryBase):
def __getitem__(self, name): def __getitem__(self, name):
if name in self.PARAMS_MAP: if name in self.PARAMS_MAP:
name = self.PARAMS_MAP[name] name = self.PARAMS_MAP[name]
return TelemetryBase.__getitem__(self, name) return super(MeasurementProtocol, self).__getitem__(name)
def __setitem__(self, name, value): def __setitem__(self, name, value):
if name in self.PARAMS_MAP: if name in self.PARAMS_MAP:
name = self.PARAMS_MAP[name] name = self.PARAMS_MAP[name]
TelemetryBase.__setitem__(self, name, value) super(MeasurementProtocol, self).__setitem__(name, value)
def _prefill_appinfo(self): def _prefill_appinfo(self):
self['av'] = __version__ self['av'] = __version__
@ -178,7 +182,7 @@ class MPDataPusher(object):
MAX_WORKERS = 5 MAX_WORKERS = 5
def __init__(self): def __init__(self):
self._queue = Queue.LifoQueue() self._queue = queue.LifoQueue()
self._failedque = deque() self._failedque = deque()
self._http_session = requests.Session() self._http_session = requests.Session()
self._http_offline = False self._http_offline = False
@ -203,7 +207,7 @@ class MPDataPusher(object):
try: try:
while True: while True:
items.append(self._queue.get_nowait()) items.append(self._queue.get_nowait())
except Queue.Empty: except queue.Empty:
pass pass
return items return items
@ -384,7 +388,7 @@ def backup_reports(items):
for params in items: for params in items:
# skip static options # skip static options
for key in params.keys(): for key in params:
if key in ("v", "tid", "cid", "cd1", "cd2", "sr", "an"): if key in ("v", "tid", "cid", "cd1", "cd2", "sr", "an"):
del params[key] del params[key]

View File

@ -64,7 +64,7 @@ class ZIPArchive(ArchiveBase):
@staticmethod @staticmethod
def preserve_permissions(item, dest_dir): def preserve_permissions(item, dest_dir):
attrs = item.external_attr >> 16L attrs = item.external_attr >> 16
if attrs: if attrs:
chmod(join(dest_dir, item.filename), attrs) chmod(join(dest_dir, item.filename), attrs)
@ -72,7 +72,7 @@ class ZIPArchive(ArchiveBase):
def preserve_mtime(item, dest_dir): def preserve_mtime(item, dest_dir):
util.change_filemtime( util.change_filemtime(
join(dest_dir, item.filename), join(dest_dir, item.filename),
mktime(list(item.date_time) + [0] * 3)) mktime(tuple(item.date_time) + tuple([0, 0, 0])))
def get_items(self): def get_items(self):
return self._afo.infolist() return self._afo.infolist()

View File

@ -34,12 +34,15 @@ import requests
from platformio import __apiurl__, __version__, exception from platformio import __apiurl__, __version__, exception
# pylint: disable=wrong-import-order, too-many-ancestors # pylint: disable=too-many-ancestors
try: PY2 = sys.version_info[0] == 2
import configparser as ConfigParser if PY2:
except ImportError:
import ConfigParser as ConfigParser import ConfigParser as ConfigParser
string_types = basestring # pylint: disable=undefined-variable
else:
import configparser as ConfigParser
string_types = str
class ProjectConfig(ConfigParser.ConfigParser): class ProjectConfig(ConfigParser.ConfigParser):
@ -52,7 +55,8 @@ class ProjectConfig(ConfigParser.ConfigParser):
items.append((option, self.get(section, option))) items.append((option, self.get(section, option)))
return items return items
def get(self, section, option, **kwargs): def get( # pylint: disable=arguments-differ
self, section, option, **kwargs):
try: try:
value = ConfigParser.ConfigParser.get(self, section, option, value = ConfigParser.ConfigParser.get(self, section, option,
**kwargs) **kwargs)
@ -177,6 +181,8 @@ def singleton(cls):
def path_to_unicode(path): def path_to_unicode(path):
if not PY2:
return path
return path.decode(sys.getfilesystemencoding()).encode("utf-8") return path.decode(sys.getfilesystemencoding()).encode("utf-8")
@ -315,8 +321,11 @@ def get_projectbuild_dir(force=False):
path = get_project_optional_dir("build_dir", path = get_project_optional_dir("build_dir",
join(get_project_dir(), ".pioenvs")) join(get_project_dir(), ".pioenvs"))
if "$PROJECT_HASH" in path: if "$PROJECT_HASH" in path:
path = path.replace("$PROJECT_HASH", project_dir = get_project_dir()
sha1(get_project_dir()).hexdigest()[:10]) path = path.replace(
"$PROJECT_HASH",
sha1(project_dir if PY2 else project_dir.encode()).hexdigest()
[:10])
try: try:
if not isdir(path): if not isdir(path):
os.makedirs(path) os.makedirs(path)
@ -414,8 +423,10 @@ def exec_command(*args, **kwargs):
result[s[3:]] = "\n".join(kwargs[s].get_buffer()) result[s[3:]] = "\n".join(kwargs[s].get_buffer())
for k, v in result.items(): for k, v in result.items():
if v and isinstance(v, basestring): if not PY2 and isinstance(result[k], bytes):
result[k].strip() result[k] = result[k].decode()
if v and isinstance(v, string_types):
result[k] = result[k].strip()
return result return result
@ -445,10 +456,13 @@ def get_serial_ports(filter_hwid=False):
if not p: if not p:
continue continue
if "windows" in get_systype(): if "windows" in get_systype():
try: if PY2:
d = unicode(d, errors="ignore") try:
except TypeError: d = unicode( # pylint: disable=undefined-variable
pass d,
errors="ignore")
except TypeError:
pass
if not filter_hwid or "VID:PID" in h: if not filter_hwid or "VID:PID" in h:
result.append({"port": p, "description": d, "hwid": h}) result.append({"port": p, "description": d, "hwid": h})
@ -490,17 +504,17 @@ def get_logical_devices():
for device in re.findall(r"[A-Z]:\\", result): for device in re.findall(r"[A-Z]:\\", result):
items.append({"path": device, "name": None}) items.append({"path": device, "name": None})
return items return items
else:
result = exec_command(["df"]).get("out") result = exec_command(["df"]).get("out")
devicenamere = re.compile(r"^/.+\d+\%\s+([a-z\d\-_/]+)$", flags=re.I) devicenamere = re.compile(r"^/.+\d+\%\s+([a-z\d\-_/]+)$", flags=re.I)
for line in result.split("\n"): for line in result.split("\n"):
match = devicenamere.match(line.strip()) match = devicenamere.match(line.strip())
if not match: if not match:
continue continue
items.append({ items.append({
"path": match.group(1), "path": match.group(1),
"name": basename(match.group(1)) "name": basename(match.group(1))
}) })
return items return items
@ -557,12 +571,16 @@ def get_mdns_services():
time.sleep(3) time.sleep(3)
for service in mdns.get_services(): for service in mdns.get_services():
properties = None properties = None
try: if service.properties:
if service.properties: try:
json.dumps(service.properties) properties = {
properties = service.properties k.decode("utf8"):
except UnicodeDecodeError: v.decode("utf8") if isinstance(v, bytes) else v
pass for k, v in service.properties.items()
}
json.dumps(properties)
except UnicodeDecodeError:
properties = None
items.append({ items.append({
"type": "type":
@ -570,7 +588,10 @@ def get_mdns_services():
"name": "name":
service.name, service.name,
"ip": "ip":
".".join([str(ord(c)) for c in service.address]), ".".join([
str(c if isinstance(c, int) else ord(c))
for c in service.address
]),
"port": "port":
service.port, service.port,
"properties": "properties":
@ -735,7 +756,7 @@ def where_is_program(program, envpath=None):
for bin_dir in env.get("PATH", "").split(os.pathsep): for bin_dir in env.get("PATH", "").split(os.pathsep):
if isfile(join(bin_dir, program)): if isfile(join(bin_dir, program)):
return join(bin_dir, program) return join(bin_dir, program)
elif isfile(join(bin_dir, "%s.exe" % program)): if isfile(join(bin_dir, "%s.exe" % program)):
return join(bin_dir, "%s.exe" % program) return join(bin_dir, "%s.exe" % program)
return program return program

View File

@ -16,11 +16,15 @@ import re
from os.path import join from os.path import join
from subprocess import CalledProcessError, check_call from subprocess import CalledProcessError, check_call
from sys import modules from sys import modules
from urlparse import urlparse
from platformio import util from platformio import util
from platformio.exception import PlatformioException, UserSideException from platformio.exception import PlatformioException, UserSideException
try:
from urllib.parse import urlparse
except ImportError:
from urlparse import urlparse
class VCSClientFactory(object): class VCSClientFactory(object):

View File

@ -21,7 +21,7 @@ from platformio import util
def main(): def main():
platforms = json.loads( platforms = json.loads(
subprocess.check_output( subprocess.check_output(
["platformio", "platform", "search", "--json-output"])) ["platformio", "platform", "search", "--json-output"]).decode())
for platform in platforms: for platform in platforms:
if platform['forDesktop']: if platform['forDesktop']:
continue continue

View File

@ -35,7 +35,8 @@ setup(
author_email=__email__, author_email=__email__,
url=__url__, url=__url__,
license=__license__, license=__license__,
python_requires='>=2.7, <3', python_requires=", ".join([
">=2.7", "!=3.0.*", "!=3.1.*", "!=3.2.*", "!=3.3.*", "!=3.4.*"]),
install_requires=install_requires, install_requires=install_requires,
packages=find_packages() + ["scripts"], packages=find_packages() + ["scripts"],
package_data={ package_data={
@ -65,6 +66,7 @@ setup(
"Operating System :: OS Independent", "Operating System :: OS Independent",
"Programming Language :: C", "Programming Language :: C",
"Programming Language :: Python", "Programming Language :: Python",
"Programming Language :: Python :: 3",
"Topic :: Software Development", "Topic :: Software Development",
"Topic :: Software Development :: Build Tools", "Topic :: Software Development :: Build Tools",
"Topic :: Software Development :: Compilers" "Topic :: Software Development :: Compilers"

View File

@ -74,7 +74,7 @@ def test_run(pioproject_dir):
["platformio", "run", "-e", ["platformio", "run", "-e",
random.choice(env_names)]) random.choice(env_names)])
if result['returncode'] != 0: if result['returncode'] != 0:
pytest.fail(result) pytest.fail(str(result))
assert isdir(build_dir) assert isdir(build_dir)

View File

@ -44,7 +44,7 @@ def test_after_upgrade_2_to_3(clirunner, validate_cliresult,
result = clirunner.invoke(cli_pio, ["settings", "get"]) result = clirunner.invoke(cli_pio, ["settings", "get"])
validate_cliresult(result) validate_cliresult(result)
assert "upgraded to 3" in result.output assert "upgraded to " in result.output
# check PlatformIO 3.0 boards # check PlatformIO 3.0 boards
assert board_ids == set([p.basename[:-5] for p in boards.listdir()]) assert board_ids == set([p.basename[:-5] for p in boards.listdir()])

View File

@ -28,7 +28,7 @@ def test_packages():
"https://dl.bintray.com/platformio/dl-packages/manifest.json").json() "https://dl.bintray.com/platformio/dl-packages/manifest.json").json()
assert isinstance(pkgs_manifest, dict) assert isinstance(pkgs_manifest, dict)
items = [] items = []
for _, variants in pkgs_manifest.iteritems(): for _, variants in pkgs_manifest.items():
for item in variants: for item in variants:
items.append(item) items.append(item)

52
tox.ini
View File

@ -13,10 +13,10 @@
# limitations under the License. # limitations under the License.
[tox] [tox]
envlist = py27, docs, lint envlist = py27, py35, py36, py37, docs
[testenv:develop] [testenv]
basepython = python2.7 passenv = *
usedevelop = True usedevelop = True
deps = deps =
isort isort
@ -24,10 +24,15 @@ deps =
pylint pylint
pytest pytest
pytest-xdist pytest-xdist
commands = python --version commands =
{envpython} --version
pylint --rcfile=./.pylintrc ./platformio
{envpython} -c "print('travis_fold:start:install_devplatforms')"
{envpython} scripts/install_devplatforms.py
{envpython} -c "print('travis_fold:end:install_devplatforms')"
py.test -v --basetemp="{envtmpdir}" tests
[testenv:docs] [testenv:docs]
basepython = python2.7
deps = deps =
sphinx sphinx
sphinx_rtd_theme sphinx_rtd_theme
@ -37,44 +42,23 @@ commands =
sphinx-build -W -b latex -d {envtmpdir}/doctrees docs docs/_build/latex sphinx-build -W -b latex -d {envtmpdir}/doctrees docs docs/_build/latex
[testenv:docslinkcheck] [testenv:docslinkcheck]
basepython = python2.7
deps = deps =
sphinx sphinx
sphinx_rtd_theme sphinx_rtd_theme
commands = commands =
sphinx-build -W -b linkcheck docs docs/_build/html sphinx-build -W -b linkcheck docs docs/_build/html
[testenv:lint]
basepython = python2.7
deps =
pylint
commands =
pylint --rcfile=./.pylintrc ./platformio
[testenv]
basepython = python2.7
passenv = *
deps =
pytest
commands =
{envpython} --version
{envpython} -c "print 'travis_fold:start:install_devplatforms'"
{envpython} scripts/install_devplatforms.py
{envpython} -c "print 'travis_fold:end:install_devplatforms'"
py.test -v --basetemp="{envtmpdir}" tests
[testenv:skipexamples] [testenv:skipexamples]
basepython = python2.7
deps = deps =
pytest pytest
commands = commands =
py.test -v --basetemp="{envtmpdir}" tests --ignore tests/test_examples.py py.test -v --basetemp="{envtmpdir}" tests --ignore tests/test_examples.py
[testenv:coverage] ; [testenv:coverage]
basepython = python2.7 ; basepython = python2
passenv = * ; passenv = *
deps = ; deps =
pytest ; pytest
pytest-cov ; pytest-cov
commands = ; commands =
py.test --cov=platformio --cov-report term --cov-report xml --ignore=tests/test_examples.py --ignore=tests/test_pkgmanifest.py -v tests ; py.test --cov=platformio --cov-report term --cov-report xml --ignore=tests/test_examples.py --ignore=tests/test_pkgmanifest.py -v tests