Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +1 -0
- .venv/lib/python3.11/site-packages/einops-0.8.0.dist-info/INSTALLER +1 -0
- .venv/lib/python3.11/site-packages/einops-0.8.0.dist-info/METADATA +360 -0
- .venv/lib/python3.11/site-packages/einops-0.8.0.dist-info/RECORD +42 -0
- .venv/lib/python3.11/site-packages/einops-0.8.0.dist-info/WHEEL +4 -0
- .venv/lib/python3.11/site-packages/einops-0.8.0.dist-info/licenses/LICENSE +21 -0
- .venv/lib/python3.11/site-packages/fsspec/__pycache__/spec.cpython-311.pyc +3 -0
- .venv/lib/python3.11/site-packages/pycountry/COPYRIGHT.txt +46 -0
- .venv/lib/python3.11/site-packages/pycountry/__init__.py +303 -0
- .venv/lib/python3.11/site-packages/pycountry/db.py +200 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/an/LC_MESSAGES/iso3166-1.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/ay/LC_MESSAGES/iso3166-1.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/bar/LC_MESSAGES/iso3166-1.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/bi/LC_MESSAGES/iso3166-1.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/byn/LC_MESSAGES/iso3166-1.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/byn/LC_MESSAGES/iso3166-3.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/byn/LC_MESSAGES/iso639-3.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/ch/LC_MESSAGES/iso3166-1.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/ckb/LC_MESSAGES/iso3166-1.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/csb/LC_MESSAGES/iso3166-1.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/el/LC_MESSAGES/iso15924.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/el/LC_MESSAGES/iso3166-1.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/el/LC_MESSAGES/iso3166-2.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/el/LC_MESSAGES/iso3166-3.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/el/LC_MESSAGES/iso4217.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/el/LC_MESSAGES/iso639-3.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/el/LC_MESSAGES/iso639-5.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/gez/LC_MESSAGES/iso3166-1.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/gez/LC_MESSAGES/iso3166-3.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/gez/LC_MESSAGES/iso639-3.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/haw/LC_MESSAGES/iso3166-1.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/haw/LC_MESSAGES/iso3166-3.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/jam/LC_MESSAGES/iso3166-1.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/nah/LC_MESSAGES/iso3166-1.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/nn/LC_MESSAGES/iso15924.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/nn/LC_MESSAGES/iso3166-1.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/nn/LC_MESSAGES/iso3166-3.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/nn/LC_MESSAGES/iso4217.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/nn/LC_MESSAGES/iso639-3.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/or/LC_MESSAGES/iso3166-1.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/or/LC_MESSAGES/iso3166-3.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/pa_PK/LC_MESSAGES/iso15924.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/pa_PK/LC_MESSAGES/iso3166-2.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/pa_PK/LC_MESSAGES/iso3166-3.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/pi/LC_MESSAGES/iso3166-1.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/ru/LC_MESSAGES/iso15924.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/ru/LC_MESSAGES/iso3166-1.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/ru/LC_MESSAGES/iso3166-3.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/ru/LC_MESSAGES/iso4217.mo +0 -0
- .venv/lib/python3.11/site-packages/pycountry/locales/ru/LC_MESSAGES/iso639-3.mo +0 -0
.gitattributes
CHANGED
|
@@ -212,3 +212,4 @@ tuning-competition-baseline/.venv/lib/python3.11/site-packages/torch/_inductor/_
|
|
| 212 |
.venv/lib/python3.11/site-packages/frozenlist/_frozenlist.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 213 |
.venv/lib/python3.11/site-packages/uvloop/loop.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 214 |
.venv/lib/python3.11/site-packages/functorch/_C.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 212 |
.venv/lib/python3.11/site-packages/frozenlist/_frozenlist.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 213 |
.venv/lib/python3.11/site-packages/uvloop/loop.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 214 |
.venv/lib/python3.11/site-packages/functorch/_C.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 215 |
+
.venv/lib/python3.11/site-packages/fsspec/__pycache__/spec.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
.venv/lib/python3.11/site-packages/einops-0.8.0.dist-info/INSTALLER
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
pip
|
.venv/lib/python3.11/site-packages/einops-0.8.0.dist-info/METADATA
ADDED
|
@@ -0,0 +1,360 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Metadata-Version: 2.3
|
| 2 |
+
Name: einops
|
| 3 |
+
Version: 0.8.0
|
| 4 |
+
Summary: A new flavour of deep learning operations
|
| 5 |
+
Project-URL: Homepage, https://github.com/arogozhnikov/einops
|
| 6 |
+
Author: Alex Rogozhnikov
|
| 7 |
+
License: MIT
|
| 8 |
+
License-File: LICENSE
|
| 9 |
+
Keywords: deep learning,einops,machine learning,neural networks,scientific computations,tensor manipulation
|
| 10 |
+
Classifier: Intended Audience :: Science/Research
|
| 11 |
+
Classifier: License :: OSI Approved :: MIT License
|
| 12 |
+
Classifier: Programming Language :: Python :: 3
|
| 13 |
+
Requires-Python: >=3.8
|
| 14 |
+
Description-Content-Type: text/markdown
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
<!--
|
| 18 |
+
<a href='http://arogozhnikov.github.io/images/einops/einops_video.mp4' >
|
| 19 |
+
<div align="center">
|
| 20 |
+
<img src="http://arogozhnikov.github.io/images/einops/einops_video.gif" alt="einops package examples" />
|
| 21 |
+
<br>
|
| 22 |
+
<small><a href='http://arogozhnikov.github.io/images/einops/einops_video.mp4'>This video in high quality (mp4)</a></small>
|
| 23 |
+
<br><br>
|
| 24 |
+
</div>
|
| 25 |
+
</a>
|
| 26 |
+
-->
|
| 27 |
+
|
| 28 |
+
<!-- this link magically rendered as video, unfortunately not in docs -->
|
| 29 |
+
|
| 30 |
+
https://user-images.githubusercontent.com/6318811/177030658-66f0eb5d-e136-44d8-99c9-86ae298ead5b.mp4
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
# einops
|
| 36 |
+
[](https://github.com/arogozhnikov/einops/actions/workflows/run_tests.yml)
|
| 37 |
+
[](https://badge.fury.io/py/einops)
|
| 38 |
+
[](https://einops.rocks/)
|
| 39 |
+

|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
Flexible and powerful tensor operations for readable and reliable code. <br />
|
| 43 |
+
Supports numpy, pytorch, tensorflow, jax, and [others](#supported-frameworks).
|
| 44 |
+
|
| 45 |
+
## Recent updates:
|
| 46 |
+
|
| 47 |
+
- 0.7.0: no-hassle `torch.compile`, support of [array api standard](https://data-apis.org/array-api/latest/API_specification/index.html) and more
|
| 48 |
+
- 10'000🎉: github reports that more than 10k project use einops
|
| 49 |
+
- einops 0.6.1: paddle backend added
|
| 50 |
+
- einops 0.6 introduces [packing and unpacking](https://github.com/arogozhnikov/einops/blob/master/docs/4-pack-and-unpack.ipynb)
|
| 51 |
+
- einops 0.5: einsum is now a part of einops
|
| 52 |
+
- [Einops paper](https://openreview.net/pdf?id=oapKSVM2bcj) is accepted for oral presentation at ICLR 2022 (yes, it worth reading).
|
| 53 |
+
Talk recordings are [available](https://iclr.cc/virtual/2022/oral/6603)
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
<details markdown="1">
|
| 57 |
+
<summary>Previous updates</summary>
|
| 58 |
+
- flax and oneflow backend added
|
| 59 |
+
- torch.jit.script is supported for pytorch layers
|
| 60 |
+
- powerful EinMix added to einops. [Einmix tutorial notebook](https://github.com/arogozhnikov/einops/blob/master/docs/3-einmix-layer.ipynb)
|
| 61 |
+
</details>
|
| 62 |
+
|
| 63 |
+
<!--<div align="center">
|
| 64 |
+
<img src="http://arogozhnikov.github.io/images/einops/einops_logo_350x350.png"
|
| 65 |
+
alt="einops package logo" width="250" height="250" />
|
| 66 |
+
<br><br>
|
| 67 |
+
</div> -->
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
## Tweets
|
| 71 |
+
|
| 72 |
+
> In case you need convincing arguments for setting aside time to learn about einsum and einops...
|
| 73 |
+
[Tim Rocktäschel](https://twitter.com/_rockt/status/1230818967205425152)
|
| 74 |
+
|
| 75 |
+
> Writing better code with PyTorch and einops 👌
|
| 76 |
+
[Andrej Karpathy](https://twitter.com/karpathy/status/1290826075916779520)
|
| 77 |
+
|
| 78 |
+
> Slowly but surely, einops is seeping in to every nook and cranny of my code. If you find yourself shuffling around bazillion dimensional tensors, this might change your life
|
| 79 |
+
[Nasim Rahaman](https://twitter.com/nasim_rahaman/status/1216022614755463169)
|
| 80 |
+
|
| 81 |
+
[More testimonials](https://einops.rocks/pages/testimonials/)
|
| 82 |
+
|
| 83 |
+
<!--
|
| 84 |
+
## Recordings of talk at ICLR 2022
|
| 85 |
+
|
| 86 |
+
<a href='https://iclr.cc/virtual/2022/oral/6603'>
|
| 87 |
+
<img width="922" alt="Screen Shot 2022-07-03 at 1 00 15 AM" src="https://user-images.githubusercontent.com/6318811/177030789-89d349bf-ef75-4af5-a71f-609896d1c8d9.png">
|
| 88 |
+
</a>
|
| 89 |
+
|
| 90 |
+
Watch [a 15-minute talk](https://iclr.cc/virtual/2022/oral/6603) focused on main problems of standard tensor manipulation methods, and how einops improves this process.
|
| 91 |
+
-->
|
| 92 |
+
|
| 93 |
+
## Contents
|
| 94 |
+
|
| 95 |
+
- [Installation](#Installation)
|
| 96 |
+
- [Documentation](https://einops.rocks/)
|
| 97 |
+
- [Tutorial](#Tutorials)
|
| 98 |
+
- [API micro-reference](#API)
|
| 99 |
+
- [Why using einops](#Why-using-einops-notation)
|
| 100 |
+
- [Supported frameworks](#Supported-frameworks)
|
| 101 |
+
- [Citing](#Citing)
|
| 102 |
+
- [Repository](https://github.com/arogozhnikov/einops) and [discussions](https://github.com/arogozhnikov/einops/discussions)
|
| 103 |
+
|
| 104 |
+
## Installation <a name="Installation"></a>
|
| 105 |
+
|
| 106 |
+
Plain and simple:
|
| 107 |
+
```bash
|
| 108 |
+
pip install einops
|
| 109 |
+
```
|
| 110 |
+
|
| 111 |
+
<!--
|
| 112 |
+
`einops` has no mandatory dependencies (code examples also require jupyter, pillow + backends).
|
| 113 |
+
To obtain the latest github version
|
| 114 |
+
|
| 115 |
+
```bash
|
| 116 |
+
pip install https://github.com/arogozhnikov/einops/archive/master.zip
|
| 117 |
+
```
|
| 118 |
+
-->
|
| 119 |
+
|
| 120 |
+
## Tutorials <a name="Tutorials"></a>
|
| 121 |
+
|
| 122 |
+
Tutorials are the most convenient way to see `einops` in action
|
| 123 |
+
|
| 124 |
+
- part 1: [einops fundamentals](https://github.com/arogozhnikov/einops/blob/master/docs/1-einops-basics.ipynb)
|
| 125 |
+
- part 2: [einops for deep learning](https://github.com/arogozhnikov/einops/blob/master/docs/2-einops-for-deep-learning.ipynb)
|
| 126 |
+
- part 3: [packing and unpacking](https://github.com/arogozhnikov/einops/blob/master/docs/4-pack-and-unpack.ipynb)
|
| 127 |
+
- part 4: [improve pytorch code with einops](http://einops.rocks/pytorch-examples.html)
|
| 128 |
+
|
| 129 |
+
Kapil Sachdeva recorded a small [intro to einops](https://www.youtube.com/watch?v=xGy75Pjsqzo).
|
| 130 |
+
|
| 131 |
+
## API <a name="API"></a>
|
| 132 |
+
|
| 133 |
+
`einops` has a minimalistic yet powerful API.
|
| 134 |
+
|
| 135 |
+
Three core operations provided ([einops tutorial](https://github.com/arogozhnikov/einops/blob/master/docs/)
|
| 136 |
+
shows those cover stacking, reshape, transposition, squeeze/unsqueeze, repeat, tile, concatenate, view and numerous reductions)
|
| 137 |
+
|
| 138 |
+
```python
|
| 139 |
+
from einops import rearrange, reduce, repeat
|
| 140 |
+
# rearrange elements according to the pattern
|
| 141 |
+
output_tensor = rearrange(input_tensor, 't b c -> b c t')
|
| 142 |
+
# combine rearrangement and reduction
|
| 143 |
+
output_tensor = reduce(input_tensor, 'b c (h h2) (w w2) -> b h w c', 'mean', h2=2, w2=2)
|
| 144 |
+
# copy along a new axis
|
| 145 |
+
output_tensor = repeat(input_tensor, 'h w -> h w c', c=3)
|
| 146 |
+
```
|
| 147 |
+
|
| 148 |
+
Later additions to the family are `pack` and `unpack` functions (better than stack/split/concatenate):
|
| 149 |
+
|
| 150 |
+
```python
|
| 151 |
+
from einops import pack, unpack
|
| 152 |
+
# pack and unpack allow reversibly 'packing' multiple tensors into one.
|
| 153 |
+
# Packed tensors may be of different dimensionality:
|
| 154 |
+
packed, ps = pack([class_token_bc, image_tokens_bhwc, text_tokens_btc], 'b * c')
|
| 155 |
+
class_emb_bc, image_emb_bhwc, text_emb_btc = unpack(transformer(packed), ps, 'b * c')
|
| 156 |
+
```
|
| 157 |
+
|
| 158 |
+
Finally, einops provides einsum with a support of multi-lettered names:
|
| 159 |
+
|
| 160 |
+
```python
|
| 161 |
+
from einops import einsum, pack, unpack
|
| 162 |
+
# einsum is like ... einsum, generic and flexible dot-product
|
| 163 |
+
# but 1) axes can be multi-lettered 2) pattern goes last 3) works with multiple frameworks
|
| 164 |
+
C = einsum(A, B, 'b t1 head c, b t2 head c -> b head t1 t2')
|
| 165 |
+
```
|
| 166 |
+
|
| 167 |
+
### EinMix
|
| 168 |
+
|
| 169 |
+
`EinMix` is a generic linear layer, perfect for MLP Mixers and similar architectures.
|
| 170 |
+
|
| 171 |
+
### Layers
|
| 172 |
+
|
| 173 |
+
Einops provides layers (`einops` keeps a separate version for each framework) that reflect corresponding functions
|
| 174 |
+
|
| 175 |
+
```python
|
| 176 |
+
from einops.layers.torch import Rearrange, Reduce
|
| 177 |
+
from einops.layers.tensorflow import Rearrange, Reduce
|
| 178 |
+
from einops.layers.flax import Rearrange, Reduce
|
| 179 |
+
from einops.layers.paddle import Rearrange, Reduce
|
| 180 |
+
from einops.layers.chainer import Rearrange, Reduce
|
| 181 |
+
```
|
| 182 |
+
|
| 183 |
+
<details markdown="1">
|
| 184 |
+
<summary>Example of using layers within a pytorch model</summary>
|
| 185 |
+
Example given for pytorch, but code in other frameworks is almost identical
|
| 186 |
+
|
| 187 |
+
```python
|
| 188 |
+
from torch.nn import Sequential, Conv2d, MaxPool2d, Linear, ReLU
|
| 189 |
+
from einops.layers.torch import Rearrange
|
| 190 |
+
|
| 191 |
+
model = Sequential(
|
| 192 |
+
...,
|
| 193 |
+
Conv2d(6, 16, kernel_size=5),
|
| 194 |
+
MaxPool2d(kernel_size=2),
|
| 195 |
+
# flattening without need to write forward
|
| 196 |
+
Rearrange('b c h w -> b (c h w)'),
|
| 197 |
+
Linear(16*5*5, 120),
|
| 198 |
+
ReLU(),
|
| 199 |
+
Linear(120, 10),
|
| 200 |
+
)
|
| 201 |
+
```
|
| 202 |
+
|
| 203 |
+
No more flatten needed!
|
| 204 |
+
|
| 205 |
+
Additionally, torch users will benefit from layers as those are script-able and compile-able.
|
| 206 |
+
</details>
|
| 207 |
+
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
## Naming <a name="Naming"></a>
|
| 212 |
+
|
| 213 |
+
`einops` stands for Einstein-Inspired Notation for operations
|
| 214 |
+
(though "Einstein operations" is more attractive and easier to remember).
|
| 215 |
+
|
| 216 |
+
Notation was loosely inspired by Einstein summation (in particular by `numpy.einsum` operation).
|
| 217 |
+
|
| 218 |
+
## Why use `einops` notation?! <a name="Why-using-einops-notation"></a>
|
| 219 |
+
|
| 220 |
+
|
| 221 |
+
### Semantic information (being verbose in expectations)
|
| 222 |
+
|
| 223 |
+
```python
|
| 224 |
+
y = x.view(x.shape[0], -1)
|
| 225 |
+
y = rearrange(x, 'b c h w -> b (c h w)')
|
| 226 |
+
```
|
| 227 |
+
While these two lines are doing the same job in *some* context,
|
| 228 |
+
the second one provides information about the input and output.
|
| 229 |
+
In other words, `einops` focuses on interface: *what is the input and output*, not *how* the output is computed.
|
| 230 |
+
|
| 231 |
+
The next operation looks similar:
|
| 232 |
+
|
| 233 |
+
```python
|
| 234 |
+
y = rearrange(x, 'time c h w -> time (c h w)')
|
| 235 |
+
```
|
| 236 |
+
but it gives the reader a hint:
|
| 237 |
+
this is not an independent batch of images we are processing,
|
| 238 |
+
but rather a sequence (video).
|
| 239 |
+
|
| 240 |
+
Semantic information makes the code easier to read and maintain.
|
| 241 |
+
|
| 242 |
+
### Convenient checks
|
| 243 |
+
|
| 244 |
+
Reconsider the same example:
|
| 245 |
+
|
| 246 |
+
```python
|
| 247 |
+
y = x.view(x.shape[0], -1) # x: (batch, 256, 19, 19)
|
| 248 |
+
y = rearrange(x, 'b c h w -> b (c h w)')
|
| 249 |
+
```
|
| 250 |
+
The second line checks that the input has four dimensions,
|
| 251 |
+
but you can also specify particular dimensions.
|
| 252 |
+
That's opposed to just writing comments about shapes since comments don't prevent mistakes, not tested, and without code review tend to be outdated
|
| 253 |
+
```python
|
| 254 |
+
y = x.view(x.shape[0], -1) # x: (batch, 256, 19, 19)
|
| 255 |
+
y = rearrange(x, 'b c h w -> b (c h w)', c=256, h=19, w=19)
|
| 256 |
+
```
|
| 257 |
+
|
| 258 |
+
### Result is strictly determined
|
| 259 |
+
|
| 260 |
+
Below we have at least two ways to define the depth-to-space operation
|
| 261 |
+
```python
|
| 262 |
+
# depth-to-space
|
| 263 |
+
rearrange(x, 'b c (h h2) (w w2) -> b (c h2 w2) h w', h2=2, w2=2)
|
| 264 |
+
rearrange(x, 'b c (h h2) (w w2) -> b (h2 w2 c) h w', h2=2, w2=2)
|
| 265 |
+
```
|
| 266 |
+
There are at least four more ways to do it. Which one is used by the framework?
|
| 267 |
+
|
| 268 |
+
These details are ignored, since *usually* it makes no difference,
|
| 269 |
+
but it can make a big difference (e.g. if you use grouped convolutions in the next stage),
|
| 270 |
+
and you'd like to specify this in your code.
|
| 271 |
+
|
| 272 |
+
|
| 273 |
+
### Uniformity
|
| 274 |
+
|
| 275 |
+
```python
|
| 276 |
+
reduce(x, 'b c (x dx) -> b c x', 'max', dx=2)
|
| 277 |
+
reduce(x, 'b c (x dx) (y dy) -> b c x y', 'max', dx=2, dy=3)
|
| 278 |
+
reduce(x, 'b c (x dx) (y dy) (z dz) -> b c x y z', 'max', dx=2, dy=3, dz=4)
|
| 279 |
+
```
|
| 280 |
+
These examples demonstrated that we don't use separate operations for 1d/2d/3d pooling,
|
| 281 |
+
those are all defined in a uniform way.
|
| 282 |
+
|
| 283 |
+
Space-to-depth and depth-to space are defined in many frameworks but how about width-to-height? Here you go:
|
| 284 |
+
|
| 285 |
+
```python
|
| 286 |
+
rearrange(x, 'b c h (w w2) -> b c (h w2) w', w2=2)
|
| 287 |
+
```
|
| 288 |
+
|
| 289 |
+
### Framework independent behavior
|
| 290 |
+
|
| 291 |
+
Even simple functions are defined differently by different frameworks
|
| 292 |
+
|
| 293 |
+
```python
|
| 294 |
+
y = x.flatten() # or flatten(x)
|
| 295 |
+
```
|
| 296 |
+
|
| 297 |
+
Suppose `x`'s shape was `(3, 4, 5)`, then `y` has shape ...
|
| 298 |
+
|
| 299 |
+
- numpy, pytorch, cupy, chainer: `(60,)`
|
| 300 |
+
- keras, tensorflow.layers, gluon: `(3, 20)`
|
| 301 |
+
|
| 302 |
+
`einops` works the same way in all frameworks.
|
| 303 |
+
|
| 304 |
+
### Independence of framework terminology
|
| 305 |
+
|
| 306 |
+
Example: `tile` vs `repeat` causes lots of confusion. To copy image along width:
|
| 307 |
+
```python
|
| 308 |
+
np.tile(image, (1, 2)) # in numpy
|
| 309 |
+
image.repeat(1, 2) # pytorch's repeat ~ numpy's tile
|
| 310 |
+
```
|
| 311 |
+
|
| 312 |
+
With einops you don't need to decipher which axis was repeated:
|
| 313 |
+
```python
|
| 314 |
+
repeat(image, 'h w -> h (tile w)', tile=2) # in numpy
|
| 315 |
+
repeat(image, 'h w -> h (tile w)', tile=2) # in pytorch
|
| 316 |
+
repeat(image, 'h w -> h (tile w)', tile=2) # in tf
|
| 317 |
+
repeat(image, 'h w -> h (tile w)', tile=2) # in jax
|
| 318 |
+
repeat(image, 'h w -> h (tile w)', tile=2) # in cupy
|
| 319 |
+
... (etc.)
|
| 320 |
+
```
|
| 321 |
+
|
| 322 |
+
[Testimonials](https://einops.rocks/pages/testimonials/) provide users' perspective on the same question.
|
| 323 |
+
|
| 324 |
+
## Supported frameworks <a name="Supported-frameworks"></a>
|
| 325 |
+
|
| 326 |
+
Einops works with ...
|
| 327 |
+
|
| 328 |
+
- [numpy](http://www.numpy.org/)
|
| 329 |
+
- [pytorch](https://pytorch.org/)
|
| 330 |
+
- [tensorflow](https://www.tensorflow.org/)
|
| 331 |
+
- [jax](https://github.com/google/jax)
|
| 332 |
+
- [cupy](https://cupy.chainer.org/)
|
| 333 |
+
- [chainer](https://chainer.org/)
|
| 334 |
+
- [tf.keras](https://www.tensorflow.org/guide/keras)
|
| 335 |
+
- [flax](https://github.com/google/flax) (experimental)
|
| 336 |
+
- [paddle](https://github.com/PaddlePaddle/Paddle) (experimental)
|
| 337 |
+
- [oneflow](https://github.com/Oneflow-Inc/oneflow) (community)
|
| 338 |
+
- [tinygrad](https://github.com/tinygrad/tinygrad) (community)
|
| 339 |
+
|
| 340 |
+
Additionally, starting from einops 0.7.0 einops can be used with any framework that supports [Python array API standard](https://data-apis.org/array-api/latest/API_specification/index.html)
|
| 341 |
+
|
| 342 |
+
## Citing einops <a name="Citing"></a>
|
| 343 |
+
|
| 344 |
+
Please use the following bibtex record
|
| 345 |
+
|
| 346 |
+
```text
|
| 347 |
+
@inproceedings{
|
| 348 |
+
rogozhnikov2022einops,
|
| 349 |
+
title={Einops: Clear and Reliable Tensor Manipulations with Einstein-like Notation},
|
| 350 |
+
author={Alex Rogozhnikov},
|
| 351 |
+
booktitle={International Conference on Learning Representations},
|
| 352 |
+
year={2022},
|
| 353 |
+
url={https://openreview.net/forum?id=oapKSVM2bcj}
|
| 354 |
+
}
|
| 355 |
+
```
|
| 356 |
+
|
| 357 |
+
|
| 358 |
+
## Supported python versions
|
| 359 |
+
|
| 360 |
+
`einops` works with python 3.8 or later.
|
.venv/lib/python3.11/site-packages/einops-0.8.0.dist-info/RECORD
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
einops-0.8.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
| 2 |
+
einops-0.8.0.dist-info/METADATA,sha256=5hTpaWnwYNe3QvhbXYTpA_LUJ2lSlyspSc0gRGni7sY,12926
|
| 3 |
+
einops-0.8.0.dist-info/RECORD,,
|
| 4 |
+
einops-0.8.0.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
|
| 5 |
+
einops-0.8.0.dist-info/licenses/LICENSE,sha256=MNmENkKW9R_67K1LAe4SfpUlDFBokY1LZvyWIGcj5DQ,1073
|
| 6 |
+
einops/__init__.py,sha256=UdixJ9CShlEOQfw0xcU6zYtrAn6Durgh6jCQWdcaQK4,422
|
| 7 |
+
einops/__pycache__/__init__.cpython-311.pyc,,
|
| 8 |
+
einops/__pycache__/_backends.cpython-311.pyc,,
|
| 9 |
+
einops/__pycache__/_torch_specific.cpython-311.pyc,,
|
| 10 |
+
einops/__pycache__/array_api.cpython-311.pyc,,
|
| 11 |
+
einops/__pycache__/einops.cpython-311.pyc,,
|
| 12 |
+
einops/__pycache__/packing.cpython-311.pyc,,
|
| 13 |
+
einops/__pycache__/parsing.cpython-311.pyc,,
|
| 14 |
+
einops/_backends.py,sha256=VHPPrL1mf0PDTvyFPZvmZeTqGJoWflqv7b-eoJUHudo,21081
|
| 15 |
+
einops/_torch_specific.py,sha256=yMaQeqAZhBLWR1Q-Jv6uRINJfzROhLb-rzKKevpefUU,4138
|
| 16 |
+
einops/array_api.py,sha256=FcKZSo7l8jC5HL8qudutz1K5x9cFpwACMDcjfbvEKmQ,5251
|
| 17 |
+
einops/einops.py,sha256=AYZe5yMlH-EXO0MWFv27ajyPdVTFpYloaSCRM9jw5sA,37252
|
| 18 |
+
einops/experimental/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 19 |
+
einops/experimental/__pycache__/__init__.cpython-311.pyc,,
|
| 20 |
+
einops/experimental/__pycache__/indexing.cpython-311.pyc,,
|
| 21 |
+
einops/experimental/indexing.py,sha256=4NtRNmSOrpUURvwhrbbGNK3NeTxHI4EW8R6ct3JZyLw,14868
|
| 22 |
+
einops/layers/__init__.py,sha256=vBtnAt2afs4QlqpeFU4dlZNxBuC9IXl3fmilk-2OzHM,3747
|
| 23 |
+
einops/layers/__pycache__/__init__.cpython-311.pyc,,
|
| 24 |
+
einops/layers/__pycache__/_einmix.cpython-311.pyc,,
|
| 25 |
+
einops/layers/__pycache__/chainer.cpython-311.pyc,,
|
| 26 |
+
einops/layers/__pycache__/flax.cpython-311.pyc,,
|
| 27 |
+
einops/layers/__pycache__/keras.cpython-311.pyc,,
|
| 28 |
+
einops/layers/__pycache__/oneflow.cpython-311.pyc,,
|
| 29 |
+
einops/layers/__pycache__/paddle.cpython-311.pyc,,
|
| 30 |
+
einops/layers/__pycache__/tensorflow.cpython-311.pyc,,
|
| 31 |
+
einops/layers/__pycache__/torch.cpython-311.pyc,,
|
| 32 |
+
einops/layers/_einmix.py,sha256=0cl3r4Xp44S2HO-tx0MHa4cMFD2KJXpG5O-4gJM5AtU,8464
|
| 33 |
+
einops/layers/chainer.py,sha256=hUB-XSjN5CP8zALZtalL3n2lQkq7vymftRI8okEMO2Q,1861
|
| 34 |
+
einops/layers/flax.py,sha256=zFy83gSLRm31cLuKFRvZ82_HsefnXPbRvkKZh1KkC1I,2536
|
| 35 |
+
einops/layers/keras.py,sha256=-7So0w94phvf9HdW0xi2mSeBg02qVPvAyfp_1XR02NM,212
|
| 36 |
+
einops/layers/oneflow.py,sha256=YEPzz4xc7BDRQfb8ulD3teqQJdbO6qQg7Z4KIPVTLz8,1864
|
| 37 |
+
einops/layers/paddle.py,sha256=8cRZQ8BT9vYEczh7pNProuTM_3XjLty2ht2sdvXNFiI,1907
|
| 38 |
+
einops/layers/tensorflow.py,sha256=T9uhSVwbXREahc31ARAHoN5K-7zsuS8NRNPdY6Zk1Bc,3324
|
| 39 |
+
einops/layers/torch.py,sha256=504G99kEgy7dk1UPBbj9hzJmZkAHwVhMDFN_8J-p3C8,2399
|
| 40 |
+
einops/packing.py,sha256=Ln2lAMko9hobi_qd-4dPtQY0Ks5hRK7x-5FthL2gunk,7654
|
| 41 |
+
einops/parsing.py,sha256=xbqcvwReLiROEucoegZ20WQiEHlLg0uxo_vYoezKB_4,6746
|
| 42 |
+
einops/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
.venv/lib/python3.11/site-packages/einops-0.8.0.dist-info/WHEEL
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Wheel-Version: 1.0
|
| 2 |
+
Generator: hatchling 1.24.2
|
| 3 |
+
Root-Is-Purelib: true
|
| 4 |
+
Tag: py3-none-any
|
.venv/lib/python3.11/site-packages/einops-0.8.0.dist-info/licenses/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2018 Alex Rogozhnikov
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
.venv/lib/python3.11/site-packages/fsspec/__pycache__/spec.cpython-311.pyc
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:35393347e555c64ec1f982848d600d95a4cba3d655679aa08a140b06534d80c6
|
| 3 |
+
size 100192
|
.venv/lib/python3.11/site-packages/pycountry/COPYRIGHT.txt
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
COPYRIGHT (c) 2008 - 2023, pycountry
|
| 2 |
+
|
| 3 |
+
Pycountry is free software; you can redistribute it and/or modify
|
| 4 |
+
it under the terms of the GNU Lesser General Public License as published by
|
| 5 |
+
the Free Software Foundation; either version 2.1 of the License, or any later version.
|
| 6 |
+
|
| 7 |
+
This project is distributed in the hope that it will be useful,
|
| 8 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 9 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 10 |
+
GNU Lesser General Public License for more details.
|
| 11 |
+
|
| 12 |
+
Contributors:
|
| 13 |
+
- Christian Theune (2008-2020, 2022)
|
| 14 |
+
- Nate Schimmoller (2022-2023)
|
| 15 |
+
- Zachary Ware (2016, 2023)
|
| 16 |
+
- Alan Orth (2023)
|
| 17 |
+
- Ashok Argent-Katwala (2020)
|
| 18 |
+
- Bastien Vallet (2020)
|
| 19 |
+
- Chris R Bunney 2020
|
| 20 |
+
- Christian Zagrodnick (2012-2013)
|
| 21 |
+
- Christoph Zwerschke (2013)
|
| 22 |
+
- Jakub Wilk (2020)
|
| 23 |
+
- Janis Kirsteins (2019)
|
| 24 |
+
- Justin Ryan Wagner 2014
|
| 25 |
+
- Kevin Deldycke (2014, 2016)
|
| 26 |
+
- Louis Sautier (2020)
|
| 27 |
+
- Lucas Wiman (2015)
|
| 28 |
+
- Mario Vilas (2014)
|
| 29 |
+
- Michael Howitz (2020)
|
| 30 |
+
- Michał Bielawski (2021, 2023)
|
| 31 |
+
- Michał Górny (2020)
|
| 32 |
+
- Mike Taves (2023)
|
| 33 |
+
- Pedro Ferreira (2013)
|
| 34 |
+
- Stuart Prescott (2021)
|
| 35 |
+
- Victor Mireyev (2016)
|
| 36 |
+
- simon klemenc (2016)
|
| 37 |
+
|
| 38 |
+
Additional Acknowledgements and Licensing Information:
|
| 39 |
+
- Data in the /src/databases/ and /src/locales/ folders is sourced from the Debian iso-codes project, available at: https://salsa.debian.org/iso-codes-team/iso-codes. This data is used under the terms of the GNU Lesser General Public License Version 2.1 (February 1999).
|
| 40 |
+
|
| 41 |
+
The Debian iso-codes project is a collection of code lists for different standards, maintained and made available under the GNU Lesser General Public License Version 2.1. We gratefully acknowledge the Debian iso-codes team and contributors for their work and for making this resource freely available.
|
| 42 |
+
|
| 43 |
+
The full text of the GNU Lesser General Public License Version 2.1 can be found at: https://salsa.debian.org/iso-codes-team/iso-codes/-/blob/main/COPYING.
|
| 44 |
+
|
| 45 |
+
For the full text of the GNU Lesser General Public License,
|
| 46 |
+
see https://github.com/pycountry/pycountry/blob/main/LICENSE.txt.
|
.venv/lib/python3.11/site-packages/pycountry/__init__.py
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""pycountry"""
|
| 2 |
+
|
| 3 |
+
import os.path
|
| 4 |
+
import unicodedata
|
| 5 |
+
from importlib import metadata as _importlib_metadata
|
| 6 |
+
from typing import Dict, List, Optional, Type
|
| 7 |
+
|
| 8 |
+
import pycountry.db
|
| 9 |
+
|
| 10 |
+
# We prioritise importing the backported `importlib_resources`
|
| 11 |
+
# because the function we use (`importlib.resources.files`) is only
|
| 12 |
+
# available from Python 3.9, but the module itself exists since 3.7.
|
| 13 |
+
# We install `importlib_resources` on Python < 3.9.
|
| 14 |
+
# TODO: Remove usage of importlib_resources once support for Python 3.8 is dropped
|
| 15 |
+
try:
|
| 16 |
+
import importlib_resources # type: ignore
|
| 17 |
+
except ModuleNotFoundError:
|
| 18 |
+
from importlib import resources as importlib_resources # type: ignore
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def resource_filename(package_or_requirement: str, resource_name: str) -> str:
|
| 22 |
+
return str(
|
| 23 |
+
importlib_resources.files(package_or_requirement) / resource_name
|
| 24 |
+
)
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def get_version(distribution_name: str) -> Optional[str]:
|
| 28 |
+
try:
|
| 29 |
+
return _importlib_metadata.version(distribution_name)
|
| 30 |
+
except _importlib_metadata.PackageNotFoundError:
|
| 31 |
+
return "n/a"
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
# Variable annotations
|
| 35 |
+
LOCALES_DIR: str = resource_filename("pycountry", "locales")
|
| 36 |
+
DATABASE_DIR: str = resource_filename("pycountry", "databases")
|
| 37 |
+
__version__: Optional[str] = get_version("pycountry")
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def remove_accents(input_str: str) -> str:
|
| 41 |
+
output_str = input_str
|
| 42 |
+
if not input_str.isascii():
|
| 43 |
+
# Borrowed from https://stackoverflow.com/a/517974/1509718
|
| 44 |
+
nfkd_form = unicodedata.normalize("NFKD", input_str)
|
| 45 |
+
output_str = "".join(
|
| 46 |
+
[c for c in nfkd_form if not unicodedata.combining(c)]
|
| 47 |
+
)
|
| 48 |
+
return output_str
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
class ExistingCountries(pycountry.db.Database):
|
| 52 |
+
"""Provides access to an ISO 3166 database (Countries)."""
|
| 53 |
+
|
| 54 |
+
data_class = pycountry.db.Country
|
| 55 |
+
root_key = "3166-1"
|
| 56 |
+
|
| 57 |
+
def search_fuzzy(self, query: str) -> List[Type["ExistingCountries"]]:
|
| 58 |
+
query = remove_accents(query.strip().lower())
|
| 59 |
+
|
| 60 |
+
# A country-code to points mapping for later sorting countries
|
| 61 |
+
# based on the query's matching incidence.
|
| 62 |
+
results: dict[str, int] = {}
|
| 63 |
+
|
| 64 |
+
def add_result(country: "pycountry.db.Country", points: int) -> None:
|
| 65 |
+
results.setdefault(country.alpha_2, 0)
|
| 66 |
+
results[country.alpha_2] += points
|
| 67 |
+
|
| 68 |
+
# Prio 1: exact matches on country names
|
| 69 |
+
try:
|
| 70 |
+
add_result(self.lookup(query), 50)
|
| 71 |
+
except LookupError:
|
| 72 |
+
pass
|
| 73 |
+
|
| 74 |
+
# Prio 2: exact matches on subdivision names
|
| 75 |
+
match_subdivions = pycountry.Subdivisions.match(
|
| 76 |
+
self=subdivisions, query=query
|
| 77 |
+
)
|
| 78 |
+
for candidate in match_subdivions:
|
| 79 |
+
add_result(candidate.country, 49)
|
| 80 |
+
|
| 81 |
+
# Prio 3: partial matches on country names
|
| 82 |
+
for candidate in self:
|
| 83 |
+
# Higher priority for a match on the common name
|
| 84 |
+
for v in [
|
| 85 |
+
candidate._fields.get("name"),
|
| 86 |
+
candidate._fields.get("official_name"),
|
| 87 |
+
candidate._fields.get("comment"),
|
| 88 |
+
]:
|
| 89 |
+
if v is not None:
|
| 90 |
+
v = remove_accents(v.lower())
|
| 91 |
+
if query in v:
|
| 92 |
+
# This prefers countries with a match early in their name
|
| 93 |
+
# and also balances against countries with a number of
|
| 94 |
+
# partial matches and their name containing 'new' in the
|
| 95 |
+
# middle
|
| 96 |
+
add_result(
|
| 97 |
+
candidate, max([5, 30 - (2 * v.find(query))])
|
| 98 |
+
)
|
| 99 |
+
break
|
| 100 |
+
|
| 101 |
+
# Prio 4: partial matches on subdivision names
|
| 102 |
+
partial_match_subdivisions = pycountry.Subdivisions.partial_match(
|
| 103 |
+
self=subdivisions, query=query
|
| 104 |
+
)
|
| 105 |
+
for candidate in partial_match_subdivisions:
|
| 106 |
+
v = candidate._fields.get("name")
|
| 107 |
+
v = remove_accents(v.lower())
|
| 108 |
+
if query in v:
|
| 109 |
+
add_result(candidate.country, max([1, 5 - v.find(query)]))
|
| 110 |
+
|
| 111 |
+
if not results:
|
| 112 |
+
raise LookupError(query)
|
| 113 |
+
|
| 114 |
+
sorted_results = [
|
| 115 |
+
self.get(alpha_2=x[0])
|
| 116 |
+
# sort by points first, by alpha2 code second, and to ensure stable
|
| 117 |
+
# results the negative value allows us to sort reversely on the
|
| 118 |
+
# points but ascending on the country code.
|
| 119 |
+
for x in sorted(results.items(), key=lambda x: (-x[1], x[0]))
|
| 120 |
+
]
|
| 121 |
+
return sorted_results
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
class HistoricCountries(ExistingCountries):
|
| 125 |
+
"""Provides access to an ISO 3166-3 database
|
| 126 |
+
(Countries that have been removed from the standard)."""
|
| 127 |
+
|
| 128 |
+
data_class = pycountry.db.Country
|
| 129 |
+
root_key = "3166-3"
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
class Scripts(pycountry.db.Database):
|
| 133 |
+
"""Provides access to an ISO 15924 database (Scripts)."""
|
| 134 |
+
|
| 135 |
+
data_class = "Script"
|
| 136 |
+
root_key = "15924"
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
class Currencies(pycountry.db.Database):
|
| 140 |
+
"""Provides access to an ISO 4217 database (Currencies)."""
|
| 141 |
+
|
| 142 |
+
data_class = "Currency"
|
| 143 |
+
root_key = "4217"
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
class Languages(pycountry.db.Database):
|
| 147 |
+
"""Provides access to an ISO 639-1/2T/3 database (Languages)."""
|
| 148 |
+
|
| 149 |
+
no_index = ["status", "scope", "type", "inverted_name", "common_name"]
|
| 150 |
+
|
| 151 |
+
data_class = "Language"
|
| 152 |
+
root_key = "639-3"
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
class LanguageFamilies(pycountry.db.Database):
|
| 156 |
+
"""Provides access to an ISO 639-5 database
|
| 157 |
+
(Language Families and Groups)."""
|
| 158 |
+
|
| 159 |
+
data_class = "LanguageFamily"
|
| 160 |
+
root_key = "639-5"
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
class SubdivisionHierarchy(pycountry.db.Data):
|
| 164 |
+
def __init__(self, **kw):
|
| 165 |
+
if "parent" in kw:
|
| 166 |
+
kw["parent_code"] = kw["parent"]
|
| 167 |
+
else:
|
| 168 |
+
kw["parent_code"] = None
|
| 169 |
+
super().__init__(**kw)
|
| 170 |
+
self.country_code = self.code.split("-")[0]
|
| 171 |
+
if self.parent_code is not None:
|
| 172 |
+
# Split the parent_code to check if the country_code is already present
|
| 173 |
+
parts = self.parent_code.split("-")
|
| 174 |
+
if parts[0] != self.country_code:
|
| 175 |
+
self.parent_code = f"{self.country_code}-{self.parent_code}"
|
| 176 |
+
|
| 177 |
+
@property
|
| 178 |
+
def country(self):
|
| 179 |
+
return countries.get(alpha_2=self.country_code)
|
| 180 |
+
|
| 181 |
+
@property
|
| 182 |
+
def parent(self):
|
| 183 |
+
if not self.parent_code:
|
| 184 |
+
return None
|
| 185 |
+
return subdivisions.get(code=self.parent_code)
|
| 186 |
+
|
| 187 |
+
|
| 188 |
+
class Subdivisions(pycountry.db.Database):
|
| 189 |
+
# Note: subdivisions can be hierarchical to other subdivisions. The
|
| 190 |
+
# parent_code attribute is related to other subdivisions, *not*
|
| 191 |
+
# the country!
|
| 192 |
+
|
| 193 |
+
data_class = SubdivisionHierarchy
|
| 194 |
+
no_index = ["name", "parent_code", "parent", "type"]
|
| 195 |
+
root_key = "3166-2"
|
| 196 |
+
|
| 197 |
+
def _load(self, *args, **kw):
|
| 198 |
+
super()._load(*args, **kw)
|
| 199 |
+
|
| 200 |
+
# Add index for the country code.
|
| 201 |
+
self.indices["country_code"] = {}
|
| 202 |
+
for subdivision in self:
|
| 203 |
+
divs = self.indices["country_code"].setdefault(
|
| 204 |
+
subdivision.country_code.lower(), set()
|
| 205 |
+
)
|
| 206 |
+
divs.add(subdivision)
|
| 207 |
+
|
| 208 |
+
def get(self, **kw):
|
| 209 |
+
default = kw.setdefault("default", None)
|
| 210 |
+
subdivisions = super().get(**kw)
|
| 211 |
+
if subdivisions is default and "country_code" in kw:
|
| 212 |
+
# This handles the case where we know about a country but there
|
| 213 |
+
# are no subdivisions: we return an empty list in this case
|
| 214 |
+
# (sticking to the expected type here) instead of None.
|
| 215 |
+
if countries.get(alpha_2=kw["country_code"]) is not None:
|
| 216 |
+
return []
|
| 217 |
+
return subdivisions
|
| 218 |
+
|
| 219 |
+
def match(self, query):
|
| 220 |
+
query = remove_accents(query.strip().lower())
|
| 221 |
+
matching_candidates = []
|
| 222 |
+
for candidate in subdivisions:
|
| 223 |
+
for v in candidate._fields.values():
|
| 224 |
+
if v is not None:
|
| 225 |
+
v = remove_accents(v.lower())
|
| 226 |
+
# Some names include alternative versions which we want to
|
| 227 |
+
# match exactly.
|
| 228 |
+
for w in v.split(";"):
|
| 229 |
+
if w == query:
|
| 230 |
+
matching_candidates.append(candidate)
|
| 231 |
+
break
|
| 232 |
+
|
| 233 |
+
return matching_candidates
|
| 234 |
+
|
| 235 |
+
def partial_match(self, query):
|
| 236 |
+
query = remove_accents(query.strip().lower())
|
| 237 |
+
matching_candidates = []
|
| 238 |
+
for candidate in subdivisions:
|
| 239 |
+
v = candidate._fields.get("name")
|
| 240 |
+
v = remove_accents(v.lower())
|
| 241 |
+
if query in v:
|
| 242 |
+
matching_candidates.append(candidate)
|
| 243 |
+
|
| 244 |
+
return matching_candidates
|
| 245 |
+
|
| 246 |
+
def search_fuzzy(self, query: str) -> List[Type["Subdivisions"]]:
|
| 247 |
+
query = remove_accents(query.strip().lower())
|
| 248 |
+
|
| 249 |
+
# A Subdivision's code to points mapping for later sorting subdivisions
|
| 250 |
+
# based on the query's matching incidence.
|
| 251 |
+
results: dict[str, int] = {}
|
| 252 |
+
|
| 253 |
+
def add_result(
|
| 254 |
+
subdivision: "pycountry.db.Subdivision", points: int
|
| 255 |
+
) -> None:
|
| 256 |
+
results.setdefault(subdivision.code, 0)
|
| 257 |
+
results[subdivision.code] += points
|
| 258 |
+
|
| 259 |
+
# Prio 1: exact matches on subdivision names
|
| 260 |
+
match_subdivisions = self.match(query)
|
| 261 |
+
for candidate in match_subdivisions:
|
| 262 |
+
add_result(candidate, 50)
|
| 263 |
+
|
| 264 |
+
# Prio 2: partial matches on subdivision names
|
| 265 |
+
partial_match_subdivisions = self.partial_match(query)
|
| 266 |
+
for candidate in partial_match_subdivisions:
|
| 267 |
+
v = candidate._fields.get("name")
|
| 268 |
+
v = remove_accents(v.lower())
|
| 269 |
+
if query in v:
|
| 270 |
+
add_result(candidate, max([1, 5 - v.find(query)]))
|
| 271 |
+
|
| 272 |
+
if not results:
|
| 273 |
+
raise LookupError(query)
|
| 274 |
+
|
| 275 |
+
sorted_results = [
|
| 276 |
+
self.get(code=x[0])
|
| 277 |
+
# sort by points first, by alpha2 code second, and to ensure stable
|
| 278 |
+
# results the negative value allows us to sort reversely on the
|
| 279 |
+
# points but ascending on the country code.
|
| 280 |
+
for x in sorted(results.items(), key=lambda x: (-x[1], x[0]))
|
| 281 |
+
]
|
| 282 |
+
return sorted_results
|
| 283 |
+
|
| 284 |
+
|
| 285 |
+
# Initialize instances with type hints
|
| 286 |
+
countries: ExistingCountries = ExistingCountries(
|
| 287 |
+
os.path.join(DATABASE_DIR, "iso3166-1.json")
|
| 288 |
+
)
|
| 289 |
+
subdivisions: Subdivisions = Subdivisions(
|
| 290 |
+
os.path.join(DATABASE_DIR, "iso3166-2.json")
|
| 291 |
+
)
|
| 292 |
+
historic_countries: HistoricCountries = HistoricCountries(
|
| 293 |
+
os.path.join(DATABASE_DIR, "iso3166-3.json")
|
| 294 |
+
)
|
| 295 |
+
|
| 296 |
+
currencies: Currencies = Currencies(os.path.join(DATABASE_DIR, "iso4217.json"))
|
| 297 |
+
|
| 298 |
+
languages: Languages = Languages(os.path.join(DATABASE_DIR, "iso639-3.json"))
|
| 299 |
+
language_families: LanguageFamilies = LanguageFamilies(
|
| 300 |
+
os.path.join(DATABASE_DIR, "iso639-5.json")
|
| 301 |
+
)
|
| 302 |
+
|
| 303 |
+
scripts: Scripts = Scripts(os.path.join(DATABASE_DIR, "iso15924.json"))
|
.venv/lib/python3.11/site-packages/pycountry/db.py
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
import logging
|
| 3 |
+
import threading
|
| 4 |
+
from typing import Any, Iterator, List, Optional, Type, Union
|
| 5 |
+
|
| 6 |
+
logger = logging.getLogger("pycountry.db")
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class Data:
|
| 10 |
+
def __init__(self, **fields: str):
|
| 11 |
+
self._fields = fields
|
| 12 |
+
|
| 13 |
+
def __getattr__(self, key):
|
| 14 |
+
if key in self._fields:
|
| 15 |
+
return self._fields[key]
|
| 16 |
+
raise AttributeError(key)
|
| 17 |
+
|
| 18 |
+
def __setattr__(self, key: str, value: str) -> None:
|
| 19 |
+
if key != "_fields":
|
| 20 |
+
self._fields[key] = value
|
| 21 |
+
super().__setattr__(key, value)
|
| 22 |
+
|
| 23 |
+
def __repr__(self) -> str:
|
| 24 |
+
cls_name = self.__class__.__name__
|
| 25 |
+
fields = ", ".join("%s=%r" % i for i in sorted(self._fields.items()))
|
| 26 |
+
return f"{cls_name}({fields})"
|
| 27 |
+
|
| 28 |
+
def __dir__(self) -> List[str]:
|
| 29 |
+
return dir(self.__class__) + list(self._fields)
|
| 30 |
+
|
| 31 |
+
def __iter__(self):
|
| 32 |
+
# allow casting into a dict
|
| 33 |
+
for field in self._fields:
|
| 34 |
+
yield field, getattr(self, field)
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
class Country(Data):
|
| 38 |
+
pass
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
class Subdivision(Data):
|
| 42 |
+
pass
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def lazy_load(f):
|
| 46 |
+
def load_if_needed(self, *args, **kw):
|
| 47 |
+
if not self._is_loaded:
|
| 48 |
+
with self._load_lock:
|
| 49 |
+
self._load()
|
| 50 |
+
return f(self, *args, **kw)
|
| 51 |
+
|
| 52 |
+
return load_if_needed
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
class Database:
|
| 56 |
+
data_class: Union[Type, str]
|
| 57 |
+
root_key: Optional[str] = None
|
| 58 |
+
no_index: List[str] = []
|
| 59 |
+
|
| 60 |
+
def __init__(self, filename: str) -> None:
|
| 61 |
+
self.filename = filename
|
| 62 |
+
self._is_loaded = False
|
| 63 |
+
self._load_lock = threading.Lock()
|
| 64 |
+
|
| 65 |
+
if isinstance(self.data_class, str):
|
| 66 |
+
self.factory = type(self.data_class, (Data,), {})
|
| 67 |
+
else:
|
| 68 |
+
self.factory = self.data_class
|
| 69 |
+
|
| 70 |
+
def _clear(self):
|
| 71 |
+
self._is_loaded = False
|
| 72 |
+
self.objects = []
|
| 73 |
+
self.index_names = set()
|
| 74 |
+
self.indices = {}
|
| 75 |
+
|
| 76 |
+
def _load(self) -> None:
|
| 77 |
+
if self._is_loaded:
|
| 78 |
+
# Help keeping the _load_if_needed code easier
|
| 79 |
+
# to read.
|
| 80 |
+
return
|
| 81 |
+
self._clear()
|
| 82 |
+
|
| 83 |
+
with open(self.filename, encoding="utf-8") as f:
|
| 84 |
+
tree = json.load(f)
|
| 85 |
+
|
| 86 |
+
for entry in tree[self.root_key]:
|
| 87 |
+
obj = self.factory(**entry)
|
| 88 |
+
self.objects.append(obj)
|
| 89 |
+
# Inject into index.
|
| 90 |
+
for key, value in entry.items():
|
| 91 |
+
if key in self.no_index:
|
| 92 |
+
continue
|
| 93 |
+
# Lookups and searches are case insensitive. Normalize
|
| 94 |
+
# here.
|
| 95 |
+
index = self.indices.setdefault(key, {})
|
| 96 |
+
value = value.lower()
|
| 97 |
+
if value in index:
|
| 98 |
+
logger.debug(
|
| 99 |
+
"%s %r already taken in index %r and will be "
|
| 100 |
+
"ignored. This is an error in the databases."
|
| 101 |
+
% (self.factory.__name__, value, key)
|
| 102 |
+
)
|
| 103 |
+
index[value] = obj
|
| 104 |
+
|
| 105 |
+
self._is_loaded = True
|
| 106 |
+
|
| 107 |
+
# Public API
|
| 108 |
+
|
| 109 |
+
@lazy_load
|
| 110 |
+
def add_entry(self, **kw):
|
| 111 |
+
# create the object with the correct dynamic type
|
| 112 |
+
obj = self.factory(**kw)
|
| 113 |
+
|
| 114 |
+
# append object
|
| 115 |
+
self.objects.append(obj)
|
| 116 |
+
|
| 117 |
+
# update indices
|
| 118 |
+
for key, value in kw.items():
|
| 119 |
+
if key in self.no_index:
|
| 120 |
+
continue
|
| 121 |
+
value = value.lower()
|
| 122 |
+
index = self.indices.setdefault(key, {})
|
| 123 |
+
index[value] = obj
|
| 124 |
+
|
| 125 |
+
@lazy_load
|
| 126 |
+
def remove_entry(self, **kw):
|
| 127 |
+
# make sure that we receive None if no entry found
|
| 128 |
+
if "default" in kw:
|
| 129 |
+
del kw["default"]
|
| 130 |
+
obj = self.get(**kw)
|
| 131 |
+
if not obj:
|
| 132 |
+
raise KeyError(
|
| 133 |
+
f"{self.factory.__name__} not found and cannot be removed: {kw}"
|
| 134 |
+
)
|
| 135 |
+
|
| 136 |
+
# remove object
|
| 137 |
+
self.objects.remove(obj)
|
| 138 |
+
|
| 139 |
+
# update indices
|
| 140 |
+
for key, value in obj:
|
| 141 |
+
if key in self.no_index:
|
| 142 |
+
continue
|
| 143 |
+
value = value.lower()
|
| 144 |
+
index = self.indices.setdefault(key, {})
|
| 145 |
+
if value in index:
|
| 146 |
+
del index[value]
|
| 147 |
+
|
| 148 |
+
@lazy_load
|
| 149 |
+
def __iter__(self) -> Iterator["Database"]:
|
| 150 |
+
return iter(self.objects)
|
| 151 |
+
|
| 152 |
+
@lazy_load
|
| 153 |
+
def __len__(self) -> int:
|
| 154 |
+
return len(self.objects)
|
| 155 |
+
|
| 156 |
+
@lazy_load
|
| 157 |
+
def get(
|
| 158 |
+
self, *, default: Optional[Any] = None, **kw: Optional[str]
|
| 159 |
+
) -> Optional[Any]:
|
| 160 |
+
if len(kw) != 1:
|
| 161 |
+
raise TypeError("Only one criteria may be given")
|
| 162 |
+
field, value = kw.popitem()
|
| 163 |
+
if not isinstance(value, str):
|
| 164 |
+
raise LookupError()
|
| 165 |
+
# Normalize for case-insensitivity
|
| 166 |
+
value = value.lower()
|
| 167 |
+
index = self.indices[field]
|
| 168 |
+
try:
|
| 169 |
+
return index[value]
|
| 170 |
+
except KeyError:
|
| 171 |
+
# Pythonic APIs implementing get() shouldn't raise KeyErrors.
|
| 172 |
+
# Those are a bit unexpected and they should rather support
|
| 173 |
+
# returning `None` by default and allow customization.
|
| 174 |
+
return default
|
| 175 |
+
|
| 176 |
+
@lazy_load
|
| 177 |
+
def lookup(self, value: str) -> Type:
|
| 178 |
+
if not isinstance(value, str):
|
| 179 |
+
raise LookupError()
|
| 180 |
+
|
| 181 |
+
# Normalize for case-insensitivity
|
| 182 |
+
value = value.lower()
|
| 183 |
+
|
| 184 |
+
# Use indexes first
|
| 185 |
+
for key in self.indices:
|
| 186 |
+
try:
|
| 187 |
+
return self.indices[key][value]
|
| 188 |
+
except LookupError:
|
| 189 |
+
pass
|
| 190 |
+
|
| 191 |
+
# Use non-indexed values now. Avoid going through indexed values.
|
| 192 |
+
for candidate in self:
|
| 193 |
+
for k in self.no_index:
|
| 194 |
+
v = candidate._fields.get(k)
|
| 195 |
+
if v is None:
|
| 196 |
+
continue
|
| 197 |
+
if v.lower() == value:
|
| 198 |
+
return candidate
|
| 199 |
+
|
| 200 |
+
raise LookupError("Could not find a record for %r" % value)
|
.venv/lib/python3.11/site-packages/pycountry/locales/an/LC_MESSAGES/iso3166-1.mo
ADDED
|
Binary file (3.81 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/ay/LC_MESSAGES/iso3166-1.mo
ADDED
|
Binary file (521 Bytes). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/bar/LC_MESSAGES/iso3166-1.mo
ADDED
|
Binary file (6.86 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/bi/LC_MESSAGES/iso3166-1.mo
ADDED
|
Binary file (526 Bytes). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/byn/LC_MESSAGES/iso3166-1.mo
ADDED
|
Binary file (5.71 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/byn/LC_MESSAGES/iso3166-3.mo
ADDED
|
Binary file (474 Bytes). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/byn/LC_MESSAGES/iso639-3.mo
ADDED
|
Binary file (5.69 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/ch/LC_MESSAGES/iso3166-1.mo
ADDED
|
Binary file (1.42 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/ckb/LC_MESSAGES/iso3166-1.mo
ADDED
|
Binary file (10.4 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/csb/LC_MESSAGES/iso3166-1.mo
ADDED
|
Binary file (4.45 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/el/LC_MESSAGES/iso15924.mo
ADDED
|
Binary file (1.86 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/el/LC_MESSAGES/iso3166-1.mo
ADDED
|
Binary file (30.8 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/el/LC_MESSAGES/iso3166-2.mo
ADDED
|
Binary file (9.26 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/el/LC_MESSAGES/iso3166-3.mo
ADDED
|
Binary file (3.43 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/el/LC_MESSAGES/iso4217.mo
ADDED
|
Binary file (9.43 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/el/LC_MESSAGES/iso639-3.mo
ADDED
|
Binary file (57.4 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/el/LC_MESSAGES/iso639-5.mo
ADDED
|
Binary file (2.39 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/gez/LC_MESSAGES/iso3166-1.mo
ADDED
|
Binary file (5.76 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/gez/LC_MESSAGES/iso3166-3.mo
ADDED
|
Binary file (476 Bytes). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/gez/LC_MESSAGES/iso639-3.mo
ADDED
|
Binary file (5.7 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/haw/LC_MESSAGES/iso3166-1.mo
ADDED
|
Binary file (1.31 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/haw/LC_MESSAGES/iso3166-3.mo
ADDED
|
Binary file (395 Bytes). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/jam/LC_MESSAGES/iso3166-1.mo
ADDED
|
Binary file (8.32 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/nah/LC_MESSAGES/iso3166-1.mo
ADDED
|
Binary file (8.12 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/nn/LC_MESSAGES/iso15924.mo
ADDED
|
Binary file (3.46 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/nn/LC_MESSAGES/iso3166-1.mo
ADDED
|
Binary file (22 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/nn/LC_MESSAGES/iso3166-3.mo
ADDED
|
Binary file (2.6 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/nn/LC_MESSAGES/iso4217.mo
ADDED
|
Binary file (7.57 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/nn/LC_MESSAGES/iso639-3.mo
ADDED
|
Binary file (7.46 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/or/LC_MESSAGES/iso3166-1.mo
ADDED
|
Binary file (34.1 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/or/LC_MESSAGES/iso3166-3.mo
ADDED
|
Binary file (3.98 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/pa_PK/LC_MESSAGES/iso15924.mo
ADDED
|
Binary file (1.42 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/pa_PK/LC_MESSAGES/iso3166-2.mo
ADDED
|
Binary file (1.02 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/pa_PK/LC_MESSAGES/iso3166-3.mo
ADDED
|
Binary file (601 Bytes). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/pi/LC_MESSAGES/iso3166-1.mo
ADDED
|
Binary file (9.26 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/ru/LC_MESSAGES/iso15924.mo
ADDED
|
Binary file (12.7 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/ru/LC_MESSAGES/iso3166-1.mo
ADDED
|
Binary file (29.8 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/ru/LC_MESSAGES/iso3166-3.mo
ADDED
|
Binary file (3.48 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/ru/LC_MESSAGES/iso4217.mo
ADDED
|
Binary file (11.5 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pycountry/locales/ru/LC_MESSAGES/iso639-3.mo
ADDED
|
Binary file (18.4 kB). View file
|
|
|