예제 #1
0
파일: pre_parser.py 프로젝트: jocw/vyper
def validate_version_pragma(version_str: str, start: ParserPosition) -> None:
    """
    Validates a version pragma directive against the current compiler version.
    """
    from vyper import __version__

    version_arr = version_str.split("@version")

    raw_file_version = version_arr[1].strip()
    strict_file_version = _convert_version_str(raw_file_version)
    strict_compiler_version = Version(_convert_version_str(__version__))

    try:
        npm_spec = NpmSpec(strict_file_version)
    except ValueError:
        raise VersionException(
            f'Version specification "{raw_file_version}" is not a valid NPM semantic '
            f"version specification",
            start,
        )

    if not npm_spec.match(strict_compiler_version):
        raise VersionException(
            f'Version specification "{raw_file_version}" is not compatible '
            f'with compiler version "{__version__}"',
            start,
        )
예제 #2
0
def validate_version_pragma(version_str: str, start: ParserPosition) -> None:
    """
    Validates a version pragma directive against the current compiler version.
    """
    from vyper import __version__

    # NOTE: should be `x.y.z.*`
    installed_version = ".".join(__version__.split(".")[:3])

    version_arr = version_str.split("@version")

    raw_file_version = version_arr[1].strip()
    strict_file_version = _convert_version_str(raw_file_version)
    strict_compiler_version = Version(_convert_version_str(installed_version))

    if len(strict_file_version) == 0:
        raise VersionException("Version specification cannot be empty", start)

    try:
        npm_spec = NpmSpec(strict_file_version)
    except ValueError:
        raise VersionException(
            f'Version specification "{raw_file_version}" is not a valid NPM semantic '
            f"version specification",
            start,
        )

    if not npm_spec.match(strict_compiler_version):
        raise VersionException(
            f'Version specification "{raw_file_version}" is not compatible '
            f'with compiler version "{installed_version}"',
            start,
        )
예제 #3
0
def get_vyper_pragma_spec(source: str, path: Optional[str] = None) -> NpmSpec:
    """
    Extracts pragma information from Vyper source code.

    Args:
        source: Vyper source code
        path: Optional path to the source (only used for error reporting)

    Returns: NpmSpec object
    """
    pragma_match = next(
        re.finditer(r"(?:\n|^)\s*#\s*@version\s*([^\n]*)", source), None)
    if pragma_match is None:
        if path:
            raise PragmaError(f"No version pragma in '{path}'")
        raise PragmaError("String does not contain a version pragma")

    pragma_string = pragma_match.groups()[0]
    pragma_string = " ".join(pragma_string.split())
    try:
        return NpmSpec(pragma_string)
    except ValueError:
        pass
    try:
        # special case for Vyper 0.1.0-beta.X
        version = to_vyper_version(pragma_string)
        return NpmSpec(str(version))
    except Exception:
        pass

    path = "" if path is None else f"{path}: "
    raise PragmaError(
        f"{path}Cannot parse Vyper version from pragma: {pragma_string}")
예제 #4
0
    def checkout_workspace(self, repo: Repository,
                           repo_info: RepoInfo) -> Workspace:
        image_tags = repo.get_all_hashes_tags()

        tag_dict = dict((tag, image_hash) for (image_hash, tag) in image_tags
                        if image_hash)  #reverse keys
        default_image = repo.images[
            tag_dict['latest']] if 'latest' in tag_dict else repo.head
        version_list = [
            parse_tag(tag)
            for tag in sorted(list(tag_dict.keys()), key=len, reverse=True)
        ]

        valid_versions = [version for version in version_list if version]

        spec_expr = f'<={repo_info.major}.{repo_info.minor}' if repo_info.minor else f'<={repo_info.major}'
        base_ref_spec = NpmSpec(spec_expr)
        base_ref = base_ref_spec.select(valid_versions)

        if repo_info.prerelease:
            assert base_ref, 'Cannot checkout using prerelease until a repo is initialized.'
            prerelease_base_version = base_ref.next_patch()
            base_ref = NpmSpec(
                f'>={str(prerelease_base_version)}-{repo_info.prerelease}'
            ).select(valid_versions)

        image_hash = tag_dict[str(
            base_ref)] if base_ref else default_image.image_hash

        image = repo.images[image_hash]
        image.checkout(force=True)
        return Workspace(repo_uri=repo_info.uri,
                         image_hash=image_hash,
                         version=base_ref)
예제 #5
0
def _parse_version_string(version_str: str) -> NpmSpec:
    result = _cache_of_parsed_version_strings.get(version_str)
    if result is not None:
        return result
    try:
        result = NpmSpec(version_str)
    except ValueError:
        try:
            version = to_vyper_version(version_str)
            result = NpmSpec(str(version))
        except Exception:
            raise InvalidVyperException(
                f"Cannot parse Vyper version from pragma: {version_str}")
    _cache_of_parsed_version_strings[version_str] = result
    return result
예제 #6
0
def select_version(versions: List[Version],
                   *,
                   spec: NpmSpec = None) -> Optional[Version]:
    """Select a version according to given specification.

    Args:
        versions: List of versions to parse.

        spec: A version specification.

    Returns:
       The selected version according to ``spec`` or highest version
       if ``spec`` is ``None``.

    """
    if len(versions) == 0:
        return None

    if spec is not None:
        selected_version = spec.select(versions)
    else:
        versions.sort()
        selected_version = versions[-1]

    return selected_version
    def test_select_version_with_empty_candidates(self):
        versions = []
        version = select_version(versions)
        self.assertIsNone(version)

        version = select_version(versions, spec=NpmSpec('0.0.x'))
        self.assertIsNone(version)
예제 #8
0
def pragma(
    *,
    compiler_version: str,
    **kwargs: Any,
) -> None:
    """
    Specify pragmas for the compiler.

    Args:
        compiler_version: Acceptable versions of the compiler. Will fail if the current PyTeal version
            is not contained in the range. Follows the npm `semver range scheme <https://github.com/npm/node-semver#ranges>`_
            for specifying compatible versions.

    For example:

        .. code-block:: python

            # this will immediately fail if the current PyTeal version does not satisfy the
            # version constraint
            pragma(compiler_version="^0.14.0")
    """
    pkg_version = pkg_resources.require("pyteal")[0].version
    pyteal_version = Version(__convert_pep440_compiler_version(pkg_version))
    if pyteal_version not in NpmSpec(
        __convert_pep440_compiler_version(compiler_version)
    ):
        raise TealPragmaError(
            "PyTeal version {} is not compatible with compiler version {}".format(
                pkg_version, compiler_version
            )
        )
예제 #9
0
def get_solc_version(version_str):
    """Extract solidity version from semantic version format

    :param version_str: solidity version is the semantic version format
    :return: raw solidity version of the file
    """
    if not version_str:
        return None  # version not found in file
    version_str = ' <'.join(version_str.split('<'))
    required_version = [v for v in NpmSpec('>=0.4.19').clause.clauses]
    given_target = sorted(v.target
                          for v in NpmSpec(version_str).clause.clauses)
    for t in given_target:
        if required_version[0].match(t):
            return str(t)
    return None  # Incompatible version
예제 #10
0
    def test_version_clean(self):
        """Calling .full_clean() should convert str to Version/Spec objects."""
        obj = models.VersionModel(version='0.1.1', spec='==0.1.1,!=0.1.1-alpha', npm_spec='1.x')
        obj.full_clean()

        self.assertEqual(Version('0.1.1'), obj.version)
        self.assertEqual(SimpleSpec('==0.1.1,!=0.1.1-alpha'), obj.spec)
        self.assertEqual(NpmSpec('1.x'), obj.npm_spec)
예제 #11
0
    def test_version(self):
        obj = models.VersionModel(
            version=Version('0.1.1'),
            spec=SimpleSpec('==0.1.1,!=0.1.1-alpha'),
            npm_spec=NpmSpec('1.2 - 2.3'),
        )

        self.assertEqual(Version('0.1.1'), obj.version)
        self.assertEqual(SimpleSpec('==0.1.1,!=0.1.1-alpha'), obj.spec)
        self.assertEqual(NpmSpec('1.2 - 2.3'), obj.npm_spec)

        alt_obj = models.VersionModel(version=obj.version, spec=obj.spec, npm_spec=obj.npm_spec)

        self.assertEqual(Version('0.1.1'), alt_obj.version)
        self.assertEqual(SimpleSpec('==0.1.1,!=0.1.1-alpha'), alt_obj.spec)
        self.assertEqual(obj.spec, alt_obj.spec)
        self.assertEqual(obj.npm_spec, alt_obj.npm_spec)
        self.assertEqual(obj.version, alt_obj.version)
예제 #12
0
def find_best_solc_version(
    contract_sources: Dict[str, str],
    install_needed: bool = False,
    install_latest: bool = False,
    silent: bool = True,
) -> str:
    """
    Analyzes contract pragmas and finds the best version compatible with all sources.

    Args:
        contract_sources: a dictionary in the form of {'path': "source code"}
        install_needed: if True, will install when no installed version matches
                        the contract pragma
        install_latest: if True, will install when a newer version is available
                        than the installed one
        silent: set to False to enable verbose reporting

    Returns: version string
    """

    available_versions, installed_versions = _get_solc_version_list()

    for path, source in contract_sources.items():

        pragma_string = next(PRAGMA_REGEX.finditer(source), None)
        if pragma_string is None:
            raise PragmaError(f"No version pragma in '{path}'")
        pragma_spec = NpmSpec(pragma_string.groups()[0])
        installed_versions = [
            i for i in installed_versions if i in pragma_spec
        ]
        available_versions = [
            i for i in available_versions if i in pragma_spec
        ]

    if not available_versions:
        raise IncompatibleSolcVersion(
            "No installable solc version compatible across all sources")

    if not installed_versions and not (install_needed or install_latest):
        raise IncompatibleSolcVersion(
            "No installed solc version compatible across all sources")

    if max(available_versions) > max(installed_versions,
                                     default=Version("0.0.0")):
        if install_latest or (install_needed and not installed_versions):
            install_solc(max(available_versions))
            return str(max(available_versions))
        if not silent:
            print(
                f"New compatible solc version available: {max(available_versions)}"
            )

    return str(max(installed_versions))
예제 #13
0
    def test_serialization(self):
        o1 = models.VersionModel(
            version=Version('0.1.1'),
            spec=SimpleSpec('==0.1.1,!=0.1.1-alpha'),
            npm_spec=NpmSpec('1.2 - 2.3'),
        )
        o2 = models.VersionModel(
            version=Version('0.4.3-rc3+build3'),
            spec=SimpleSpec('<=0.1.1-rc2,!=0.1.1-rc1'),
            npm_spec=NpmSpec('1.2 - 2.3'),
        )

        data = serializers.serialize('json', [o1, o2])

        obj1, obj2 = serializers.deserialize('json', data)
        self.assertEqual(o1.version, obj1.object.version)
        self.assertEqual(o1.spec, obj1.object.spec)
        self.assertEqual(o1.npm_spec, obj1.object.npm_spec)
        self.assertEqual(o2.version, obj2.object.version)
        self.assertEqual(o2.spec, obj2.object.spec)
        self.assertEqual(o2.npm_spec, obj2.object.npm_spec)
예제 #14
0
def is_valid_compiler_version(compiler_version: str):
    """Check if the compiler version is valid.

    Args:
        compiler_version: The compiler version to check.

    Returns:
        True if the compiler version is a valid NPM specification range
        using either the PEP 440 or semantic version format, otherwise False.
    """
    try:
        pep440_converted = __convert_pep440_compiler_version(compiler_version)
        NpmSpec(pep440_converted)
        return True
    except ValueError:
        return False
예제 #15
0
파일: build_ast.py 프로젝트: nibau/zkay
    def visitVersionPragma(self, ctx: SolidityParser.VersionPragmaContext):
        version = ctx.ver.getText().strip()
        spec = NpmSpec(version)
        name = self.handle_field(ctx.name)
        if name == 'zkay' and Version(cfg.zkay_version) not in spec:
            raise SyntaxException(f'Contract requires a different zkay version.\n'
                                  f'Current version is {cfg.zkay_version} but pragma zkay mandates {version}.',
                                  ctx.ver, self.code)
        elif name != 'zkay' and spec != cfg.zkay_solc_version_compatibility:
            # For backwards compatibility with older zkay versions
            assert name == 'solidity'
            raise SyntaxException(f'Contract requires solidity version {spec}, which is not compatible '
                                  f'with the current zkay version (requires {cfg.zkay_solc_version_compatibility}).',
                                  ctx.ver, self.code)

        return f'{name} {version}'
예제 #16
0
def get_pragma_spec(source: str, path: Optional[str] = None) -> NpmSpec:
    """
    Extracts pragma information from Solidity source code.

    Args:
        source: Solidity source code
        path: Optional path to the source (only used for error reporting)

    Returns: NpmSpec object
    """

    pragma_match = next(re.finditer(r"pragma +solidity([^;]*);", source), None)
    if pragma_match is not None:
        pragma_string = pragma_match.groups()[0]
        pragma_string = " ".join(pragma_string.split())
        return NpmSpec(pragma_string)
    if path:
        raise PragmaError(f"No version pragma in '{path}'")
    raise PragmaError("String does not contain a version pragma")
예제 #17
0
def get_pragma_spec(source: str) -> Optional[NpmSpec]:
    """
    Extracts pragma information from Solidity source code.
    Args:
        source: Solidity source code
    Returns: NpmSpec object or None, if no valid pragma is found
    """
    pragma_match = next(
        re.finditer(r"(?:\n|^)\s*pragma\s*solidity\s*([^;\n]*)", source), None)
    if pragma_match is None:
        return None  # Try compiling with latest

    pragma_string = pragma_match.groups()[0]
    pragma_string = " ".join(pragma_string.split())

    try:
        return NpmSpec(pragma_string)

    except ValueError:
        return None
예제 #18
0
import json
import logging
import subprocess
from abc import abstractmethod
from pathlib import Path
from typing import Dict, Optional, Set

import attr
from semantic_version import NpmSpec, Version

from bento.error import NodeError
from bento.tool import Tool

NODE_VERSION_RANGE = NpmSpec("^8.10.0 || ^10.13.0 || >=11.10.1")

VersionDict = Dict[str, Version]


@attr.s(auto_attribs=True)
class NpmDeps(object):
    """Represents top-level npm package dependencies for a project"""

    main: Dict[str, NpmSpec]
    dev: Dict[str, NpmSpec]

    def __contains__(self, item: str) -> bool:
        return item in self.main or item in self.dev


class JsTool(Tool):
    @property
 def test_select_version_with_spec(self):
     versions = [Version('0.0.3'), Version('1.1.1'), Version('1.1.2')]
     version = select_version(versions, spec=NpmSpec('0.0.x'))
     self.assertEqual(version, Version('0.0.3'))
예제 #20
0
def find_solc_versions(
    contract_sources: Dict[str, str],
    install_needed: bool = False,
    install_latest: bool = False,
    silent: bool = True,
) -> Dict:
    """
    Analyzes contract pragmas and determines which solc version(s) to use.

    Args:
        contract_sources: a dictionary in the form of {'path': "source code"}
        install_needed: if True, will install when no installed version matches
                        the contract pragma
        install_latest: if True, will install when a newer version is available
                        than the installed one
        silent: set to False to enable verbose reporting

    Returns: dictionary of {'version': ['path', 'path', ..]}
    """

    available_versions, installed_versions = _get_solc_version_list()

    pragma_specs: Dict = {}
    to_install = set()
    new_versions = set()

    for path, source in contract_sources.items():

        pragma_string = next(PRAGMA_REGEX.finditer(source), None)
        if pragma_string is None:
            raise PragmaError(f"No version pragma in '{path}'")
        pragma_specs[path] = NpmSpec(pragma_string.groups()[0])
        version = pragma_specs[path].select(installed_versions)

        if not version and not (install_needed or install_latest):
            raise IncompatibleSolcVersion(
                f"No installed solc version matching '{pragma_string[0]}' in '{path}'"
            )

        # if no installed version of solc matches the pragma, find the latest available version
        latest = pragma_specs[path].select(available_versions)

        if not version and not latest:
            raise IncompatibleSolcVersion(
                f"No installable solc version matching '{pragma_string[0]}' in '{path}'"
            )

        if not version or (install_latest and latest > version):
            to_install.add(latest)
        elif latest and latest > version:
            new_versions.add(str(version))

    # install new versions if needed
    if to_install:
        install_solc(*to_install)
        installed_versions = [
            Version(i[1:]) for i in solcx.get_installed_solc_versions()
        ]
    elif new_versions and not silent:
        print(
            f"New compatible solc version{'s' if len(new_versions) > 1 else ''}"
            f" available: {', '.join(new_versions)}")

    # organize source paths by latest available solc version
    compiler_versions: Dict = {}
    for path, spec in pragma_specs.items():
        version = spec.select(installed_versions)
        compiler_versions.setdefault(str(version), []).append(path)

    return compiler_versions
예제 #21
0
    def describe_by_name(self, name: str, *,
                         version: str = None) -> Optional[Resource]:
        """Describe an analytic by name.

        When the optional ``version`` argument is ``None``, the
        analytic with highest version is returned.

        When the optional ``version`` argument is not ``None``, the
        analytic with that version is returned. If no such analytic
        exist, ``None`` is returned.

        When ``version`` is a version range, the analytic with highest
        version within the specified range is returned.

        Note that ``version`` is expected to follow the `syntax
        defined by npm <https://semver.npmjs.com/>`_.

        Args:
            analytic: Identifier or name of the analytic to describe.

            version: Optional version or version range used to select
                the analytic to describe.

        Examples:
            >>> sdk.analytics.describe_by_name('photogrammetry',
            ...     version='1.0.x')
            Resource(_id='60c331fed5ffbd0012f1fb1a')

        """
        if not name:
            return None

        search_filter = {'name': {'$eq': name}}

        if version is not None:
            try:
                query_exact_version = Version(version)
            except ValueError:
                # may be a version range
                query_exact_version = False

            if query_exact_version:
                search_filter['version'] = {'$eq': version}
                candidates = cast(List[Resource],
                                  self.search(filter=search_filter, limit=1))
                return candidates[0] if len(candidates) else None

            try:
                version_spec = NpmSpec(version)
            except ValueError:
                # malformed version range
                return None
        else:
            version_spec = None

        fields = {'include': ['_id', 'name', 'version']}
        candidates = [a for a in self.search_generator(filter=search_filter,
                                                       fields=fields)
                      if hasattr(a, 'version')]
        # check on version property should not be necessary but API
        # documentation doesn't say this property is required...

        candidates_by_version = dict([(a.version, a) for a in candidates])
        candidate_versions = [Version(a.version) for a in candidates]
        selected_version = select_version(candidate_versions, spec=version_spec)
        if selected_version:
            return candidates_by_version[str(selected_version)]

        return None
예제 #22
0
def test_get_pragma_spec():
    assert sources.get_pragma_spec(MESSY_SOURCE) == NpmSpec(">=0.4.22 <0.7.0")
예제 #23
0
        ("Foo", "contract"),
        ("Bar", "interface"),
        ("Baz", "abstract contract"),
        ("Potato", "library"),
        ("Foo2", "contract"),
        ("Bar2", "library"),
    ]


def test_load_messy_project():
    project = compile_source(MESSY_SOURCE)
    assert list(project.keys()) == ["Bar2", "Foo", "Foo2", "Potato"]


def test_get_pragma_spec():
    assert sources.get_pragma_spec(MESSY_SOURCE) == NpmSpec(">=0.4.22 <0.7.0")


@pytest.mark.parametrize(
    "version, spec",
    [
        ("0.1.0b16", NpmSpec("0.1.0-beta.16")),
        ("0.1.0Beta17", NpmSpec("0.1.0-beta.17")),
        ("^0.2.0", NpmSpec("^0.2.0")),
        ("<=0.2.4", NpmSpec("<=0.2.4")),
    ],
)
def test_get_vyper_pragma_spec(version, spec):
    source = f"""# @version {version}"""
    assert sources.get_vyper_pragma_spec(source) == spec