aridity 74__tar.gz → 76__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {aridity-74 → aridity-76}/PKG-INFO +1 -1
- {aridity-74 → aridity-76}/aridity/config.py +2 -2
- {aridity-74 → aridity-76}/aridity/functions.py +10 -9
- {aridity-74 → aridity-76}/aridity/model.py +2 -2
- aridity-76/aridity/resolve.py +83 -0
- {aridity-74 → aridity-76}/aridity/scope.py +18 -26
- {aridity-74 → aridity-76}/aridity/search.py +8 -12
- {aridity-74 → aridity-76}/aridity/util.py +1 -1
- {aridity-74 → aridity-76}/aridity.egg-info/PKG-INFO +1 -1
- {aridity-74 → aridity-76}/aridity.egg-info/SOURCES.txt +1 -0
- {aridity-74 → aridity-76}/setup.py +1 -1
- {aridity-74 → aridity-76}/README.md +0 -0
- {aridity-74 → aridity-76}/aridity/__init__.py +0 -0
- {aridity-74 → aridity-76}/aridity/arid_config.py +0 -0
- {aridity-74 → aridity-76}/aridity/directives.py +0 -0
- {aridity-74 → aridity-76}/aridity/grammar.py +0 -0
- {aridity-74 → aridity-76}/aridity/keyring.py +0 -0
- {aridity-74 → aridity-76}/aridity/processtemplate.py +0 -0
- {aridity-74 → aridity-76}/aridity/repl.py +0 -0
- {aridity-74 → aridity-76}/aridity/stacks.py +0 -0
- {aridity-74 → aridity-76}/aridity.egg-info/dependency_links.txt +0 -0
- {aridity-74 → aridity-76}/aridity.egg-info/entry_points.txt +0 -0
- {aridity-74 → aridity-76}/aridity.egg-info/requires.txt +0 -0
- {aridity-74 → aridity-76}/aridity.egg-info/top_level.txt +0 -0
- {aridity-74 → aridity-76}/parabject.py +0 -0
- {aridity-74 → aridity-76}/setup.cfg +0 -0
|
@@ -3,7 +3,7 @@ from .model import Entry, Function, Locator, Number, Resource, Scalar, Stream, T
|
|
|
3
3
|
from .repl import Repl
|
|
4
4
|
from .scope import Scope
|
|
5
5
|
from .search import resolvedscopeornone
|
|
6
|
-
from .util import
|
|
6
|
+
from .util import dotpy, NoSuchPathException, qualname, selectentrypoints, solo
|
|
7
7
|
from functools import partial
|
|
8
8
|
from itertools import chain
|
|
9
9
|
from parabject import Parabject, register
|
|
@@ -172,7 +172,7 @@ class Config(Parabject):
|
|
|
172
172
|
path = ctrl.prefix + [name]
|
|
173
173
|
try:
|
|
174
174
|
obj = ctrl.basescope.resolved(*path) # TODO LATER: Guidance for how lazy non-scalars should be in this situation.
|
|
175
|
-
except
|
|
175
|
+
except NoSuchPathException:
|
|
176
176
|
raise AttributeError(' '.join(path))
|
|
177
177
|
try:
|
|
178
178
|
return obj.scalar
|
|
@@ -2,10 +2,11 @@ from __future__ import division
|
|
|
2
2
|
from .model import Boolean, Number, Resource, Text, wrap
|
|
3
3
|
from .util import allfunctions, dotpy, NoSuchPathException, realname
|
|
4
4
|
from importlib import import_module
|
|
5
|
-
|
|
5
|
+
from itertools import chain
|
|
6
|
+
import json, re, shlex
|
|
6
7
|
|
|
7
8
|
xmlentities = dict([c, "&%s;" % w] for c, w in [['"', 'quot'], ["'", 'apos']])
|
|
8
|
-
tomlbasicbadchars = re.compile('[%s]+' % re.escape(r'\"' + ''.join(chr(x) for x in
|
|
9
|
+
tomlbasicbadchars = re.compile('[%s]+' % re.escape(r'\"' + ''.join(chr(x) for x in chain(range(0x08 + 1), range(0x0A, 0x1F + 1), [0x7F]))))
|
|
9
10
|
zeroormoredots = re.compile('[.]*')
|
|
10
11
|
|
|
11
12
|
def _tomlquote(text):
|
|
@@ -136,11 +137,6 @@ class Functions:
|
|
|
136
137
|
s = resolvables.resolve(scope)
|
|
137
138
|
return Text(separator.join(o.cat() for _, o in s.resolveditems()))
|
|
138
139
|
|
|
139
|
-
def get(*args): return getimpl(*args)
|
|
140
|
-
|
|
141
|
-
@realname('')
|
|
142
|
-
def get_(*args): return getimpl(*args)
|
|
143
|
-
|
|
144
140
|
@realname(',') # XXX: Oh yeah?
|
|
145
141
|
def aslist(scope, *resolvables):
|
|
146
142
|
return scope.resolved(*(r.resolve(scope).cat() for r in resolvables), **{'aslist': True})
|
|
@@ -246,8 +242,13 @@ class Functions:
|
|
|
246
242
|
raise NoSuchPathException('No line terminator to remove.')
|
|
247
243
|
return Text(text[:-n])
|
|
248
244
|
|
|
249
|
-
def
|
|
250
|
-
|
|
245
|
+
def indentmorelines(scope, resolvable):
|
|
246
|
+
indent = scope.resolved('indent').cat()
|
|
247
|
+
lines = resolvable.resolve(scope).cat().splitlines(True)
|
|
248
|
+
return Text(''.join(chain(lines[:1], (indent + line for line in lines[1:]))))
|
|
249
|
+
|
|
250
|
+
def getimpl(scope, *resolvables, **kwargs):
|
|
251
|
+
return scope.resolved(*(r.resolve(scope).cat() for r in resolvables), **kwargs)
|
|
251
252
|
|
|
252
253
|
def getfunctions():
|
|
253
254
|
return allfunctions(Functions)
|
|
@@ -302,11 +302,11 @@ class Call(Resolvable):
|
|
|
302
302
|
yield a
|
|
303
303
|
|
|
304
304
|
def resolve(self, scope, aslist = False):
|
|
305
|
-
result = self._functionvalue(scope)(scope, *self._resolvables())
|
|
305
|
+
result = self._functionvalue(scope)(scope.getresolvecontext(), *self._resolvables())
|
|
306
306
|
return List([result]) if aslist else result
|
|
307
307
|
|
|
308
308
|
def resolvemulti(self, j, scope):
|
|
309
|
-
f = self._functionvalue(scope)
|
|
309
|
+
f = self._functionvalue(scope.getresolvecontext())
|
|
310
310
|
if star != f:
|
|
311
311
|
yield j, f(scope, *self._resolvables())
|
|
312
312
|
else:
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
from .search import Query
|
|
2
|
+
from .util import CycleException, NoSuchPathException, TreeNoSuchPathException
|
|
3
|
+
from itertools import chain
|
|
4
|
+
|
|
5
|
+
def _slices(path):
|
|
6
|
+
yield path
|
|
7
|
+
limit = len(path) + 1
|
|
8
|
+
for k in range(1, limit):
|
|
9
|
+
for i in range(limit - k):
|
|
10
|
+
yield path[:i] + path[i + k:]
|
|
11
|
+
|
|
12
|
+
class BaseResolveContext:
|
|
13
|
+
|
|
14
|
+
@property
|
|
15
|
+
def label(self):
|
|
16
|
+
return self.leafscope().label
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def parents(self):
|
|
20
|
+
return self.leafscope().parents
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def resolvables(self):
|
|
24
|
+
return self.leafscope().resolvables
|
|
25
|
+
|
|
26
|
+
def createchild(self, **kwargs):
|
|
27
|
+
return self.leafscope().createchild(**kwargs)
|
|
28
|
+
|
|
29
|
+
def getresolvecontext(self):
|
|
30
|
+
return self
|
|
31
|
+
|
|
32
|
+
def resolvableornone(self, key):
|
|
33
|
+
return self.leafscope().resolvableornone(key)
|
|
34
|
+
|
|
35
|
+
def resolved(self, *path, **kwargs):
|
|
36
|
+
return self.resolvedimpl(path, kwargs) if path else self.leafscope()
|
|
37
|
+
|
|
38
|
+
def staticscope(self):
|
|
39
|
+
return self.leafscope().staticscope()
|
|
40
|
+
|
|
41
|
+
class AnchorResolveContext(BaseResolveContext):
|
|
42
|
+
|
|
43
|
+
def __init__(self, anchorscope):
|
|
44
|
+
self.anchorscope = anchorscope
|
|
45
|
+
|
|
46
|
+
def leafscope(self):
|
|
47
|
+
return self.anchorscope
|
|
48
|
+
|
|
49
|
+
def resolvedimpl(self, path, kwargs):
|
|
50
|
+
hit = Query(path).search(self.anchorscope)
|
|
51
|
+
return hit.resolvable.resolve(ResolveContext(self.anchorscope, path, [hit.address]), **kwargs)
|
|
52
|
+
|
|
53
|
+
class ResolveContext(BaseResolveContext):
|
|
54
|
+
|
|
55
|
+
@classmethod
|
|
56
|
+
def _of(cls, *args):
|
|
57
|
+
return cls(*args)
|
|
58
|
+
|
|
59
|
+
def __init__(self, anchorscope, exprpath, addresses):
|
|
60
|
+
self.anchorscope = anchorscope
|
|
61
|
+
self.scopepath = exprpath[:-1]
|
|
62
|
+
self.exprpath = exprpath
|
|
63
|
+
self.addresses = addresses
|
|
64
|
+
|
|
65
|
+
def leafscope(self):
|
|
66
|
+
return Query(self.scopepath).search(self.anchorscope).naiveresolve() if self.scopepath else self.anchorscope # XXX: Is naiveresolve correct here?
|
|
67
|
+
|
|
68
|
+
def resolvedimpl(self, path, kwargs):
|
|
69
|
+
errors = []
|
|
70
|
+
for prefix in _slices(self.scopepath):
|
|
71
|
+
try:
|
|
72
|
+
hit = Query(list(chain(prefix, path))).search(self.anchorscope)
|
|
73
|
+
if hit.address in self.addresses: # XXX: Could it be valid to resolve the same address recursively with 2 different contexts?
|
|
74
|
+
raise CycleException(path)
|
|
75
|
+
except NoSuchPathException as e:
|
|
76
|
+
errors.append(e)
|
|
77
|
+
continue
|
|
78
|
+
try:
|
|
79
|
+
return hit.resolvable.resolve(self._of(self.anchorscope, list(chain(self.scopepath, path)), self.addresses + [hit.address]), **kwargs)
|
|
80
|
+
except NoSuchPathException as e:
|
|
81
|
+
errors.append(e)
|
|
82
|
+
break # XXX: Or continue?
|
|
83
|
+
raise TreeNoSuchPathException(self.exprpath, errors)
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
from . import directives
|
|
2
2
|
from .directives import Precedence
|
|
3
|
-
from .functions import getfunctions, OpaqueKey
|
|
3
|
+
from .functions import getfunctions, getimpl, OpaqueKey
|
|
4
4
|
from .model import CatNotSupportedException, Directive, Function, Resolvable, Scalar, star, Stream, Text
|
|
5
|
-
from .
|
|
5
|
+
from .resolve import AnchorResolveContext
|
|
6
|
+
from .search import Query
|
|
6
7
|
from .stacks import IndentStack, SimpleStack, ThreadLocalResolvable
|
|
7
|
-
from .util import
|
|
8
|
+
from .util import NoSuchPathException, OrderedDict, solo, UnsupportedEntryException
|
|
8
9
|
from itertools import chain
|
|
9
10
|
import collections, os, sys, threading, unicodedata
|
|
10
11
|
|
|
@@ -118,31 +119,20 @@ class AbstractScope(Resolvable): # TODO LATER: Some methods should probably be m
|
|
|
118
119
|
s.resolvables.put(k, v)
|
|
119
120
|
return s
|
|
120
121
|
|
|
122
|
+
def getresolvecontext(self):
|
|
123
|
+
return AnchorResolveContext(self)
|
|
124
|
+
|
|
121
125
|
def resolved(self, *path, **kwargs):
|
|
122
126
|
'Follow the given path to get an expression, evaluate it (resolving any paths it requires, recursively), and return the resulting model object.'
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
return self
|
|
133
|
-
hit = Query(path).search(self)
|
|
134
|
-
# TODO: Review this algo.
|
|
135
|
-
errors = []
|
|
136
|
-
for words in slices(path):
|
|
137
|
-
for s in (resolvedscopeornone(s, words) for s in chain.from_iterable(self.scopedepths())):
|
|
138
|
-
if s is not None:
|
|
139
|
-
try:
|
|
140
|
-
return hit.resolvable.resolve(s, **kwargs)
|
|
141
|
-
except NoSuchPathException as e:
|
|
142
|
-
errors.append(e)
|
|
143
|
-
raise TreeNoSuchPathException(path, errors)
|
|
144
|
-
finally:
|
|
145
|
-
resolving.remove(path)
|
|
127
|
+
# TODO LATER: API to filter out results unsuitable for context.
|
|
128
|
+
for s in chain.from_iterable(self.scopedepths()):
|
|
129
|
+
obj = getimpl(s.getresolvecontext(), Text(''))
|
|
130
|
+
try:
|
|
131
|
+
g = obj.functionvalue
|
|
132
|
+
break
|
|
133
|
+
except AttributeError:
|
|
134
|
+
pass
|
|
135
|
+
return g(self.getresolvecontext(), *map(Text, path), **kwargs)
|
|
146
136
|
|
|
147
137
|
def resolvableornone(self, key):
|
|
148
138
|
return self.resolvables.getornone(key)
|
|
@@ -229,6 +219,8 @@ class StaticScope(AbstractScope):
|
|
|
229
219
|
self[word.cat(),] = Directive(d)
|
|
230
220
|
for name, f in getfunctions():
|
|
231
221
|
self[name,] = Function(f)
|
|
222
|
+
self['',] = Function(getimpl) # TODO: Refer to the other one.
|
|
223
|
+
self['get',] = Function(getimpl)
|
|
232
224
|
self['keyring_cron',] = Scalar(False)
|
|
233
225
|
self['keyring_force',] = Scalar(False)
|
|
234
226
|
self['~',] = Text(os.path.expanduser('~'))
|
|
@@ -13,10 +13,15 @@ def resolvedscopeornone(s, path):
|
|
|
13
13
|
return
|
|
14
14
|
return s
|
|
15
15
|
|
|
16
|
-
class
|
|
16
|
+
class Address(namedtuple('BaseAddress', 'scope key')): pass
|
|
17
|
+
|
|
18
|
+
class Hit(namedtuple('BaseHit', 'depths address resolvable')):
|
|
19
|
+
|
|
20
|
+
def naiveresolve(self):
|
|
21
|
+
return self.resolvable.resolve(self.address.scope) # XXX: Wise?
|
|
17
22
|
|
|
18
23
|
def iterornone(self, word):
|
|
19
|
-
contextscope = self.
|
|
24
|
+
contextscope = self.naiveresolve()
|
|
20
25
|
if hasattr(contextscope, 'resolvableornone'):
|
|
21
26
|
return Iterator(self.depths, contextscope, word)
|
|
22
27
|
|
|
@@ -36,7 +41,7 @@ class Iterator(Iterable):
|
|
|
36
41
|
for scope in scopes:
|
|
37
42
|
resolvable = scope.resolvableornone(word)
|
|
38
43
|
if resolvable is not None:
|
|
39
|
-
yield Hit(depths + [depth], scope, resolvable)
|
|
44
|
+
yield Hit(depths + [depth], Address(scope, word), resolvable)
|
|
40
45
|
self.iterator = g()
|
|
41
46
|
|
|
42
47
|
def next(self):
|
|
@@ -116,12 +121,3 @@ class Query:
|
|
|
116
121
|
return hit
|
|
117
122
|
sump.offer(hit)
|
|
118
123
|
raise UnparseNoSuchPathException(self.path)
|
|
119
|
-
|
|
120
|
-
def slices(path):
|
|
121
|
-
n = len(path)
|
|
122
|
-
for k in range(n)[::-1]:
|
|
123
|
-
for start in range(n - k):
|
|
124
|
-
v = path[start:start + k]
|
|
125
|
-
yield v
|
|
126
|
-
if not v:
|
|
127
|
-
return
|
|
@@ -33,7 +33,7 @@ class TreeNoSuchPathException(NoSuchPathException):
|
|
|
33
33
|
lines.append(" %s" % l)
|
|
34
34
|
return '\n'.join(lines)
|
|
35
35
|
|
|
36
|
-
class CycleException(
|
|
36
|
+
class CycleException(UnparseNoSuchPathException): pass
|
|
37
37
|
|
|
38
38
|
class UnsupportedEntryException(Exception): pass
|
|
39
39
|
|
|
@@ -6,7 +6,7 @@ def long_description():
|
|
|
6
6
|
|
|
7
7
|
setup(
|
|
8
8
|
name = 'aridity',
|
|
9
|
-
version = '
|
|
9
|
+
version = '76',
|
|
10
10
|
description = 'DRY config and template system, easily extensible with Python',
|
|
11
11
|
long_description = long_description(),
|
|
12
12
|
long_description_content_type = 'text/markdown',
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|