DuniterPy issueshttps://git.duniter.org/clients/python/duniterpy/-/issues2023-09-23T09:28:38+02:00https://git.duniter.org/clients/python/duniterpy/-/issues/203Store authentication files only as user readable2023-09-23T09:28:38+02:00MoulStore authentication files only as user readableAs reported into silkaj#420, save v1 auth file as user readable `600` `rw-------` mode, not group and world readable.
I found two approaches:
## Using the `umask`
Set `077` umask (for `600` permissions) and restore previous one:
```py
...As reported into silkaj#420, save v1 auth file as user readable `600` `rw-------` mode, not group and world readable.
I found two approaches:
## Using the `umask`
Set `077` umask (for `600` permissions) and restore previous one:
```py
current_umask = os.umask(0o077)
with open(path, encoding="utf-8") as fh:
fh.write(seedhex)
os.umask(current_umask)
```
- Inspired from [`libnacl`](https://github.com/saltstack/libnacl/blob/872303050f49d1daf7471c862e9fce9dbf6e8134/libnacl/base.py#L67-L73) that we are [already using](https://git.duniter.org/clients/python/duniterpy/-/blob/02cb8758f365b3a6c86e67af6614a9b44dda45cb/duniterpy/key/signing_key.py#L144).
## Using an opener
```py
def opener_user_rw(path, flags):
return os.open(path, flags, 0o600)
with open(path, "w", encoding="utf-8", opener=self.opener_user_rw) as fh:
fh.write(seedhex)
```
- https://docs.python.org/3/library/functions.html#open
- https://stackoverflow.com/a/45368120
- https://github.com/python/cpython/issues/73400#issuecomment-10937369381.2.0MoulMoulhttps://git.duniter.org/clients/python/duniterpy/-/issues/200Define custom exceptions to support new Pylint v2.16 rule: broad-exception-ra...2023-07-04T20:35:30+02:00MoulDefine custom exceptions to support new Pylint v2.16 rule: broad-exception-raisedSince [Pylint v2.16](https://pylint.readthedocs.io/en/latest/whatsnew/2/2.16/index.html), following report is raised:
- `W0719: Raising too general exception: Exception (broad-exception-raised)`
- [x] Define more precise (sub-set) except...Since [Pylint v2.16](https://pylint.readthedocs.io/en/latest/whatsnew/2/2.16/index.html), following report is raised:
- `W0719: Raising too general exception: Exception (broad-exception-raised)`
- [x] Define more precise (sub-set) exceptions:
- `api.ws2p.requests`
- `key.signing_key`
- `documents`
```py
class XxxException(Exception):
"""Raised when xxxx"""
```
- [x] Bump Pylint to latest version (v2.17+, or v3 if released as stable)
- [x] Silkaj: Remove/fix `disable=broad-except` in `auth.py`1.2.0MoulMoulhttps://git.duniter.org/clients/python/duniterpy/-/issues/88WS2P head: Use dataclasses in place of attrs2023-06-30T08:58:43+02:00MoulWS2P head: Use dataclasses in place of attrs[Would allow to get rid of `attrs` dependency](https://git.duniter.org/clients/python/duniterpy/-/merge_requests/151#note_29359)?
- https://www.attrs.org/en/stable/why.html
- https://docs.python.org/3/library/dataclasses.html
- [French ...[Would allow to get rid of `attrs` dependency](https://git.duniter.org/clients/python/duniterpy/-/merge_requests/151#note_29359)?
- https://www.attrs.org/en/stable/why.html
- https://docs.python.org/3/library/dataclasses.html
- [French article about dataclasses](https://linuxfr.org/news/sortie-de-python-3-7#toc-pep557-dataclasses)
## Tasks
- [x] Switch to `dataclasses` stdlib usage
- [x] Remove `attrs` dependency1.2.0MoulMoulhttps://git.duniter.org/clients/python/duniterpy/-/issues/93MyPy ask for a type annotation in an example, but everything is already typed...2023-06-29T19:34:28+02:00Vincent TexierMyPy ask for a type annotation in an example, but everything is already typed in the classmethod called...We use the correct way to type classmethod in `SigningKey` class, regarding that you can not annotate a class type inside his declaration.
See : https://mypy.readthedocs.io/en/stable/generics.html#generic-methods-and-generic-self
But `...We use the correct way to type classmethod in `SigningKey` class, regarding that you can not annotate a class type inside his declaration.
See : https://mypy.readthedocs.io/en/stable/generics.html#generic-methods-and-generic-self
But `mypy` is complaining on an example :
```
examples/save_and_load_private_key_file_wif.py:52: error: Need type annotation for 'loaded_signer'
examples/save_and_load_private_key_file_wif.py:54: error: Cannot determine type of 'loaded_signer'
```
Using the debug command `reveal_type()` of `mypy` give us the type returned by the classmethod :
```python
try:
# load private keys from file
reveal_type(SigningKey.from_wif_file(PRIVATE_KEY_FILE_PATH))
loaded_signer = SigningKey.from_wif_file(PRIVATE_KEY_FILE_PATH)
```
`examples/save_and_load_private_key_file_wif.py:50: error: Revealed type is '<nothing>'`
* **Workaround solution for Python 3.5 and 3.6: add required type annotation everytime we call a classmethod.**
* To test : upgrading to Python 3.7 will allow us to use the postponed annotations feature, that, may be, could resolve the problem:
https://stackoverflow.com/questions/44640479/mypy-annotation-for-classmethod-returning-instance1.2.0https://git.duniter.org/clients/python/duniterpy/-/issues/201Support BMA changes2023-06-06T21:53:33+02:00MoulSupport BMA changes### Sources and transactions retrieval
- nodes/typescript/duniter!1420+:
- `/tx/sources/$pubkey`
- `/tx/sources/$pubkey/pending`
- `/tx/history/$pubkey/`: nodes/typescript/duniter!1425+
- [x] jsonschema: `HISTORY_SCHEMA` set `receivi...### Sources and transactions retrieval
- nodes/typescript/duniter!1420+:
- `/tx/sources/$pubkey`
- `/tx/sources/$pubkey/pending`
- `/tx/history/$pubkey/`: nodes/typescript/duniter!1425+
- [x] jsonschema: `HISTORY_SCHEMA` set `receiving` as non required since the field was removed (also removed from Duniter v1.9)
### Wot: Support to pass `?pubkey` query
- Defaulting `pubkey_query` to:
- `True` would be breaking change when passing a `uid`, but would allow to use the optimization by default
- `False` would not be a breaking change, but requires a change to get the optimization: I go for this option
- `/wot/requirements/$pubkey?pubkey`: nodes/typescript/duniter!1422+
- nodes/typescript/duniter!1423+:
- `/wot/certifiers-of/$pubkey?pubkey`
- `/wot/certified-by/$pubkey?pubkey`
### `node/summary` storage
In `/node/summary` new fields can be added to the jsonschema, but do not set them as mandatory since it would break the backward compatibility
- nodes/typescript/duniter!1424+1.2.0MoulMoulhttps://git.duniter.org/clients/python/duniterpy/-/issues/187Implement __eq__() methods on Revocation, Identity, Membership, and Certifica...2021-11-12T22:23:31+01:00MoulImplement __eq__() methods on Revocation, Identity, Membership, and Certification classes- [x] Implement `__eq__` in `Document`
- [x] Call `super().__eq__()` in `Transaction`’s `__eq__()` method
- Implement `__eq__()` and `__hash__()` methods in:
- [x] `Identity`:
- [x] `Revocation`
- [x] `Certification`
- [x] `Membershi...- [x] Implement `__eq__` in `Document`
- [x] Call `super().__eq__()` in `Transaction`’s `__eq__()` method
- Implement `__eq__()` and `__hash__()` methods in:
- [x] `Identity`:
- [x] `Revocation`
- [x] `Certification`
- [x] `Membership`
Useful to write tests.
`__eq__()` is already implemented on `Transation`, `Block`, and `BlockUID` classes.1.1.0MoulMoulhttps://git.duniter.org/clients/python/duniterpy/-/issues/149Change workflow by changing from 'master' and default 'dev' branches to a sin...2021-07-25T12:05:56+02:00Vincent TexierChange workflow by changing from 'master' and default 'dev' branches to a single 'main' branchFor now, we use a procedure of release (see [CONTRIBUTING.md](https://git.duniter.org/clients/python/duniterpy/-/blob/dev/CONTRIBUTING.md)) by working directly on the `dev` branch.
When the commits for the release are done locally on th...For now, we use a procedure of release (see [CONTRIBUTING.md](https://git.duniter.org/clients/python/duniterpy/-/blob/dev/CONTRIBUTING.md)) by working directly on the `dev` branch.
When the commits for the release are done locally on the developer repository, they are pushed to Gitlab on the `dev` branch.
If the integration tests failed, we are stuck because the `dev` branch is protected.
The only solution is to remove the protection to allow a **force push** on the `dev` branch.
Do you see it coming ? A **force push** on a critical branch containing all the commits since the last release ?
What happens if the local repository of the developer is not up to date with the Gitlab `dev` branch ?
The problem has just happened, and I propose a new workflow to secure the process:
* We remove the `dev` branch after the next release, when it is on the same commit as the `master` branch as it is useless in the new workflow.
* For every release, we create a `release_x.y.z` branch to work on the release commits, and use it to create a MR.
* If integration tests fail, we can just **force push** on the `release_x.y.z` branch, no risk here.
* When the MR is approved, we merge the release branch in `master`.
The advantage of this workflow is also to have a default `master` branch with an up to date stable code, coming from the approved and tested MR.
We always have the release tags for the release references.1.0.0MoulMoulhttps://git.duniter.org/clients/python/duniterpy/-/issues/170Endpoints' regex improvement2021-07-22T18:27:29+02:00MoulEndpoints' regex improvement- [x] Change host regex, to support IDN: Internationalized domain names
- [x] Define more compact ipv6 and ipv4 regex
- [x] Define port regex
- [x] Name capturing groups
- [x] Fix/overcome server/host and ipv4 mix up with BMA(S) and GVA ...- [x] Change host regex, to support IDN: Internationalized domain names
- [x] Define more compact ipv6 and ipv4 regex
- [x] Define port regex
- [x] Name capturing groups
- [x] Fix/overcome server/host and ipv4 mix up with BMA(S) and GVA endpoints1.0.0MoulMoulhttps://git.duniter.org/clients/python/duniterpy/-/issues/175Rename timestamp and blockstamp attributes/arguments depending on the type2021-07-08T10:14:43+02:00Vincent TexierRename timestamp and blockstamp attributes/arguments depending on the type`blockstamp` arguments/attributes should be renamed `block_uid` and only contains `BlockUID` instance type.
`timestamp` arguments/attributes should only contains an integer timestamp in seconds.
Rename all arguments/attributes to refle...`blockstamp` arguments/attributes should be renamed `block_uid` and only contains `BlockUID` instance type.
`timestamp` arguments/attributes should only contains an integer timestamp in seconds.
Rename all arguments/attributes to reflect what type they are.1.0.0Vincent TexierVincent Texierhttps://git.duniter.org/clients/python/duniterpy/-/issues/181CRCPubkey class should be moved away from documents package2021-07-03T10:05:32+02:00Vincent TexierCRCPubkey class should be moved away from documents package`CRCPubkey` is not a `Document` subclass.
It should be out of documents folder, in `key` package.`CRCPubkey` is not a `Document` subclass.
It should be out of documents folder, in `key` package.1.0.0Vincent TexierVincent Texierhttps://git.duniter.org/clients/python/duniterpy/-/issues/95Remove `signatures` argument from all `__init__()`’s documents subclasses2021-06-29T19:00:14+02:00Vincent TexierRemove `signatures` argument from all `__init__()`’s documents subclassesWhen we instantiate a `Document` instance, or a `Document` subclass instance, we do not have the signatures of the document as it is not created yet.
**So we can remove the `signatures` argument in the `__init__()` of `Document` and all...When we instantiate a `Document` instance, or a `Document` subclass instance, we do not have the signatures of the document as it is not created yet.
**So we can remove the `signatures` argument in the `__init__()` of `Document` and all his subclass.**
It will be a big backward compatibility break. But the code will be more logic and simple.
### Deprecation first
Deprecation need to be done in a previous release (say %"0.60.0" for example).
It will be Deprecated gracefully with warnings, thanks to python deprecation system.
http://www.jaggedverge.com/2016/09/deprecation-warnings-in-python/
To ease the migration, perhaps start by set the argument as Optional with deprecationWarning.
Then remove it in a future version...
### Previous thoughts
All documents classes inherit of the `Document` class.
The `Document` class has a required `signatures` parameter which type is `List[str]`.
But most of the subclass does not have any signature when creating an instance.
So, when `None` is passed, the subclass handle it differently.
See `Identity` subclass handling (and the fact that you must provide a `None` parameter):
```python
def __init__(
self,
version: int,
currency: str,
pubkey: str,
uid: str,
ts: BlockUID,
signature: Optional[str],
) -> None:
...
if signature:
super().__init__(version, currency, [signature])
else:
super().__init__(version, currency, [])
```
See `Membership` subclass, consider it to be the best way to do it:
```python
def __init__(
self,
version: int,
currency: str,
issuer: str,
membership_ts: BlockUID,
membership_type: str,
uid: str,
identity_ts: BlockUID,
signature: Optional[str] = None,
) -> None:
...
super().__init__(version, currency, [signature] if signature else [])
```
Here, the `signature` parameter is not required, and we prepare a `signatures` parameter for the parent `Document` class.
We should do it for all subclass of `Document`, being careful as some are multi-signature.1.0.0Vincent TexierVincent Texierhttps://git.duniter.org/clients/python/duniterpy/-/issues/139Rename Endpoints attributes from server to host(name)2021-06-29T18:58:02+02:00MoulRename Endpoints attributes from server to host(name)In `Endpoint`s classes, rename `server` attribute to `host` or `hostname`.
`ConnectionHandler`’s `server` attribute is used as an alias and can contains a domain name, an ipv6, and an ipv4. Could be renamed as `address`. `server` is qui...In `Endpoint`s classes, rename `server` attribute to `host` or `hostname`.
`ConnectionHandler`’s `server` attribute is used as an alias and can contains a domain name, an ipv6, and an ipv4. Could be renamed as `address`. `server` is quite fine.1.0.0MoulMoulhttps://git.duniter.org/clients/python/duniterpy/-/issues/172Document.version field should be optional with default=[last_document_version]2021-06-29T14:31:52+02:00Vincent TexierDocument.version field should be optional with default=[last_document_version]**Break backward compatibility.**
`Document` class set the protocol version as the first mandatory constructor field.
It is not easy for a new user to find the last version of the protocol.
To ease the creation of a document, this fie...**Break backward compatibility.**
`Document` class set the protocol version as the first mandatory constructor field.
It is not easy for a new user to find the last version of the protocol.
To ease the creation of a document, this field should be set by default to the last protocol version.
So we need to set the field in last position, with the last protocol version of Duniter (12 at the time of writing) as default value.
Before:
```python
def __init__(self, version: int, currency: str) -> None:
...
```
After:
```python
def __init__(self, currency: str, version: int = 12) -> None:
...
```1.0.0Vincent TexierVincent Texierhttps://git.duniter.org/clients/python/duniterpy/-/issues/60Drop Python v3.5 support2021-06-28T22:30:37+02:00Vincent TexierDrop Python v3.5 supportTo allow static typing on local variables, we must upgrade to Python 3.6.
To help automatically fulfilled the code with static typing, we need to use [MonkeyType](https://pypi.org/project/MonkeyType/).
To automatically freeze code styl...To allow static typing on local variables, we must upgrade to Python 3.6.
To help automatically fulfilled the code with static typing, we need to use [MonkeyType](https://pypi.org/project/MonkeyType/).
To automatically freeze code style, we need [Black](https://github.com/ambv/black).
Both require Python 3.6 version.
So I suggest to require Python 3.6 minimum to use this library.0.60.0MoulMoul2020-09-30https://git.duniter.org/clients/python/duniterpy/-/issues/140Replace aiohttp with a non async http library2021-06-21T10:35:56+02:00Vincent TexierReplace aiohttp with a non async http libraryAfter learning a lot on differences between mono-thread async, concurrency, parallel execution, threads, etc, I came to the conclusion that aiohttp is:
* Overkill for the DuniterPy usage.
* Hard to implement (need an async loop, recursiv...After learning a lot on differences between mono-thread async, concurrency, parallel execution, threads, etc, I came to the conclusion that aiohttp is:
* Overkill for the DuniterPy usage.
* Hard to implement (need an async loop, recursively add async and await keywords on all functions).
* Not used in terminal little scripts, only in Sakia (may be Silkaj?).
So I want to get rid of `aiohttp` library and replace it with, to choose:
* `urllib` (low-level but standard python module)
* `requests` (high-level but external dependency)
Pro:
* The developers will be able to choose their own concurrency method if needed.
* The library usage will be more simple for everyone (no more async loop and keywords to understand).
* Maintainers will have a simpler code to maintain.
Con:
* Mostly all of the code must be refactored.
* May not be ready for 1.0, but for 2.0.1.0.0Vincent TexierVincent Texier2021-04-05https://git.duniter.org/clients/python/duniterpy/-/issues/52Add type annotations (python 3.5) for static typing2021-06-18T13:16:55+02:00Vincent TexierAdd type annotations (python 3.5) for static typingTo get a strongly typed code, we can use typing annotations and the typing module.
To type-check the code before run-time, we can use our IDE integrated type checking, or better :
* [mypy](http://mypy-lang.org/)
* [pyre](https://pyre-...To get a strongly typed code, we can use typing annotations and the typing module.
To type-check the code before run-time, we can use our IDE integrated type checking, or better :
* [mypy](http://mypy-lang.org/)
* [pyre](https://pyre-check.org/)
A video about typing : https://hooktube.com/watch?v=QCGwDOk-pIs0.50.0Vincent TexierVincent Texierhttps://git.duniter.org/clients/python/duniterpy/-/issues/163Revocation.from_signed_raw() do not stores timestamps into a BlockUID object2021-05-22T12:50:59+02:00MoulRevocation.from_signed_raw() do not stores timestamps into a BlockUID object> From https://git.duniter.org/clients/python/silkaj/-/merge_requests/170#note_26657 & https://git.duniter.org/clients/python/silkaj/-/merge_requests/170#note_26658
`from_signed_raw()` methods from `Membership`, `Identity`, and `Certifi...> From https://git.duniter.org/clients/python/silkaj/-/merge_requests/170#note_26657 & https://git.duniter.org/clients/python/silkaj/-/merge_requests/170#note_26658
`from_signed_raw()` methods from `Membership`, `Identity`, and `Certification` classes store timestamps into a `BlockUID` object. This is not the case of `Revocation.from_signed_raw()`. Let's make it consistent and more convenient to use.1.0.0MoulMoulhttps://git.duniter.org/clients/python/duniterpy/-/issues/160Include examples into Python package2021-05-22T12:27:43+02:00MoulInclude examples into Python package- [Integration into Debian package](https://salsa.debian.org/cryptocoin-team/python-duniterpy/-/commit/d5a3e0204a6776b947a1dcf6ab2a270b273697b0)
---
- Include examples into the Python package to use them.
- Make the tests more usable in...- [Integration into Debian package](https://salsa.debian.org/cryptocoin-team/python-duniterpy/-/commit/d5a3e0204a6776b947a1dcf6ab2a270b273697b0)
---
- Include examples into the Python package to use them.
- Make the tests more usable in Python interpreter
---
- [x] Include `examples`
- Could collide with [`example`](https://pypi.org/project/examples/) package from PyPI in local `site-packages`.
- [Nothing on Repology](https://repology.org/badge/vertical-allrepos/python:examples.svg)
- [Present on Debian](https://packages.debian.org/search?suite=default§ion=all&arch=any&searchon=names&keywords=python3-examples)
- [x] Define functions in examples
- [x] Introduce `__init__.py`
- [x] Document how to the examples from Python shell1.0.0MoulMoulhttps://git.duniter.org/clients/python/duniterpy/-/issues/157Create identity attribute on the Revocation and Certification classes2021-04-25T14:46:34+02:00matograineCreate identity attribute on the Revocation and Certification classes> Coming from the [implementation of the `revoke` command implementation on Silkaj](https://git.duniter.org/clients/python/silkaj/-/merge_requests/170#note_26655).
The `Revocation` has `extract_self_cert()` method that needs a signed ra...> Coming from the [implementation of the `revoke` command implementation on Silkaj](https://git.duniter.org/clients/python/silkaj/-/merge_requests/170#note_26655).
The `Revocation` has `extract_self_cert()` method that needs a signed raw document.
However, a `Revocation` object could have an `identity` attribute. Same for `Certification`.
Or a dedicated method, like `Revocation.extract_identity()`.
### Todo
- [ ] `Revocation.identity()`
- [ ] `Certification.identity()`Backloghttps://git.duniter.org/clients/python/duniterpy/-/issues/97Optimize .gitlab-ci.yml which run two pipelines when pushing a release tag2021-03-07T17:14:52+01:00Vincent TexierOptimize .gitlab-ci.yml which run two pipelines when pushing a release tagWhen we push a release `tag`, two pipelines are started, one for the `tag` and one for the `branch` update.
We need to remove one trigger.
I propose to remove the `tag` trigger, cause it is useless, as we publish release manually.When we push a release `tag`, two pipelines are started, one for the `tag` and one for the `branch` update.
We need to remove one trigger.
I propose to remove the `tag` trigger, cause it is useless, as we publish release manually.BacklogMoulMoul