npdict 0.0.1__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.
@@ -0,0 +1,28 @@
1
+ name: CI/CD Pipeline
2
+
3
+ on:
4
+ pull_request:
5
+
6
+ jobs:
7
+ build:
8
+ runs-on: ubuntu-latest
9
+ strategy:
10
+ matrix:
11
+ python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
12
+
13
+ steps:
14
+ - uses: actions/checkout@v3
15
+
16
+ - name: Set up Python ${{ matrix.python-version }}
17
+ uses: actions/setup-python@v3
18
+ with:
19
+ python-version: ${{ matrix.python-version }}
20
+
21
+ - name: Install dependencies
22
+ run: |
23
+ python -m pip install --upgrade pip
24
+ pip install -e .[test]
25
+
26
+ - name: Test with pytest
27
+ run: |
28
+ pytest
@@ -0,0 +1,486 @@
1
+ ### JetBrains+all template
2
+ # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
3
+ # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
4
+
5
+ # User-specific stuff
6
+ .idea/**/workspace.xml
7
+ .idea/**/tasks.xml
8
+ .idea/**/usage.statistics.xml
9
+ .idea/**/dictionaries
10
+ .idea/**/shelf
11
+
12
+ # AWS User-specific
13
+ .idea/**/aws.xml
14
+
15
+ # Generated files
16
+ .idea/**/contentModel.xml
17
+
18
+ # Sensitive or high-churn files
19
+ .idea/**/dataSources/
20
+ .idea/**/dataSources.ids
21
+ .idea/**/dataSources.local.xml
22
+ .idea/**/sqlDataSources.xml
23
+ .idea/**/dynamic.xml
24
+ .idea/**/uiDesigner.xml
25
+ .idea/**/dbnavigator.xml
26
+
27
+ # Gradle
28
+ .idea/**/gradle.xml
29
+ .idea/**/libraries
30
+
31
+ # Gradle and Maven with auto-import
32
+ # When using Gradle or Maven with auto-import, you should exclude module files,
33
+ # since they will be recreated, and may cause churn. Uncomment if using
34
+ # auto-import.
35
+ # .idea/artifacts
36
+ # .idea/compiler.xml
37
+ # .idea/jarRepositories.xml
38
+ # .idea/modules.xml
39
+ # .idea/*.iml
40
+ # .idea/modules
41
+ # *.iml
42
+ # *.ipr
43
+
44
+ # CMake
45
+ cmake-build-*/
46
+
47
+ # Mongo Explorer plugin
48
+ .idea/**/mongoSettings.xml
49
+
50
+ # File-based project format
51
+ *.iws
52
+
53
+ # IntelliJ
54
+ out/
55
+
56
+ # mpeltonen/sbt-idea plugin
57
+ .idea_modules/
58
+
59
+ # JIRA plugin
60
+ atlassian-ide-plugin.xml
61
+
62
+ # Cursive Clojure plugin
63
+ .idea/replstate.xml
64
+
65
+ # SonarLint plugin
66
+ .idea/sonarlint/
67
+
68
+ # Crashlytics plugin (for Android Studio and IntelliJ)
69
+ com_crashlytics_export_strings.xml
70
+ crashlytics.properties
71
+ crashlytics-build.properties
72
+ fabric.properties
73
+
74
+ # Editor-based Rest Client
75
+ .idea/httpRequests
76
+
77
+ # Android studio 3.1+ serialized cache file
78
+ .idea/caches/build_file_checksums.ser
79
+
80
+ ### VisualStudioCode template
81
+ .vscode/*
82
+ !.vscode/settings.json
83
+ !.vscode/tasks.json
84
+ !.vscode/launch.json
85
+ !.vscode/extensions.json
86
+ !.vscode/*.code-snippets
87
+
88
+ # Local History for Visual Studio Code
89
+ .history/
90
+
91
+ # Built Visual Studio Code Extensions
92
+ *.vsix
93
+
94
+ ### JetBrains template
95
+ # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
96
+ # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
97
+
98
+ # User-specific stuff
99
+ .idea/**/workspace.xml
100
+ .idea/**/tasks.xml
101
+ .idea/**/usage.statistics.xml
102
+ .idea/**/dictionaries
103
+ .idea/**/shelf
104
+
105
+ # AWS User-specific
106
+ .idea/**/aws.xml
107
+
108
+ # Generated files
109
+ .idea/**/contentModel.xml
110
+
111
+ # Sensitive or high-churn files
112
+ .idea/**/dataSources/
113
+ .idea/**/dataSources.ids
114
+ .idea/**/dataSources.local.xml
115
+ .idea/**/sqlDataSources.xml
116
+ .idea/**/dynamic.xml
117
+ .idea/**/uiDesigner.xml
118
+ .idea/**/dbnavigator.xml
119
+
120
+ # Gradle
121
+ .idea/**/gradle.xml
122
+ .idea/**/libraries
123
+
124
+ # Gradle and Maven with auto-import
125
+ # When using Gradle or Maven with auto-import, you should exclude module files,
126
+ # since they will be recreated, and may cause churn. Uncomment if using
127
+ # auto-import.
128
+ # .idea/artifacts
129
+ # .idea/compiler.xml
130
+ # .idea/jarRepositories.xml
131
+ # .idea/modules.xml
132
+ # .idea/*.iml
133
+ # .idea/modules
134
+ # *.iml
135
+ # *.ipr
136
+
137
+ # CMake
138
+ cmake-build-*/
139
+
140
+ # Mongo Explorer plugin
141
+ .idea/**/mongoSettings.xml
142
+
143
+ # File-based project format
144
+ *.iws
145
+
146
+ # IntelliJ
147
+ out/
148
+
149
+ # mpeltonen/sbt-idea plugin
150
+ .idea_modules/
151
+
152
+ # JIRA plugin
153
+ atlassian-ide-plugin.xml
154
+
155
+ # Cursive Clojure plugin
156
+ .idea/replstate.xml
157
+
158
+ # SonarLint plugin
159
+ .idea/sonarlint/
160
+
161
+ # Crashlytics plugin (for Android Studio and IntelliJ)
162
+ com_crashlytics_export_strings.xml
163
+ crashlytics.properties
164
+ crashlytics-build.properties
165
+ fabric.properties
166
+
167
+ # Editor-based Rest Client
168
+ .idea/httpRequests
169
+
170
+ # Android studio 3.1+ serialized cache file
171
+ .idea/caches/build_file_checksums.ser
172
+
173
+ ### VirtualEnv template
174
+ # Virtualenv
175
+ # http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
176
+ .Python
177
+ [Bb]in
178
+ [Ii]nclude
179
+ [Ll]ib
180
+ [Ll]ib64
181
+ [Ll]ocal
182
+ [Ss]cripts
183
+ pyvenv.cfg
184
+ .venv
185
+ pip-selfcheck.json
186
+
187
+ ### Linux template
188
+ *~
189
+
190
+ # temporary files which can be created if a process still has a handle open of a deleted file
191
+ .fuse_hidden*
192
+
193
+ # KDE directory preferences
194
+ .directory
195
+
196
+ # Linux trash folder which might appear on any partition or disk
197
+ .Trash-*
198
+
199
+ # .nfs files are created when an open file is removed but is still being accessed
200
+ .nfs*
201
+
202
+ ### JupyterNotebooks template
203
+ # gitignore template for Jupyter Notebooks
204
+ # website: http://jupyter.org/
205
+
206
+ .ipynb_checkpoints
207
+ */.ipynb_checkpoints/*
208
+
209
+ # IPython
210
+ profile_default/
211
+ ipython_config.py
212
+
213
+ # Remove previous ipynb_checkpoints
214
+ # git rm -r .ipynb_checkpoints/
215
+
216
+ ### JetBrains+iml template
217
+ # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
218
+ # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
219
+
220
+ # User-specific stuff
221
+ .idea/**/workspace.xml
222
+ .idea/**/tasks.xml
223
+ .idea/**/usage.statistics.xml
224
+ .idea/**/dictionaries
225
+ .idea/**/shelf
226
+
227
+ # AWS User-specific
228
+ .idea/**/aws.xml
229
+
230
+ # Generated files
231
+ .idea/**/contentModel.xml
232
+
233
+ # Sensitive or high-churn files
234
+ .idea/**/dataSources/
235
+ .idea/**/dataSources.ids
236
+ .idea/**/dataSources.local.xml
237
+ .idea/**/sqlDataSources.xml
238
+ .idea/**/dynamic.xml
239
+ .idea/**/uiDesigner.xml
240
+ .idea/**/dbnavigator.xml
241
+
242
+ # Gradle
243
+ .idea/**/gradle.xml
244
+ .idea/**/libraries
245
+
246
+ # Gradle and Maven with auto-import
247
+ # When using Gradle or Maven with auto-import, you should exclude module files,
248
+ # since they will be recreated, and may cause churn. Uncomment if using
249
+ # auto-import.
250
+ # .idea/artifacts
251
+ # .idea/compiler.xml
252
+ # .idea/jarRepositories.xml
253
+ # .idea/modules.xml
254
+ # .idea/*.iml
255
+ # .idea/modules
256
+ # *.iml
257
+ # *.ipr
258
+
259
+ # CMake
260
+ cmake-build-*/
261
+
262
+ # Mongo Explorer plugin
263
+ .idea/**/mongoSettings.xml
264
+
265
+ # File-based project format
266
+ *.iws
267
+
268
+ # IntelliJ
269
+ out/
270
+
271
+ # mpeltonen/sbt-idea plugin
272
+ .idea_modules/
273
+
274
+ # JIRA plugin
275
+ atlassian-ide-plugin.xml
276
+
277
+ # Cursive Clojure plugin
278
+ .idea/replstate.xml
279
+
280
+ # SonarLint plugin
281
+ .idea/sonarlint/
282
+
283
+ # Crashlytics plugin (for Android Studio and IntelliJ)
284
+ com_crashlytics_export_strings.xml
285
+ crashlytics.properties
286
+ crashlytics-build.properties
287
+ fabric.properties
288
+
289
+ # Editor-based Rest Client
290
+ .idea/httpRequests
291
+
292
+ # Android studio 3.1+ serialized cache file
293
+ .idea/caches/build_file_checksums.ser
294
+
295
+ ### macOS template
296
+ # General
297
+ .DS_Store
298
+ .AppleDouble
299
+ .LSOverride
300
+
301
+ # Icon must end with two \r
302
+ Icon
303
+
304
+ # Thumbnails
305
+ ._*
306
+
307
+ # Files that might appear in the root of a volume
308
+ .DocumentRevisions-V100
309
+ .fseventsd
310
+ .Spotlight-V100
311
+ .TemporaryItems
312
+ .Trashes
313
+ .VolumeIcon.icns
314
+ .com.apple.timemachine.donotpresent
315
+
316
+ # Directories potentially created on remote AFP share
317
+ .AppleDB
318
+ .AppleDesktop
319
+ Network Trash Folder
320
+ Temporary Items
321
+ .apdisk
322
+
323
+ ### Python template
324
+ # Byte-compiled / optimized / DLL files
325
+ __pycache__/
326
+ *.py[cod]
327
+ *$py.class
328
+
329
+ # C extensions
330
+ *.so
331
+
332
+ # Distribution / packaging
333
+ .Python
334
+ build/
335
+ develop-eggs/
336
+ dist/
337
+ downloads/
338
+ eggs/
339
+ .eggs/
340
+ lib/
341
+ lib64/
342
+ parts/
343
+ sdist/
344
+ var/
345
+ wheels/
346
+ share/python-wheels/
347
+ *.egg-info/
348
+ .installed.cfg
349
+ *.egg
350
+ MANIFEST
351
+
352
+ # PyInstaller
353
+ # Usually these files are written by a python script from a template
354
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
355
+ *.manifest
356
+ *.spec
357
+
358
+ # Installer logs
359
+ pip-log.txt
360
+ pip-delete-this-directory.txt
361
+
362
+ # Unit test / coverage reports
363
+ htmlcov/
364
+ .tox/
365
+ .nox/
366
+ .coverage
367
+ .coverage.*
368
+ .cache
369
+ nosetests.xml
370
+ coverage.xml
371
+ *.cover
372
+ *.py,cover
373
+ .hypothesis/
374
+ .pytest_cache/
375
+ cover/
376
+
377
+ # Translations
378
+ *.mo
379
+ *.pot
380
+
381
+ # Django stuff:
382
+ *.log
383
+ local_settings.py
384
+ db.sqlite3
385
+ db.sqlite3-journal
386
+
387
+ # Flask stuff:
388
+ instance/
389
+ .webassets-cache
390
+
391
+ # Scrapy stuff:
392
+ .scrapy
393
+
394
+ # Sphinx documentation
395
+ docs/_build/
396
+
397
+ # PyBuilder
398
+ .pybuilder/
399
+ target/
400
+
401
+ # Jupyter Notebook
402
+ .ipynb_checkpoints
403
+
404
+ # IPython
405
+ profile_default/
406
+ ipython_config.py
407
+
408
+ # pyenv
409
+ # For a library or package, you might want to ignore these files since the code is
410
+ # intended to run in multiple environments; otherwise, check them in:
411
+ # .python-version
412
+
413
+ # pipenv
414
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
415
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
416
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
417
+ # install all needed dependencies.
418
+ #Pipfile.lock
419
+
420
+ # poetry
421
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
422
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
423
+ # commonly ignored for libraries.
424
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
425
+ #poetry.lock
426
+
427
+ # pdm
428
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
429
+ #pdm.lock
430
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
431
+ # in version control.
432
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
433
+ .pdm.toml
434
+ .pdm-python
435
+ .pdm-build/
436
+
437
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
438
+ __pypackages__/
439
+
440
+ # Celery stuff
441
+ celerybeat-schedule
442
+ celerybeat.pid
443
+
444
+ # SageMath parsed files
445
+ *.sage.py
446
+
447
+ # Environments
448
+ .env
449
+ .venv
450
+ env/
451
+ venv/
452
+ ENV/
453
+ env.bak/
454
+ venv.bak/
455
+
456
+ # Spyder project settings
457
+ .spyderproject
458
+ .spyproject
459
+
460
+ # Rope project settings
461
+ .ropeproject
462
+
463
+ # mkdocs documentation
464
+ /site
465
+
466
+ # mypy
467
+ .mypy_cache/
468
+ .dmypy.json
469
+ dmypy.json
470
+
471
+ # Pyre type checker
472
+ .pyre/
473
+
474
+ # pytype static type analyzer
475
+ .pytype/
476
+
477
+ # Cython debug symbols
478
+ cython_debug/
479
+
480
+ # PyCharm
481
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
482
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
483
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
484
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
485
+ .idea/
486
+
npdict-0.0.1/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2025 Kwan Yuet Stephen Ho
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1,3 @@
1
+ include README.md
2
+ include pyproject.toml
3
+ include LICENSE
npdict-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,171 @@
1
+ Metadata-Version: 2.4
2
+ Name: npdict
3
+ Version: 0.0.1
4
+ Summary: A Python dictionary wrapper for numpy arrays
5
+ Author-email: Kwan Yuet Stephen Ho <stephenhky@yahoo.com.hk>
6
+ License: MIT
7
+ Project-URL: Repository, https://github.com/stephenhky/npdict
8
+ Project-URL: Issues, https://github.com/stephenhky/npdict/issues
9
+ Keywords: dictionary,numpy
10
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
13
+ Classifier: Topic :: Software Development :: Version Control :: Git
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Intended Audience :: Science/Research
20
+ Classifier: Intended Audience :: Developers
21
+ Requires-Python: >=3.9
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: numpy
25
+ Requires-Dist: typing-extensions
26
+ Provides-Extra: test
27
+ Requires-Dist: pytest; extra == "test"
28
+ Dynamic: license-file
29
+
30
+
31
+ [![GitHub release](https://img.shields.io/github/release/stephenhky/npdict.svg?maxAge=3600)](https://github.com/stephenhky/npdict/releases)
32
+ [![pypi](https://img.shields.io/pypi/v/npdict.svg?maxAge=3600)](https://pypi.org/project/npdict/)
33
+ [![download](https://img.shields.io/pypi/dm/npdict.svg?maxAge=2592000&label=installs&color=%2327B1FF)](https://pypi.org/project/npdict/)
34
+
35
+ # `npdict`: Python Package for Dictionary Wrappers for Numpy Arrays
36
+
37
+ This Python package, `npdict`, aims at facilitating holding numerical
38
+ values in a Python dictionary, but at the same time retaining the
39
+ ultra-high performance supported by NumPy. It supports an object
40
+ which is a Python dictionary on the surface, but numpy behind the
41
+ back, facilitating fast assignment and retrieval of values
42
+ and fast computation of numpy arrays.
43
+
44
+ ## Installation
45
+
46
+ To install, in your terminal, simply enter:
47
+
48
+ ```
49
+ pip install npdict
50
+ ```
51
+
52
+ ## Quickstart
53
+
54
+ ### Instantiation
55
+
56
+ Suppose you are doing a similarity dictionary between two sets of words.
57
+ And each of these sets have words:
58
+
59
+ ```
60
+ document1 = ['president', 'computer', 'tree']
61
+ document2 = ['chairman', 'abacus', 'trees']
62
+ ```
63
+
64
+ And you can build a dictionary like this:
65
+
66
+ ```
67
+ import numpy as np
68
+ from npdict import NumpyNDArrayWrappedDict
69
+
70
+ similarity_dict = NumpyNDArrayWrappedDict([document1, document2])
71
+ ```
72
+
73
+ An `npdict.NumpyNDArrayWrappedDict` instance is instantiated. It is
74
+ a Python dict:
75
+
76
+ ```
77
+ isinstance(similarity_dict, dict) # which gives `True`
78
+ ```
79
+
80
+ It has a matrix inside with default value 0.0 (and the initial default value can
81
+ be changed to other values when the instance is instantiated.)
82
+
83
+ ```
84
+ similarity_dict.to_numpy()
85
+ ```
86
+ giving
87
+ ```
88
+ array([[0., 0., 0.],
89
+ [0., 0., 0.],
90
+ [0., 0., 0.]])
91
+ ```
92
+
93
+ ### Value Assignments
94
+
95
+ Now you can assign values just like what you do to a Python dictionary:
96
+
97
+ ```
98
+ similarity_dict['president', 'chairman'] = 0.9
99
+ similarity_dict['computer', 'abacus'] = 0.7
100
+ similarity_dict['tree', 'trees'] = 0.95
101
+ ```
102
+
103
+ And it has changed the inside numpy array to be:
104
+
105
+ ```
106
+ array([[0.9 , 0. , 0. ],
107
+ [0. , 0.7 , 0. ],
108
+ [0. , 0. , 0.95]])
109
+ ```
110
+
111
+ ### Generation of New Object from the Old One
112
+
113
+ If you want to create another dict using the same words, but
114
+ a manipulation of the original value, 25 percent discount
115
+ of the original one for example, you can do something like this:
116
+
117
+ ```
118
+ new_similarity_dict = similarity_dict.generate_dict(similarity_dict.to_numpy()*0.75)
119
+ ```
120
+
121
+ And you got a new dictionary with numpy array to be:
122
+
123
+ ```
124
+ new_similarity_dict.to_numpy()
125
+ ```
126
+ giving
127
+ ```
128
+ array([[0.675 , 0. , 0. ],
129
+ [0. , 0.525 , 0. ],
130
+ [0. , 0. , 0.7125]])
131
+ ```
132
+
133
+ This is a simple operation. But the design of this wrapped Python
134
+ dictionary is that you can perform any fast or optimized operation
135
+ on your numpy array (using numba or Cython, for examples),
136
+ while retaining the keywords as your dictionary.
137
+
138
+ ### Retrieval of Values
139
+
140
+ At the same time, you can set new values just like above, or retrieve
141
+ values as if it is a Python dictionary:
142
+
143
+ ```
144
+ similarity_dict['president', 'chairman']
145
+ ```
146
+
147
+ ### Conversion to a Python Dictionary
148
+
149
+ You can also convert this to an ordinary Python dictionary:
150
+
151
+ ```
152
+ raw_similarity_dict = similarity_dict.to_dict()
153
+ ```
154
+
155
+ ### Instantiation from a Python Dictionary
156
+
157
+ And you can convert a Python dictionary of this type back to
158
+ `npdict.NumpyNDArrayWrappedDict` by (recommended)
159
+
160
+ ```
161
+ new_similarity_dict_2 = NumpyNDArrayWrappedDict.from_dict_given_keywords([document1, document2], raw_similarity_dict)
162
+ ```
163
+
164
+ Or you can even do this (not recommended):
165
+
166
+ ```
167
+ new_similarity_dict_3 = NumpyNDArrayWrappedDict.from_dict(raw_similarity_dict)
168
+ ```
169
+
170
+ It is not recommended because the order of the keys are not retained in this way.
171
+ Use it with caution.
npdict-0.0.1/README.md ADDED
@@ -0,0 +1,142 @@
1
+
2
+ [![GitHub release](https://img.shields.io/github/release/stephenhky/npdict.svg?maxAge=3600)](https://github.com/stephenhky/npdict/releases)
3
+ [![pypi](https://img.shields.io/pypi/v/npdict.svg?maxAge=3600)](https://pypi.org/project/npdict/)
4
+ [![download](https://img.shields.io/pypi/dm/npdict.svg?maxAge=2592000&label=installs&color=%2327B1FF)](https://pypi.org/project/npdict/)
5
+
6
+ # `npdict`: Python Package for Dictionary Wrappers for Numpy Arrays
7
+
8
+ This Python package, `npdict`, aims at facilitating holding numerical
9
+ values in a Python dictionary, but at the same time retaining the
10
+ ultra-high performance supported by NumPy. It supports an object
11
+ which is a Python dictionary on the surface, but numpy behind the
12
+ back, facilitating fast assignment and retrieval of values
13
+ and fast computation of numpy arrays.
14
+
15
+ ## Installation
16
+
17
+ To install, in your terminal, simply enter:
18
+
19
+ ```
20
+ pip install npdict
21
+ ```
22
+
23
+ ## Quickstart
24
+
25
+ ### Instantiation
26
+
27
+ Suppose you are doing a similarity dictionary between two sets of words.
28
+ And each of these sets have words:
29
+
30
+ ```
31
+ document1 = ['president', 'computer', 'tree']
32
+ document2 = ['chairman', 'abacus', 'trees']
33
+ ```
34
+
35
+ And you can build a dictionary like this:
36
+
37
+ ```
38
+ import numpy as np
39
+ from npdict import NumpyNDArrayWrappedDict
40
+
41
+ similarity_dict = NumpyNDArrayWrappedDict([document1, document2])
42
+ ```
43
+
44
+ An `npdict.NumpyNDArrayWrappedDict` instance is instantiated. It is
45
+ a Python dict:
46
+
47
+ ```
48
+ isinstance(similarity_dict, dict) # which gives `True`
49
+ ```
50
+
51
+ It has a matrix inside with default value 0.0 (and the initial default value can
52
+ be changed to other values when the instance is instantiated.)
53
+
54
+ ```
55
+ similarity_dict.to_numpy()
56
+ ```
57
+ giving
58
+ ```
59
+ array([[0., 0., 0.],
60
+ [0., 0., 0.],
61
+ [0., 0., 0.]])
62
+ ```
63
+
64
+ ### Value Assignments
65
+
66
+ Now you can assign values just like what you do to a Python dictionary:
67
+
68
+ ```
69
+ similarity_dict['president', 'chairman'] = 0.9
70
+ similarity_dict['computer', 'abacus'] = 0.7
71
+ similarity_dict['tree', 'trees'] = 0.95
72
+ ```
73
+
74
+ And it has changed the inside numpy array to be:
75
+
76
+ ```
77
+ array([[0.9 , 0. , 0. ],
78
+ [0. , 0.7 , 0. ],
79
+ [0. , 0. , 0.95]])
80
+ ```
81
+
82
+ ### Generation of New Object from the Old One
83
+
84
+ If you want to create another dict using the same words, but
85
+ a manipulation of the original value, 25 percent discount
86
+ of the original one for example, you can do something like this:
87
+
88
+ ```
89
+ new_similarity_dict = similarity_dict.generate_dict(similarity_dict.to_numpy()*0.75)
90
+ ```
91
+
92
+ And you got a new dictionary with numpy array to be:
93
+
94
+ ```
95
+ new_similarity_dict.to_numpy()
96
+ ```
97
+ giving
98
+ ```
99
+ array([[0.675 , 0. , 0. ],
100
+ [0. , 0.525 , 0. ],
101
+ [0. , 0. , 0.7125]])
102
+ ```
103
+
104
+ This is a simple operation. But the design of this wrapped Python
105
+ dictionary is that you can perform any fast or optimized operation
106
+ on your numpy array (using numba or Cython, for examples),
107
+ while retaining the keywords as your dictionary.
108
+
109
+ ### Retrieval of Values
110
+
111
+ At the same time, you can set new values just like above, or retrieve
112
+ values as if it is a Python dictionary:
113
+
114
+ ```
115
+ similarity_dict['president', 'chairman']
116
+ ```
117
+
118
+ ### Conversion to a Python Dictionary
119
+
120
+ You can also convert this to an ordinary Python dictionary:
121
+
122
+ ```
123
+ raw_similarity_dict = similarity_dict.to_dict()
124
+ ```
125
+
126
+ ### Instantiation from a Python Dictionary
127
+
128
+ And you can convert a Python dictionary of this type back to
129
+ `npdict.NumpyNDArrayWrappedDict` by (recommended)
130
+
131
+ ```
132
+ new_similarity_dict_2 = NumpyNDArrayWrappedDict.from_dict_given_keywords([document1, document2], raw_similarity_dict)
133
+ ```
134
+
135
+ Or you can even do this (not recommended):
136
+
137
+ ```
138
+ new_similarity_dict_3 = NumpyNDArrayWrappedDict.from_dict(raw_similarity_dict)
139
+ ```
140
+
141
+ It is not recommended because the order of the keys are not retained in this way.
142
+ Use it with caution.
@@ -0,0 +1,2 @@
1
+
2
+ from .wrap import NumpyNDArrayWrappedDict
@@ -0,0 +1,18 @@
1
+
2
+
3
+ from typing import Tuple
4
+
5
+
6
+ class DuplicatedKeyError(Exception):
7
+ def __init__(self):
8
+ self.message = "Duplicated keys!"
9
+
10
+
11
+ class WrongArrayDimensionException(Exception):
12
+ def __init__(self, expected_dimension: int, given_dimensions: int):
13
+ self.message = f"Expected dimension: {expected_dimension}, but {given_dimensions} dimensions are given!"
14
+
15
+
16
+ class WrongArrayShapeException(Exception):
17
+ def __init__(self, expected_shape: Tuple[int, ...], given_shape: Tuple[int, ...]):
18
+ self.message = f"Expected shape: {', '.join(str(dim_len) for dim_len in expected_shape)}, but the given array shape is {', '.join(str(dim_len) for dim_len in given_shape)}!"
@@ -0,0 +1,143 @@
1
+
2
+ from typing import Tuple, Generator
3
+ import sys
4
+ from itertools import product
5
+ from functools import reduce
6
+
7
+ import numpy as np
8
+
9
+ if sys.version_info < (3, 11):
10
+ from typing_extensions import Self
11
+ else:
12
+ from typing import Self
13
+
14
+ from .utils import DuplicatedKeyError, WrongArrayDimensionException, WrongArrayShapeException
15
+
16
+
17
+ class NumpyNDArrayWrappedDict(dict):
18
+ def __init__(
19
+ self,
20
+ lists_keystrings: list[list[str]],
21
+ default_initial_value: float=0.0
22
+ ):
23
+ super(dict, self).__init__()
24
+ for list_keystrings in lists_keystrings:
25
+ if (len(list_keystrings)) != len(set(list_keystrings)):
26
+ raise DuplicatedKeyError()
27
+ self._lists_keystrings = lists_keystrings
28
+ self._keystrings_to_indices = [
29
+ {
30
+ keyword: idx for idx, keyword in enumerate(list_keystrings)
31
+ }
32
+ for list_keystrings in self._lists_keystrings
33
+ ]
34
+
35
+ self._tensor_dimensions = len(self._lists_keystrings)
36
+ self._dimension_sizes = [len(l) for l in self._lists_keystrings]
37
+ self._total_size = reduce(lambda a, b: a*b, self._dimension_sizes)
38
+
39
+ self._numpyarray = np.empty(tuple(len(l) for l in self._lists_keystrings))
40
+ self._numpyarray.fill(default_initial_value)
41
+
42
+ def _get_indices(self, item: Tuple[str, ...]) -> list[int]:
43
+ return [
44
+ mapping[keyword]
45
+ for mapping, keyword in zip(self._keystrings_to_indices, item)
46
+ ]
47
+
48
+ def __getitem__(self, item: Tuple[str, ...]) -> float:
49
+ if len(item) != self.tensor_dimensions:
50
+ raise WrongArrayDimensionException(self.tensor_dimensions, len(item))
51
+ indices = self._get_indices(item)
52
+ return self._numpyarray[tuple(indices)]
53
+
54
+ def __setitem__(self, key: Tuple[str, ...], value: float) -> None:
55
+ if len(key) != self.tensor_dimensions:
56
+ raise WrongArrayDimensionException(self.tensor_dimensions, len(key))
57
+ indices = self._get_indices(key)
58
+ self._numpyarray[tuple(indices)] = value
59
+
60
+ def update(self, new_dict: dict):
61
+ raise TypeError("We cannot update this kind of dict this way!")
62
+
63
+ def __iter__(self) -> Generator[Tuple[str, ...], None, None]:
64
+ for keywords_tuple in product(*self._lists_keystrings):
65
+ yield keywords_tuple
66
+
67
+ def keys(self):
68
+ return list(self.__iter__())
69
+
70
+ def values(self):
71
+ return [self.__getitem__(keywords_tuple) for keywords_tuple in self.__iter__()]
72
+
73
+ def items(self):
74
+ return [
75
+ (keywords_tuple, self.__getitem__(keywords_tuple))
76
+ for keywords_tuple in self.__iter__()
77
+ ]
78
+
79
+ def to_numpy(self) -> np.ndarray:
80
+ return self._numpyarray
81
+
82
+ def generate_dict(self, nparray: np.ndarray) -> Self:
83
+ if len(nparray.shape) != self.tensor_dimensions:
84
+ raise WrongArrayDimensionException(self.tensor_dimensions, len(nparray.shape))
85
+ if nparray.shape != self._numpyarray.shape:
86
+ raise WrongArrayShapeException(self._numpyarray.shape, nparray.shape)
87
+ wrapped_dict = NumpyNDArrayWrappedDict(self._lists_keystrings)
88
+ wrapped_dict._numpyarray = nparray
89
+ return wrapped_dict
90
+
91
+ def __repr__(self) -> str:
92
+ return f"<NumpyNDArrayWrappedDict: dimensions ({', '.join(map(str, self.dimension_sizes))})>"
93
+
94
+ def __str__(self) -> str:
95
+ return self.__repr__()
96
+
97
+ def __len__(self) -> int:
98
+ return self._total_size
99
+
100
+ def to_dict(self) -> dict[Tuple[str, ...], float]:
101
+ return {
102
+ keywords_tuple: value for keywords_tuple, value in self.items()
103
+ }
104
+
105
+ @classmethod
106
+ def from_dict_given_keywords(
107
+ cls,
108
+ lists_keywords: list[list[str]],
109
+ oridict: dict[Tuple[str, ...], float],
110
+ default_initial_value: float = 0.0
111
+ ) -> Self:
112
+ wrapped_dict = NumpyNDArrayWrappedDict(
113
+ lists_keywords,
114
+ default_initial_value=default_initial_value
115
+ )
116
+ for keywords_tuple in product(*lists_keywords):
117
+ wrapped_dict[keywords_tuple] = oridict.get(keywords_tuple, default_initial_value)
118
+ return wrapped_dict
119
+
120
+ @classmethod
121
+ def from_dict(
122
+ cls,
123
+ oridict: dict[Tuple[str, ...], float],
124
+ default_initial_value: float = 0.0
125
+ ) -> Self:
126
+ nbdims = len(next(iter(oridict)))
127
+ lists_keystrings = [
128
+ list(set(keystring[i] for keystring in oridict.keys()))
129
+ for i in range(nbdims)
130
+ ]
131
+ return cls.from_dict_given_keywords(
132
+ lists_keystrings,
133
+ oridict,
134
+ default_initial_value=default_initial_value
135
+ )
136
+
137
+ @property
138
+ def tensor_dimensions(self) -> int:
139
+ return self._tensor_dimensions
140
+
141
+ @property
142
+ def dimension_sizes(self) -> list[int]:
143
+ return self._dimension_sizes
@@ -0,0 +1,171 @@
1
+ Metadata-Version: 2.4
2
+ Name: npdict
3
+ Version: 0.0.1
4
+ Summary: A Python dictionary wrapper for numpy arrays
5
+ Author-email: Kwan Yuet Stephen Ho <stephenhky@yahoo.com.hk>
6
+ License: MIT
7
+ Project-URL: Repository, https://github.com/stephenhky/npdict
8
+ Project-URL: Issues, https://github.com/stephenhky/npdict/issues
9
+ Keywords: dictionary,numpy
10
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
13
+ Classifier: Topic :: Software Development :: Version Control :: Git
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Intended Audience :: Science/Research
20
+ Classifier: Intended Audience :: Developers
21
+ Requires-Python: >=3.9
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: numpy
25
+ Requires-Dist: typing-extensions
26
+ Provides-Extra: test
27
+ Requires-Dist: pytest; extra == "test"
28
+ Dynamic: license-file
29
+
30
+
31
+ [![GitHub release](https://img.shields.io/github/release/stephenhky/npdict.svg?maxAge=3600)](https://github.com/stephenhky/npdict/releases)
32
+ [![pypi](https://img.shields.io/pypi/v/npdict.svg?maxAge=3600)](https://pypi.org/project/npdict/)
33
+ [![download](https://img.shields.io/pypi/dm/npdict.svg?maxAge=2592000&label=installs&color=%2327B1FF)](https://pypi.org/project/npdict/)
34
+
35
+ # `npdict`: Python Package for Dictionary Wrappers for Numpy Arrays
36
+
37
+ This Python package, `npdict`, aims at facilitating holding numerical
38
+ values in a Python dictionary, but at the same time retaining the
39
+ ultra-high performance supported by NumPy. It supports an object
40
+ which is a Python dictionary on the surface, but numpy behind the
41
+ back, facilitating fast assignment and retrieval of values
42
+ and fast computation of numpy arrays.
43
+
44
+ ## Installation
45
+
46
+ To install, in your terminal, simply enter:
47
+
48
+ ```
49
+ pip install npdict
50
+ ```
51
+
52
+ ## Quickstart
53
+
54
+ ### Instantiation
55
+
56
+ Suppose you are doing a similarity dictionary between two sets of words.
57
+ And each of these sets have words:
58
+
59
+ ```
60
+ document1 = ['president', 'computer', 'tree']
61
+ document2 = ['chairman', 'abacus', 'trees']
62
+ ```
63
+
64
+ And you can build a dictionary like this:
65
+
66
+ ```
67
+ import numpy as np
68
+ from npdict import NumpyNDArrayWrappedDict
69
+
70
+ similarity_dict = NumpyNDArrayWrappedDict([document1, document2])
71
+ ```
72
+
73
+ An `npdict.NumpyNDArrayWrappedDict` instance is instantiated. It is
74
+ a Python dict:
75
+
76
+ ```
77
+ isinstance(similarity_dict, dict) # which gives `True`
78
+ ```
79
+
80
+ It has a matrix inside with default value 0.0 (and the initial default value can
81
+ be changed to other values when the instance is instantiated.)
82
+
83
+ ```
84
+ similarity_dict.to_numpy()
85
+ ```
86
+ giving
87
+ ```
88
+ array([[0., 0., 0.],
89
+ [0., 0., 0.],
90
+ [0., 0., 0.]])
91
+ ```
92
+
93
+ ### Value Assignments
94
+
95
+ Now you can assign values just like what you do to a Python dictionary:
96
+
97
+ ```
98
+ similarity_dict['president', 'chairman'] = 0.9
99
+ similarity_dict['computer', 'abacus'] = 0.7
100
+ similarity_dict['tree', 'trees'] = 0.95
101
+ ```
102
+
103
+ And it has changed the inside numpy array to be:
104
+
105
+ ```
106
+ array([[0.9 , 0. , 0. ],
107
+ [0. , 0.7 , 0. ],
108
+ [0. , 0. , 0.95]])
109
+ ```
110
+
111
+ ### Generation of New Object from the Old One
112
+
113
+ If you want to create another dict using the same words, but
114
+ a manipulation of the original value, 25 percent discount
115
+ of the original one for example, you can do something like this:
116
+
117
+ ```
118
+ new_similarity_dict = similarity_dict.generate_dict(similarity_dict.to_numpy()*0.75)
119
+ ```
120
+
121
+ And you got a new dictionary with numpy array to be:
122
+
123
+ ```
124
+ new_similarity_dict.to_numpy()
125
+ ```
126
+ giving
127
+ ```
128
+ array([[0.675 , 0. , 0. ],
129
+ [0. , 0.525 , 0. ],
130
+ [0. , 0. , 0.7125]])
131
+ ```
132
+
133
+ This is a simple operation. But the design of this wrapped Python
134
+ dictionary is that you can perform any fast or optimized operation
135
+ on your numpy array (using numba or Cython, for examples),
136
+ while retaining the keywords as your dictionary.
137
+
138
+ ### Retrieval of Values
139
+
140
+ At the same time, you can set new values just like above, or retrieve
141
+ values as if it is a Python dictionary:
142
+
143
+ ```
144
+ similarity_dict['president', 'chairman']
145
+ ```
146
+
147
+ ### Conversion to a Python Dictionary
148
+
149
+ You can also convert this to an ordinary Python dictionary:
150
+
151
+ ```
152
+ raw_similarity_dict = similarity_dict.to_dict()
153
+ ```
154
+
155
+ ### Instantiation from a Python Dictionary
156
+
157
+ And you can convert a Python dictionary of this type back to
158
+ `npdict.NumpyNDArrayWrappedDict` by (recommended)
159
+
160
+ ```
161
+ new_similarity_dict_2 = NumpyNDArrayWrappedDict.from_dict_given_keywords([document1, document2], raw_similarity_dict)
162
+ ```
163
+
164
+ Or you can even do this (not recommended):
165
+
166
+ ```
167
+ new_similarity_dict_3 = NumpyNDArrayWrappedDict.from_dict(raw_similarity_dict)
168
+ ```
169
+
170
+ It is not recommended because the order of the keys are not retained in this way.
171
+ Use it with caution.
@@ -0,0 +1,17 @@
1
+ .gitignore
2
+ LICENSE
3
+ MANIFEST.in
4
+ README.md
5
+ pyproject.toml
6
+ .github/workflows/ci.yml
7
+ npdict/__init__.py
8
+ npdict/utils.py
9
+ npdict/wrap.py
10
+ npdict.egg-info/PKG-INFO
11
+ npdict.egg-info/SOURCES.txt
12
+ npdict.egg-info/dependency_links.txt
13
+ npdict.egg-info/not-zip-safe
14
+ npdict.egg-info/requires.txt
15
+ npdict.egg-info/top_level.txt
16
+ test/__init__.py
17
+ test/test_wrap.py
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,5 @@
1
+ numpy
2
+ typing-extensions
3
+
4
+ [test]
5
+ pytest
@@ -0,0 +1 @@
1
+ npdict
@@ -0,0 +1,40 @@
1
+ [build-system]
2
+ requires = ["setuptools", "setuptools-scm", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "npdict"
7
+ version = "0.0.1"
8
+ authors = [
9
+ {name = "Kwan Yuet Stephen Ho", email = "stephenhky@yahoo.com.hk"}
10
+ ]
11
+ description = "A Python dictionary wrapper for numpy arrays"
12
+ readme = {file = "README.md", content-type = "text/markdown"}
13
+ license = {text = "MIT"}
14
+ keywords = ["dictionary", "numpy"]
15
+ requires-python = ">=3.9"
16
+ classifiers = [
17
+ "Topic :: Scientific/Engineering :: Mathematics",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Topic :: Software Development :: Libraries :: Python Modules",
20
+ "Topic :: Software Development :: Version Control :: Git",
21
+ "Programming Language :: Python :: 3.9",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Intended Audience :: Science/Research",
27
+ "Intended Audience :: Developers",
28
+ ]
29
+ dependencies = ["numpy", "typing-extensions"]
30
+
31
+ [project.urls]
32
+ Repository = "https://github.com/stephenhky/npdict"
33
+ Issues = "https://github.com/stephenhky/npdict/issues"
34
+
35
+ [tool.setuptools]
36
+ packages = ["npdict"]
37
+ zip-safe = false
38
+
39
+ [project.optional-dependencies]
40
+ test = ["pytest"]
npdict-0.0.1/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
@@ -0,0 +1,110 @@
1
+ import unittest
2
+ import numpy as np
3
+
4
+ from npdict import NumpyNDArrayWrappedDict
5
+ from npdict.utils import DuplicatedKeyError, WrongArrayDimensionException, WrongArrayShapeException
6
+
7
+
8
+ class TestNumpyNDArrayWrappedDict(unittest.TestCase):
9
+
10
+ def setUp(self):
11
+ self.lists_keystrings = [
12
+ ['a', 'b', 'c'],
13
+ ['d', 'e']
14
+ ]
15
+ self.wrapped_dict = NumpyNDArrayWrappedDict(self.lists_keystrings, default_initial_value=1.0)
16
+
17
+ def test_initialization(self):
18
+ self.assertEqual(self.wrapped_dict.tensor_dimensions, 2)
19
+ self.assertEqual(self.wrapped_dict.dimension_sizes, [3, 2])
20
+ self.assertEqual(len(self.wrapped_dict), 6)
21
+ np.testing.assert_array_equal(self.wrapped_dict.to_numpy(), np.ones((3, 2)))
22
+
23
+ def test_initialization_with_duplicated_keys(self):
24
+ with self.assertRaises(DuplicatedKeyError):
25
+ NumpyNDArrayWrappedDict([['a', 'a'], ['b', 'c']])
26
+
27
+ def test_getitem(self):
28
+ self.wrapped_dict[('a', 'd')] = 2.0
29
+ self.assertEqual(self.wrapped_dict[('a', 'd')], 2.0)
30
+
31
+ def test_getitem_wrong_dimension(self):
32
+ with self.assertRaises(WrongArrayDimensionException):
33
+ _ = self.wrapped_dict[('a',)]
34
+
35
+ def test_setitem(self):
36
+ self.wrapped_dict[('b', 'e')] = 3.0
37
+ self.assertEqual(self.wrapped_dict.to_numpy()[1, 1], 3.0)
38
+
39
+ def test_setitem_wrong_dimension(self):
40
+ with self.assertRaises(WrongArrayDimensionException):
41
+ self.wrapped_dict[('a', 'b', 'c')] = 1.0
42
+
43
+ def test_iteration(self):
44
+ keys = list(self.wrapped_dict)
45
+ self.assertEqual(len(keys), 6)
46
+ self.assertIn(('a', 'd'), keys)
47
+ self.assertIn(('c', 'e'), keys)
48
+
49
+ def test_keys(self):
50
+ keys = self.wrapped_dict.keys()
51
+ self.assertEqual(len(keys), 6)
52
+ self.assertIn(('a', 'd'), keys)
53
+
54
+ def test_values(self):
55
+ self.wrapped_dict[('a', 'd')] = 5.0
56
+ self.wrapped_dict[('c', 'e')] = 6.0
57
+ values = self.wrapped_dict.values()
58
+ self.assertIn(1.0, values)
59
+ self.assertIn(5.0, values)
60
+ self.assertIn(6.0, values)
61
+
62
+ def test_items(self):
63
+ self.wrapped_dict[('a', 'd')] = 7.0
64
+ items = self.wrapped_dict.items()
65
+ self.assertIn((('a', 'd'), 7.0), items)
66
+ self.assertIn((('b', 'd'), 1.0), items)
67
+
68
+ def test_to_dict(self):
69
+ self.wrapped_dict[('a', 'd')] = 8.0
70
+ d = self.wrapped_dict.to_dict()
71
+ self.assertEqual(d[('a', 'd')], 8.0)
72
+ self.assertEqual(d[('b', 'e')], 1.0)
73
+
74
+ def test_from_dict(self):
75
+ d = {('a', 'x'): 1, ('b', 'y'): 2}
76
+ wrapped = NumpyNDArrayWrappedDict.from_dict(d)
77
+ self.assertEqual(wrapped[('a', 'x')], 1)
78
+ self.assertEqual(wrapped[('b', 'y')], 2)
79
+ self.assertEqual(wrapped[('a', 'y')], 0.0)
80
+ self.assertEqual(wrapped[('b', 'x')], 0.0)
81
+
82
+ def test_from_dict_given_keywords(self):
83
+ d = {('a', 'x'): 1}
84
+ keywords = [['a', 'b'], ['x', 'y']]
85
+ wrapped = NumpyNDArrayWrappedDict.from_dict_given_keywords(keywords, d, default_initial_value=-1)
86
+ self.assertEqual(wrapped[('a', 'x')], 1)
87
+ self.assertEqual(wrapped[('b', 'y')], -1)
88
+
89
+ def test_repr_str(self):
90
+ self.assertEqual(repr(self.wrapped_dict), f"<NumpyNDArrayWrappedDict: dimensions ({', '.join(map(str, self.wrapped_dict.dimension_sizes))})>")
91
+ self.assertEqual(str(self.wrapped_dict), repr(self.wrapped_dict))
92
+
93
+ def test_update(self):
94
+ with self.assertRaises(TypeError):
95
+ self.wrapped_dict.update({('a', 'd'): 1})
96
+
97
+ def test_generate_dict(self):
98
+ new_array = np.zeros((3, 2))
99
+ new_wrapped_dict = self.wrapped_dict.generate_dict(new_array)
100
+ np.testing.assert_array_equal(new_wrapped_dict.to_numpy(), new_array)
101
+ self.assertEqual(new_wrapped_dict.dimension_sizes, self.wrapped_dict.dimension_sizes)
102
+
103
+ def test_generate_dict_wrong_shape(self):
104
+ new_array = np.zeros((2, 3))
105
+ with self.assertRaises(WrongArrayShapeException):
106
+ self.wrapped_dict.generate_dict(new_array)
107
+
108
+
109
+ if __name__ == '__main__':
110
+ unittest.main()