Skip to content

Commit

Permalink
Add T6: Implementation for F.template
Browse files Browse the repository at this point in the history
Refactor bit on T4: Refactor built-in features
Implement T3: simpleeval options
Update readme
  • Loading branch information
kororo committed Jun 5, 2018
1 parent 94ca122 commit dad09b9
Show file tree
Hide file tree
Showing 12 changed files with 253 additions and 122 deletions.
156 changes: 95 additions & 61 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,18 @@ This project inspired of the necessity complex config in a project. By means com
- Flexible

- Make logical expression to derive values
- Combine with `jinja2 <http://jinja.pocoo.org/docs/2.10/>`_ template based

- Powerful

- Add custom functions in Python
- Link name data from Python

Feedback and Discussion
-----------------------

Come to Gitter channel to discuss, pass any feedbacks and suggestions. If you like to be contributor, please do let me know.

Important Notes
---------------

Expand Down Expand Up @@ -73,21 +79,37 @@ Basic Usage

To get very basic parsing:

Simple parse
^^^^^^^^^^^^

.. code:: python
import conff
p = conff.Parser()
r = p.parse_dict({'math': '1 + 3'})
r == {'math': 4}
r = p.parse({'math': '1 + 3'})
assert r == {'math': 4}
load YAML file
Load YAML file
^^^^^^^^^^^^^^

.. code:: python
import conff
p = conff.Parser()
r = p.parse_file('path_of_file.yaml')
r = p.load('path_of_file.yml')
Template based config
^^^^^^^^^^^^^^^^^^^^^

Using `jinja2 <http://jinja.pocoo.org/docs/2.10/>`_ to craft more powerful config.

.. code:: python
import conff
p = conff.Parser()
r = p.parse('F.template("{{ 1 + 2 }}")')
assert r == 3
Examples
--------
Expand All @@ -99,115 +121,123 @@ Parse with simple expression

.. code:: python
import conff
r = conff.parse('1 + 2')
r = 3
import conff
p = conff.Parser()
r = p.parse('1 + 2')
assert r == 3
Parse object
^^^^^^^^^^^^

.. code:: python
import conff
r = conff.parse({"math": "1 + 2"})
r = {'math': 3}
import conff
p = conff.Parser()
r = p.parse({"math": "1 + 2"})
assert r == {'math': 3}
Ignore expression (declare it as string)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code:: python
import conff
r = conff.parse('"1 + 2"')
r = '1 + 2'
import conff
p = conff.Parser()
r = conff.parse('"1 + 2"')
assert r == '1 + 2'
Parse error behaviours
^^^^^^^^^^^^^^^^^^^^^^

.. code:: python
import conff
errors = []
r = conff.parse({"math": "1 / 0"}, errors=errors)
r = {'math': '1 / 0'}
errors = [['1 / 0', ZeroDivisionError('division by zero',)]]
import conff
p = conff.Parser()
r = p.parse({'math': '1 / 0'})
# Exception raised
# ZeroDivisionError: division by zero
import files
^^^^^^^^^^^^

.. code:: python
import conff
## y1.yml
# shared_conf: 1
## y2.yml
# conf: F.inc('y1.yml')
import conff
## y1.yml
# shared_conf: 1
## y2.yml
# conf: F.inc('y1.yml')
r = conff.load('y2.yml')
r = {'conf': {'shared_conf': 1}}
p = conff.Parser()
r = p.load('y2.yml')
assert r == {'conf': {'shared_conf': 1}}
Parse with functions
^^^^^^^^^^^^^^^^^^^^

.. code:: python
import conff
def fn_add(a, b):
return a + b
r = conff.parse('F.add(1, 2)', fns={'add': fn_add})
r = 3
import conff
def fn_add(a, b):
return a + b
p = conff.Parser(fns={'add': fn_add})
r = p.parse('F.add(1, 2)')
assert r == 3
Parse with names
^^^^^^^^^^^^^^^^

.. code:: python
import conff
r = conff.parse('a + b', names={'a': 1, 'b': 2})
r = 3
import conff
p = conff.Parser(names={'a': 1, 'b': 2})
r = conff.parse('a + b')
assert r == 3
Parse with extends
^^^^^^^^^^^^^^^^^^

.. code:: python
import conff
data = {
import conff
data = {
't1': {'a': 'a'},
't2': {
'F.extend': 'R.t1',
'b': 'b'
}
}
r = conff.parse(data)
r = {'t1': {'a': 'a'}, 't2': {'a': 'a', 'b': 'b'}}
}
p = conff.Parser()
r = p.parse(data)
assert r == {'t1': {'a': 'a'}, 't2': {'a': 'a', 'b': 'b'}}
Parse with updates
^^^^^^^^^^^^^^^^^^

.. code:: python
import conff
data = {
import conff
data = {
't1': {'a': 'a'},
't2': {
'b': 'b',
'F.update': {
'c': 'c'
},
}
}
r = conff.parse(data)
r = {'t1': {'a': 'a'}, 't2': {'b': 'b', 'c': 'c'}}
}
p = conff.Parser()
r = p.parse(data)
assert r == {'t1': {'a': 'a'}, 't2': {'b': 'b', 'c': 'c'}}
Parse with extends and updates
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code:: python
import conff
data = {
import conff
data = {
't1': {'a': 'a'},
't2': {
'F.extend': 'R.t1',
Expand All @@ -217,31 +247,34 @@ Parse with extends and updates
'c': 'c'
},
}
}
r = conff.parse(data)
r = {'t1': {'a': 'a'}, 't2': {'a': 'A', 'b': 'b', 'c': 'c'}}
}
p = conff.Parser()
r = p.parse(data)
assert r == {'t1': {'a': 'a'}, 't2': {'a': 'A', 'b': 'b', 'c': 'c'}}
Create a list of Values
Create a list of values
^^^^^^^^^^^^^^^^^^^^^^^

This creates a list of floats, similar to numpy.linspace

.. code:: python
import conff
data = {'t2': 'F.linspace(0, 10, 5)'}
r = conff.parse(data)
r = {'t2': [0.0, 2.5, 5.0, 7.5, 10.0]}
import conff
data = {'t2': 'F.linspace(0, 10, 5)'}
p = conff.Parser()
r = p.parse(data)
assert r == {'t2': [0.0, 2.5, 5.0, 7.5, 10.0]}
This also creates a list of floats, but behaves like numpy.arange (although
slightly different in that it is inclusive of the endpoint).

.. code:: python
import conff
data = {'t2': 'F.arange(0, 10, 2)'}
r = conff.parse(data)
r = {'t2': [0, 2, 4, 6, 8, 10]}
import conff
data = {'t2': 'F.arange(0, 10, 2)'}
p = conff.Parser()
r = p.parse(data)
assert r == {'t2': [0, 2, 4, 6, 8, 10]}
Parse with for each
^^^^^^^^^^^^^^^^^^^
Expand All @@ -250,8 +283,8 @@ One can mimic the logic of a for loop with the following example

.. code:: python
import conff
data = {'t1': 2,
import conff
data = {'t1': 2,
'F.foreach': {
'values': 'F.linspace(0, 10, 2)',
# You have access to loop.index, loop.value, and loop.length
Expand All @@ -262,8 +295,9 @@ One can mimic the logic of a for loop with the following example
}
}
}
r = conff.parse(data)
r = {'length': 3, 't1': 2, 'test0': 0.0, 'test1': 10.0, 'test2': 20.0}
p = conff.Parser()
r = p.parse(data)
assert r == {'length': 3, 't1': 2, 'test0': 0.0, 'test1': 10.0, 'test2': 20.0}
Encryption
----------
Expand Down
4 changes: 4 additions & 0 deletions conff/data/test_config_01.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"test_1": 1,
"test_2": "1 + 1"
}
32 changes: 32 additions & 0 deletions conff/data/test_config_05.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# test: simple value
test_1: 1
# test: template as string, it is seamless names from input (test) and template (test_1)
test_2:
F.template: "'{{ R.test_1 + test }}'"
# test: template as file (borrowing F.inc capabilities), if test_tpl_01.tpl is {{1 + 2}}
test_3:
F.template: F.inc('test_tpl_01.tpl')
# test: this where attaching more complex object
test_4:
test_4_0: [3, 4]
F.template: |
test_4_1: {{ R.test_1 }}
test_4_2: {{ 1 + 1 }}
{% for i in R.test_4.test_4_0 %}
test_4_{{ i }}: {{ i }}
{% endfor %}
# data type is very important here
test_4_5: {{ R.test_2 | int + R.test_3 | int }}
{% if R.test_1 == 1 %}
test_4_6: 6
{% else %}
test_4_6: 'error'
{% endif %}
# test behaviour of replace
test_4_1: 'error'
# TODO: test this
# test_5:
# F.template: "{{ }}"
# TODO: test this
# test_6:
# F.template: "{{ "
1 change: 1 addition & 0 deletions conff/data/test_tpl_01.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{1 + 2}}
27 changes: 14 additions & 13 deletions conff/ee.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,27 @@

def parse(root, names: dict = None, fns: dict = None, errors: list = None):
from conff import Parser
parser = Parser(names=names, fns=fns)
if isinstance(root, str):
result = parser.parse_expr(root)
else:
result = parser.parse_dict(root)
p = Parser(names=names, fns=fns)
result = p.parse(root)
errors = errors or []
errors.extend(p.errors)
return result


def load(fs_path: str, fs_root: str = '', params: dict = None, errors: list = None):
from conff import Parser
parser = Parser(params=params)
result = parser.parse_file(fs_path=fs_path, fs_root=fs_root)
p = Parser(params=params)
result = p.load(fs_path=fs_path, fs_root=fs_root)
errors = errors or []
errors.extend(p.errors)
return result


def encrypt(names: dict):
def fn_encrypt(data):
from conff import Parser
parser = Parser(names=names, params=names.get('R', {}).get('_', {}))
result = parser.fn_encrypt(data)
p = Parser(names=names, params=names.get('R', {}).get('_', {}))
result = p.fn_encrypt(data)
return result

return fn_encrypt
Expand All @@ -31,8 +32,8 @@ def fn_encrypt(data):
def decrypt(names: dict):
def fn_decrypt(data):
from conff import Parser
parser = Parser(names=names, params=names.get('R', {}).get('_', {}))
result = parser.fn_decrypt(data)
p = Parser(names=names, params=names.get('R', {}).get('_', {}))
result = p.fn_decrypt(data)
return result

return fn_decrypt
Expand All @@ -41,8 +42,8 @@ def fn_decrypt(data):
def generate_key(names: dict):
def fn_generate_key():
from conff import Parser
parser = Parser(names=names, params=names.get('R', {}).get('_', {}))
result = parser.generate_crypto_key()
p = Parser(names=names, params=names.get('R', {}).get('_', {}))
result = p.generate_crypto_key()
return result

return fn_generate_key
Loading

0 comments on commit dad09b9

Please sign in to comment.