ramp-core 0.0.4__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.
- ramp_core-0.0.4/.github/ISSUE_TEMPLATE/bug_report.md +30 -0
- ramp_core-0.0.4/.github/ISSUE_TEMPLATE/documentation-improvement.md +20 -0
- ramp_core-0.0.4/.github/ISSUE_TEMPLATE/feature_request.md +21 -0
- ramp_core-0.0.4/.github/workflows/publish.yml +70 -0
- ramp_core-0.0.4/.github/workflows/test.yml +51 -0
- ramp_core-0.0.4/.gitignore +7 -0
- ramp_core-0.0.4/CODE_OF_CONDUCT.md +109 -0
- ramp_core-0.0.4/CONTRIBUTING.md +47 -0
- ramp_core-0.0.4/LICENSE +21 -0
- ramp_core-0.0.4/PKG-INFO +63 -0
- ramp_core-0.0.4/README.md +14 -0
- ramp_core-0.0.4/pyproject.toml +44 -0
- ramp_core-0.0.4/ramp_core/__init__.py +2 -0
- ramp_core-0.0.4/ramp_core/json.py +111 -0
- ramp_core-0.0.4/ramp_core/serializable.py +116 -0
- ramp_core-0.0.4/ramp_core/tempdir.py +24 -0
- ramp_core-0.0.4/ramp_core.egg-info/PKG-INFO +63 -0
- ramp_core-0.0.4/ramp_core.egg-info/SOURCES.txt +24 -0
- ramp_core-0.0.4/ramp_core.egg-info/dependency_links.txt +1 -0
- ramp_core-0.0.4/ramp_core.egg-info/requires.txt +6 -0
- ramp_core-0.0.4/ramp_core.egg-info/top_level.txt +1 -0
- ramp_core-0.0.4/requirements.yml +3 -0
- ramp_core-0.0.4/ruff.toml +5 -0
- ramp_core-0.0.4/setup.cfg +4 -0
- ramp_core-0.0.4/tests/test_prefer_list.py +20 -0
- ramp_core-0.0.4/tests_requirements.yml +3 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: Create a report to help us improve
|
|
4
|
+
title: "[Bug]"
|
|
5
|
+
labels: bug
|
|
6
|
+
assignees: ''
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
**Describe the bug**
|
|
11
|
+
A clear and concise description of what the bug is.
|
|
12
|
+
|
|
13
|
+
**To Reproduce**
|
|
14
|
+
Steps to reproduce the behavior:
|
|
15
|
+
1. Go to '...'
|
|
16
|
+
2. Run '...'
|
|
17
|
+
3. See error
|
|
18
|
+
|
|
19
|
+
**Expected behavior**
|
|
20
|
+
A clear and concise description of what you expected to happen.
|
|
21
|
+
|
|
22
|
+
**Screenshots**
|
|
23
|
+
If applicable, add screenshots to help explain your problem.
|
|
24
|
+
|
|
25
|
+
**System configuration (please complete the following information):**
|
|
26
|
+
- OS: [e.g. Ubuntu]
|
|
27
|
+
- Package Version [e.g. 0.0.0]
|
|
28
|
+
|
|
29
|
+
**Additional context**
|
|
30
|
+
Add any other context about the problem here.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Documentation Improvement
|
|
3
|
+
about: Proposed changes to the documentation
|
|
4
|
+
title: "[Doc]"
|
|
5
|
+
labels: documentation
|
|
6
|
+
assignees: ''
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Is anything incorrect?
|
|
11
|
+
Usually, when a change is proposed to the documentation it is because we forgot to update it, and documentation rot took hold.
|
|
12
|
+
Please let us know what you found to be incorrect, if applicable.
|
|
13
|
+
|
|
14
|
+
# Is anything missing?
|
|
15
|
+
Sometimes, you want an explanation for a particular piece of code, or an example for how to use something, that is simply not there.
|
|
16
|
+
Please let us know what you'd like to see, and we can try to write it!
|
|
17
|
+
|
|
18
|
+
# Can something be improved?
|
|
19
|
+
It isn't very often that someone takes the time to help us improve our documentation when something is there and presented correctly, but could be better.
|
|
20
|
+
Thank you for taking the time to let us know! Please give us a suggestion for what we could improve next, or even better, open a pull request with your changes! We'd love for you to help out with either of these methods.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature request
|
|
3
|
+
about: Suggest an idea for this project
|
|
4
|
+
title: "[Feature]"
|
|
5
|
+
labels: enhancement
|
|
6
|
+
assignees: ''
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
**Is your feature request related to a problem? Please describe.**
|
|
11
|
+
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
|
12
|
+
|
|
13
|
+
**Describe the solution you'd like**
|
|
14
|
+
A clear and concise description of what you want things to look like.
|
|
15
|
+
|
|
16
|
+
**Describe proposed solutions you've considered**
|
|
17
|
+
A clear and concise description of proposed solutions you considered.
|
|
18
|
+
If you can argue for and against them so we can pick the best one, please do.
|
|
19
|
+
|
|
20
|
+
**Additional context**
|
|
21
|
+
Add any other context or screenshots about the feature request here.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# This workflow will upload a Python Package to PyPI when a release is created
|
|
2
|
+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
|
|
3
|
+
|
|
4
|
+
# This workflow uses actions that are not certified by GitHub.
|
|
5
|
+
# They are provided by a third-party and are governed by
|
|
6
|
+
# separate terms of service, privacy policy, and support
|
|
7
|
+
# documentation.
|
|
8
|
+
|
|
9
|
+
name: Upload Python Package
|
|
10
|
+
|
|
11
|
+
on:
|
|
12
|
+
release:
|
|
13
|
+
types: [published]
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
release-build:
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
|
|
25
|
+
- uses: actions/setup-python@v5
|
|
26
|
+
with:
|
|
27
|
+
python-version: "3.x"
|
|
28
|
+
|
|
29
|
+
- name: Build release distributions
|
|
30
|
+
run: |
|
|
31
|
+
# NOTE: put your own distribution build steps here.
|
|
32
|
+
python -m pip install build
|
|
33
|
+
python -m build
|
|
34
|
+
|
|
35
|
+
- name: Upload distributions
|
|
36
|
+
uses: actions/upload-artifact@v4
|
|
37
|
+
with:
|
|
38
|
+
name: release-dists
|
|
39
|
+
path: dist/
|
|
40
|
+
|
|
41
|
+
pypi-publish:
|
|
42
|
+
runs-on: ubuntu-latest
|
|
43
|
+
needs:
|
|
44
|
+
- release-build
|
|
45
|
+
permissions:
|
|
46
|
+
# IMPORTANT: this permission is mandatory for trusted publishing
|
|
47
|
+
id-token: write
|
|
48
|
+
|
|
49
|
+
# Dedicated environments with protections for publishing are strongly recommended.
|
|
50
|
+
# For more information, see: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules
|
|
51
|
+
environment:
|
|
52
|
+
name: deployment
|
|
53
|
+
# OPTIONAL: uncomment and update to include your PyPI project URL in the deployment status:
|
|
54
|
+
url: https://test.pypi.org/project/ramp-core/
|
|
55
|
+
#
|
|
56
|
+
# ALTERNATIVE: if your GitHub Release name is the PyPI project version string
|
|
57
|
+
# ALTERNATIVE: exactly, uncomment the following line instead:
|
|
58
|
+
# url: https://pypi.org/project/YOURPROJECT/${{ github.event.release.name }}
|
|
59
|
+
|
|
60
|
+
steps:
|
|
61
|
+
- name: Retrieve release distributions
|
|
62
|
+
uses: actions/download-artifact@v4
|
|
63
|
+
with:
|
|
64
|
+
name: release-dists
|
|
65
|
+
path: dist/
|
|
66
|
+
|
|
67
|
+
- name: Publish release distributions to PyPI
|
|
68
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
69
|
+
with:
|
|
70
|
+
packages-dir: dist/
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
|
|
2
|
+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
|
|
3
|
+
|
|
4
|
+
name: Python package
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches: [ "main" ]
|
|
9
|
+
pull_request:
|
|
10
|
+
branches: [ "dev" ]
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
lint:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- name: Ruff check
|
|
18
|
+
uses: astral-sh/ruff-action@v3
|
|
19
|
+
|
|
20
|
+
build:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
- uses: actions/setup-python@v6
|
|
25
|
+
with:
|
|
26
|
+
python-version: '3.14'
|
|
27
|
+
- name: Install this package
|
|
28
|
+
run: |
|
|
29
|
+
pip install .
|
|
30
|
+
- name: Run and import
|
|
31
|
+
run: |
|
|
32
|
+
python3 -c "from ramp_core.serializable import Serializable"
|
|
33
|
+
|
|
34
|
+
test:
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v4
|
|
38
|
+
- uses: actions/setup-python@v6
|
|
39
|
+
with:
|
|
40
|
+
python-version: '3.14'
|
|
41
|
+
- name: Install this package
|
|
42
|
+
run: |
|
|
43
|
+
pip install .[test]
|
|
44
|
+
- name: Doctest
|
|
45
|
+
run: |
|
|
46
|
+
pytest -v --doctest-modules ramp_core
|
|
47
|
+
- name: Test in test directory
|
|
48
|
+
run: |
|
|
49
|
+
cd tests
|
|
50
|
+
pytest -v
|
|
51
|
+
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our
|
|
6
|
+
community a harassment-free experience for everyone, regardless of any personal characteristics or identity.
|
|
7
|
+
We pledge to treat everyone with civility, to act and interact in ways that contribute to an open,
|
|
8
|
+
welcoming and healthy community.
|
|
9
|
+
|
|
10
|
+
## Our Standards
|
|
11
|
+
|
|
12
|
+
Examples of behavior that contributes to a positive environment for our
|
|
13
|
+
community include:
|
|
14
|
+
|
|
15
|
+
* Demonstrating empathy and kindness toward other people
|
|
16
|
+
* Being respectful of differing opinions, viewpoints, and experiences
|
|
17
|
+
* Giving and gracefully accepting constructive feedback
|
|
18
|
+
* Accepting responsibility and apologizing to those affected by our mistakes,
|
|
19
|
+
and learning from the experience
|
|
20
|
+
* Focusing on what is best not just for us as individuals, but for the
|
|
21
|
+
overall community
|
|
22
|
+
|
|
23
|
+
Examples of unacceptable behavior include:
|
|
24
|
+
|
|
25
|
+
* The use of sexualized language or imagery, and sexual attention or
|
|
26
|
+
advances of any kind
|
|
27
|
+
* Trolling, insulting or derogatory comments, and personal or political attacks
|
|
28
|
+
* Public or private harassment
|
|
29
|
+
* Publishing others' private information, such as a physical or email
|
|
30
|
+
address, without their explicit permission
|
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
|
32
|
+
professional setting
|
|
33
|
+
|
|
34
|
+
## Enforcement Responsibilities
|
|
35
|
+
|
|
36
|
+
Community leaders are responsible for clarifying and enforcing our standards of
|
|
37
|
+
acceptable behavior and will take appropriate and fair corrective action in
|
|
38
|
+
response to any behavior that they deem inappropriate, threatening, offensive,
|
|
39
|
+
or harmful.
|
|
40
|
+
|
|
41
|
+
Community leaders have the right and responsibility to remove, edit, or reject
|
|
42
|
+
comments, commits, code, wiki edits, issues, and other contributions that are
|
|
43
|
+
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
|
44
|
+
decisions when appropriate.
|
|
45
|
+
|
|
46
|
+
## Scope
|
|
47
|
+
|
|
48
|
+
This Code of Conduct applies within all community spaces, and also applies when
|
|
49
|
+
an individual is officially representing the community in public spaces.
|
|
50
|
+
Examples of representing our community include using an official e-mail address,
|
|
51
|
+
or acting as an appointed representative at an online or offline event.
|
|
52
|
+
|
|
53
|
+
## Enforcement
|
|
54
|
+
|
|
55
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
56
|
+
reported to the community leaders responsible for enforcement at
|
|
57
|
+
nuclear.ramp.dev@gmail.com.
|
|
58
|
+
All complaints will be reviewed and investigated promptly and fairly.
|
|
59
|
+
|
|
60
|
+
All community leaders are obligated to respect the privacy and security of the
|
|
61
|
+
reporter of any incident.
|
|
62
|
+
|
|
63
|
+
## Enforcement Guidelines
|
|
64
|
+
|
|
65
|
+
Community leaders should consult these enforcement methods for any action they
|
|
66
|
+
deem in violation of this Code of Conduct:
|
|
67
|
+
|
|
68
|
+
### 1. Correction
|
|
69
|
+
A private, written warning from community leaders, providing
|
|
70
|
+
clarity around the nature of the violation and an explanation of why the
|
|
71
|
+
behavior was inappropriate. A public apology may be requested.
|
|
72
|
+
|
|
73
|
+
### 2. Warning
|
|
74
|
+
A privately written warning with explicit consequences for continued behavior.
|
|
75
|
+
The warning should include the information as in a Correction, but also include
|
|
76
|
+
a demand that the offending party will avoid interaction with the affected party
|
|
77
|
+
for a specified period of time. This includes interaction in community events,
|
|
78
|
+
on this project or outside these spaces such as on social media.
|
|
79
|
+
Violating these terms may lead to a temporary or permanent ban.
|
|
80
|
+
|
|
81
|
+
### 3. Temporary Ban
|
|
82
|
+
A temporary ban from any sort of interaction or public
|
|
83
|
+
communication with the community for a specified period of time. No public or
|
|
84
|
+
private interaction with the people involved, including unsolicited interaction
|
|
85
|
+
with those enforcing the Code of Conduct, is allowed during this period.
|
|
86
|
+
Violating these terms may lead to a permanent ban.
|
|
87
|
+
This step should only be taken if a warning was previously given to the
|
|
88
|
+
offending party or for more serious violations that require a public and immediate
|
|
89
|
+
action.
|
|
90
|
+
|
|
91
|
+
### 4. Permanent Ban
|
|
92
|
+
A permanent ban from any sort of public interaction within the community.
|
|
93
|
+
A permanent ban should only result from continued violations or a pattern
|
|
94
|
+
of behavior that is incompatible with this Code of Conduct.
|
|
95
|
+
|
|
96
|
+
## Attribution
|
|
97
|
+
|
|
98
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
|
99
|
+
version 2.0, available at
|
|
100
|
+
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
|
101
|
+
|
|
102
|
+
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
|
103
|
+
enforcement ladder](https://github.com/mozilla/diversity).
|
|
104
|
+
|
|
105
|
+
[homepage]: https://www.contributor-covenant.org
|
|
106
|
+
|
|
107
|
+
For answers to common questions about this code of conduct, see the FAQ at
|
|
108
|
+
https://www.contributor-covenant.org/faq. Translations are available at
|
|
109
|
+
https://www.contributor-covenant.org/translations.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thank you for considering a contribution to our project.
|
|
4
|
+
We welcome new members to the community and this guide is meant to help you make your
|
|
5
|
+
first steps with our community.
|
|
6
|
+
|
|
7
|
+
## Code of Conduct
|
|
8
|
+
|
|
9
|
+
Participants in the this project are expected to follow and uphold the [Code
|
|
10
|
+
of Conduct](CODE_OF_CONDUCT.md).
|
|
11
|
+
Please report any unacceptable behavior to the email described therein.
|
|
12
|
+
|
|
13
|
+
## How to report bugs
|
|
14
|
+
We have a template for bugs in our issue tracker.
|
|
15
|
+
All bugs are tracked through the issue tracker, so please use that!
|
|
16
|
+
|
|
17
|
+
## How to ask for improvements or new features
|
|
18
|
+
|
|
19
|
+
We welcome constant improvement, and we have a template for new features in our issues tracker.
|
|
20
|
+
You should notice that our team is small, and it may take some time for us to deal with any
|
|
21
|
+
specific request, or we may find that the request creates too heavy a burden for us to maintain.
|
|
22
|
+
If you are interested in contributing yourself, please say so in your issue. It is much easier
|
|
23
|
+
for us to accept new features when the community is willing to work alongside the core team on them.
|
|
24
|
+
|
|
25
|
+
## How to submit changes
|
|
26
|
+
|
|
27
|
+
All changes to the `dev` and `main` branches happen through pull requests.
|
|
28
|
+
Feature branches should target the `dev` branch for their pull request, where the code will be reviewed
|
|
29
|
+
and any appropriate checks will run.
|
|
30
|
+
The code will be reviewed by the community, and such a review should ensure that the committed code is
|
|
31
|
+
correct as well as that its quality meets our standards.
|
|
32
|
+
The reviewers may ask you for some changes before they are willing to merge your changes in, or they
|
|
33
|
+
may change some things themselves in a collaborative effort. Please remember that while your contribution
|
|
34
|
+
is welcome, it is always part of a group effort, and the group has the right to edit or even reject parts
|
|
35
|
+
of your contribution to meet the community's needs.
|
|
36
|
+
Such changes, suggestions and requests should always follow the Code of Conduct, as well as your own
|
|
37
|
+
contribution. Please report any unacceptable behavior during the review process if you encounter it.
|
|
38
|
+
|
|
39
|
+
## Code Style
|
|
40
|
+
|
|
41
|
+
We currently don't have a written-down style guide, and we should get around to it.
|
|
42
|
+
This may cause some friction, since style is a matter of preference, but if both you and your reviewers
|
|
43
|
+
apply a positive mindset that we're all trying to get the project to be at its best, we will likely
|
|
44
|
+
find a suitable solution.
|
|
45
|
+
|
|
46
|
+
If you find that much of your time is taken on discussions about a style guide that isn't there,
|
|
47
|
+
please let us know and we'll make this a higher priority.
|
ramp_core-0.0.4/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Eshed Magali
|
|
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.
|
ramp_core-0.0.4/PKG-INFO
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ramp-core
|
|
3
|
+
Version: 0.0.4
|
|
4
|
+
Summary: Utilities package for the Nuclear RAMP
|
|
5
|
+
Author-email: Nuclear RAMP team <nuclear.ramp.dev@gmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Eshed Magali
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Classifier: Development Status :: 4 - Beta
|
|
29
|
+
Classifier: Intended Audience :: Developers
|
|
30
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
31
|
+
Classifier: Intended Audience :: Science/Research
|
|
32
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
33
|
+
Classifier: Natural Language :: English
|
|
34
|
+
Classifier: Topic :: Scientific/Engineering
|
|
35
|
+
Classifier: Programming Language :: Python :: 3
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
40
|
+
Requires-Python: >=3.11
|
|
41
|
+
Description-Content-Type: text/markdown
|
|
42
|
+
License-File: LICENSE
|
|
43
|
+
Requires-Dist: cytoolz
|
|
44
|
+
Requires-Dist: numpy
|
|
45
|
+
Provides-Extra: test
|
|
46
|
+
Requires-Dist: hypothesis; extra == "test"
|
|
47
|
+
Requires-Dist: pytest; extra == "test"
|
|
48
|
+
Dynamic: license-file
|
|
49
|
+
|
|
50
|
+
# ramp-core
|
|
51
|
+
Welcome to the core utilities package of the nuclear Reactor Analysis
|
|
52
|
+
Management Project!
|
|
53
|
+
|
|
54
|
+
## Core utilities of RAMP
|
|
55
|
+
|
|
56
|
+
This is where we handle serialization, pickling and such things that are used everywhere in the wide project.
|
|
57
|
+
|
|
58
|
+
This package does almost nothing on its own, and one would usually only
|
|
59
|
+
interact with it as a dependency.
|
|
60
|
+
More often than not, people reading this will find other packages more
|
|
61
|
+
useful, but you're welcome to contribute here too if you came all this
|
|
62
|
+
way :)
|
|
63
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# ramp-core
|
|
2
|
+
Welcome to the core utilities package of the nuclear Reactor Analysis
|
|
3
|
+
Management Project!
|
|
4
|
+
|
|
5
|
+
## Core utilities of RAMP
|
|
6
|
+
|
|
7
|
+
This is where we handle serialization, pickling and such things that are used everywhere in the wide project.
|
|
8
|
+
|
|
9
|
+
This package does almost nothing on its own, and one would usually only
|
|
10
|
+
interact with it as a dependency.
|
|
11
|
+
More often than not, people reading this will find other packages more
|
|
12
|
+
useful, but you're welcome to contribute here too if you came all this
|
|
13
|
+
way :)
|
|
14
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools", "setuptools-scm", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "ramp-core"
|
|
7
|
+
authors = [
|
|
8
|
+
{name = "Nuclear RAMP team", email = "nuclear.ramp.dev@gmail.com"},
|
|
9
|
+
]
|
|
10
|
+
description = "Utilities package for the Nuclear RAMP"
|
|
11
|
+
dynamic = ["version"]
|
|
12
|
+
requires-python = ">=3.11"
|
|
13
|
+
license = {file = "LICENSE"}
|
|
14
|
+
readme = "README.md"
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Intended Audience :: End Users/Desktop",
|
|
19
|
+
"Intended Audience :: Science/Research",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Natural Language :: English",
|
|
22
|
+
"Topic :: Scientific/Engineering",
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Programming Language :: Python :: 3.13",
|
|
27
|
+
"Programming Language :: Python :: 3.14",
|
|
28
|
+
]
|
|
29
|
+
dependencies = [
|
|
30
|
+
"cytoolz",
|
|
31
|
+
"numpy",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.optional-dependencies]
|
|
35
|
+
test = [
|
|
36
|
+
"hypothesis",
|
|
37
|
+
"pytest",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[tool.setuptools.packages.find]
|
|
41
|
+
include = ['ramp_core*']
|
|
42
|
+
exclude = ['tests*']
|
|
43
|
+
|
|
44
|
+
[tool.setuptools_scm]
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""JSON encoding and decoding tools for RAMP objects"""
|
|
2
|
+
import json
|
|
3
|
+
from typing import Any, Hashable
|
|
4
|
+
|
|
5
|
+
from ramp_core.serializable import Serializable
|
|
6
|
+
|
|
7
|
+
IDENTIFIER = 'cls'
|
|
8
|
+
DATA = '__data'
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class RampJSONEncoder(json.JSONEncoder):
|
|
12
|
+
"""JSONEncoder for ramp objects that can handle Serializable objects.
|
|
13
|
+
|
|
14
|
+
It is useful to have a single json-compatible class to handle our long-term serialization of Ramp objects.
|
|
15
|
+
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def default(self, obj):
|
|
19
|
+
try:
|
|
20
|
+
ident, s = obj.serialize()
|
|
21
|
+
return s | {IDENTIFIER: ident} if isinstance(s, dict) else {IDENTIFIER: ident, DATA: s}
|
|
22
|
+
except AttributeError:
|
|
23
|
+
pass
|
|
24
|
+
return json.JSONEncoder.default(self, obj)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class RampJSONDecoder(json.JSONDecoder):
|
|
28
|
+
"""JSONDecoder for ramp objects that can reconstruct Serializable objects.
|
|
29
|
+
|
|
30
|
+
It will be useful to be able to recreate our Python objects for the ramp objects if we serialize them in a
|
|
31
|
+
long term, non-pickle method.
|
|
32
|
+
|
|
33
|
+
The idea is that we save an identifier which allows us to know which Python object to reconstruct.
|
|
34
|
+
To avoid the Pickle problem, the way we do this is that we assume the decoding user can create a mapping of
|
|
35
|
+
serialization identifiers to factory classes that have a deserialize method.
|
|
36
|
+
|
|
37
|
+
Examples
|
|
38
|
+
--------
|
|
39
|
+
>>> class A:
|
|
40
|
+
... ser_identifier = "AA"
|
|
41
|
+
...
|
|
42
|
+
... def __init__(self, a):
|
|
43
|
+
... self.a = a
|
|
44
|
+
...
|
|
45
|
+
... def serialize(self):
|
|
46
|
+
... return self.ser_identifier, {'a': self.a}
|
|
47
|
+
...
|
|
48
|
+
... @classmethod
|
|
49
|
+
... def deserialize(cls, d, **_):
|
|
50
|
+
... return cls(**d)
|
|
51
|
+
>>>
|
|
52
|
+
>>> b = A(5)
|
|
53
|
+
>>> s = json.dumps(b, cls=RampJSONEncoder)
|
|
54
|
+
>>> try: # This fails because we didn't set the supported attribute
|
|
55
|
+
... v = json.loads(s, cls=RampJSONDecoder)
|
|
56
|
+
... except AttributeError:
|
|
57
|
+
... pass
|
|
58
|
+
... else:
|
|
59
|
+
... raise RuntimeError("Should have crashed")
|
|
60
|
+
>>> RampJSONDecoder.supported = {type(b).ser_identifier: b}
|
|
61
|
+
>>> v = json.loads(s, cls=RampJSONDecoder) # And now it succeeds
|
|
62
|
+
>>> v.a == b.a
|
|
63
|
+
True
|
|
64
|
+
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
supported: dict[str, Serializable]
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def decode(self, s: str, **kw):
|
|
71
|
+
pobj = super().decode(s, **kw)
|
|
72
|
+
if not isinstance(pobj, dict):
|
|
73
|
+
return pobj
|
|
74
|
+
if IDENTIFIER not in pobj:
|
|
75
|
+
return pobj
|
|
76
|
+
styp = pobj[IDENTIFIER]
|
|
77
|
+
if styp in self.supported:
|
|
78
|
+
del pobj[IDENTIFIER]
|
|
79
|
+
typ = self.supported[styp]
|
|
80
|
+
if DATA in pobj:
|
|
81
|
+
return typ.deserialize(pobj[DATA], supported=self.supported)
|
|
82
|
+
return typ.deserialize(pobj, supported=self.supported)
|
|
83
|
+
return pobj
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def unserializable(d: dict | list | tuple) -> list[tuple[list[Hashable], Any]]:
|
|
87
|
+
"""Returns which items were unserializable. Useful to debug serializability.
|
|
88
|
+
"""
|
|
89
|
+
lst = []
|
|
90
|
+
if isinstance(d, dict):
|
|
91
|
+
iters = d.items()
|
|
92
|
+
elif isinstance(d, (list, tuple)):
|
|
93
|
+
iters = enumerate(d)
|
|
94
|
+
else:
|
|
95
|
+
try:
|
|
96
|
+
json.dumps(d, cls=RampJSONEncoder)
|
|
97
|
+
except TypeError:
|
|
98
|
+
return [([], d)]
|
|
99
|
+
else:
|
|
100
|
+
return []
|
|
101
|
+
|
|
102
|
+
for a, b in iters:
|
|
103
|
+
if isinstance(b, (dict, list, tuple)):
|
|
104
|
+
lst.extend([([a] + access, v) for access, v in unserializable(b)])
|
|
105
|
+
else:
|
|
106
|
+
try:
|
|
107
|
+
json.dumps(b, cls=RampJSONEncoder)
|
|
108
|
+
except TypeError:
|
|
109
|
+
lst.append(([a], b))
|
|
110
|
+
return lst
|
|
111
|
+
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""Defines the Serializable protocol, which is what we expect things to have, so we can serialize and deserialize them
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from pathlib import PurePath
|
|
6
|
+
from typing import Any, ClassVar, Protocol, Sequence, Type, TypeVar, runtime_checkable
|
|
7
|
+
|
|
8
|
+
try: # To allow for older Python versions where Self was not supported
|
|
9
|
+
from typing import Self
|
|
10
|
+
except ImportError:
|
|
11
|
+
Self = TypeVar("Self")
|
|
12
|
+
|
|
13
|
+
import numpy as np
|
|
14
|
+
from cytoolz import valmap
|
|
15
|
+
|
|
16
|
+
T = TypeVar("T", bound="Serializable")
|
|
17
|
+
D = TypeVar("D", bound="_Deserializable")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class _Deserializable(Protocol):
|
|
21
|
+
@classmethod
|
|
22
|
+
def deserialize(cls: Type[D], d: dict[str, Any], *, supported: dict[str, Type["Serializable"]]) -> D:
|
|
23
|
+
...
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@runtime_checkable
|
|
27
|
+
class Serializable(Protocol):
|
|
28
|
+
"""Protocol for classes that we can serialize to JSON-able formats and deserialize from.
|
|
29
|
+
|
|
30
|
+
Serializable objects must be capable of being equal to themselves by going through serialization and deserialization
|
|
31
|
+
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
ser_identifier: ClassVar[str]
|
|
35
|
+
|
|
36
|
+
def serialize(self) -> tuple[str, dict[str, Any]]:
|
|
37
|
+
"""Serializes the object to return its class' identifier and the data that allows to recreate the instance.
|
|
38
|
+
|
|
39
|
+
Returns
|
|
40
|
+
-------
|
|
41
|
+
str, dict[str, data]
|
|
42
|
+
The ser_identifier and the data that allows to recreate an instance.
|
|
43
|
+
|
|
44
|
+
"""
|
|
45
|
+
return self.ser_identifier, _ensure_list(_save_attributes(self))
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def deserialize(cls: Type[Self], d: dict[str, Any], *, supported: dict[str, Type["Serializable"]]) -> Self:
|
|
49
|
+
"""Create a new instance given the data generated by an instance's serialize method.
|
|
50
|
+
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
53
|
+
d: dict[str, Any]
|
|
54
|
+
The data dictionary returned by the original object's serialize method.
|
|
55
|
+
supported: dict[str, Type[Serializable]]
|
|
56
|
+
A dictionary of which types are supported for deserialization.
|
|
57
|
+
|
|
58
|
+
"""
|
|
59
|
+
return cls(**_default_tuple(d))
|
|
60
|
+
|
|
61
|
+
def __eq__(self: T, other: T) -> bool:
|
|
62
|
+
...
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def deserialize_default(data: tuple[str, dict[str, Any]],
|
|
66
|
+
supported: dict[str, Type[Serializable]],
|
|
67
|
+
default: Type[_Deserializable] | None = None) -> _Deserializable:
|
|
68
|
+
"""Deserialize the data given by a Serializable object's `serialize` method given class deserialization
|
|
69
|
+
|
|
70
|
+
Parameters
|
|
71
|
+
----------
|
|
72
|
+
data: str, dict[str, Any]
|
|
73
|
+
The result from the object's Serialize method. See :func:Serializable.serialize.
|
|
74
|
+
supported: dict[str, Type[Serializable]]
|
|
75
|
+
A mapping of serialization identifiers to the classes they represent.
|
|
76
|
+
default: Type[Serializable] or None
|
|
77
|
+
The default type to use if the serialization identifier is not recognized. If None, raises an error if the
|
|
78
|
+
identifier isn't there.
|
|
79
|
+
|
|
80
|
+
Returns
|
|
81
|
+
-------
|
|
82
|
+
Serializable
|
|
83
|
+
The deserialized object
|
|
84
|
+
|
|
85
|
+
"""
|
|
86
|
+
name, d = data
|
|
87
|
+
if default is not None:
|
|
88
|
+
typ = supported.get(name, default)
|
|
89
|
+
else:
|
|
90
|
+
if name not in supported:
|
|
91
|
+
raise TypeError(f"Deserialization of {name} from json isn't supported by the deserializer")
|
|
92
|
+
typ = supported[name]
|
|
93
|
+
return typ.deserialize(d, supported=supported)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _save_attributes(self) -> dict:
|
|
97
|
+
sd = {k: self.__getattribute__(k) for k in self.__slots__} if self.__slots__ else {}
|
|
98
|
+
return self.__dict__ | sd
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _default_tuple(d: dict) -> dict:
|
|
102
|
+
return valmap(lambda x: tuple(x) if isinstance(x, list) else x, d)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _prefer_list(x):
|
|
106
|
+
if isinstance(x, Sequence) and not isinstance(x, str):
|
|
107
|
+
return list(x)
|
|
108
|
+
if isinstance(x, np.ndarray):
|
|
109
|
+
return x.tolist()
|
|
110
|
+
if isinstance(x, PurePath):
|
|
111
|
+
return str(x)
|
|
112
|
+
return x
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _ensure_list(d: dict) -> dict:
|
|
116
|
+
return valmap(_prefer_list, d)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Temporary directory utilities
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
import tempfile
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TemporaryDirectory(tempfile.TemporaryDirectory):
|
|
8
|
+
"""
|
|
9
|
+
like tempfile.TemporaryDirectory but with an optional argument to not
|
|
10
|
+
clean the directory afterwards.
|
|
11
|
+
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, suffix=None, prefix=None, dir=None, clean_dir=True):
|
|
15
|
+
self.clean_dir = clean_dir
|
|
16
|
+
if self.clean_dir:
|
|
17
|
+
super(TemporaryDirectory, self).__init__(suffix=suffix, prefix=prefix, dir=dir)
|
|
18
|
+
else:
|
|
19
|
+
self.name = tempfile.mkdtemp(suffix, prefix, dir)
|
|
20
|
+
|
|
21
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
22
|
+
if self.clean_dir:
|
|
23
|
+
super(TemporaryDirectory, self).__exit__(exc_type, exc_val, exc_tb)
|
|
24
|
+
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ramp-core
|
|
3
|
+
Version: 0.0.4
|
|
4
|
+
Summary: Utilities package for the Nuclear RAMP
|
|
5
|
+
Author-email: Nuclear RAMP team <nuclear.ramp.dev@gmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Eshed Magali
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Classifier: Development Status :: 4 - Beta
|
|
29
|
+
Classifier: Intended Audience :: Developers
|
|
30
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
31
|
+
Classifier: Intended Audience :: Science/Research
|
|
32
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
33
|
+
Classifier: Natural Language :: English
|
|
34
|
+
Classifier: Topic :: Scientific/Engineering
|
|
35
|
+
Classifier: Programming Language :: Python :: 3
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
40
|
+
Requires-Python: >=3.11
|
|
41
|
+
Description-Content-Type: text/markdown
|
|
42
|
+
License-File: LICENSE
|
|
43
|
+
Requires-Dist: cytoolz
|
|
44
|
+
Requires-Dist: numpy
|
|
45
|
+
Provides-Extra: test
|
|
46
|
+
Requires-Dist: hypothesis; extra == "test"
|
|
47
|
+
Requires-Dist: pytest; extra == "test"
|
|
48
|
+
Dynamic: license-file
|
|
49
|
+
|
|
50
|
+
# ramp-core
|
|
51
|
+
Welcome to the core utilities package of the nuclear Reactor Analysis
|
|
52
|
+
Management Project!
|
|
53
|
+
|
|
54
|
+
## Core utilities of RAMP
|
|
55
|
+
|
|
56
|
+
This is where we handle serialization, pickling and such things that are used everywhere in the wide project.
|
|
57
|
+
|
|
58
|
+
This package does almost nothing on its own, and one would usually only
|
|
59
|
+
interact with it as a dependency.
|
|
60
|
+
More often than not, people reading this will find other packages more
|
|
61
|
+
useful, but you're welcome to contribute here too if you came all this
|
|
62
|
+
way :)
|
|
63
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
.gitignore
|
|
2
|
+
CODE_OF_CONDUCT.md
|
|
3
|
+
CONTRIBUTING.md
|
|
4
|
+
LICENSE
|
|
5
|
+
README.md
|
|
6
|
+
pyproject.toml
|
|
7
|
+
requirements.yml
|
|
8
|
+
ruff.toml
|
|
9
|
+
tests_requirements.yml
|
|
10
|
+
.github/ISSUE_TEMPLATE/bug_report.md
|
|
11
|
+
.github/ISSUE_TEMPLATE/documentation-improvement.md
|
|
12
|
+
.github/ISSUE_TEMPLATE/feature_request.md
|
|
13
|
+
.github/workflows/publish.yml
|
|
14
|
+
.github/workflows/test.yml
|
|
15
|
+
ramp_core/__init__.py
|
|
16
|
+
ramp_core/json.py
|
|
17
|
+
ramp_core/serializable.py
|
|
18
|
+
ramp_core/tempdir.py
|
|
19
|
+
ramp_core.egg-info/PKG-INFO
|
|
20
|
+
ramp_core.egg-info/SOURCES.txt
|
|
21
|
+
ramp_core.egg-info/dependency_links.txt
|
|
22
|
+
ramp_core.egg-info/requires.txt
|
|
23
|
+
ramp_core.egg-info/top_level.txt
|
|
24
|
+
tests/test_prefer_list.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ramp_core
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from string import ascii_lowercase
|
|
2
|
+
|
|
3
|
+
import hypothesis.strategies as st
|
|
4
|
+
from hypothesis import given
|
|
5
|
+
|
|
6
|
+
from ramp_core.serializable import _prefer_list
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@given(st.text(alphabet=ascii_lowercase, min_size=1))
|
|
10
|
+
def test_prefer_list_for_str_is_str(sold):
|
|
11
|
+
s = _prefer_list(sold)
|
|
12
|
+
assert type(s) is str
|
|
13
|
+
assert s == sold
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@given(st.lists(elements=st.integers(), min_size=1).map(tuple))
|
|
17
|
+
def test_prefer_list_for_tuple_is_list(x):
|
|
18
|
+
y = _prefer_list(x)
|
|
19
|
+
assert type(y) is list
|
|
20
|
+
assert all(yv == xv for yv, xv in zip(y, x))
|