diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 50bf19eb90..0aeec585c2 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - python-version: [2.7.18, 3.8.14] + python-version: [3.8.14] steps: - uses: actions/checkout@v3 diff --git a/INSTALL.md b/INSTALL.md index 79e148b427..a8d15e75e8 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -22,13 +22,7 @@ ALICEVISION_ROOT=/path/to/AliceVision/install/directory ### Python Environment * Windows: Python 3 (>=3.5) -* Linux: Python 3 (>=3.5) or Python 2 (>= 2.7) - -> No Python 2.7 support on Windows ? -> -> Official Python 2.7 binary package is built with Visual Studio 2008, while PySide2/Qt is built using Visual Studio 2015/2017. ->Therefore, in order to avoid mixing MSVC runtime libraries, Qt does not ship PySide2 wheels for Python 2.7 on Windows (as explained [here](https://wiki.qt.io/Qt_for_Python/Considerations#Missing_Windows_.2F_Python_2.7_release)). ->Note that for using Meshroom in command line mode only (no UI), PySide2 is not required and Python 2.7 would be fine. +* Linux: Python 3 (>=3.5) To install all the requirements for runtime, development and packaging, simply run: diff --git a/bin/meshroom_batch b/bin/meshroom_batch index a4cd1a7476..7c948fb740 100755 --- a/bin/meshroom_batch +++ b/bin/meshroom_batch @@ -144,9 +144,8 @@ with multiview.GraphModification(graph): publish.output.value = args.output if args.overrides: - import io import json - with io.open(args.overrides, 'r', encoding='utf-8', errors='ignore') as f: + with open(args.overrides, 'r', encoding='utf-8', errors='ignore') as f: data = json.load(f) for nodeName, overrides in data.items(): for attrName, value in overrides.items(): diff --git a/docker/Dockerfile_centos_deps_py2 b/docker/Dockerfile_centos_deps_py2 deleted file mode 100644 index 8038fb255f..0000000000 --- a/docker/Dockerfile_centos_deps_py2 +++ /dev/null @@ -1,68 +0,0 @@ -ARG AV_VERSION -ARG CUDA_VERSION -ARG CENTOS_VERSION=7 -FROM alicevision/alicevision:${AV_VERSION}-centos${CENTOS_VERSION}-cuda${CUDA_VERSION} -LABEL maintainer="AliceVision Team alicevision-team@googlegroups.com" - -# Execute with nvidia docker (https://github.com/nvidia/nvidia-docker/wiki/Installation-(version-2.0)) -# docker run -it --runtime=nvidia meshroom - -ENV MESHROOM_DEV=/opt/Meshroom \ - MESHROOM_BUILD=/tmp/Meshroom_build \ - MESHROOM_BUNDLE=/opt/Meshroom_bundle \ - QT_DIR=/opt/Qt5.14.1/5.14.1/gcc_64 \ - QT_CI_LOGIN=alicevisionjunk@gmail.com \ - QT_CI_PASSWORD=azerty1. - -WORKDIR ${MESHROOM_BUNDLE} -RUN mv "${AV_BUNDLE}" "${MESHROOM_BUNDLE}/aliceVision" && \ - rm -rf ${MESHROOM_BUNDLE}/aliceVision/share/doc \ - ${MESHROOM_BUNDLE}/aliceVision/share/eigen3 \ - ${MESHROOM_BUNDLE}/aliceVision/share/fonts \ - ${MESHROOM_BUNDLE}/aliceVision/share/lemon \ - ${MESHROOM_BUNDLE}/aliceVision/share/libraw \ - ${MESHROOM_BUNDLE}/aliceVision/share/man \ - ${MESHROOM_BUNDLE}/aliceVision/share/pkgconfig - -# Install libs needed by Qt -RUN yum install -y \ - flex \ - fontconfig \ - freetype \ - glib2 \ - libICE \ - libX11 \ - libxcb \ - libXext \ - libXi \ - libXrender \ - libSM \ - libXt-devel \ - libGLU-devel \ - mesa-libOSMesa-devel \ - mesa-libGL-devel \ - mesa-libGLU-devel \ - xcb-util-keysyms \ - xcb-util-image \ - libxkbcommon-x11 - -# Install Python2 -RUN yum install -y python27-python-devel python-devel && \ - curl https://bootstrap.pypa.io/2.7/get-pip.py -o /tmp/get-pip.py && \ - python /tmp/get-pip.py && \ - pip install --upgrade pip - -COPY ./*requirements.txt ${MESHROOM_DEV}/ - -# Install Meshroom requirements and freeze bundle -WORKDIR "${MESHROOM_DEV}" -RUN pip install -r dev_requirements.txt -r requirements.txt - -# Install Qt (to build plugins) -WORKDIR /tmp/qt -COPY dl/qt.run /tmp/qt -COPY ./docker/qt-installer-noninteractive.qs ${MESHROOM_DEV}/docker/ -RUN chmod +x qt.run && \ - ./qt.run --verbose --platform minimal --script "${MESHROOM_DEV}/docker/qt-installer-noninteractive.qs" && \ - rm qt.run - diff --git a/docker/Dockerfile_centos_py2 b/docker/Dockerfile_centos_py2 deleted file mode 100644 index 7b41cbac9e..0000000000 --- a/docker/Dockerfile_centos_py2 +++ /dev/null @@ -1,72 +0,0 @@ -ARG MESHROOM_VERSION -ARG AV_VERSION -ARG CUDA_VERSION -ARG CENTOS_VERSION -FROM alicevision/meshroom-deps:${MESHROOM_VERSION}-av${AV_VERSION}-centos${CENTOS_VERSION}-cuda${CUDA_VERSION}-py2 -LABEL maintainer="AliceVision Team alicevision-team@googlegroups.com" - -# Execute with nvidia docker (https://github.com/nvidia/nvidia-docker/wiki/Installation-(version-2.0)) -# docker run -it --runtime nvidia -p 2222:22 --name meshroom -v:/data alicevision/meshroom:develop-av2.2.8.develop-ubuntu20.04-cuda11.0 -# ssh -p 2222 -X root@ /opt/Meshroom_bundle/Meshroom # Password is 'meshroom' - -ENV MESHROOM_DEV=/opt/Meshroom \ - MESHROOM_BUILD=/tmp/Meshroom_build \ - MESHROOM_BUNDLE=/opt/Meshroom_bundle \ - AV_INSTALL=/opt/AliceVision_install \ - QT_DIR=/opt/Qt5.14.1/5.14.1/gcc_64 \ - PATH="${PATH}:${MESHROOM_BUNDLE}" \ - OPENIMAGEIO_LIBRARY=/opt/AliceVision_install/lib - -COPY *.txt *.md *.py ${MESHROOM_DEV}/ -COPY ./docs ${MESHROOM_DEV}/docs -COPY ./meshroom ${MESHROOM_DEV}/meshroom -COPY ./tests ${MESHROOM_DEV}/tests -COPY ./bin ${MESHROOM_DEV}/bin - -WORKDIR ${MESHROOM_DEV} - -RUN python setup.py install_exe -d "${MESHROOM_BUNDLE}" && \ - find ${MESHROOM_BUNDLE} -name "*Qt5Web*" -delete && \ - find ${MESHROOM_BUNDLE} -name "*Qt5Designer*" -delete && \ - rm -rf ${MESHROOM_BUNDLE}/lib/PySide2/typesystems/ \ - ${MESHROOM_BUNDLE}/lib/PySide2/examples/ \ - ${MESHROOM_BUNDLE}/lib/PySide2/include/ \ - ${MESHROOM_BUNDLE}/lib/PySide2/Qt/translations/ \ - ${MESHROOM_BUNDLE}/lib/PySide2/Qt/resources/ \ - ${MESHROOM_BUNDLE}/lib/PySide2/QtWeb* \ - ${MESHROOM_BUNDLE}/lib/PySide2/pyside2-lupdate \ - ${MESHROOM_BUNDLE}/lib/PySide2/rcc \ - ${MESHROOM_BUNDLE}/lib/PySide2/designer - -WORKDIR ${MESHROOM_BUILD} - -# Build Meshroom plugins -RUN cmake "${MESHROOM_DEV}" -DALICEVISION_ROOT="${AV_INSTALL}" -DCMAKE_INSTALL_PREFIX="${MESHROOM_BUNDLE}/qtPlugins" -RUN make "-j$(nproc)" qtOIIO - -RUN make "-j$(nproc)" qmlAlembic -RUN make "-j$(nproc)" qtAliceVision -RUN make "-j$(nproc)" && \ - rm -rf "${MESHROOM_BUILD}" "${MESHROOM_DEV}" \ - ${MESHROOM_BUNDLE}/aliceVision/share/doc \ - ${MESHROOM_BUNDLE}/aliceVision/share/eigen3 \ - ${MESHROOM_BUNDLE}/aliceVision/share/fonts \ - ${MESHROOM_BUNDLE}/aliceVision/share/lemon \ - ${MESHROOM_BUNDLE}/aliceVision/share/libraw \ - ${MESHROOM_BUNDLE}/aliceVision/share/man \ - ${MESHROOM_BUNDLE}/aliceVision/share/pkgconfig - -# Enable SSH X11 forwarding, needed when the Docker image -# is run on a remote machine -RUN yum -y install openssh-server xauth mesa-dri-drivers && \ - systemctl enable sshd && \ - mkdir -p /run/sshd - -RUN sed -i "s/^.*X11Forwarding.*$/X11Forwarding yes/; s/^.*X11UseLocalhost.*$/X11UseLocalhost no/; s/^.*PermitRootLogin prohibit-password/PermitRootLogin yes/; s/^.*X11UseLocalhost.*/X11UseLocalhost no/;" /etc/ssh/sshd_config -RUN echo "root:meshroom" | chpasswd - -WORKDIR /root - -EXPOSE 22 -CMD bash -c "test -s /etc/machine-id || systemd-machine-id-setup; sshd-keygen; /usr/sbin/sshd -D" - diff --git a/docker/build-centos.sh b/docker/build-centos.sh index bf61f20187..63b2cc7e75 100755 --- a/docker/build-centos.sh +++ b/docker/build-centos.sh @@ -6,10 +6,6 @@ test -z "$MESHROOM_VERSION" && MESHROOM_VERSION="$(git rev-parse --abbrev-ref HE test -z "$AV_VERSION" && echo "AliceVision version not specified, set AV_VERSION in the environment" && exit 1 test -z "$CUDA_VERSION" && CUDA_VERSION="10.2" test -z "$CENTOS_VERSION" && CENTOS_VERSION="7" -test -z "$MESHROOM_PYTHON2" || echo "========== Build for Python 2 ==========" -test -z "$MESHROOM_PYTHON2" || export PYTHON2_DOCKER_EXT="-py2" -test -z "$MESHROOM_PYTHON2" || export PYTHON2_DOCKERFILE_EXT="_py2" -test -z "$MESHROOM_PYTHON2" && echo "========== Build for Python 3 ==========" test -d docker || ( echo This script must be run from the top level Meshroom directory @@ -27,8 +23,8 @@ docker build \ --build-arg "CUDA_VERSION=${CUDA_VERSION}" \ --build-arg "CENTOS_VERSION=${CENTOS_VERSION}" \ --build-arg "AV_VERSION=${AV_VERSION}" \ - --tag "alicevision/meshroom-deps:${MESHROOM_VERSION}-av${AV_VERSION}-centos${CENTOS_VERSION}-cuda${CUDA_VERSION}${PYTHON2_DOCKER_EXT}" \ - -f docker/Dockerfile_centos_deps${PYTHON2_DOCKERFILE_EXT} . + --tag "alicevision/meshroom-deps:${MESHROOM_VERSION}-av${AV_VERSION}-centos${CENTOS_VERSION}-cuda${CUDA_VERSION}" \ + -f docker/Dockerfile_centos_deps . # Meshroom docker build \ @@ -37,6 +33,6 @@ docker build \ --build-arg "CUDA_VERSION=${CUDA_VERSION}" \ --build-arg "CENTOS_VERSION=${CENTOS_VERSION}" \ --build-arg "AV_VERSION=${AV_VERSION}" \ - --tag "alicevision/meshroom:${MESHROOM_VERSION}-av${AV_VERSION}-centos${CENTOS_VERSION}-cuda${CUDA_VERSION}${PYTHON2_DOCKER_EXT}" \ - -f docker/Dockerfile_centos${PYTHON2_DOCKERFILE_EXT} . + --tag "alicevision/meshroom:${MESHROOM_VERSION}-av${AV_VERSION}-centos${CENTOS_VERSION}-cuda${CUDA_VERSION}" \ + -f docker/Dockerfile_centos . diff --git a/docker/extract.sh b/docker/extract.sh index 055e0ff479..1fb0bc77c5 100755 --- a/docker/extract.sh +++ b/docker/extract.sh @@ -8,17 +8,13 @@ test -z "$MESHROOM_VERSION" && MESHROOM_VERSION="$(git rev-parse --abbrev-ref HE test -z "$AV_VERSION" && echo "AliceVision version not specified, set AV_VERSION in the environment" && exit 1 test -z "$CUDA_VERSION" && CUDA_VERSION="10.2" test -z "$CENTOS_VERSION" && CENTOS_VERSION="7" -test -z "$MESHROOM_PYTHON2" || echo "========== Build for Python 2 ==========" -test -z "$MESHROOM_PYTHON2" || export PYTHON2_DOCKER_EXT="-py2" -test -z "$MESHROOM_PYTHON2" || export PYTHON2_DOCKERFILE_EXT="_py2" -test -z "$MESHROOM_PYTHON2" && echo "========== Build for Python 3 ==========" test -d docker || ( echo This script must be run from the top level Meshroom directory exit 1 ) -VERSION_NAME=${MESHROOM_VERSION}-av${AV_VERSION}-centos${CENTOS_VERSION}-cuda${CUDA_VERSION}${PYTHON2_DOCKER_EXT} +VERSION_NAME=${MESHROOM_VERSION}-av${AV_VERSION}-centos${CENTOS_VERSION}-cuda${CUDA_VERSION} # Retrieve the Meshroom bundle folder rm -rf ./Meshroom-${VERSION_NAME} diff --git a/docs/source/_ext/fetch_md.py b/docs/source/_ext/fetch_md.py index fa85fcc316..8d37e88227 100644 --- a/docs/source/_ext/fetch_md.py +++ b/docs/source/_ext/fetch_md.py @@ -17,12 +17,6 @@ from docutils.parsers.rst import Directive from utils import md_to_docutils, get_link_key -# Python2 compatibility -try: - FileNotFoundError -except NameError: - FileNotFoundError = IOError - class Relinker(SparseNodeVisitor): diff --git a/meshroom/common/PySignal.py b/meshroom/common/PySignal.py index 1dde99aba7..7b93e162f3 100644 --- a/meshroom/common/PySignal.py +++ b/meshroom/common/PySignal.py @@ -13,59 +13,7 @@ import sys import weakref from functools import partial - - -# weakref.WeakMethod backport -try: - from weakref import WeakMethod - -except ImportError: - import types - - class WeakMethod(object): - """Light WeakMethod backport compiled from various sources. Tested in 2.7""" - - def __init__(self, func): - if inspect.ismethod(func): - self._obj = weakref.ref(func.__self__) - self._func = weakref.ref(func.__func__) - - else: - self._obj = None - - try: - self._func = weakref.ref(func.__func__) - - # Rather than attempting to handle this, raise the same exception - # you get from WeakMethod. - except AttributeError: - raise TypeError("argument should be a bound method, not %s" % type(func)) - - def __call__(self): - if self._obj is not None: - obj = self._obj() - func = self._func() - if func is None or obj is None: - return None - - else: - return types.MethodType(func, obj, obj.__class__) - - elif self._func is not None: - return self._func() - - else: - return None - - def __eq__(self, other): - try: - return type(self) is type(other) and self() == other() - - except Exception: - return False - - def __ne__(self, other): - return not self.__eq__(other) +from weakref import WeakMethod class Signal(object): diff --git a/meshroom/core/__init__.py b/meshroom/core/__init__.py index 425806c6c9..b57e587125 100644 --- a/meshroom/core/__init__.py +++ b/meshroom/core/__init__.py @@ -23,7 +23,6 @@ from meshroom.core.submitter import BaseSubmitter from . import desc -from . import pyCompatibility # Setup logging logging.basicConfig(format='[%(asctime)s][%(levelname)s] %(message)s', level=logging.INFO) @@ -150,7 +149,7 @@ def __init__(self, *args): self.components = tuple() elif len(args) == 1: versionName = args[0] - if isinstance(versionName, pyCompatibility.basestring): + if isinstance(versionName, str): self.components = Version.toComponents(versionName) elif isinstance(versionName, (list, tuple)): self.components = tuple([int(v) for v in versionName]) diff --git a/meshroom/core/attribute.py b/meshroom/core/attribute.py index eccffd6479..e0d71cd339 100644 --- a/meshroom/core/attribute.py +++ b/meshroom/core/attribute.py @@ -7,9 +7,10 @@ import types import logging +from collections.abc import Sequence from string import Template from meshroom.common import BaseObject, Property, Variant, Signal, ListModel, DictModel, Slot -from meshroom.core import desc, pyCompatibility, hashValue +from meshroom.core import desc, hashValue def attributeFactory(description, value, isOutput, node, root=None, parent=None): @@ -213,7 +214,7 @@ def isLinkExpression(value): Return whether the given argument is a link expression. A link expression is a string matching the {nodeName.attrName} pattern. """ - return isinstance(value, pyCompatibility.basestring) and Attribute.stringIsLinkRe.match(value) + return isinstance(value, str) and Attribute.stringIsLinkRe.match(value) def getLinkParam(self, recursive=False): if not self.isLink: @@ -264,13 +265,13 @@ def getExportValue(self): return self._value def getEvalValue(self): - if isinstance(self.value, pyCompatibility.basestring): + if isinstance(self.value, str): return Template(self.value).safe_substitute(os.environ) return self.value def getValueStr(self): if isinstance(self.attributeDesc, desc.ChoiceParam) and not self.attributeDesc.exclusive: - assert(isinstance(self.value, pyCompatibility.Sequence) and not isinstance(self.value, pyCompatibility.basestring)) + assert(isinstance(self.value, Sequence) and not isinstance(self.value, str)) return self.attributeDesc.joinChar.join(self.getEvalValue()) if isinstance(self.attributeDesc, (desc.StringParam, desc.File)): return '"{}"'.format(self.getEvalValue()) diff --git a/meshroom/core/desc.py b/meshroom/core/desc.py index 53e08ab8f6..a893162655 100644 --- a/meshroom/core/desc.py +++ b/meshroom/core/desc.py @@ -1,7 +1,7 @@ from meshroom.common import BaseObject, Property, Variant, VariantList, JSValue -from meshroom.core import pyCompatibility -from enum import Enum # available by default in python3. For python2: "pip install enum34" +from collections.abc import Iterable +from enum import Enum import math import os import psutil @@ -85,7 +85,7 @@ def validateValue(self, value): if JSValue is not None and isinstance(value, JSValue): # Note: we could use isArray(), property("length").toInt() to retrieve all values raise ValueError("ListAttribute.validateValue: cannot recognize QJSValue. Please, use JSON.stringify(value) in QML.") - if isinstance(value, pyCompatibility.basestring): + if isinstance(value, str): # Alternative solution to set values from QML is to convert values to JSON string # In this case, it works with all data types value = ast.literal_eval(value) @@ -124,7 +124,7 @@ def validateValue(self, value): if JSValue is not None and isinstance(value, JSValue): # Note: we could use isArray(), property("length").toInt() to retrieve all values raise ValueError("GroupAttribute.validateValue: cannot recognize QJSValue. Please, use JSON.stringify(value) in QML.") - if isinstance(value, pyCompatibility.basestring): + if isinstance(value, str): # Alternative solution to set values from QML is to convert values to JSON string # In this case, it works with all data types value = ast.literal_eval(value) @@ -211,14 +211,14 @@ def __init__(self, name, label, description, value, uid, group='allParams', adva super(File, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled) def validateValue(self, value): - if not isinstance(value, pyCompatibility.basestring): + if not isinstance(value, str): raise ValueError('File only supports string input (param:{}, value:{}, type:{})'.format(self.name, value, type(value))) return os.path.normpath(value).replace('\\', '/') if value else '' def checkValueTypes(self): # Some File values are functions generating a string: check whether the value is a string or if it # is a function (but there is no way to check that the function's output is indeed a string) - if not isinstance(self.value, pyCompatibility.basestring) and not callable(self.value): + if not isinstance(self.value, str) and not callable(self.value): return self.name return "" @@ -231,7 +231,7 @@ def __init__(self, name, label, description, value, uid, group='allParams', adva def validateValue(self, value): try: - if isinstance(value, pyCompatibility.basestring): + if isinstance(value, str): # use distutils.util.strtobool to handle (1/0, true/false, on/off, y/n) return bool(distutils.util.strtobool(value)) return bool(value) @@ -254,9 +254,7 @@ def __init__(self, name, label, description, value, range, uid, group='allParams def validateValue(self, value): # handle unsigned int values that are translated to int by shiboken and may overflow try: - return long(value) # Python 2 - except NameError: - return int(value) # Python 3 + return int(value) except: raise ValueError('IntParam only supports int value (param:{}, value:{}, type:{})'.format(self.name, value, type(value))) @@ -311,10 +309,10 @@ def validateValue(self, value): if self.exclusive: return self.conformValue(value) - if isinstance(value, pyCompatibility.basestring): + if isinstance(value, str): value = value.split(',') - if not isinstance(value, pyCompatibility.Iterable): + if not isinstance(value, Iterable): raise ValueError('Non exclusive ChoiceParam value should be iterable (param:{}, value:{}, type:{})'.format(self.name, value, type(value))) return [self.conformValue(v) for v in value] @@ -334,12 +332,12 @@ def __init__(self, name, label, description, value, uid, group='allParams', adva super(StringParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled) def validateValue(self, value): - if not isinstance(value, pyCompatibility.basestring): + if not isinstance(value, str): raise ValueError('StringParam value should be a string (param:{}, value:{}, type:{})'.format(self.name, value, type(value))) return value def checkValueTypes(self): - if not isinstance(self.value, pyCompatibility.basestring): + if not isinstance(self.value, str): return self.name return "" diff --git a/meshroom/core/graph.py b/meshroom/core/graph.py index c444b45421..8acd9295ce 100644 --- a/meshroom/core/graph.py +++ b/meshroom/core/graph.py @@ -13,7 +13,7 @@ import meshroom import meshroom.core from meshroom.common import BaseObject, DictModel, Slot, Signal, Property -from meshroom.core import Version, pyCompatibility +from meshroom.core import Version from meshroom.core.attribute import Attribute, ListAttribute from meshroom.core.exception import StopGraphVisit, StopBranchVisit from meshroom.core.node import nodeFactory, Status, Node, CompatibilityNode @@ -195,7 +195,7 @@ def getFeaturesForVersion(fileVersion): Returns: tuple of Graph.IO.Features: the list of supported features """ - if isinstance(fileVersion, pyCompatibility.basestring): + if isinstance(fileVersion, str): fileVersion = Version(fileVersion) features = [Graph.IO.Features.Graph] @@ -382,11 +382,11 @@ def updateLinks(attributes, nameCorrespondences): """ for key, val in attributes.items(): for corr in nameCorrespondences.keys(): - if isinstance(val, pyCompatibility.basestring) and corr in val: + if isinstance(val, str) and corr in val: attributes[key] = val.replace(corr, nameCorrespondences[corr]) elif isinstance(val, list): for v in val: - if isinstance(v, pyCompatibility.basestring): + if isinstance(v, str): if corr in v: val[val.index(v)] = v.replace(corr, nameCorrespondences[corr]) else: # the list does not contain strings, so there cannot be links to update @@ -419,7 +419,7 @@ def resetExternalLinks(attributes, nodeDesc, newNames): defaultValue = desc.value break - if isinstance(val, pyCompatibility.basestring): + if isinstance(val, str): if Attribute.isLinkExpression(val) and not any(name in val for name in newNames): if defaultValue is not None: # prevents from not entering condition if defaultValue = '' attributes[key] = defaultValue @@ -428,8 +428,7 @@ def resetExternalLinks(attributes, nodeDesc, newNames): removedCnt = len(val) # counter to know whether all the list entries will be deemed invalid tmpVal = list(val) # deep copy to ensure we iterate over the entire list (even if elements are removed) for v in tmpVal: - if isinstance(v, pyCompatibility.basestring) and Attribute.isLinkExpression(v) and not any( - name in v for name in newNames): + if isinstance(v, str) and Attribute.isLinkExpression(v) and not any(name in v for name in newNames): val.remove(v) removedCnt -= 1 if removedCnt == 0 and defaultValue is not None: # if all links were wrong, reset the attribute diff --git a/meshroom/core/node.py b/meshroom/core/node.py index dd992e044f..7a9c057c55 100644 --- a/meshroom/core/node.py +++ b/meshroom/core/node.py @@ -17,7 +17,7 @@ import meshroom from meshroom.common import Signal, Variant, Property, BaseObject, Slot, ListModel, DictModel -from meshroom.core import desc, stats, hashValue, pyCompatibility, nodeVersion, Version +from meshroom.core import desc, stats, hashValue, nodeVersion, Version from meshroom.core.attribute import attributeFactory, ListAttribute, GroupAttribute, Attribute from meshroom.core.exception import NodeUpgradeError, UnknownNodeTypeError @@ -510,8 +510,7 @@ def __init__(self, nodeType, position=None, parent=None, **kwargs): def __getattr__(self, k): try: # Throws exception if not in prototype chain - # return object.__getattribute__(self, k) # doesn't work in python2 - return object.__getattr__(self, k) + return object.__getattribute__(self, k) except AttributeError as e: try: return self.attribute(k) @@ -1264,7 +1263,7 @@ def attributeDescFromValue(attrName, value, isOutput): return desc.IntParam(range=None, **params) elif isinstance(value, float): return desc.FloatParam(range=None, **params) - elif isinstance(value, pyCompatibility.basestring): + elif isinstance(value, str): if isOutput or os.path.isabs(value) or Attribute.isLinkExpression(value): return desc.File(**params) else: diff --git a/meshroom/core/pyCompatibility.py b/meshroom/core/pyCompatibility.py deleted file mode 100644 index 50e9027138..0000000000 --- a/meshroom/core/pyCompatibility.py +++ /dev/null @@ -1,22 +0,0 @@ - -try: - unicode = unicode -except NameError: - # 'unicode' is undefined, must be Python 3 - str = str - unicode = str - bytes = bytes - basestring = (str, bytes) -else: - # 'unicode' exists, must be Python 2 - str = str - unicode = unicode - bytes = str - basestring = basestring - -try: - # Import ABC from collections.abc in Python 3.4+ - from collections.abc import Sequence, Iterable -except ImportError: - # Import ABC from collections in Python 2 support - from collections import Sequence, Iterable diff --git a/meshroom/core/stats.py b/meshroom/core/stats.py index 046b1c5ca3..f396a52675 100644 --- a/meshroom/core/stats.py +++ b/meshroom/core/stats.py @@ -8,11 +8,7 @@ import os import sys -if sys.version_info[0] == 2: - # On Python 2 use C implementation for performance and to avoid lots of warnings - from xml.etree import cElementTree as ET -else: - import xml.etree.ElementTree as ET +import xml.etree.ElementTree as ET def bytes2human(n): @@ -95,11 +91,7 @@ def updateGpu(self): return try: p = subprocess.Popen([self.nvidia_smi, "-q", "-x"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - if sys.version_info[0] == 2: - # no timeout in python-2 - xmlGpu, stdError = p.communicate() - else: - xmlGpu, stdError = p.communicate(timeout=10) # 10 seconds + xmlGpu, stdError = p.communicate(timeout=10) # 10 seconds smiTree = ET.fromstring(xmlGpu) gpuTree = smiTree.find('gpu') diff --git a/meshroom/core/taskManager.py b/meshroom/core/taskManager.py index 77d5d6e022..164b832dd7 100644 --- a/meshroom/core/taskManager.py +++ b/meshroom/core/taskManager.py @@ -348,7 +348,7 @@ def checkNodesDependencies(self, graph, toNodes, context): raise ValueError("Argument 'context' must be: 'COMPUTATION' or 'SUBMITTING'") if len(ready) + len(computed) != len(toNodes): - del toNodes[:] # for python 2 compatibility, else use: toNodes.clear() + toNodes.clear() toNodes.extend(ready) return False diff --git a/meshroom/nodes/aliceVision/CameraInit.py b/meshroom/nodes/aliceVision/CameraInit.py index 9bc0e4e284..feb529cd29 100644 --- a/meshroom/nodes/aliceVision/CameraInit.py +++ b/meshroom/nodes/aliceVision/CameraInit.py @@ -94,9 +94,8 @@ def readSfMData(sfmFile): Returns: The views and intrinsics of the .sfm as two separate lists """ - import io # use io.open for Python2/3 compatibility (allow to specify encoding + errors handling) # skip decoding errors to avoid potential exceptions due to non utf-8 characters in images metadata - with io.open(sfmFile, 'r', encoding='utf-8', errors='ignore') as f: + with open(sfmFile, 'r', encoding='utf-8', errors='ignore') as f: data = json.load(f) intrinsicsKeys = [i.name for i in Intrinsic] @@ -223,9 +222,9 @@ class CameraInit(desc.CommandLineNode, desc.InitNode): description='Regex used to catch number used as viewId in filename.' 'You should capture specific parts of the filename with parenthesis to define matching elements. (only number will works)\n' 'Some examples of patterns:\n' - ' - Match the longest number at the end of filename (default value): ".*?(\d+)"\n' - ' - Match the first number found in filename : "(\d+).*"\n', - value='.*?(\d+)', + r' - Match the longest number at the end of filename (default value): ".*?(\d+)"' + '\n' + + r' - Match the first number found in filename : "(\d+).*"', + value=r'.*?(\d+)', uid=[], advanced=True, enabled=lambda node: node.viewIdMethod.value == 'filename', diff --git a/meshroom/nodes/aliceVision/SfMAlignment.py b/meshroom/nodes/aliceVision/SfMAlignment.py index accd9bfbd5..a001f7cd19 100644 --- a/meshroom/nodes/aliceVision/SfMAlignment.py +++ b/meshroom/nodes/aliceVision/SfMAlignment.py @@ -57,10 +57,10 @@ class SfMAlignment(desc.CommandLineNode): description='Matching regular expression for the "from_cameras_filepath" method. ' 'You should capture specific parts of the filepath with parenthesis to define matching elements.\n' 'Some examples of patterns:\n' - ' - Match the filename without extension (default value): ".*\/(.*?)\.\w{3}"\n' - ' - Match the filename suffix after "_": ".*\/.*(_.*?\.\w{3})"\n' - ' - Match the filename prefix before "_": ".*\/(.*?)_.*\.\w{3}"\n', - value='.*\/(.*?)\.\w{3}', + r' - Match the filename without extension (default value): ".*\/(.*?)\.\w{3}"' + '\n' + + r' - Match the filename suffix after "_": ".*\/.*(_.*?\.\w{3})"' + '\n' + + r' - Match the filename prefix before "_": ".*\/(.*?)_.*\.\w{3}"', + value=r'.*\/(.*?)\.\w{3}', uid=[0], ), desc.ListAttribute( diff --git a/meshroom/nodes/aliceVision/SfMTransfer.py b/meshroom/nodes/aliceVision/SfMTransfer.py index edc5acffd9..22f1313a5d 100644 --- a/meshroom/nodes/aliceVision/SfMTransfer.py +++ b/meshroom/nodes/aliceVision/SfMTransfer.py @@ -48,10 +48,10 @@ class SfMTransfer(desc.CommandLineNode): description='Matching regular expression for the "from_cameras_filepath" method. ' 'You should capture specific parts of the filepath with parenthesis to define matching elements.\n' 'Some examples of patterns:\n' - ' - Match the filename without extension (default value): ".*\/(.*?)\.\w{3}"\n' - ' - Match the filename suffix after "_": ".*\/.*(_.*?\.\w{3})"\n' - ' - Match the filename prefix before "_": ".*\/(.*?)_.*\.\w{3}"\n', - value='.*\/(.*?)\.\w{3}', + r' - Match the filename without extension (default value): ".*\/(.*?)\.\w{3}"' + '\n' + + r' - Match the filename suffix after "_": ".*\/.*(_.*?\.\w{3})"' + '\n' + + r' - Match the filename prefix before "_": ".*\/(.*?)_.*\.\w{3}"', + value=r'.*\/(.*?)\.\w{3}', uid=[0], ), desc.ListAttribute( diff --git a/meshroom/nodes/aliceVision/Texturing.py b/meshroom/nodes/aliceVision/Texturing.py index 83d46d90d1..d7eb6f7cf1 100644 --- a/meshroom/nodes/aliceVision/Texturing.py +++ b/meshroom/nodes/aliceVision/Texturing.py @@ -1,6 +1,6 @@ __version__ = "6.0" -from meshroom.core import desc, Version, pyCompatibility +from meshroom.core import desc, Version import logging @@ -355,7 +355,7 @@ class Texturing(desc.CommandLineNode): def upgradeAttributeValues(self, attrValues, fromVersion): if fromVersion < Version(6, 0): outputTextureFileType = attrValues['outputTextureFileType'] - if isinstance(outputTextureFileType, pyCompatibility.basestring): + if isinstance(outputTextureFileType, str): attrValues['colorMapping'] = {} attrValues['colorMapping']['colorMappingFileType'] = outputTextureFileType return attrValues diff --git a/meshroom/ui/app.py b/meshroom/ui/app.py index dc436c1859..36f7472c22 100644 --- a/meshroom/ui/app.py +++ b/meshroom/ui/app.py @@ -9,7 +9,6 @@ import meshroom from meshroom.core import nodesDesc -from meshroom.core import pyCompatibility from meshroom.core.taskManager import TaskManager from meshroom.ui import components @@ -225,7 +224,7 @@ def _recentProjectFiles(self): @Slot(str) @Slot(QUrl) def addRecentProjectFile(self, projectFile): - if not isinstance(projectFile, (QUrl, pyCompatibility.basestring)): + if not isinstance(projectFile, (QUrl, str)): raise TypeError("Unexpected data type: {}".format(projectFile.__class__)) if isinstance(projectFile, QUrl): projectFileNorm = projectFile.toLocalFile() @@ -265,7 +264,7 @@ def addRecentProjectFile(self, projectFile): @Slot(str) @Slot(QUrl) def removeRecentProjectFile(self, projectFile): - if not isinstance(projectFile, (QUrl, pyCompatibility.basestring)): + if not isinstance(projectFile, (QUrl, str)): raise TypeError("Unexpected data type: {}".format(projectFile.__class__)) if isinstance(projectFile, QUrl): projectFileNorm = projectFile.toLocalFile() diff --git a/meshroom/ui/components/filepath.py b/meshroom/ui/components/filepath.py index 6c19e87f8b..233a67f52e 100644 --- a/meshroom/ui/components/filepath.py +++ b/meshroom/ui/components/filepath.py @@ -1,7 +1,5 @@ #!/usr/bin/env python # coding:utf-8 -from meshroom.core import pyCompatibility - from PySide2.QtCore import QUrl, QFileInfo from PySide2.QtCore import QObject, Slot @@ -27,7 +25,7 @@ def asStr(path): Returns: str: String representation of 'path' """ - if not isinstance(path, (QUrl, pyCompatibility.basestring)): + if not isinstance(path, (QUrl, str)): raise TypeError("Unexpected data type: {}".format(path.__class__)) if isinstance(path, QUrl): path = path.toLocalFile() diff --git a/meshroom/ui/reconstruction.py b/meshroom/ui/reconstruction.py index 27d4ef94bf..3dc794c61c 100755 --- a/meshroom/ui/reconstruction.py +++ b/meshroom/ui/reconstruction.py @@ -2,6 +2,7 @@ import logging import math import os +from collections.abc import Iterable from threading import Thread from PySide2.QtCore import QObject, Slot, Property, Signal, QUrl, QSizeF @@ -13,16 +14,9 @@ from meshroom.common.qt import QObjectListModel from meshroom.core import Version from meshroom.core.node import Node, CompatibilityNode, Status, Position -from meshroom.core.pyCompatibility import Iterable from meshroom.ui.graph import UIGraph from meshroom.ui.utils import makeProperty -# Python2 compatibility -try: - FileNotFoundError -except NameError: - FileNotFoundError = IOError - class Message(QObject): """ Simple structure wrapping a high-level message. """ @@ -623,9 +617,8 @@ def getAutoFisheyeCircle(self, panoramaInit): sfmFile = panoramaInit.attribute('outSfMData').value if not os.path.exists(sfmFile): return QVector3D(0.0, 0.0, 0.0) - import io # use io.open for Python2/3 compatibility (allow to specify encoding + errors handling) # skip decoding errors to avoid potential exceptions due to non utf-8 characters in images metadata - with io.open(sfmFile, 'r', encoding='utf-8', errors='ignore') as f: + with open(sfmFile, 'r', encoding='utf-8', errors='ignore') as f: data = json.load(f) intrinsics = data.get('intrinsics', []) diff --git a/requirements.txt b/requirements.txt index d43e19234d..c121fa7e77 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,5 @@ # runtime psutil>=5.6.3 -enum34;python_version<"3.4" PySide2==5.14.1 markdown==2.6.11 requests==2.22.0