Repository: maztohir/dict-path

Issue:
supporting array inside dict
date.get('foo1/foo2/0/2/foo3')

Discussion:

Patch:
diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml
new file mode 100644
index 0000000..07af7b1
--- /dev/null
+++ b/.github/workflows/cd.yml
@@ -0,0 +1,46 @@
+# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
+# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
+
+name: CD
+
+on:
+  push:
+    branches:
+      - main
+  workflow_dispatch:
+
+jobs:
+  build:
+
+    runs-on: ubuntu-latest
+    environment: production
+    steps:
+    - uses: actions/checkout@v3
+    - name: Set up Python ${{ matrix.python-version }}
+      uses: actions/setup-python@v3
+      with:
+        python-version: "3.9"
+    - name: Install dependencies
+      run: |
+        python -m pip install --upgrade pip
+        python -m pip install flake8 pytest
+        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
+    - name: Lint with flake8
+      run: |
+        # stop the build if there are Python syntax errors or undefined names
+        flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
+        # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
+        flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
+    - name: Test with pytest
+      run: |
+        pytest test*
+    - name: Build dist
+      if: github.ref == 'refs/heads/master'
+      run: |
+        python setup.py sdist bdist_wheel
+    - name: Publish to PyPI
+      if: github.ref == 'refs/heads/master'
+      uses: pypa/gh-action-pypi-publish@release/v1
+      with:
+        user: __token__
+        password: ${{ secrets.PYPI_API_TOKEN }}
\ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..e6f3719
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,40 @@
+# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
+# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
+
+name: CI
+
+on:
+  pull_request:
+    branches:
+      - main
+  workflow_dispatch:
+
+jobs:
+  build:
+
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        python-version: ["3.9", "3.10", "3.11"]
+
+    steps:
+    - uses: actions/checkout@v3
+    - name: Set up Python ${{ matrix.python-version }}
+      uses: actions/setup-python@v3
+      with:
+        python-version: ${{ matrix.python-version }}
+    - name: Install dependencies
+      run: |
+        python -m pip install --upgrade pip
+        python -m pip install flake8 pytest
+        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
+    - name: Lint with flake8
+      run: |
+        # stop the build if there are Python syntax errors or undefined names
+        flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
+        # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
+        flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
+    - name: Test with pytest
+      run: |
+        pytest test*
\ No newline at end of file
diff --git a/README.md b/README.md
index 650c73b..6b2d157 100644
--- a/README.md
+++ b/README.md
@@ -73,7 +73,7 @@ joe = DictPath(user, deepcopy=True)
 
 #### Invalid path will return None
 ```python
-from dict_path import extract_dict, inject_dict
+from dict_path import DictPath
 
 test_dict = {'foo1':{'foo2':{'foo3':{'foo4':'bar'}}}}
 data = DictPath(test_dict)
@@ -82,7 +82,7 @@ data.get('foo1/foo2/foo3/foo4/foo6')
 ```
 #### Set up unknown path will create an actual dict
 ```python
-from dict_path import extract_dict, inject_dict
+from dict_path import DictPath
 
 test_dict = {'foo1':{'foo2':{'foo3':{'foo4':'bar'}}}}
 data = DictPath(test_dict)
@@ -90,6 +90,21 @@ data.set('foo1/foo2/foo3/foo5/foo6/foo7/foo8/', 'bar1')
 data.get('foo1/foo2/foo3/foo5/foo6/foo7/foo8/')
 #result: bar1
 ```
+
+#### Its also working with array
+Note: For now its only working with get or extract_dict.
+```python
+from dict_path import extract_dict, DictPath
+
+test_dict = {'foo1':{'foo2':[{'foo3':'bar'},{'foo4':[[{'foo5': 'bar'}]]}]}}
+data = DictPath(test_dict)
+data.get('foo1/foo2/1/foo4/0/0/foo5/')
+#result: bar
+
+extract_dict(test_dict, 'foo1/foo2/1/foo4/0/0/foo5/')
+```
+
+
 ## Contributing
 Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
 
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..30aadb4
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,4 @@
+pytest==6.2.5
+twine==1.13.0
+wheel
+bump2version==1.0.1
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 820bccd..3ef3283 100644
--- a/setup.py
+++ b/setup.py
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
 
 setuptools.setup(
     name="dict-path",
-    version="1.0.1",
+    version="1.0.2",
     author="Muhamad Tohir",
     author_email="maztohir@gmail.com",
     description="Python library to work with complicated nested dict",
diff --git a/src/dict_path/__init__.py b/src/dict_path/__init__.py
index f9cfcaa..5bb26ff 100644
--- a/src/dict_path/__init__.py
+++ b/src/dict_path/__init__.py
@@ -66,11 +66,16 @@ class DictPath(UserDict):
 			return self
 		current = self.data
 		for attr in path:
-			if not isinstance(current, dict):
-				raise Exception(f"Your path is not a path of dicts (value at key {attr} is of type {type(current)})")
-			if attr not in current:
+			if isinstance(current, dict):
+				print(current, attr)
+				current = current.get(attr)
+			elif isinstance(current, list):
+				print(current, attr)
+				current = current[int(attr)]
+			elif current is None:
 				return None
-			current = current[attr]
+			else:
+				raise Exception(f"Your path is not a path of dicts (value at key {attr} is of type {type(current)})")
 		if isinstance(current, dict):
 			return DictPath(current)
 		return current
@@ -109,27 +114,30 @@ class DictPath(UserDict):
 		self.set(path, value=value)
 
 def extract_dict(dictionary, path):
-    path = path[1:] if path.startswith('/') else path
-    paths = path.split('/')
-    active_dict = dictionary
-    for p in paths:
-        if active_dict.get(p) != None:
-            active_dict = active_dict.get(p)
-        else:
-            return None
-    return active_dict
+	path = path[1:] if path.startswith('/') else path
+	paths = path.split('/')
+	active_dict = dictionary
+	for p in paths:
+		if active_dict is None:
+			return None
+		if isinstance(active_dict, dict):
+			active_dict = active_dict.get(p)
+		elif isinstance(active_dict, list):
+			active_dict = active_dict[int(p)]
+	return active_dict
 
 def inject_dict(dictionary, path, value):
-    path = path[1:] if path.startswith('/') else path
-    paths = path.split('/')
-    path_len = len(paths)
-    _active_dict = dictionary
-    for i, p in enumerate(paths):
-        if i == path_len - 1:
-            _active_dict[p] = value
-        else:
-            if _active_dict.get(p) == None:
-                _active_dict[p] = {}
-            _active_dict = _active_dict.get(p)
-    return dictionary
-    
+	path = path[1:] if path.startswith('/') else path
+	paths = path.split('/')
+	path_len = len(paths)
+	_active_dict = dictionary
+	for i, p in enumerate(paths):
+
+		if i == path_len - 1:
+			_active_dict[p] = value
+			continue
+
+		if _active_dict.get(p) == None:
+			_active_dict[p] = {}
+		_active_dict = _active_dict.get(p)
+	return dictionary


Test patch:
diff --git a/test.py b/test.py
index b3ff6a8..8bedb84 100644
--- a/test.py
+++ b/test.py
@@ -13,6 +13,10 @@ def test_inject_value():
     inject_dict(test_dict, 'foo1/foo2/foo3', {'foo4':'bar'})
     assert extract_dict(test_dict, 'foo1/foo2/foo3/foo4') == 'bar'
 
+def test_extract_array():
+    test_dict = {'foo1':{'foo2':[{'foo3':'bar'},{'foo4':[[{'foo5': 'bar'}]]}]}}
+    assert extract_dict(test_dict, 'foo1/foo2/1/foo4/0/0/foo5') == 'bar'
+
 test_dict = {'foo1':{'foo2':{'foo3':{'foo4':'bar'}}}}
 data = DictPath(test_dict)
 
@@ -48,4 +52,14 @@ def test_equalness_with_normal_dict():
     normal_dict = {'foo1':{'foo2':{'foo3':{'foo4':'bar'}}}}
     dic_path = DictPath(normal_dict)
     assert normal_dict == dic_path
-    assert dic_path.dict is normal_dict
\ No newline at end of file
+    assert dic_path.dict is normal_dict
+
+def test_extract_array_with_dict():
+    test_dict = {'foo1':{'foo2':[{'foo3':'bar'},{'foo4':[[{'foo5': 'bar'}]]}]}}
+    dic_path = DictPath(test_dict)
+    assert dic_path.get('foo1/foo2/1/foo4/0/0/foo5') == 'bar'
+
+def test_extract_array_with_dict():
+    test_dict = {'foo1':{'foo2':[{'foo3':'bar'},{'foo4':[[{'foo5': 'bar'}]]}]}}
+    dic_path = DictPath(test_dict)
+    assert dic_path.get('foo1/foo2/1/foo4/0/0/foo6/foo7') == None