aridity 83__tar.gz → 85__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-83 → aridity-85}/PKG-INFO +3 -13
- {aridity-83 → aridity-85}/README.md +2 -12
- {aridity-83 → aridity-85}/aridity/config.py +34 -62
- {aridity-83 → aridity-85}/aridity/directives.py +2 -2
- {aridity-83 → aridity-85}/aridity/functions.py +53 -34
- {aridity-83 → aridity-85}/aridity/keyring.py +3 -3
- {aridity-83 → aridity-85}/aridity/model.py +34 -42
- {aridity-83 → aridity-85}/aridity/scope.py +5 -5
- {aridity-83 → aridity-85}/aridity.egg-info/PKG-INFO +3 -13
- {aridity-83 → aridity-85}/parabject.py +1 -1
- {aridity-83 → aridity-85}/setup.py +1 -1
- {aridity-83 → aridity-85}/aridity/__init__.py +0 -0
- {aridity-83 → aridity-85}/aridity/arid_config.py +0 -0
- {aridity-83 → aridity-85}/aridity/grammar.py +0 -0
- {aridity-83 → aridity-85}/aridity/processtemplate.py +0 -0
- {aridity-83 → aridity-85}/aridity/repl.py +0 -0
- {aridity-83 → aridity-85}/aridity/resolve.py +0 -0
- {aridity-83 → aridity-85}/aridity/search.py +0 -0
- {aridity-83 → aridity-85}/aridity/stacks.py +0 -0
- {aridity-83 → aridity-85}/aridity/util.py +0 -0
- {aridity-83 → aridity-85}/aridity.egg-info/SOURCES.txt +0 -0
- {aridity-83 → aridity-85}/aridity.egg-info/dependency_links.txt +0 -0
- {aridity-83 → aridity-85}/aridity.egg-info/entry_points.txt +0 -0
- {aridity-83 → aridity-85}/aridity.egg-info/requires.txt +0 -0
- {aridity-83 → aridity-85}/aridity.egg-info/top_level.txt +0 -0
- {aridity-83 → aridity-85}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: aridity
|
|
3
|
-
Version:
|
|
3
|
+
Version: 85
|
|
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
|
|
@@ -247,16 +247,6 @@ Process the given template to stdout using config from stdin.
|
|
|
247
247
|
|
|
248
248
|
### aridity.config
|
|
249
249
|
|
|
250
|
-
<a id="aridity.config.ForeignScopeException"></a>
|
|
251
|
-
|
|
252
|
-
#### ForeignScopeException Objects
|
|
253
|
-
|
|
254
|
-
```python
|
|
255
|
-
class ForeignScopeException(Exception)
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
The operation required a scope at precisely the given path.
|
|
259
|
-
|
|
260
250
|
<a id="aridity.config.ConfigCtrl"></a>
|
|
261
251
|
|
|
262
252
|
#### ConfigCtrl Objects
|
|
@@ -558,7 +548,7 @@ If given 3 args, the first two are variable names for scope key and scope respec
|
|
|
558
548
|
###### join
|
|
559
549
|
|
|
560
550
|
```python
|
|
561
|
-
def join(scope,
|
|
551
|
+
def join(scope, partsresolvable, sepresolvable=None)
|
|
562
552
|
```
|
|
563
553
|
|
|
564
554
|
Concatenate the given list, using optional separator. Frequently used with `map`.
|
|
@@ -780,7 +770,7 @@ Get the regular object associated with `parabject` or raise UnknownParabjectExce
|
|
|
780
770
|
#### Parabject Objects
|
|
781
771
|
|
|
782
772
|
```python
|
|
783
|
-
class Parabject(
|
|
773
|
+
class Parabject()
|
|
784
774
|
```
|
|
785
775
|
|
|
786
776
|
Subclasses typically implement `__getattr__` for dynamic behaviour on attribute access.
|
|
@@ -237,16 +237,6 @@ Process the given template to stdout using config from stdin.
|
|
|
237
237
|
|
|
238
238
|
### aridity.config
|
|
239
239
|
|
|
240
|
-
<a id="aridity.config.ForeignScopeException"></a>
|
|
241
|
-
|
|
242
|
-
#### ForeignScopeException Objects
|
|
243
|
-
|
|
244
|
-
```python
|
|
245
|
-
class ForeignScopeException(Exception)
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
The operation required a scope at precisely the given path.
|
|
249
|
-
|
|
250
240
|
<a id="aridity.config.ConfigCtrl"></a>
|
|
251
241
|
|
|
252
242
|
#### ConfigCtrl Objects
|
|
@@ -548,7 +538,7 @@ If given 3 args, the first two are variable names for scope key and scope respec
|
|
|
548
538
|
###### join
|
|
549
539
|
|
|
550
540
|
```python
|
|
551
|
-
def join(scope,
|
|
541
|
+
def join(scope, partsresolvable, sepresolvable=None)
|
|
552
542
|
```
|
|
553
543
|
|
|
554
544
|
Concatenate the given list, using optional separator. Frequently used with `map`.
|
|
@@ -770,7 +760,7 @@ Get the regular object associated with `parabject` or raise UnknownParabjectExce
|
|
|
770
760
|
#### Parabject Objects
|
|
771
761
|
|
|
772
762
|
```python
|
|
773
|
-
class Parabject(
|
|
763
|
+
class Parabject()
|
|
774
764
|
```
|
|
775
765
|
|
|
776
766
|
Subclasses typically implement `__getattr__` for dynamic behaviour on attribute access.
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
from .functions import OpaqueKey
|
|
2
|
-
from .model import Entry,
|
|
2
|
+
from .model import Entry, Locator, Resource, Stream, Text, wrap
|
|
3
3
|
from .repl import Repl
|
|
4
4
|
from .scope import Scope
|
|
5
5
|
from .search import resolvedscopeornone
|
|
6
6
|
from .util import dotpy, NoSuchPathException, qualname, selectentrypoints, solo
|
|
7
|
-
from functools import partial
|
|
8
|
-
from itertools import chain
|
|
9
7
|
from parabject import Parabject, register
|
|
8
|
+
from pathlib import Path
|
|
10
9
|
import errno, logging, os, sys
|
|
11
10
|
|
|
12
11
|
log = logging.getLogger(__name__)
|
|
@@ -29,19 +28,22 @@ def _processmainfunction(mainfunction):
|
|
|
29
28
|
appname, = (ep.name for ep in selectentrypoints('console_scripts') if ep.module == module and ep.attr == attr)
|
|
30
29
|
return module, appname
|
|
31
30
|
|
|
32
|
-
class ForeignScopeException(Exception):
|
|
33
|
-
'The operation required a scope at precisely the given path.'
|
|
34
|
-
|
|
35
31
|
def _wrappathorstream(pathorstream):
|
|
36
32
|
return (Stream if getattr(pathorstream, 'readable', lambda: False)() else Locator)(pathorstream)
|
|
37
33
|
|
|
38
34
|
class ConfigCtrl:
|
|
39
35
|
'High level scope API.'
|
|
40
36
|
|
|
37
|
+
settingsopenable = Locator(Path.home() / '.settings.arid')
|
|
38
|
+
|
|
41
39
|
@classmethod
|
|
42
40
|
def _of(cls, *args, **kwargs):
|
|
43
41
|
return cls(*args, **kwargs)
|
|
44
42
|
|
|
43
|
+
@property
|
|
44
|
+
def node(self):
|
|
45
|
+
return register(self, Config)
|
|
46
|
+
|
|
45
47
|
@property
|
|
46
48
|
def r(self):
|
|
47
49
|
'Get config object for reading, i.e. missing scopes will error.'
|
|
@@ -53,7 +55,6 @@ class ConfigCtrl:
|
|
|
53
55
|
return register(self, WConfig)
|
|
54
56
|
|
|
55
57
|
def __init__(self, basescope = None, prefix = None):
|
|
56
|
-
self.node = register(self, Config)
|
|
57
58
|
self.basescope = Scope() if basescope is None else basescope
|
|
58
59
|
self.prefix = [] if prefix is None else prefix
|
|
59
60
|
|
|
@@ -73,7 +74,7 @@ class ConfigCtrl:
|
|
|
73
74
|
return appconfig
|
|
74
75
|
|
|
75
76
|
def _loadappconfig(self, appname, resource):
|
|
76
|
-
resource.source(self.basescope.getorcreatesubscope(self.prefix
|
|
77
|
+
resource.source(self.basescope.getorcreatesubscope([*self.prefix, appname]), Entry([]))
|
|
77
78
|
return getattr(self.node, appname)
|
|
78
79
|
|
|
79
80
|
def reapplysettings(self, mainfunction):
|
|
@@ -81,7 +82,7 @@ class ConfigCtrl:
|
|
|
81
82
|
appname = mainfunction
|
|
82
83
|
else:
|
|
83
84
|
_, appname = _processmainfunction(mainfunction)
|
|
84
|
-
s = self.scope
|
|
85
|
+
s = self.scope.duplicate()
|
|
85
86
|
s.label = Text(appname)
|
|
86
87
|
p = solo(s.parents)
|
|
87
88
|
p[appname,] = s
|
|
@@ -89,101 +90,72 @@ class ConfigCtrl:
|
|
|
89
90
|
parent.loadsettings()
|
|
90
91
|
return getattr(parent.node, appname)
|
|
91
92
|
|
|
92
|
-
def printf(self, template, *args):
|
|
93
|
-
with Repl(self.basescope) as repl:
|
|
94
|
-
repl.printf(''.join(chain(("%s " for _ in self.prefix), [template])), *chain(self.prefix, args))
|
|
95
|
-
|
|
96
93
|
def load(self, pathorstream):
|
|
97
94
|
'Execute config from the given path or stream.'
|
|
98
|
-
|
|
99
|
-
_wrappathorstream(pathorstream).source(s, Entry([]))
|
|
95
|
+
_wrappathorstream(pathorstream).source(self.scope, Entry([]))
|
|
100
96
|
|
|
101
97
|
def loadsettings(self):
|
|
102
|
-
self.
|
|
103
|
-
|
|
104
|
-
def repl(self):
|
|
105
|
-
assert not self.prefix # XXX: Support prefix?
|
|
106
|
-
return Repl(self.basescope)
|
|
98
|
+
self.settingsopenable.source(self.scope, Entry([]))
|
|
107
99
|
|
|
108
100
|
def execute(self, text):
|
|
109
101
|
'Execute given config text.'
|
|
110
|
-
with self.
|
|
102
|
+
with Repl(self.scope) as repl:
|
|
111
103
|
for line in text.splitlines(True):
|
|
112
104
|
repl(line)
|
|
113
105
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
[Scalar, 'scalar'],
|
|
120
|
-
[Text, 'text'],
|
|
121
|
-
[lambda x: x, 'resolvable']]:
|
|
122
|
-
try:
|
|
123
|
-
yield t, kwargs[k]
|
|
124
|
-
except KeyError:
|
|
125
|
-
pass
|
|
126
|
-
# XXX: Support combination of types e.g. slash is both function and text?
|
|
127
|
-
factory, = (partial(t, v) for t, v in pairs())
|
|
128
|
-
self.basescope[tuple(self.prefix) + path] = factory()
|
|
129
|
-
|
|
130
|
-
def scope(self, strict = False):
|
|
131
|
-
if strict:
|
|
132
|
-
s = resolvedscopeornone(self.basescope, self.prefix)
|
|
133
|
-
if s is None:
|
|
134
|
-
raise ForeignScopeException
|
|
135
|
-
return s
|
|
136
|
-
return self.basescope.resolved(*self.prefix) # TODO: Test what happens if it changes.
|
|
106
|
+
@property
|
|
107
|
+
def scope(self):
|
|
108
|
+
s = resolvedscopeornone(self.basescope, self.prefix)
|
|
109
|
+
assert s is not None
|
|
110
|
+
return s
|
|
137
111
|
|
|
138
112
|
def __iter__(self): # TODO: Add API to get keys without resolving values.
|
|
139
113
|
'Yield keys and values.'
|
|
140
|
-
for k, o in self.
|
|
114
|
+
for k, o in self.resolve().resolveditems():
|
|
141
115
|
try:
|
|
142
116
|
yield k, o.scalar
|
|
143
117
|
except AttributeError:
|
|
144
|
-
yield k, self.
|
|
118
|
+
yield k, self.addname(k).node
|
|
145
119
|
|
|
146
120
|
def processtemplate(self, frompathorstream, topathorstream):
|
|
147
121
|
'Evaluate expression from path/stream and write result to path/stream.'
|
|
148
|
-
|
|
149
|
-
obj = _wrappathorstream(frompathorstream).processtemplate(s)
|
|
122
|
+
obj = _wrappathorstream(frompathorstream).processtemplate(self.resolve())
|
|
150
123
|
if getattr(topathorstream, 'writable', lambda: False)():
|
|
151
|
-
topathorstream.write(obj.
|
|
124
|
+
topathorstream.write(obj.textvalue if hasattr(topathorstream, 'encoding') else obj.binaryvalue)
|
|
152
125
|
else:
|
|
153
126
|
obj.writeout(topathorstream)
|
|
154
127
|
|
|
155
|
-
def freectrl(self):
|
|
156
|
-
return self._of(self.scope()) # XXX: Strict?
|
|
157
|
-
|
|
158
128
|
def childctrl(self):
|
|
159
|
-
return self._of(self.scope
|
|
129
|
+
return self._of(self.scope.createchild())
|
|
160
130
|
|
|
161
131
|
def addname(self, name):
|
|
162
|
-
return self._of(self.basescope, self.prefix
|
|
132
|
+
return self._of(self.basescope, [*self.prefix, name])
|
|
163
133
|
|
|
164
134
|
def resolve(self):
|
|
165
135
|
return self.basescope.resolved(*self.prefix)
|
|
166
136
|
|
|
137
|
+
def prefixrepr(self):
|
|
138
|
+
return '.'.join(w if w.isidentifier() else repr(w) for w in self.prefix)
|
|
139
|
+
|
|
167
140
|
class Config(Parabject):
|
|
168
141
|
|
|
169
142
|
def __getattr__(self, name):
|
|
170
|
-
|
|
171
|
-
path = ctrl.prefix + [name]
|
|
143
|
+
query = (-self).addname(name)
|
|
172
144
|
try:
|
|
173
|
-
obj =
|
|
145
|
+
obj = query.resolve() # TODO LATER: Guidance for how lazy non-scalars should be in this situation.
|
|
174
146
|
except NoSuchPathException:
|
|
175
|
-
raise AttributeError(
|
|
147
|
+
raise AttributeError(query.prefixrepr())
|
|
176
148
|
try:
|
|
177
149
|
return obj.scalar
|
|
178
150
|
except AttributeError:
|
|
179
|
-
return
|
|
151
|
+
return query.node
|
|
180
152
|
|
|
181
153
|
def __iter__(self):
|
|
182
154
|
for _, o in -self:
|
|
183
155
|
yield o
|
|
184
156
|
|
|
185
157
|
def __setattr__(self, name, value):
|
|
186
|
-
(-self).scope
|
|
158
|
+
(-self).scope[name,] = wrap(value)
|
|
187
159
|
|
|
188
160
|
class RConfig(Parabject):
|
|
189
161
|
|
|
@@ -192,7 +164,7 @@ class RConfig(Parabject):
|
|
|
192
164
|
try:
|
|
193
165
|
obj = query.resolve()
|
|
194
166
|
except NoSuchPathException:
|
|
195
|
-
raise AttributeError
|
|
167
|
+
raise AttributeError(query.prefixrepr())
|
|
196
168
|
try:
|
|
197
169
|
return obj.scalar
|
|
198
170
|
except AttributeError:
|
|
@@ -200,7 +172,7 @@ class RConfig(Parabject):
|
|
|
200
172
|
|
|
201
173
|
def __iter__(self):
|
|
202
174
|
'Yield values only. Iterate over `-self` for keys and values.'
|
|
203
|
-
for _, o in (-self).
|
|
175
|
+
for _, o in (-self).resolve().resolveditems(): # TODO: Investigate how iteration should work.
|
|
204
176
|
yield o.scalar
|
|
205
177
|
|
|
206
178
|
class WConfig(Parabject):
|
|
@@ -36,7 +36,7 @@ class Redirect:
|
|
|
36
36
|
class Write:
|
|
37
37
|
name = '!write'
|
|
38
38
|
def __call__(self, prefix, suffix, scope):
|
|
39
|
-
scope.resolved('stdout').flush(suffix.tophrase().resolve(scope).
|
|
39
|
+
scope.resolved('stdout').flush(suffix.tophrase().resolve(scope).textvalue)
|
|
40
40
|
|
|
41
41
|
@_directive
|
|
42
42
|
class Source:
|
|
@@ -94,4 +94,4 @@ class Cat:
|
|
|
94
94
|
name = '<'
|
|
95
95
|
def __call__(self, prefix, suffix, scope):
|
|
96
96
|
scope = scope.getorcreatesubscope(prefix.topath(scope))
|
|
97
|
-
scope.resolved('stdout').flush(suffix.tophrase().resolve(scope).openable(scope).processtemplate(scope).
|
|
97
|
+
scope.resolved('stdout').flush(suffix.tophrase().resolve(scope).openable(scope).processtemplate(scope).textvalue)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from .model import Boolean, Hole, Number, Resource, Text, wrap
|
|
1
|
+
from .model import Boolean, Hole, Indeterminate, Number, Resource, Text, wrap
|
|
2
2
|
from .util import allfunctions, dotpy, NoSuchPathException, realname
|
|
3
3
|
from importlib import import_module
|
|
4
4
|
from itertools import chain
|
|
@@ -13,7 +13,7 @@ def _tomlquote(text):
|
|
|
13
13
|
return ''.join(fr"\u{ord(c):04X}" for c in m.group())
|
|
14
14
|
return f'"{tomlbasicbadchars.sub(repl, text)}"'
|
|
15
15
|
|
|
16
|
-
class OpaqueKey
|
|
16
|
+
class OpaqueKey:
|
|
17
17
|
|
|
18
18
|
@classmethod
|
|
19
19
|
def isopaque(cls, key):
|
|
@@ -25,19 +25,19 @@ class Functions:
|
|
|
25
25
|
|
|
26
26
|
def screenstr(scope, resolvable):
|
|
27
27
|
'GNU Screen string literal.'
|
|
28
|
-
return Text('"{}"'.format(re.sub(r'[\\\n"]', r'\\\g<0>', resolvable.resolve(scope).
|
|
28
|
+
return Text('"{}"'.format(re.sub(r'[\\\n"]', r'\\\g<0>', resolvable.resolve(scope).textvalue)))
|
|
29
29
|
|
|
30
30
|
def scstr(scope, resolvable):
|
|
31
31
|
'SuperCollider string literal.'
|
|
32
|
-
return Text('"{}"'.format(re.sub(r'[\\\n"]', r'\\\g<0>', resolvable.resolve(scope).
|
|
32
|
+
return Text('"{}"'.format(re.sub(r'[\\\n"]', r'\\\g<0>', resolvable.resolve(scope).textvalue)))
|
|
33
33
|
|
|
34
34
|
def hclstr(scope, resolvable):
|
|
35
35
|
'HashiCorp configuration language string literal.'
|
|
36
|
-
return Text('"{}"'.format(re.sub(r'[\\\n"]', r'\\\g<0>', resolvable.resolve(scope).
|
|
36
|
+
return Text('"{}"'.format(re.sub(r'[\\\n"]', r'\\\g<0>', resolvable.resolve(scope).textvalue)))
|
|
37
37
|
|
|
38
38
|
def groovystr(scope, resolvable):
|
|
39
39
|
'Groovy string literal.'
|
|
40
|
-
return Text("'{}'".format(re.sub(r"[\\\n']", r'\\\g<0>', resolvable.resolve(scope).
|
|
40
|
+
return Text("'{}'".format(re.sub(r"[\\\n']", r'\\\g<0>', resolvable.resolve(scope).textvalue)))
|
|
41
41
|
|
|
42
42
|
def pystr(scope, resolvable):
|
|
43
43
|
'Python literal.'
|
|
@@ -45,7 +45,7 @@ class Functions:
|
|
|
45
45
|
|
|
46
46
|
def shstr(scope, resolvable):
|
|
47
47
|
'Shell string literal.'
|
|
48
|
-
return Text(shlex.quote(resolvable.resolve(scope).
|
|
48
|
+
return Text(shlex.quote(resolvable.resolve(scope).textvalue))
|
|
49
49
|
|
|
50
50
|
def jsonquote(scope, resolvable):
|
|
51
51
|
'JSON literal, also suitable for YAML.'
|
|
@@ -54,21 +54,21 @@ class Functions:
|
|
|
54
54
|
def xmlattr(scope, resolvable):
|
|
55
55
|
'XML attribute literal (including quotes).'
|
|
56
56
|
from xml.sax.saxutils import quoteattr
|
|
57
|
-
return Text(quoteattr(resolvable.resolve(scope).
|
|
57
|
+
return Text(quoteattr(resolvable.resolve(scope).textvalue)) # TODO: Support booleans.
|
|
58
58
|
|
|
59
59
|
def xmltext(scope, resolvable):
|
|
60
60
|
'XML content, suggest assigning this to & with xmlattr assigned to " as is convention.'
|
|
61
61
|
from xml.sax.saxutils import escape
|
|
62
|
-
return Text(escape(resolvable.resolve(scope).
|
|
62
|
+
return Text(escape(resolvable.resolve(scope).textvalue, xmlentities))
|
|
63
63
|
|
|
64
64
|
def tomlquote(scope, resolvable):
|
|
65
65
|
'TOML string literal.'
|
|
66
|
-
return Text(_tomlquote(resolvable.resolve(scope).
|
|
66
|
+
return Text(_tomlquote(resolvable.resolve(scope).textvalue))
|
|
67
67
|
|
|
68
68
|
def urlquote(scope, resolvable):
|
|
69
69
|
'Percent-encode all reserved characters.'
|
|
70
70
|
from urllib.parse import quote
|
|
71
|
-
return Text(quote(resolvable.resolve(scope).
|
|
71
|
+
return Text(quote(resolvable.resolve(scope).textvalue, safe = ''))
|
|
72
72
|
|
|
73
73
|
def map(scope, objsresolvable, *args):
|
|
74
74
|
'''If given 1 arg, evaluate it against every scope in `objsresolvable` and return that list.
|
|
@@ -96,7 +96,7 @@ class Functions:
|
|
|
96
96
|
s[vname,] = v
|
|
97
97
|
return s
|
|
98
98
|
vname, resolvable = args
|
|
99
|
-
vname = vname.resolve(scope).
|
|
99
|
+
vname = vname.resolve(scope).textvalue
|
|
100
100
|
else:
|
|
101
101
|
def context(k, v):
|
|
102
102
|
s = Scope(parents)
|
|
@@ -104,8 +104,8 @@ class Functions:
|
|
|
104
104
|
s[vname,] = v
|
|
105
105
|
return s
|
|
106
106
|
kname, vname, resolvable = args
|
|
107
|
-
kname = kname.resolve(scope).
|
|
108
|
-
vname = vname.resolve(scope).
|
|
107
|
+
kname = kname.resolve(scope).textvalue
|
|
108
|
+
vname = vname.resolve(scope).textvalue
|
|
109
109
|
result = Scope(islist = True) # XXX: Really no parent?
|
|
110
110
|
for k, v in objs.resolveditems():
|
|
111
111
|
result.resolvables.put(k, resolvable.resolve(context(k, v)))
|
|
@@ -122,19 +122,13 @@ class Functions:
|
|
|
122
122
|
def label(scope):
|
|
123
123
|
return scope.label
|
|
124
124
|
|
|
125
|
-
def join(scope,
|
|
125
|
+
def join(scope, partsresolvable, sepresolvable = None):
|
|
126
126
|
'Concatenate the given list, using optional separator. Frequently used with `map`.'
|
|
127
|
-
|
|
128
|
-
r, = args
|
|
129
|
-
separator = r.resolve(scope).cat()
|
|
130
|
-
else:
|
|
131
|
-
separator = ''
|
|
132
|
-
s = resolvables.resolve(scope)
|
|
133
|
-
return Text(separator.join(o.cat() for _, o in s.resolveditems()))
|
|
127
|
+
return Join(scope, partsresolvable).execute(sepresolvable)
|
|
134
128
|
|
|
135
129
|
@realname(',') # XXX: Oh yeah?
|
|
136
130
|
def aslist(scope, *resolvables):
|
|
137
|
-
return scope.resolved(*(r.resolve(scope).
|
|
131
|
+
return scope.resolved(*(r.resolve(scope).textvalue for r in resolvables), **{'aslist': True})
|
|
138
132
|
|
|
139
133
|
def str(scope, resolvable):
|
|
140
134
|
'Coerce to string.'
|
|
@@ -178,7 +172,7 @@ class Functions:
|
|
|
178
172
|
@realname('./')
|
|
179
173
|
def hereslash(scope, *resolvables):
|
|
180
174
|
'Join the given path components with the directory of the current resource.'
|
|
181
|
-
return scope.resolved('here').slash((r.resolve(scope).
|
|
175
|
+
return scope.resolved('here').slash((r.resolve(scope).textvalue for r in resolvables), False)
|
|
182
176
|
|
|
183
177
|
def readfile(scope, resolvable):
|
|
184
178
|
'Include the content of the given path.'
|
|
@@ -190,12 +184,12 @@ class Functions:
|
|
|
190
184
|
return resolvable.resolve(scope).openable(scope).processtemplate(scope)
|
|
191
185
|
|
|
192
186
|
def lower(scope, resolvable):
|
|
193
|
-
return Text(resolvable.resolve(scope).
|
|
187
|
+
return Text(resolvable.resolve(scope).textvalue.lower())
|
|
194
188
|
|
|
195
189
|
def pyref(scope, moduleresolvable, qualnameresolvable):
|
|
196
190
|
'Python object in given module with given qualified name. Module may be relative to current resource, in which case assignment with `:=` is normally necessary. Typically used to import functions.'
|
|
197
191
|
def moduleobj():
|
|
198
|
-
moduleref = moduleresolvable.resolve(scope).
|
|
192
|
+
moduleref = moduleresolvable.resolve(scope).textvalue
|
|
199
193
|
leadingdots = len(zeroormoredots.match(moduleref).group())
|
|
200
194
|
if not leadingdots:
|
|
201
195
|
return import_module(moduleref)
|
|
@@ -212,23 +206,23 @@ class Functions:
|
|
|
212
206
|
exec(f.read(), g)
|
|
213
207
|
return M()
|
|
214
208
|
pyobj = moduleobj()
|
|
215
|
-
for name in qualnameresolvable.resolve(scope).
|
|
209
|
+
for name in qualnameresolvable.resolve(scope).textvalue.split('.'):
|
|
216
210
|
pyobj = getattr(pyobj, name)
|
|
217
211
|
return wrap(pyobj)
|
|
218
212
|
|
|
219
213
|
def pyres(scope, packageresolvable, nameresolvable, encoding = Text('ascii')):
|
|
220
214
|
'Python resource for inclusion with `.` directive.'
|
|
221
|
-
return Resource(packageresolvable.resolve(scope).
|
|
215
|
+
return Resource(packageresolvable.resolve(scope).textvalue, nameresolvable.resolve(scope).textvalue, encoding.resolve(scope).textvalue)
|
|
222
216
|
|
|
223
217
|
@realname('\N{NOT SIGN}')
|
|
224
218
|
def not_(scope, resolvable):
|
|
225
219
|
return Boolean(not resolvable.resolve(scope).truth())
|
|
226
220
|
|
|
227
221
|
def getfrom(scope, scoperesolvable, *resolvables):
|
|
228
|
-
return scoperesolvable.resolve(scope).resolved(*(r.resolve(scope).
|
|
222
|
+
return scoperesolvable.resolve(scope).resolved(*(r.resolve(scope).textvalue for r in resolvables))
|
|
229
223
|
|
|
230
224
|
def rmeol(scope, resolvable):
|
|
231
|
-
text = resolvable.resolve(scope).
|
|
225
|
+
text = resolvable.resolve(scope).textvalue
|
|
232
226
|
if text.endswith('\r\n'):
|
|
233
227
|
n = 2
|
|
234
228
|
elif text.endswith(('\r', '\n')):
|
|
@@ -238,15 +232,40 @@ class Functions:
|
|
|
238
232
|
return Text(text[:-n])
|
|
239
233
|
|
|
240
234
|
def indentmorelines(scope, resolvable):
|
|
241
|
-
indent = scope.resolved('indent').
|
|
242
|
-
lines = resolvable.resolve(scope).
|
|
235
|
+
indent = scope.resolved('indent').textvalue
|
|
236
|
+
lines = resolvable.resolve(scope).textvalue.splitlines(True)
|
|
243
237
|
return Text(''.join(chain(lines[:1], (indent + line for line in lines[1:]))))
|
|
244
238
|
|
|
245
239
|
def hole(scope, resolvable):
|
|
246
|
-
return Hole(Text(''), resolvable.resolve(scope).
|
|
240
|
+
return Hole(Text(''), resolvable.resolve(scope).textvalue)
|
|
241
|
+
|
|
242
|
+
class Join:
|
|
243
|
+
|
|
244
|
+
def __init__(self, scope, partsresolvable):
|
|
245
|
+
self.i = (o for _, o in partsresolvable.resolve(scope).resolveditems())
|
|
246
|
+
self.scope = scope
|
|
247
|
+
|
|
248
|
+
def _load(self):
|
|
249
|
+
try:
|
|
250
|
+
self.obj = next(self.i)
|
|
251
|
+
return True
|
|
252
|
+
except StopIteration:
|
|
253
|
+
pass
|
|
254
|
+
|
|
255
|
+
def execute(self, sepresolvable):
|
|
256
|
+
resobj = Indeterminate
|
|
257
|
+
if self._load():
|
|
258
|
+
resobj = resobj.plus(self.obj)
|
|
259
|
+
if self._load():
|
|
260
|
+
sepobj = Indeterminate if sepresolvable is None else sepresolvable.resolve(self.scope)
|
|
261
|
+
while True:
|
|
262
|
+
resobj = resobj.plus(sepobj).plus(self.obj)
|
|
263
|
+
if not self._load():
|
|
264
|
+
break
|
|
265
|
+
return resobj
|
|
247
266
|
|
|
248
267
|
def getimpl(scope, *resolvables, **kwargs):
|
|
249
|
-
return scope.resolved(*(r.resolve(scope).
|
|
268
|
+
return scope.resolved(*(r.resolve(scope).textvalue for r in resolvables), **kwargs)
|
|
250
269
|
|
|
251
270
|
def getfunctions():
|
|
252
271
|
return allfunctions(Functions)
|
|
@@ -33,8 +33,8 @@ def keyring(scope, serviceres, usernameres):
|
|
|
33
33
|
log.debug("Set %s to: %s", key, value)
|
|
34
34
|
os.environ[key] = value
|
|
35
35
|
from keyring import get_password, set_password
|
|
36
|
-
service = serviceres.resolve(scope).
|
|
37
|
-
username = usernameres.resolve(scope).
|
|
36
|
+
service = serviceres.resolve(scope).textvalue
|
|
37
|
+
username = usernameres.resolve(scope).textvalue
|
|
38
38
|
password = None if scope.resolved('keyring_force').scalar else get_password(service, username)
|
|
39
39
|
return Scalar(Password(*[getpass(), partial(set_password, service, username)] if password is None else [password, None]))
|
|
40
40
|
|
|
@@ -43,7 +43,7 @@ class DecryptionFailedException(Exception): pass
|
|
|
43
43
|
def gpg(scope, resolvable):
|
|
44
44
|
'Use gpg to decrypt the given base64-encoded blob.'
|
|
45
45
|
with NamedTemporaryFile() as f:
|
|
46
|
-
f.write(b64decode(resolvable.resolve(scope).
|
|
46
|
+
f.write(b64decode(resolvable.resolve(scope).textvalue))
|
|
47
47
|
f.flush()
|
|
48
48
|
try:
|
|
49
49
|
return Scalar(Password(check_output(['gpg', '-d', f.name]).decode('ascii'), None))
|
|
@@ -7,7 +7,7 @@ from itertools import chain, islice
|
|
|
7
7
|
from parabject import dereference, UnknownParabjectException
|
|
8
8
|
import numbers, os
|
|
9
9
|
|
|
10
|
-
class Struct
|
|
10
|
+
class Struct:
|
|
11
11
|
|
|
12
12
|
def __eq__(self, that):
|
|
13
13
|
if type(self) != type(that):
|
|
@@ -52,7 +52,7 @@ class NegBuffer:
|
|
|
52
52
|
def annihilate(self, obj):
|
|
53
53
|
if not self.text:
|
|
54
54
|
return obj
|
|
55
|
-
text = obj.
|
|
55
|
+
text = obj.textvalue
|
|
56
56
|
if not text:
|
|
57
57
|
return obj
|
|
58
58
|
k = min(len(self.text), len(text))
|
|
@@ -63,7 +63,7 @@ class NegBuffer:
|
|
|
63
63
|
def propagate(self, obj):
|
|
64
64
|
return Hole(obj, self.text) if self.text else obj
|
|
65
65
|
|
|
66
|
-
class Concat(Resolvable):
|
|
66
|
+
class Concat(Resolvable): # TODO: Ban in path components.
|
|
67
67
|
|
|
68
68
|
ignorable = False
|
|
69
69
|
|
|
@@ -95,17 +95,14 @@ class Concat(Resolvable):
|
|
|
95
95
|
obj = negbuffer.annihilate(obj)
|
|
96
96
|
result = result.plus(obj)
|
|
97
97
|
try:
|
|
98
|
-
text = obj.
|
|
99
|
-
except
|
|
98
|
+
text = obj.textvalue
|
|
99
|
+
except AttributeError:
|
|
100
100
|
pass
|
|
101
101
|
else:
|
|
102
102
|
self.monitor(text)
|
|
103
103
|
negbuffer.insert(negtext)
|
|
104
104
|
return negbuffer.propagate(result)
|
|
105
105
|
|
|
106
|
-
# TODO: Always throw when concatenation within a path component is attempted.
|
|
107
|
-
class CatNotSupportedException(Exception): pass
|
|
108
|
-
|
|
109
106
|
class BaseSimpleValue(Resolved):
|
|
110
107
|
|
|
111
108
|
@classmethod
|
|
@@ -113,35 +110,28 @@ class BaseSimpleValue(Resolved):
|
|
|
113
110
|
value, = t
|
|
114
111
|
return cls(value)
|
|
115
112
|
|
|
116
|
-
def cat(self):
|
|
117
|
-
raise CatNotSupportedException(self)
|
|
118
|
-
|
|
119
113
|
def unravel(self):
|
|
120
114
|
return self.scalar
|
|
121
115
|
|
|
122
|
-
class
|
|
123
|
-
|
|
124
|
-
def __init__(self, scalar):
|
|
125
|
-
self.scalar = scalar
|
|
126
|
-
|
|
127
|
-
class Cat:
|
|
128
|
-
|
|
129
|
-
def cat(self):
|
|
130
|
-
return self.scalar
|
|
131
|
-
|
|
132
|
-
class Blank(Cat, SimpleValue):
|
|
116
|
+
class Blank(BaseSimpleValue):
|
|
133
117
|
|
|
134
118
|
ignorable = True
|
|
135
119
|
boundary = False
|
|
136
120
|
|
|
121
|
+
def __init__(self, textvalue):
|
|
122
|
+
self.textvalue = textvalue
|
|
123
|
+
|
|
137
124
|
def plus(self, that):
|
|
138
|
-
return Text(self.
|
|
125
|
+
return Text(self.textvalue + that.textvalue)
|
|
139
126
|
|
|
140
|
-
class Boundary(
|
|
127
|
+
class Boundary(BaseSimpleValue):
|
|
141
128
|
|
|
142
129
|
ignorable = True
|
|
143
130
|
boundary = True
|
|
144
131
|
|
|
132
|
+
def __init__(self, scalar):
|
|
133
|
+
self.scalar = scalar
|
|
134
|
+
|
|
145
135
|
class BaseScalar(BaseSimpleValue):
|
|
146
136
|
|
|
147
137
|
ignorable = False
|
|
@@ -154,12 +144,18 @@ class BaseScalar(BaseSimpleValue):
|
|
|
154
144
|
setattr(self, k, v)
|
|
155
145
|
return self
|
|
156
146
|
|
|
147
|
+
def __getattr__(self, name):
|
|
148
|
+
raise self.attrerror(name)
|
|
149
|
+
|
|
150
|
+
def attrerror(self, name):
|
|
151
|
+
return AttributeError(f"{self} does not have: {name}")
|
|
152
|
+
|
|
157
153
|
class Scalar(BaseScalar):
|
|
158
154
|
|
|
159
155
|
def __init__(self, scalar):
|
|
160
156
|
self.scalar = scalar
|
|
161
157
|
|
|
162
|
-
class Text(
|
|
158
|
+
class Text(BaseScalar):
|
|
163
159
|
|
|
164
160
|
@classmethod
|
|
165
161
|
def joinpa(cls, s, l, t):
|
|
@@ -176,7 +172,7 @@ class Text(Cat, BaseScalar):
|
|
|
176
172
|
@property
|
|
177
173
|
def binaryvalue(self):
|
|
178
174
|
if self.textvalue:
|
|
179
|
-
raise
|
|
175
|
+
raise self.attrerror('binaryvalue')
|
|
180
176
|
return b''
|
|
181
177
|
|
|
182
178
|
def __init__(self, textvalue):
|
|
@@ -203,12 +199,12 @@ class Text(Cat, BaseScalar):
|
|
|
203
199
|
return Locator(s)
|
|
204
200
|
|
|
205
201
|
def plus(self, that):
|
|
206
|
-
return self._of(self.textvalue + that.
|
|
202
|
+
return self._of(self.textvalue + that.textvalue)
|
|
207
203
|
|
|
208
|
-
class Indeterminate:
|
|
204
|
+
class Indeterminate(BaseSimpleValue): # XXX: Base class needed?
|
|
209
205
|
|
|
210
|
-
|
|
211
|
-
|
|
206
|
+
binaryvalue = b''
|
|
207
|
+
textvalue = ''
|
|
212
208
|
|
|
213
209
|
def plus(self, that):
|
|
214
210
|
return that
|
|
@@ -218,11 +214,13 @@ class Indeterminate:
|
|
|
218
214
|
|
|
219
215
|
Indeterminate = Indeterminate()
|
|
220
216
|
|
|
217
|
+
class ResidualHoleException(Exception): pass
|
|
218
|
+
|
|
221
219
|
class Hole(BaseScalar):
|
|
222
220
|
|
|
223
221
|
@property
|
|
224
222
|
def scalar(self):
|
|
225
|
-
raise
|
|
223
|
+
raise ResidualHoleException
|
|
226
224
|
|
|
227
225
|
def __init__(self, prefix, holevalue):
|
|
228
226
|
self.prefix = prefix
|
|
@@ -341,14 +339,8 @@ class Number(BaseScalar):
|
|
|
341
339
|
text = str(self.numbervalue) # TODO: Test this.
|
|
342
340
|
return Text(text)
|
|
343
341
|
|
|
344
|
-
def cat(self):
|
|
345
|
-
try:
|
|
346
|
-
return self.textvalue
|
|
347
|
-
except AttributeError:
|
|
348
|
-
raise CatNotSupportedException
|
|
349
|
-
|
|
350
342
|
def plus(self, that):
|
|
351
|
-
return Text(self.textvalue + that.
|
|
343
|
+
return Text(self.textvalue + that.textvalue)
|
|
352
344
|
|
|
353
345
|
class Boolean(BaseScalar):
|
|
354
346
|
|
|
@@ -399,7 +391,7 @@ def List(objs):
|
|
|
399
391
|
from .scope import Scope
|
|
400
392
|
s = Scope(islist = True)
|
|
401
393
|
for obj in objs:
|
|
402
|
-
s.resolvables.put(object(), obj)
|
|
394
|
+
s.resolvables.put(object(), obj) # XXX: Not OpaqueKey?
|
|
403
395
|
return s
|
|
404
396
|
|
|
405
397
|
class Directive(Resolved):
|
|
@@ -472,7 +464,7 @@ class Entry(Struct):
|
|
|
472
464
|
return [r for r in self.resolvables if not r.ignorable]
|
|
473
465
|
|
|
474
466
|
def topath(self, scope):
|
|
475
|
-
return tuple((None if self.wildcard == r else r.resolve(scope).totext().
|
|
467
|
+
return tuple((None if self.wildcard == r else r.resolve(scope).totext().textvalue) for r in self.resolvables if not r.ignorable)
|
|
476
468
|
|
|
477
469
|
def subentry(self, i, j):
|
|
478
470
|
v = list(self.resolvables)
|
|
@@ -501,7 +493,7 @@ class Entry(Struct):
|
|
|
501
493
|
if not r.ignorable or r.boundary:
|
|
502
494
|
break
|
|
503
495
|
indent.append(r) # XXX: Can we simply grab its value?
|
|
504
|
-
return Concat.unlesssingleton(indent).resolve(None).
|
|
496
|
+
return Concat.unlesssingleton(indent).resolve(None).textvalue
|
|
505
497
|
|
|
506
498
|
def wrap(value):
|
|
507
499
|
'Attempt to wrap the given value in a model object of the most specific type.'
|
|
@@ -510,7 +502,7 @@ def wrap(value):
|
|
|
510
502
|
except UnknownParabjectException:
|
|
511
503
|
pass
|
|
512
504
|
else:
|
|
513
|
-
return ctrl.scope
|
|
505
|
+
return ctrl.scope
|
|
514
506
|
for b in map(bool, range(2)):
|
|
515
507
|
if value is b:
|
|
516
508
|
return Boolean(value)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from . import directives
|
|
2
2
|
from .directives import Precedence
|
|
3
3
|
from .functions import getfunctions, getimpl, OpaqueKey
|
|
4
|
-
from .model import
|
|
4
|
+
from .model import Directive, Function, Hole, Resolvable, Scalar, star, Stream, Text
|
|
5
5
|
from .resolve import AnchorResolveContext
|
|
6
6
|
from .search import Query
|
|
7
7
|
from .stacks import IndentStack, SimpleStack, ThreadLocalResolvable
|
|
@@ -160,7 +160,7 @@ class AbstractScope(Resolvable): # TODO LATER: Some methods should probably be m
|
|
|
160
160
|
precedence = Precedence.void
|
|
161
161
|
for i, wordobj in enumerate(entry.words()):
|
|
162
162
|
try:
|
|
163
|
-
word = wordobj.
|
|
163
|
+
word = wordobj.textvalue
|
|
164
164
|
if not word:
|
|
165
165
|
continue
|
|
166
166
|
initialcategory = _categoryornone(word[0])
|
|
@@ -172,7 +172,7 @@ class AbstractScope(Resolvable): # TODO LATER: Some methods should probably be m
|
|
|
172
172
|
del directives[:]
|
|
173
173
|
precedence = p
|
|
174
174
|
directives.append((d, i))
|
|
175
|
-
except (AttributeError,
|
|
175
|
+
except (AttributeError, NoSuchPathException):
|
|
176
176
|
pass
|
|
177
177
|
if directives:
|
|
178
178
|
d, i = directives[0] # XXX: Always use first?
|
|
@@ -216,7 +216,7 @@ class StaticScope(AbstractScope):
|
|
|
216
216
|
def __init__(self):
|
|
217
217
|
super(StaticScope, self).__init__(())
|
|
218
218
|
for word, d in directives.lookup.items():
|
|
219
|
-
self[word.
|
|
219
|
+
self[word.textvalue,] = Directive(d)
|
|
220
220
|
for name, f in getfunctions():
|
|
221
221
|
self[name,] = Function(f)
|
|
222
222
|
self['',] = Function(getimpl) # TODO: Refer to the other one.
|
|
@@ -253,7 +253,7 @@ class Slash(Text, Function):
|
|
|
253
253
|
def slashfunction(scope, *resolvables):
|
|
254
254
|
path = None
|
|
255
255
|
for r in reversed(resolvables):
|
|
256
|
-
component = r.resolve(scope).
|
|
256
|
+
component = r.resolve(scope).textvalue
|
|
257
257
|
path = component if path is None else os.path.join(component, path)
|
|
258
258
|
if os.path.isabs(path):
|
|
259
259
|
break
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: aridity
|
|
3
|
-
Version:
|
|
3
|
+
Version: 85
|
|
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
|
|
@@ -247,16 +247,6 @@ Process the given template to stdout using config from stdin.
|
|
|
247
247
|
|
|
248
248
|
### aridity.config
|
|
249
249
|
|
|
250
|
-
<a id="aridity.config.ForeignScopeException"></a>
|
|
251
|
-
|
|
252
|
-
#### ForeignScopeException Objects
|
|
253
|
-
|
|
254
|
-
```python
|
|
255
|
-
class ForeignScopeException(Exception)
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
The operation required a scope at precisely the given path.
|
|
259
|
-
|
|
260
250
|
<a id="aridity.config.ConfigCtrl"></a>
|
|
261
251
|
|
|
262
252
|
#### ConfigCtrl Objects
|
|
@@ -558,7 +548,7 @@ If given 3 args, the first two are variable names for scope key and scope respec
|
|
|
558
548
|
###### join
|
|
559
549
|
|
|
560
550
|
```python
|
|
561
|
-
def join(scope,
|
|
551
|
+
def join(scope, partsresolvable, sepresolvable=None)
|
|
562
552
|
```
|
|
563
553
|
|
|
564
554
|
Concatenate the given list, using optional separator. Frequently used with `map`.
|
|
@@ -780,7 +770,7 @@ Get the regular object associated with `parabject` or raise UnknownParabjectExce
|
|
|
780
770
|
#### Parabject Objects
|
|
781
771
|
|
|
782
772
|
```python
|
|
783
|
-
class Parabject(
|
|
773
|
+
class Parabject()
|
|
784
774
|
```
|
|
785
775
|
|
|
786
776
|
Subclasses typically implement `__getattr__` for dynamic behaviour on attribute access.
|
|
@@ -17,7 +17,7 @@ def dereference(parabject):
|
|
|
17
17
|
except (KeyError, TypeError):
|
|
18
18
|
raise UnknownParabjectException
|
|
19
19
|
|
|
20
|
-
class Parabject
|
|
20
|
+
class Parabject:
|
|
21
21
|
'Subclasses typically implement `__getattr__` for dynamic behaviour on attribute access.'
|
|
22
22
|
|
|
23
23
|
def __neg__(self):
|
|
@@ -49,7 +49,7 @@ class SourceInfo:
|
|
|
49
49
|
sourceinfo = SourceInfo('.')
|
|
50
50
|
setup(
|
|
51
51
|
name = 'aridity',
|
|
52
|
-
version = '
|
|
52
|
+
version = '85',
|
|
53
53
|
description = 'DRY config and template system, easily extensible with Python',
|
|
54
54
|
url = 'https://pypi.org/project/aridity/',
|
|
55
55
|
author = 'foyono',
|
|
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
|