diff options
author | CoprDistGit <infra@openeuler.org> | 2023-05-31 06:54:53 +0000 |
---|---|---|
committer | CoprDistGit <infra@openeuler.org> | 2023-05-31 06:54:53 +0000 |
commit | 87c6915bcdc97421ef3eaa957411b39ed5e0c017 (patch) | |
tree | c15451ace47c6b7282d2444ac617983820546c7c | |
parent | bd23735c9ff7162173043f3511aa3bcdcac8a87a (diff) |
automatic import of python-dotted-notation
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | python-dotted-notation.spec | 1053 | ||||
-rw-r--r-- | sources | 1 |
3 files changed, 1055 insertions, 0 deletions
@@ -0,0 +1 @@ +/dotted-notation-0.10.0.tar.gz diff --git a/python-dotted-notation.spec b/python-dotted-notation.spec new file mode 100644 index 0000000..caf11bd --- /dev/null +++ b/python-dotted-notation.spec @@ -0,0 +1,1053 @@ +%global _empty_manifest_terminate_build 0 +Name: python-dotted-notation +Version: 0.10.0 +Release: 1 +Summary: Dotted notation parser with pattern matching +License: MIT license +URL: https://github.com/freywaid/dotted +Source0: https://mirrors.nju.edu.cn/pypi/web/packages/7e/f3/9493a7a026fed3bc3f166dca5c625de180088ec8d1e3135f429d00cc8c4a/dotted-notation-0.10.0.tar.gz +BuildArch: noarch + + +%description +# Dotted + +Sometimes you want to fetch data from a deeply nested data structure. Dotted notation +helps you do that. + +Let's say you have a dictionary containing a dictionary containing a list and you wish +to fetch the ith value from that nested list. + + >>> import dotted + >>> d = {'hi': {'there': [1, 2, 3]}} + >>> dotted.get(d, 'hi.there[1]') + 2 + +## API + +Probably the easiest thing to do is pydoc the api layer. + + $ pydoc dotted.api + +### Get + +See grammar discussion below about things you can do get data via dotted. + + >>> import dotted + >>> dotted.get({'a': {'b': {'c': {'d': 'nested'}}}}, 'a.b.c.d') + 'nested' + +### Update + +Update will mutate the object if it can. It always returns the changed object though. If +it's not mutable, then get via the return. + + >>> import dotted + >>> l = [] + >>> t = () + >>> dotted.update(l, '[0]', 'hello') + ['hello'] + >>> l + ['hello'] + >>> dotted.update(t, '[0]', 'hello') + ('hello',) + >>> t + () + ``` +#### Update via pattern + +You can update all fields that match pattern given by either a wildcard OR regex. + + >>> import dotted + >>> d = {'a': 'hello', 'b': {'bye'}} + >>> dotted.update(d, '*', 'me') + {'a': 'me', 'b': 'me'} + +### Remove + +You can remove a field or do so only if it matches value. For example, + + >>> import dotted + >>> d = {'a': 'hello', 'b': 'bye'} + >>> dotted.remove(d, 'b') + {'a': 'hello'} + >>> dotted.remove(d, 'a', 'bye') + {'a': 'hello'} + +#### Remove via pattern + +Similar to update, all patterns that match will be removed. If you provide a value as +well, only the matched patterns that also match the value will be removed. + +### Match + +Use to match a dotted-style pattern to a field. Partial matching is on by default. You +can match via wildcard OR via regex. Here's a regex example: + + >>> import dotted + >>> dotted.match('/a.+/', 'abced.b') + 'abced.b' + >>> dotted.match('/a.+/', 'abced.b', partial=False) + +With the `groups=True` parameter, you'll see how it was matched: + + >>> import dotted + >>> match('hello.*', 'hello.there.bye', groups=True) + ('hello.there.bye', ('hello', 'there.bye')) + +In the above example, `hello` matched to `hello` and `*` matched to `there.bye` (partial +matching is enabled by default). + +### Expand + +You may wish to _expand_ all fields that match a pattern in an object. + + >>> import dotted + >>> d = {'hello': {'there': [1, 2, 3]}, 'bye': 7} + >>> dotted.expand(d, '*') + ('hello', 'bye') + >>> dotted.expand(d, '*.*') + ('hello.there',) + >>> dptted.expand(d, '*.*[*]') + ('hello.there[0]', 'hello.there[1]', 'hello.there[2]') + >>> dotted.expand(d, '*.*[1:]') + ('hello.there[1:]',) + +## Grammar + +Dotted notation looks similar to python. Both _dot_ fields and _bracketed_ fields +use `keys()` and `__getitem__()` internally. A _dot_ field expects to see a +dictionary-like object. A _slot_ field is biased towards sequences (like lists, tuples, +and strs) but can act on dicts as well. Dotted also supports slicing notation as well as +transforms discussed below. + +### Key fields + +A key field is expressed as `a` or part of a dotted expression, such as `a.b`. The +grammar parser is permissive for what can be in a key field. Pretty much any non-reserved +char will match. Note that key fields will only work on objects that have a `keys()` +method. Basically, they work with dictionary or dictionary-like objects. + + >>> import dotted + >>> dotted.get({'a': {'b': 'hello'}}, 'a.b') + 'hello' + +If the key field starts with a space or `-`, you should either quote it OR you may use +a `\` as the first char. + +### Bracketed fields + +You may also use bracket notation, such as `a[0]` which does a `__getitem__` at key 0. +The parser prefers numeric types over string types (if you wish to look up a non-numeric +field using brackets be sure to quote it). Bracketed fields will work with pretty much +any object that can be looked up via `__getitem__`. + + >>> import dotted + >>> dotted.get({'a': ['first', 'second', 'third']}, 'a[0]') + 'first' + >>> dotted.get({'a': {'b': 'hello'}}, 'a["b"]') + 'first' + +### Numeric types + +The parser will attempt to interpret a field numerically if it can, such as `field.1` +will interpret the `1` part numerically. + + >>> import dotted + >>> dotted.get({'7': 'me', 7: 'you'}, '7') + 'you' + +### Quoting + +Sometimes you need to quote a field which you can do by just putting the field in quotes. + + >>> import dotted + >>> dotted.get({'has . in it': 7}, '"has . in it"') + 7 + +### The numericize `#` operator + +Non-integer numeric fields may be interpreted incorrectly if they have decimal point. To +solve, use the numerize operator `#` at the front of a quoted field, such as `#'123.45'`. +This will coerce to a numeric type (e.g. float). + + >>> import dotted + >>> d = {'a': {1.2: 'hello', 1: {2: 'fooled you'}}} + >>> dotted.get(d, 'a.1.2') + 'fooled you' + >>> dotted.get(d, 'a.#"1.2"') + 'hello' + +### Slicing + +Dotted slicing works like python slicing and all that entails. + + >>> import dotted + >>> d = {'hi': {'there': [1, 2, 3]}, 'bye': {'there': [4, 5, 6]}} + >>> dotted.get(d, 'hi.there[::2]') + [1, 3] + >>> dotted.get(d, '*.there[1:]') + ([2, 3], [5, 6]) + +### The append `+` operator + +Both bracketed fileds and slices support the '+' operator which refers to the end of +sequence. You may append an item or slice to the end a sequence. + + >>> import dotted + >>> d = {'hi': {'there': [1, 2, 3]}, 'bye': {'there': [4, 5, 6]}} + >>> dotted.update(d, '*.there[+]', 8) + {'hi': {'there': [1, 2, 3, 8]}, 'bye': {'there': [4, 5, 6, 8]}} + >>> dotted.update(d, '*.there[+:]', [999]) + {'hi': {'there': [1, 2, 3, 8, 999]}, 'bye': {'there': [4, 5, 6, 8, 999]}} + +### The append-unique `+?` operator + +If you want to update only _unique_ items to a list, you can use the `?` +postfix. This will ensure that it's only added once (see match-first below). + + >>> import dotted + >>> items = [1, 2] + >>> dotted.update(items, '[+?]', 3) + [1, 2, 3] + >>> dotted.update(items, '[+?]', 3) + [1, 2, 3] + +### The invert `-` operator + +You can invert the meaning of the notation by prefixing a `-`. For example, +to remove an item using `update`: + + >>> import dotted + >>> d = {'a': 'hello', 'b': 'bye'} + >>> dotted.update(d, '-b', dotted.ANY) + {'a': 'hello'} + >>> dotted.remove(d, '-b', 'bye again') + {'a': 'hello', 'b': 'bye again'} + +## Patterns + +You may use dotted for pattern matching. You can match to wildcards or regular +expressions. You'll note that patterns always return a tuple of matches. + + >>> import dotted + >>> d = {'hi': {'there': [1, 2, 3]}, 'bye': {'there': [4, 5, 6]}} + >>> dotted.get(d, '*.there[2]') + (3, 6) + >>> dotted.get(d, '/h.*/.*') + ([1, 2, 3],) + +Dotted will return all values that match the pattern(s). + +### Wildcards + +The wildcard pattern is `*`. It will match anything. + +### Regular expressions + +The regex pattern is enclosed in slashes: `/regex/`. Note that if the field is a non-str, +the regex pattern will internally match to its str representation. + +### The match-first operatoer + +You can also postfix any pattern with a `?`. This will return only +the first match. + + >>> import dotted + >>> d = {'hi': {'there': [1, 2, 3]}, 'bye': {'there': [4, 5, 6]}} + >>> dotted.get(d, '*?.there[2]') + (3,) + +## Transforms + +You can optionally add transforms to the end of dotted notation. These will +be applied on `get` and `update`. Transforms are separated by the `|` operator +and multiple may be chained together. Transforms may be parameterized using +the `:` operator. + + >>> import dotted + >>> d = [1, '2', 3] + >>> dotted.get(d, '[1]') + '2' + >>> dotted.get(d, '[1]|int') + 2 + >>> dotted.get(d, '[0]|str:number=%d') + 'number=1' + +You may register new transforms via either `register` or the `@transform` +decorator. Look at transforms.py for preregistered. + +## Filters + +### The key-value filter + +You may filter by key-value to narrow your result set. You may use with __key__ or +__bracketed__ fields. Key-value fields may be disjunctively (OR) specified via the `,` +delimiter. + +A key-value field on __key__ field looks like: `keyfield.key1=value1,key2=value2...`. +This will return all key-value matches on a subordinate dict-like object. For example, + + >>> d = { + ... 'a': { + ... 'id': 1, + ... 'hello': 'there', + ... }, + ... 'b': { + ... 'id': 2, + ... 'hello': 'there', + ... }, + ... } + >>> dotted.get(d, '*.id=1') + ({'id': 1, 'hello': 'there'},) + >>> dotted.get(d, '*.id=*') + ({'id': 1, 'hello': 'there'}, {'id': 2, 'hello': 'there'}) + +A key-value field on a __bracketed__ field looks like: `[key1=value1,key2=value2...]`. +This will return all items in a list that match key-value filter. For example, + + >>> d = { + ... 'a': [{'id': 1, 'hello': 'there'}, {'id': 2, 'hello': 'there'}], + ... 'b': [{'id': 3, 'hello': 'there'}, {'id': 4, 'hello': 'bye'}], + ... } + >>> dotted.get(d, 'a[hello="there"][*].id') + (1, 2) + >>> dotted.get(d, '*[hello="there"][*].id') + r == (1, 2, 3) + +### The key-value first filter + +You can have it match first by appending a `?` to the end of the filter. + + >>> d = { + ... 'a': [{'id': 1, 'hello': 'there'}, {'id': 2, 'hello': 'there'}], + ... 'b': [{'id': 3, 'hello': 'there'}, {'id': 4, 'hello': 'bye'}], + ... } + >>> dotted.get(d, 'a[hello="there"?]') + return [{'id': 1, 'hello': 'there'}] + +### Conjunction vs disjunction + +To _conjunctively_ connect filters use the `.` operator. Filters offer the ability to act +_disjunctively_ as well by using the `,` operator. + +For example, given +`*.key1=value1,key2=value2.key3=value3`. This will filter +(`key1=value1` OR `key2=value2`) AND `key3=value3`. + +Note that this gives you the abilty to have a key filter multiple values, such as: +`*.key1=value1,key2=value2`. + + +%package -n python3-dotted-notation +Summary: Dotted notation parser with pattern matching +Provides: python-dotted-notation +BuildRequires: python3-devel +BuildRequires: python3-setuptools +BuildRequires: python3-pip +%description -n python3-dotted-notation +# Dotted + +Sometimes you want to fetch data from a deeply nested data structure. Dotted notation +helps you do that. + +Let's say you have a dictionary containing a dictionary containing a list and you wish +to fetch the ith value from that nested list. + + >>> import dotted + >>> d = {'hi': {'there': [1, 2, 3]}} + >>> dotted.get(d, 'hi.there[1]') + 2 + +## API + +Probably the easiest thing to do is pydoc the api layer. + + $ pydoc dotted.api + +### Get + +See grammar discussion below about things you can do get data via dotted. + + >>> import dotted + >>> dotted.get({'a': {'b': {'c': {'d': 'nested'}}}}, 'a.b.c.d') + 'nested' + +### Update + +Update will mutate the object if it can. It always returns the changed object though. If +it's not mutable, then get via the return. + + >>> import dotted + >>> l = [] + >>> t = () + >>> dotted.update(l, '[0]', 'hello') + ['hello'] + >>> l + ['hello'] + >>> dotted.update(t, '[0]', 'hello') + ('hello',) + >>> t + () + ``` +#### Update via pattern + +You can update all fields that match pattern given by either a wildcard OR regex. + + >>> import dotted + >>> d = {'a': 'hello', 'b': {'bye'}} + >>> dotted.update(d, '*', 'me') + {'a': 'me', 'b': 'me'} + +### Remove + +You can remove a field or do so only if it matches value. For example, + + >>> import dotted + >>> d = {'a': 'hello', 'b': 'bye'} + >>> dotted.remove(d, 'b') + {'a': 'hello'} + >>> dotted.remove(d, 'a', 'bye') + {'a': 'hello'} + +#### Remove via pattern + +Similar to update, all patterns that match will be removed. If you provide a value as +well, only the matched patterns that also match the value will be removed. + +### Match + +Use to match a dotted-style pattern to a field. Partial matching is on by default. You +can match via wildcard OR via regex. Here's a regex example: + + >>> import dotted + >>> dotted.match('/a.+/', 'abced.b') + 'abced.b' + >>> dotted.match('/a.+/', 'abced.b', partial=False) + +With the `groups=True` parameter, you'll see how it was matched: + + >>> import dotted + >>> match('hello.*', 'hello.there.bye', groups=True) + ('hello.there.bye', ('hello', 'there.bye')) + +In the above example, `hello` matched to `hello` and `*` matched to `there.bye` (partial +matching is enabled by default). + +### Expand + +You may wish to _expand_ all fields that match a pattern in an object. + + >>> import dotted + >>> d = {'hello': {'there': [1, 2, 3]}, 'bye': 7} + >>> dotted.expand(d, '*') + ('hello', 'bye') + >>> dotted.expand(d, '*.*') + ('hello.there',) + >>> dptted.expand(d, '*.*[*]') + ('hello.there[0]', 'hello.there[1]', 'hello.there[2]') + >>> dotted.expand(d, '*.*[1:]') + ('hello.there[1:]',) + +## Grammar + +Dotted notation looks similar to python. Both _dot_ fields and _bracketed_ fields +use `keys()` and `__getitem__()` internally. A _dot_ field expects to see a +dictionary-like object. A _slot_ field is biased towards sequences (like lists, tuples, +and strs) but can act on dicts as well. Dotted also supports slicing notation as well as +transforms discussed below. + +### Key fields + +A key field is expressed as `a` or part of a dotted expression, such as `a.b`. The +grammar parser is permissive for what can be in a key field. Pretty much any non-reserved +char will match. Note that key fields will only work on objects that have a `keys()` +method. Basically, they work with dictionary or dictionary-like objects. + + >>> import dotted + >>> dotted.get({'a': {'b': 'hello'}}, 'a.b') + 'hello' + +If the key field starts with a space or `-`, you should either quote it OR you may use +a `\` as the first char. + +### Bracketed fields + +You may also use bracket notation, such as `a[0]` which does a `__getitem__` at key 0. +The parser prefers numeric types over string types (if you wish to look up a non-numeric +field using brackets be sure to quote it). Bracketed fields will work with pretty much +any object that can be looked up via `__getitem__`. + + >>> import dotted + >>> dotted.get({'a': ['first', 'second', 'third']}, 'a[0]') + 'first' + >>> dotted.get({'a': {'b': 'hello'}}, 'a["b"]') + 'first' + +### Numeric types + +The parser will attempt to interpret a field numerically if it can, such as `field.1` +will interpret the `1` part numerically. + + >>> import dotted + >>> dotted.get({'7': 'me', 7: 'you'}, '7') + 'you' + +### Quoting + +Sometimes you need to quote a field which you can do by just putting the field in quotes. + + >>> import dotted + >>> dotted.get({'has . in it': 7}, '"has . in it"') + 7 + +### The numericize `#` operator + +Non-integer numeric fields may be interpreted incorrectly if they have decimal point. To +solve, use the numerize operator `#` at the front of a quoted field, such as `#'123.45'`. +This will coerce to a numeric type (e.g. float). + + >>> import dotted + >>> d = {'a': {1.2: 'hello', 1: {2: 'fooled you'}}} + >>> dotted.get(d, 'a.1.2') + 'fooled you' + >>> dotted.get(d, 'a.#"1.2"') + 'hello' + +### Slicing + +Dotted slicing works like python slicing and all that entails. + + >>> import dotted + >>> d = {'hi': {'there': [1, 2, 3]}, 'bye': {'there': [4, 5, 6]}} + >>> dotted.get(d, 'hi.there[::2]') + [1, 3] + >>> dotted.get(d, '*.there[1:]') + ([2, 3], [5, 6]) + +### The append `+` operator + +Both bracketed fileds and slices support the '+' operator which refers to the end of +sequence. You may append an item or slice to the end a sequence. + + >>> import dotted + >>> d = {'hi': {'there': [1, 2, 3]}, 'bye': {'there': [4, 5, 6]}} + >>> dotted.update(d, '*.there[+]', 8) + {'hi': {'there': [1, 2, 3, 8]}, 'bye': {'there': [4, 5, 6, 8]}} + >>> dotted.update(d, '*.there[+:]', [999]) + {'hi': {'there': [1, 2, 3, 8, 999]}, 'bye': {'there': [4, 5, 6, 8, 999]}} + +### The append-unique `+?` operator + +If you want to update only _unique_ items to a list, you can use the `?` +postfix. This will ensure that it's only added once (see match-first below). + + >>> import dotted + >>> items = [1, 2] + >>> dotted.update(items, '[+?]', 3) + [1, 2, 3] + >>> dotted.update(items, '[+?]', 3) + [1, 2, 3] + +### The invert `-` operator + +You can invert the meaning of the notation by prefixing a `-`. For example, +to remove an item using `update`: + + >>> import dotted + >>> d = {'a': 'hello', 'b': 'bye'} + >>> dotted.update(d, '-b', dotted.ANY) + {'a': 'hello'} + >>> dotted.remove(d, '-b', 'bye again') + {'a': 'hello', 'b': 'bye again'} + +## Patterns + +You may use dotted for pattern matching. You can match to wildcards or regular +expressions. You'll note that patterns always return a tuple of matches. + + >>> import dotted + >>> d = {'hi': {'there': [1, 2, 3]}, 'bye': {'there': [4, 5, 6]}} + >>> dotted.get(d, '*.there[2]') + (3, 6) + >>> dotted.get(d, '/h.*/.*') + ([1, 2, 3],) + +Dotted will return all values that match the pattern(s). + +### Wildcards + +The wildcard pattern is `*`. It will match anything. + +### Regular expressions + +The regex pattern is enclosed in slashes: `/regex/`. Note that if the field is a non-str, +the regex pattern will internally match to its str representation. + +### The match-first operatoer + +You can also postfix any pattern with a `?`. This will return only +the first match. + + >>> import dotted + >>> d = {'hi': {'there': [1, 2, 3]}, 'bye': {'there': [4, 5, 6]}} + >>> dotted.get(d, '*?.there[2]') + (3,) + +## Transforms + +You can optionally add transforms to the end of dotted notation. These will +be applied on `get` and `update`. Transforms are separated by the `|` operator +and multiple may be chained together. Transforms may be parameterized using +the `:` operator. + + >>> import dotted + >>> d = [1, '2', 3] + >>> dotted.get(d, '[1]') + '2' + >>> dotted.get(d, '[1]|int') + 2 + >>> dotted.get(d, '[0]|str:number=%d') + 'number=1' + +You may register new transforms via either `register` or the `@transform` +decorator. Look at transforms.py for preregistered. + +## Filters + +### The key-value filter + +You may filter by key-value to narrow your result set. You may use with __key__ or +__bracketed__ fields. Key-value fields may be disjunctively (OR) specified via the `,` +delimiter. + +A key-value field on __key__ field looks like: `keyfield.key1=value1,key2=value2...`. +This will return all key-value matches on a subordinate dict-like object. For example, + + >>> d = { + ... 'a': { + ... 'id': 1, + ... 'hello': 'there', + ... }, + ... 'b': { + ... 'id': 2, + ... 'hello': 'there', + ... }, + ... } + >>> dotted.get(d, '*.id=1') + ({'id': 1, 'hello': 'there'},) + >>> dotted.get(d, '*.id=*') + ({'id': 1, 'hello': 'there'}, {'id': 2, 'hello': 'there'}) + +A key-value field on a __bracketed__ field looks like: `[key1=value1,key2=value2...]`. +This will return all items in a list that match key-value filter. For example, + + >>> d = { + ... 'a': [{'id': 1, 'hello': 'there'}, {'id': 2, 'hello': 'there'}], + ... 'b': [{'id': 3, 'hello': 'there'}, {'id': 4, 'hello': 'bye'}], + ... } + >>> dotted.get(d, 'a[hello="there"][*].id') + (1, 2) + >>> dotted.get(d, '*[hello="there"][*].id') + r == (1, 2, 3) + +### The key-value first filter + +You can have it match first by appending a `?` to the end of the filter. + + >>> d = { + ... 'a': [{'id': 1, 'hello': 'there'}, {'id': 2, 'hello': 'there'}], + ... 'b': [{'id': 3, 'hello': 'there'}, {'id': 4, 'hello': 'bye'}], + ... } + >>> dotted.get(d, 'a[hello="there"?]') + return [{'id': 1, 'hello': 'there'}] + +### Conjunction vs disjunction + +To _conjunctively_ connect filters use the `.` operator. Filters offer the ability to act +_disjunctively_ as well by using the `,` operator. + +For example, given +`*.key1=value1,key2=value2.key3=value3`. This will filter +(`key1=value1` OR `key2=value2`) AND `key3=value3`. + +Note that this gives you the abilty to have a key filter multiple values, such as: +`*.key1=value1,key2=value2`. + + +%package help +Summary: Development documents and examples for dotted-notation +Provides: python3-dotted-notation-doc +%description help +# Dotted + +Sometimes you want to fetch data from a deeply nested data structure. Dotted notation +helps you do that. + +Let's say you have a dictionary containing a dictionary containing a list and you wish +to fetch the ith value from that nested list. + + >>> import dotted + >>> d = {'hi': {'there': [1, 2, 3]}} + >>> dotted.get(d, 'hi.there[1]') + 2 + +## API + +Probably the easiest thing to do is pydoc the api layer. + + $ pydoc dotted.api + +### Get + +See grammar discussion below about things you can do get data via dotted. + + >>> import dotted + >>> dotted.get({'a': {'b': {'c': {'d': 'nested'}}}}, 'a.b.c.d') + 'nested' + +### Update + +Update will mutate the object if it can. It always returns the changed object though. If +it's not mutable, then get via the return. + + >>> import dotted + >>> l = [] + >>> t = () + >>> dotted.update(l, '[0]', 'hello') + ['hello'] + >>> l + ['hello'] + >>> dotted.update(t, '[0]', 'hello') + ('hello',) + >>> t + () + ``` +#### Update via pattern + +You can update all fields that match pattern given by either a wildcard OR regex. + + >>> import dotted + >>> d = {'a': 'hello', 'b': {'bye'}} + >>> dotted.update(d, '*', 'me') + {'a': 'me', 'b': 'me'} + +### Remove + +You can remove a field or do so only if it matches value. For example, + + >>> import dotted + >>> d = {'a': 'hello', 'b': 'bye'} + >>> dotted.remove(d, 'b') + {'a': 'hello'} + >>> dotted.remove(d, 'a', 'bye') + {'a': 'hello'} + +#### Remove via pattern + +Similar to update, all patterns that match will be removed. If you provide a value as +well, only the matched patterns that also match the value will be removed. + +### Match + +Use to match a dotted-style pattern to a field. Partial matching is on by default. You +can match via wildcard OR via regex. Here's a regex example: + + >>> import dotted + >>> dotted.match('/a.+/', 'abced.b') + 'abced.b' + >>> dotted.match('/a.+/', 'abced.b', partial=False) + +With the `groups=True` parameter, you'll see how it was matched: + + >>> import dotted + >>> match('hello.*', 'hello.there.bye', groups=True) + ('hello.there.bye', ('hello', 'there.bye')) + +In the above example, `hello` matched to `hello` and `*` matched to `there.bye` (partial +matching is enabled by default). + +### Expand + +You may wish to _expand_ all fields that match a pattern in an object. + + >>> import dotted + >>> d = {'hello': {'there': [1, 2, 3]}, 'bye': 7} + >>> dotted.expand(d, '*') + ('hello', 'bye') + >>> dotted.expand(d, '*.*') + ('hello.there',) + >>> dptted.expand(d, '*.*[*]') + ('hello.there[0]', 'hello.there[1]', 'hello.there[2]') + >>> dotted.expand(d, '*.*[1:]') + ('hello.there[1:]',) + +## Grammar + +Dotted notation looks similar to python. Both _dot_ fields and _bracketed_ fields +use `keys()` and `__getitem__()` internally. A _dot_ field expects to see a +dictionary-like object. A _slot_ field is biased towards sequences (like lists, tuples, +and strs) but can act on dicts as well. Dotted also supports slicing notation as well as +transforms discussed below. + +### Key fields + +A key field is expressed as `a` or part of a dotted expression, such as `a.b`. The +grammar parser is permissive for what can be in a key field. Pretty much any non-reserved +char will match. Note that key fields will only work on objects that have a `keys()` +method. Basically, they work with dictionary or dictionary-like objects. + + >>> import dotted + >>> dotted.get({'a': {'b': 'hello'}}, 'a.b') + 'hello' + +If the key field starts with a space or `-`, you should either quote it OR you may use +a `\` as the first char. + +### Bracketed fields + +You may also use bracket notation, such as `a[0]` which does a `__getitem__` at key 0. +The parser prefers numeric types over string types (if you wish to look up a non-numeric +field using brackets be sure to quote it). Bracketed fields will work with pretty much +any object that can be looked up via `__getitem__`. + + >>> import dotted + >>> dotted.get({'a': ['first', 'second', 'third']}, 'a[0]') + 'first' + >>> dotted.get({'a': {'b': 'hello'}}, 'a["b"]') + 'first' + +### Numeric types + +The parser will attempt to interpret a field numerically if it can, such as `field.1` +will interpret the `1` part numerically. + + >>> import dotted + >>> dotted.get({'7': 'me', 7: 'you'}, '7') + 'you' + +### Quoting + +Sometimes you need to quote a field which you can do by just putting the field in quotes. + + >>> import dotted + >>> dotted.get({'has . in it': 7}, '"has . in it"') + 7 + +### The numericize `#` operator + +Non-integer numeric fields may be interpreted incorrectly if they have decimal point. To +solve, use the numerize operator `#` at the front of a quoted field, such as `#'123.45'`. +This will coerce to a numeric type (e.g. float). + + >>> import dotted + >>> d = {'a': {1.2: 'hello', 1: {2: 'fooled you'}}} + >>> dotted.get(d, 'a.1.2') + 'fooled you' + >>> dotted.get(d, 'a.#"1.2"') + 'hello' + +### Slicing + +Dotted slicing works like python slicing and all that entails. + + >>> import dotted + >>> d = {'hi': {'there': [1, 2, 3]}, 'bye': {'there': [4, 5, 6]}} + >>> dotted.get(d, 'hi.there[::2]') + [1, 3] + >>> dotted.get(d, '*.there[1:]') + ([2, 3], [5, 6]) + +### The append `+` operator + +Both bracketed fileds and slices support the '+' operator which refers to the end of +sequence. You may append an item or slice to the end a sequence. + + >>> import dotted + >>> d = {'hi': {'there': [1, 2, 3]}, 'bye': {'there': [4, 5, 6]}} + >>> dotted.update(d, '*.there[+]', 8) + {'hi': {'there': [1, 2, 3, 8]}, 'bye': {'there': [4, 5, 6, 8]}} + >>> dotted.update(d, '*.there[+:]', [999]) + {'hi': {'there': [1, 2, 3, 8, 999]}, 'bye': {'there': [4, 5, 6, 8, 999]}} + +### The append-unique `+?` operator + +If you want to update only _unique_ items to a list, you can use the `?` +postfix. This will ensure that it's only added once (see match-first below). + + >>> import dotted + >>> items = [1, 2] + >>> dotted.update(items, '[+?]', 3) + [1, 2, 3] + >>> dotted.update(items, '[+?]', 3) + [1, 2, 3] + +### The invert `-` operator + +You can invert the meaning of the notation by prefixing a `-`. For example, +to remove an item using `update`: + + >>> import dotted + >>> d = {'a': 'hello', 'b': 'bye'} + >>> dotted.update(d, '-b', dotted.ANY) + {'a': 'hello'} + >>> dotted.remove(d, '-b', 'bye again') + {'a': 'hello', 'b': 'bye again'} + +## Patterns + +You may use dotted for pattern matching. You can match to wildcards or regular +expressions. You'll note that patterns always return a tuple of matches. + + >>> import dotted + >>> d = {'hi': {'there': [1, 2, 3]}, 'bye': {'there': [4, 5, 6]}} + >>> dotted.get(d, '*.there[2]') + (3, 6) + >>> dotted.get(d, '/h.*/.*') + ([1, 2, 3],) + +Dotted will return all values that match the pattern(s). + +### Wildcards + +The wildcard pattern is `*`. It will match anything. + +### Regular expressions + +The regex pattern is enclosed in slashes: `/regex/`. Note that if the field is a non-str, +the regex pattern will internally match to its str representation. + +### The match-first operatoer + +You can also postfix any pattern with a `?`. This will return only +the first match. + + >>> import dotted + >>> d = {'hi': {'there': [1, 2, 3]}, 'bye': {'there': [4, 5, 6]}} + >>> dotted.get(d, '*?.there[2]') + (3,) + +## Transforms + +You can optionally add transforms to the end of dotted notation. These will +be applied on `get` and `update`. Transforms are separated by the `|` operator +and multiple may be chained together. Transforms may be parameterized using +the `:` operator. + + >>> import dotted + >>> d = [1, '2', 3] + >>> dotted.get(d, '[1]') + '2' + >>> dotted.get(d, '[1]|int') + 2 + >>> dotted.get(d, '[0]|str:number=%d') + 'number=1' + +You may register new transforms via either `register` or the `@transform` +decorator. Look at transforms.py for preregistered. + +## Filters + +### The key-value filter + +You may filter by key-value to narrow your result set. You may use with __key__ or +__bracketed__ fields. Key-value fields may be disjunctively (OR) specified via the `,` +delimiter. + +A key-value field on __key__ field looks like: `keyfield.key1=value1,key2=value2...`. +This will return all key-value matches on a subordinate dict-like object. For example, + + >>> d = { + ... 'a': { + ... 'id': 1, + ... 'hello': 'there', + ... }, + ... 'b': { + ... 'id': 2, + ... 'hello': 'there', + ... }, + ... } + >>> dotted.get(d, '*.id=1') + ({'id': 1, 'hello': 'there'},) + >>> dotted.get(d, '*.id=*') + ({'id': 1, 'hello': 'there'}, {'id': 2, 'hello': 'there'}) + +A key-value field on a __bracketed__ field looks like: `[key1=value1,key2=value2...]`. +This will return all items in a list that match key-value filter. For example, + + >>> d = { + ... 'a': [{'id': 1, 'hello': 'there'}, {'id': 2, 'hello': 'there'}], + ... 'b': [{'id': 3, 'hello': 'there'}, {'id': 4, 'hello': 'bye'}], + ... } + >>> dotted.get(d, 'a[hello="there"][*].id') + (1, 2) + >>> dotted.get(d, '*[hello="there"][*].id') + r == (1, 2, 3) + +### The key-value first filter + +You can have it match first by appending a `?` to the end of the filter. + + >>> d = { + ... 'a': [{'id': 1, 'hello': 'there'}, {'id': 2, 'hello': 'there'}], + ... 'b': [{'id': 3, 'hello': 'there'}, {'id': 4, 'hello': 'bye'}], + ... } + >>> dotted.get(d, 'a[hello="there"?]') + return [{'id': 1, 'hello': 'there'}] + +### Conjunction vs disjunction + +To _conjunctively_ connect filters use the `.` operator. Filters offer the ability to act +_disjunctively_ as well by using the `,` operator. + +For example, given +`*.key1=value1,key2=value2.key3=value3`. This will filter +(`key1=value1` OR `key2=value2`) AND `key3=value3`. + +Note that this gives you the abilty to have a key filter multiple values, such as: +`*.key1=value1,key2=value2`. + + +%prep +%autosetup -n dotted-notation-0.10.0 + +%build +%py3_build + +%install +%py3_install +install -d -m755 %{buildroot}/%{_pkgdocdir} +if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi +if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi +if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi +if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi +pushd %{buildroot} +if [ -d usr/lib ]; then + find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/lib64 ]; then + find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/bin ]; then + find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/sbin ]; then + find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst +fi +touch doclist.lst +if [ -d usr/share/man ]; then + find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst +fi +popd +mv %{buildroot}/filelist.lst . +mv %{buildroot}/doclist.lst . + +%files -n python3-dotted-notation -f filelist.lst +%dir %{python3_sitelib}/* + +%files help -f doclist.lst +%{_docdir}/* + +%changelog +* Wed May 31 2023 Python_Bot <Python_Bot@openeuler.org> - 0.10.0-1 +- Package Spec generated @@ -0,0 +1 @@ +17bed76accda500ab2775765098f5416 dotted-notation-0.10.0.tar.gz |