Skip to content
This repository has been archived by the owner on Jul 16, 2023. It is now read-only.

Commit

Permalink
moved symbols from main_actual.py to a statically compiled parser.py
Browse files Browse the repository at this point in the history
  • Loading branch information
rjdbcm committed Nov 21, 2021
1 parent 3907a84 commit 46039a9
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 89 deletions.
1 change: 1 addition & 0 deletions Aspidites/_vendor/apm/_util.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# cython: language_level=3, annotation_typing=True, c_string_encoding=utf-8, boundscheck=False, wraparound=False, initializedcheck=False
import inspect
from inspect import CO_VARARGS # pylint: disable=no-name-in-module
from itertools import chain, repeat
Expand Down
1 change: 1 addition & 0 deletions Aspidites/_vendor/apm/error.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# cython: language_level=3, annotation_typing=True, c_string_encoding=utf-8, boundscheck=False, wraparound=False, initializedcheck=False
class MatchError(Exception):
pass
2 changes: 2 additions & 0 deletions Aspidites/_vendor/contracts/inspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
from typing import Callable
from inspect import FullArgSpec, getfullargspec
import cython
from .interface import Where, ContractSyntaxError
from .syntax import contract_expression
from ..fn.underscore import ArityError

inPy2 = sys.version_info[0] == 2
Expand Down
6 changes: 3 additions & 3 deletions Aspidites/_vendor/contracts/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
MissingContract,
describe_value,
)
from .parser import parse_contract_string_actual, check_contracts

from .main_actual import (
parse_contract_string_actual,
check_contracts,
get_all_arg_names,
get_all_arg_names
)
from .library import CheckType

Expand Down
133 changes: 47 additions & 86 deletions Aspidites/_vendor/contracts/main_actual.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,14 @@
from .library import CheckCallable, Extension, SeparateContext, identifier_expression
from .inspection import can_accept_self, can_accept_at_least_one_argument
from .interface import (
Contract,
ContractSyntaxError,
Where,
describe_value,
ContractNotRespected,
)
from .syntax import contract_expression
from .parser import parse_contract_string_actual
from .inspection import getfullargspec


class Storage:
# Cache storage
string2contract = {}


def _cacheable(string, c):
"""Returns whether the contract c defined by string string is cacheable."""
# XXX need a more general way of indicating
# whether a contract is safely cacheable
return "$" not in string


def get_annotations(function):
return getfullargspec(function).annotations
Expand All @@ -48,12 +35,6 @@ def get_all_arg_names(function):
return all_args


def check_param_is_string(x):
if not isinstance(x, str):
msg = "Expected a string, obtained %s" % type(x)
raise ValueError(msg)


def new_contract_impl(identifier, condition):
from .main import parse_flexible_spec

Expand Down Expand Up @@ -166,70 +147,50 @@ def new_contract_impl(identifier, condition):
return contract


def parse_contract_string_actual(string):
msg: str
where: Where
check_param_is_string(string)
if string in Storage.string2contract:
return Storage.string2contract[string]
try:
c = contract_expression.parseString(string, parseAll=True)[0]
assert hasattr(c, "__contract__"), "Want Contract, not %r" % c
if _cacheable(string, c):
Storage.string2contract[string] = c
return c
except Exception as e:
msg = "%s" % e
if hasattr(e, "loc"): # ParseBaseException
where = Where(string, character=e.loc)
raise ContractSyntaxError(msg, where=where)
else:
raise # ContractDefinitionError


def check_contracts(contracts, values, context_variables=None):
"""
Checks that the values respect the contract.
Not a public function -- no friendly messages.
:param contracts: List of contracts.
:type contracts: ``list[N](str),N>0``
:param values: Values that should match the contracts.
:type values: ``list[N]``
:param context_variables: Initial context
:type context_variables: ``dict(str[1]: *)``
:return: a Context variable
:rtype: type(Context)
:raise: ContractSyntaxError
:raise: ContractNotRespected
:raise: ValueError
"""
assert isinstance(contracts, list)
assert isinstance(contracts, list)
assert len(contracts) == len(values)

if context_variables is None:
context_variables = {}

for var in context_variables:
if not (isinstance(var, str) and len(var) == 1): # XXX: isalpha
msg = (
"Invalid name %r for a variable. "
"I expect a string of length 1." % var
)
raise ValueError(msg)

C = []
for x in contracts:
assert isinstance(x, str)
C.append(parse_contract_string_actual(x))

context = context_variables.copy()
for i in range(len(contracts)):
C[i]._check_contract(context, values[i], silent=False)

return context
# def check_contracts(contracts, values, context_variables=None):
# """
# Checks that the values respect the contract.
# Not a public function -- no friendly messages.
#
# :param contracts: List of contracts.
# :type contracts: ``list[N](str),N>0``
#
# :param values: Values that should match the contracts.
# :type values: ``list[N]``
#
# :param context_variables: Initial context
# :type context_variables: ``dict(str[1]: *)``
#
# :return: a Context variable
# :rtype: type(Context)
#
# :raise: ContractSyntaxError
# :raise: ContractNotRespected
# :raise: ValueError
# """
# assert isinstance(contracts, list)
# assert isinstance(contracts, list)
# assert len(contracts) == len(values)
#
# if context_variables is None:
# context_variables = {}
#
# for var in context_variables:
# if not (isinstance(var, str) and len(var) == 1): # XXX: isalpha
# msg = (
# "Invalid name %r for a variable. "
# "I expect a string of length 1." % var
# )
# raise ValueError(msg)
#
# C = []
# for x in contracts:
# assert isinstance(x, str)
# C.append(parse_contract_string_actual(x))
#
# context = context_variables.copy()
# for i in range(len(contracts)):
# C[i]._check_contract(context, values[i], silent=False)
#
# return context
92 changes: 92 additions & 0 deletions Aspidites/_vendor/contracts/parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# cython: language_level=3, annotation_typing=True, c_string_encoding=utf-8, boundscheck=False, wraparound=False, initializedcheck=False
from .interface import Where
from .syntax import contract_expression
from .interface import ContractSyntaxError


class Storage:
# Cache storage
string2contract = {}


def check_param_is_string(x):
if not isinstance(x, str):
msg = "Expected a string, obtained %s" % type(x)
raise ValueError(msg)


def _cacheable(string, c):
"""Returns whether the contract c defined by string string is cacheable."""
# XXX need a more general way of indicating
# whether a contract is safely cacheable
return "$" not in string


def parse_contract_string_actual(string):
msg: str
where: Where
check_param_is_string(string)
if string in Storage.string2contract:
return Storage.string2contract[string]
try:
c = contract_expression.parseString(string, parseAll=True)[0]
assert hasattr(c, "__contract__"), "Want Contract, not %r" % c
if _cacheable(string, c):
Storage.string2contract[string] = c
return c
except Exception as e:
msg = "%s" % e
if hasattr(e, "loc"): # ParseBaseException
where = Where(string, character=e.loc)
raise ContractSyntaxError(msg, where=where)
else:
raise # ContractDefinitionError


def check_contracts(contracts, values, context_variables=None):
"""
Checks that the values respect the contract.
Not a public function -- no friendly messages.
:param contracts: List of contracts.
:type contracts: ``list[N](str),N>0``
:param values: Values that should match the contracts.
:type values: ``list[N]``
:param context_variables: Initial context
:type context_variables: ``dict(str[1]: *)``
:return: a Context variable
:rtype: type(Context)
:raise: ContractSyntaxError
:raise: ContractNotRespected
:raise: ValueError
"""
assert isinstance(contracts, list)
assert isinstance(contracts, list)
assert len(contracts) == len(values)

if context_variables is None:
context_variables = {}

for var in context_variables:
if not (isinstance(var, str) and len(var) == 1): # XXX: isalpha
msg = (
"Invalid name %r for a variable. "
"I expect a string of length 1." % var
)
raise ValueError(msg)

C = []
for x in contracts:
assert isinstance(x, str)
C.append(parse_contract_string_actual(x))

context = context_variables.copy()
for i in range(len(contracts)):
C[i]._check_contract(context, values[i], silent=False)

return context

1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

module_paths = [str(Path('Aspidites/_vendor/contracts/metaclass.py')),
str(Path('Aspidites/_vendor/contracts/interface.py')),
str(Path('Aspidites/_vendor/contracts/parser.py')),
str(Path('Aspidites/_vendor/contracts/syntax.py')),
str(Path('Aspidites/_vendor/contracts/inspection.py')),
str(Path('Aspidites/_vendor/contracts/docstring_parsing.py')),
Expand Down

0 comments on commit 46039a9

Please sign in to comment.