aridity 94__tar.gz → 96__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,11 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: aridity
3
- Version: 94
3
+ Version: 96
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
7
7
  Author-email: shrovis@foyono.com
8
8
  Description-Content-Type: text/markdown
9
+ Requires-Dist: foyndation>=13
9
10
  Requires-Dist: pyparsing>=3.0.2
10
11
 
11
12
  # aridity
@@ -158,6 +159,17 @@ def source(prefix, suffix, scope)
158
159
 
159
160
  Include path or resource at prefix.
160
161
 
162
+ <a id="aridity.directives.sourceifexists"></a>
163
+
164
+ ###### sourceifexists
165
+
166
+ ```python
167
+ @prime
168
+ def sourceifexists(prefix, suffix, scope)
169
+ ```
170
+
171
+ Like `.` but allow the resource to be absent.
172
+
161
173
  <a id="aridity.directives.equals"></a>
162
174
 
163
175
  ###### equals
@@ -514,16 +526,6 @@ def openresource(package_or_name, resource_name, encoding='ascii')
514
526
 
515
527
  Like `pkg_resources.resource_stream` but text mode.
516
528
 
517
- <a id="aridity.util.solo"></a>
518
-
519
- ###### solo
520
-
521
- ```python
522
- def solo(v)
523
- ```
524
-
525
- Assert exactly one object in the given sequence and return it.
526
-
527
529
  <a id="parabject"></a>
528
530
 
529
531
  ### parabject
@@ -148,6 +148,17 @@ def source(prefix, suffix, scope)
148
148
 
149
149
  Include path or resource at prefix.
150
150
 
151
+ <a id="aridity.directives.sourceifexists"></a>
152
+
153
+ ###### sourceifexists
154
+
155
+ ```python
156
+ @prime
157
+ def sourceifexists(prefix, suffix, scope)
158
+ ```
159
+
160
+ Like `.` but allow the resource to be absent.
161
+
151
162
  <a id="aridity.directives.equals"></a>
152
163
 
153
164
  ###### equals
@@ -504,16 +515,6 @@ def openresource(package_or_name, resource_name, encoding='ascii')
504
515
 
505
516
  Like `pkg_resources.resource_stream` but text mode.
506
517
 
507
- <a id="aridity.util.solo"></a>
508
-
509
- ###### solo
510
-
511
- ```python
512
- def solo(v)
513
- ```
514
-
515
- Assert exactly one object in the given sequence and return it.
516
-
517
518
  <a id="parabject"></a>
518
519
 
519
520
  ### parabject
@@ -2,7 +2,8 @@ from .functions import OpaqueKey
2
2
  from .model import Entry, Locator, Resource, Stream, Text, wrap
3
3
  from .scope import StaticScope
4
4
  from .search import resolvedscopeornone
5
- from .util import dotpy, Forkable, NoSuchPathException, qualname, selectentrypoints, solo
5
+ from .util import NoSuchPathException, qualname, selectentrypoints
6
+ from foyndation import dotpy, Forkable, rmsuffix, solo
6
7
  from io import StringIO
7
8
  from parabject import Parabject, register
8
9
  from pathlib import Path
@@ -13,13 +14,12 @@ log = logging.getLogger(__name__)
13
14
  def _processmainfunction(mainfunction):
14
15
  module = mainfunction.__module__
15
16
  if '__main__' == module:
16
- p = sys.argv[0]
17
- name = os.path.basename(p)
18
- if '__main__.py' == name:
19
- stem = os.path.basename(os.path.dirname(p))
17
+ p = Path(sys.argv[0])
18
+ name = p.name
19
+ if name in {'__init__.py', '__main__.py'}:
20
+ stem = p.parent.name
20
21
  else:
21
- assert name.endswith(dotpy)
22
- stem = name[:-len(dotpy)]
22
+ assert (stem := rmsuffix(name, dotpy)) is not None
23
23
  assert '-' not in stem
24
24
  appname = stem.replace('_', '-')
25
25
  else:
@@ -183,3 +183,8 @@ class WConfig(Parabject):
183
183
  query = (-self).addname(OpaqueKey())
184
184
  query.basescope[tuple(query.prefix)] = wrap(value)
185
185
  return self
186
+
187
+ def __neg__(self):
188
+ query = super().__neg__()
189
+ query.basescope.getorcreatesubscope(query.prefix) # TODO: Too eager.
190
+ return query
@@ -1,7 +1,10 @@
1
1
  from .model import Stream
2
2
  from .search import resolvedscopeornone
3
+ from .util import Burial
3
4
  from itertools import chain
4
- import os, sys, unicodedata
5
+ import logging, os, sys, unicodedata
6
+
7
+ log = logging.getLogger(__name__)
5
8
 
6
9
  def acceptdirectivename(word):
7
10
  return word and unicodedata.category(word[0])[0] in 'PS'
@@ -48,7 +51,19 @@ def source(prefix, suffix, scope):
48
51
  if s is None:
49
52
  break
50
53
  phrasescope = s
51
- suffix.tophrase().resolve(phrasescope).openable(phrasescope).source(scope, prefix.subentry(k, n))
54
+ with Burial.bumping(FileNotFoundError):
55
+ openable = suffix.tophrase().resolve(phrasescope).openable(phrasescope)
56
+ openable.source(scope, prefix.subentry(k, n))
57
+
58
+ @prime
59
+ def sourceifexists(prefix, suffix, scope):
60
+ 'Like `.` but allow the resource to be absent.'
61
+ try:
62
+ source(prefix, suffix, scope)
63
+ except FileNotFoundError as e:
64
+ if Burial.value(e):
65
+ raise
66
+ log.debug("Ignore absence: %s", e)
52
67
 
53
68
  @prime
54
69
  def _cd(prefix, suffix, scope):
@@ -95,6 +110,7 @@ def coredirectives():
95
110
  yield '!redirect', _redirect
96
111
  yield '!write', _write
97
112
  yield '.', source
113
+ yield '.?', sourceifexists
98
114
  yield '!cd', _cd
99
115
  yield '!test', _test
100
116
  yield '=', equals
@@ -1,6 +1,7 @@
1
1
  from .keyring import gpg, keyring
2
2
  from .model import Boolean, Hole, Indeterminate, Number, Resource, Text, wrap
3
- from .util import dotpy, NoSuchPathException
3
+ from .util import NoSuchPathException
4
+ from foyndation import dotpy
4
5
  from importlib import import_module
5
6
  from itertools import chain
6
7
  import json, re, shlex
@@ -1,5 +1,6 @@
1
- from .util import dotpy, Forkable
1
+ from .util import Burial
2
2
  from contextlib import contextmanager
3
+ from foyndation import dotpy, Forkable, rmsuffix
3
4
  from importlib import import_module
4
5
  from importlib.resources import files
5
6
  from io import TextIOWrapper
@@ -232,7 +233,7 @@ class Openable:
232
233
  yield f
233
234
 
234
235
  def source(self, scope, prefix):
235
- with self.pushopen(scope) as f:
236
+ with self.pushopen(scope) as f, Burial.bumping(FileNotFoundError):
236
237
  Stream(f).source(scope, prefix)
237
238
 
238
239
  def processtemplate(self, scope):
@@ -287,8 +288,8 @@ class Resource(Resolved, Openable, Forkable):
287
288
  return self._of(self.package_or_requirement, '/'.join(v) if v else None, self.encoding)
288
289
 
289
290
  def modulenameornone(self):
290
- if self.resource_name.endswith(dotpy):
291
- return f"{self._packagename()}.{self.resource_name[:-len(dotpy)].replace('/', '.')}"
291
+ if (stem := rmsuffix(self.resource_name, dotpy)) is not None:
292
+ return f"{self._packagename()}.{stem.replace('/', '.')}"
292
293
 
293
294
  class Binary(BaseScalar, Forkable):
294
295
 
@@ -1,44 +1,39 @@
1
1
  from .search import Query
2
- from .util import CycleException, Forkable, NoSuchPathException, TreeNoSuchPathException
2
+ from .util import CycleException, NoSuchPathException, TreeNoSuchPathException
3
+ from foyndation import Forkable
3
4
 
4
5
  class BaseResolveContext:
5
6
 
6
7
  @property
7
8
  def label(self):
8
- return self.leafscope().label
9
+ return self.resolved().label
9
10
 
10
11
  @property
11
12
  def parents(self):
12
- return self.leafscope().parents
13
+ return self.resolved().parents
13
14
 
14
15
  @property
15
16
  def resolvables(self):
16
- return self.leafscope().resolvables
17
+ return self.resolved().resolvables
17
18
 
18
19
  def createchild(self):
19
- return self.leafscope().createchild()
20
+ return self.resolved().createchild()
20
21
 
21
22
  def getresolvecontext(self):
22
23
  return self
23
24
 
24
25
  def resolvableornone(self, key):
25
- return self.leafscope().resolvableornone(key)
26
-
27
- def resolved(self, *path):
28
- return self.resolvedimpl(path) if path else self.leafscope()
26
+ return self.resolved().resolvableornone(key)
29
27
 
30
28
  def staticscope(self):
31
- return self.leafscope().staticscope()
29
+ return self.resolved().staticscope()
32
30
 
33
31
  class AnchorResolveContext(BaseResolveContext):
34
32
 
35
33
  def __init__(self, anchorscope):
36
34
  self.anchorscope = anchorscope
37
35
 
38
- def leafscope(self):
39
- return self.anchorscope
40
-
41
- def resolvedimpl(self, path):
36
+ def resolved(self, *path):
42
37
  hit = Query([], path).search(self.anchorscope)
43
38
  return hit.resolvable.resolve(ResolveContext(self.anchorscope, path, [hit.address]))
44
39
 
@@ -50,10 +45,7 @@ class ResolveContext(BaseResolveContext, Forkable):
50
45
  self.exprpath = exprpath
51
46
  self.addresses = addresses
52
47
 
53
- def leafscope(self):
54
- return Query([], self.scopepath).search(self.anchorscope).naiveresolve() if self.scopepath else self.anchorscope # XXX: Is naiveresolve correct here?
55
-
56
- def resolvedimpl(self, path):
48
+ def resolved(self, *path):
57
49
  try:
58
50
  hit = Query(self.scopepath, path).search(self.anchorscope)
59
51
  if hit.address in self.addresses: # XXX: Could it be valid to resolve the same address recursively with 2 different contexts?
@@ -4,7 +4,8 @@ from .model import Directive, Function, Hole, Resolvable, Scalar, star, Stream,
4
4
  from .resolve import AnchorResolveContext
5
5
  from .search import Query
6
6
  from .stacks import IndentStack, SimpleStack, ThreadLocalResolvable
7
- from .util import NoSuchPathException, solo, UnsupportedEntryException
7
+ from .util import NoSuchPathException, UnsupportedEntryException
8
+ from foyndation import solo
8
9
  from itertools import chain
9
10
  import os, sys, threading
10
11
 
@@ -111,4 +111,4 @@ class Query:
111
111
  return hit
112
112
  if besthit is None or _lt(hit.depths, besthit.depths):
113
113
  besthit = hit
114
- raise UnparseNoSuchPathException(self.path)
114
+ raise UnparseNoSuchPathException(scope, self.path[:self.prefixlen], self.path[self.prefixlen:])
@@ -1,7 +1,7 @@
1
+ from contextlib import contextmanager
1
2
  from importlib.metadata import entry_points
2
3
  import sys
3
4
 
4
- dotpy = '.py'
5
5
  inf = float('inf')
6
6
  null_exc_info = None, None, None
7
7
 
@@ -9,9 +9,12 @@ class NoSuchPathException(Exception): pass
9
9
 
10
10
  class UnparseNoSuchPathException(NoSuchPathException):
11
11
 
12
+ @property
13
+ def path(self):
14
+ return self.args[-1]
15
+
12
16
  def __str__(self):
13
- path, = self.args
14
- return ' '.join(path)
17
+ return ' '.join(self.path)
15
18
 
16
19
  class TreeNoSuchPathException(NoSuchPathException):
17
20
 
@@ -40,11 +43,6 @@ def openresource(package_or_name, resource_name, encoding = 'ascii'):
40
43
  from .model import Resource
41
44
  return Resource(package_or_name, resource_name, encoding).open(False)
42
45
 
43
- def solo(v):
44
- 'Assert exactly one object in the given sequence and return it.'
45
- x, = v
46
- return x
47
-
48
46
  def qualname(obj):
49
47
  try:
50
48
  return obj.__qualname__
@@ -67,8 +65,19 @@ def popattr(obj, name):
67
65
  delattr(obj, name)
68
66
  return val
69
67
 
70
- class Forkable:
68
+ class Burial:
69
+
70
+ name = 'burial'
71
71
 
72
72
  @classmethod
73
- def _of(cls, *args, **kwargs):
74
- return cls(*args, **kwargs)
73
+ def value(cls, e):
74
+ return getattr(e, cls.name, 0)
75
+
76
+ @classmethod
77
+ @contextmanager
78
+ def bumping(cls, exctype):
79
+ try:
80
+ yield
81
+ except exctype as e:
82
+ setattr(e, cls.name, cls.value(e) + 1)
83
+ raise
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: aridity
3
- Version: 94
3
+ Version: 96
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
7
7
  Author-email: shrovis@foyono.com
8
8
  Description-Content-Type: text/markdown
9
+ Requires-Dist: foyndation>=13
9
10
  Requires-Dist: pyparsing>=3.0.2
10
11
 
11
12
  # aridity
@@ -158,6 +159,17 @@ def source(prefix, suffix, scope)
158
159
 
159
160
  Include path or resource at prefix.
160
161
 
162
+ <a id="aridity.directives.sourceifexists"></a>
163
+
164
+ ###### sourceifexists
165
+
166
+ ```python
167
+ @prime
168
+ def sourceifexists(prefix, suffix, scope)
169
+ ```
170
+
171
+ Like `.` but allow the resource to be absent.
172
+
161
173
  <a id="aridity.directives.equals"></a>
162
174
 
163
175
  ###### equals
@@ -514,16 +526,6 @@ def openresource(package_or_name, resource_name, encoding='ascii')
514
526
 
515
527
  Like `pkg_resources.resource_stream` but text mode.
516
528
 
517
- <a id="aridity.util.solo"></a>
518
-
519
- ###### solo
520
-
521
- ```python
522
- def solo(v)
523
- ```
524
-
525
- Assert exactly one object in the given sequence and return it.
526
-
527
529
  <a id="parabject"></a>
528
530
 
529
531
  ### parabject
@@ -1 +1,2 @@
1
+ foyndation>=13
1
2
  pyparsing>=3.0.2
@@ -49,13 +49,13 @@ class SourceInfo:
49
49
  sourceinfo = SourceInfo('.')
50
50
  setup(
51
51
  name = 'aridity',
52
- version = '94',
52
+ version = '96',
53
53
  description = 'DRY config and template system, easily extensible with Python',
54
54
  url = 'https://pypi.org/project/aridity/',
55
55
  author = 'foyono',
56
56
  author_email = 'shrovis@foyono.com',
57
57
  py_modules = ['parabject'],
58
- install_requires = ['pyparsing>=3.0.2'],
58
+ install_requires = ['foyndation>=13', 'pyparsing>=3.0.2'],
59
59
  package_data = {'': ['*.pxd', '*.pyx', '*.pyxbld', '*.arid', '*.aridt']},
60
60
  entry_points = {'console_scripts': ['aridity=aridity.__init__:main', 'arid-config=aridity.arid_config:main', 'processtemplate=aridity.processtemplate:main']},
61
61
  **sourceinfo.setup_kwargs(),
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