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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: aridity
3
- Version: 74
3
+ Version: 76
4
4
  Summary: DRY config and template system, easily extensible with Python
5
5
  Home-page: https://pypi.org/project/aridity/
6
6
  Author: foyono
@@ -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 CycleException, dotpy, NoSuchPathException, qualname, selectentrypoints, solo
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 (CycleException, NoSuchPathException): # XXX: Should this really translate CycleException?
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
- import itertools, json, re, shlex
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 itertools.chain(range(0x08 + 1), range(0x0A, 0x1F + 1), [0x7F]))))
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 getimpl(scope, *resolvables):
250
- return scope.resolved(*(r.resolve(scope).cat() for r in resolvables))
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 .search import Query, resolvedscopeornone, slices
5
+ from .resolve import AnchorResolveContext
6
+ from .search import Query
6
7
  from .stacks import IndentStack, SimpleStack, ThreadLocalResolvable
7
- from .util import CycleException, NoSuchPathException, OrderedDict, solo, TreeNoSuchPathException, UnsupportedEntryException
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
- try:
124
- resolving = self.threadlocals.resolving
125
- except AttributeError:
126
- self.threadlocals.resolving = resolving = set()
127
- if path in resolving:
128
- raise CycleException(path)
129
- resolving.add(path)
130
- try:
131
- if not path:
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 Hit(namedtuple('BaseHit', 'depths scope resolvable')):
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.resolvable.resolve(self.scope) # XXX: Wise?
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(Exception): pass
36
+ class CycleException(UnparseNoSuchPathException): pass
37
37
 
38
38
  class UnsupportedEntryException(Exception): pass
39
39
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: aridity
3
- Version: 74
3
+ Version: 76
4
4
  Summary: DRY config and template system, easily extensible with Python
5
5
  Home-page: https://pypi.org/project/aridity/
6
6
  Author: foyono
@@ -12,6 +12,7 @@ aridity/keyring.py
12
12
  aridity/model.py
13
13
  aridity/processtemplate.py
14
14
  aridity/repl.py
15
+ aridity/resolve.py
15
16
  aridity/scope.py
16
17
  aridity/search.py
17
18
  aridity/stacks.py
@@ -6,7 +6,7 @@ def long_description():
6
6
 
7
7
  setup(
8
8
  name = 'aridity',
9
- version = '74',
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