Name | adif-io JSON |
Version |
0.5.3
JSON |
| download |
home_page | None |
Summary | Input and output of ADIF radio amateur log files. |
upload_time | 2024-11-28 12:09:28 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.9 |
license | None |
keywords |
ham
amateur radio
|
VCS |
|
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# This is an ADIF parser in Python.
## Actual usage
Main result of parsing: List of QSOs:
* Each QSO is represented by a special-purpose Python mapping.
* Keys in that mapping are ADIF field names in upper case,
* value for a key is whatever was found in the ADIF, as a string
(though some values are converted to upper case on output),
* you can access individual field values via either
`qso[fieldname]` or [`qso.get(fieldname)`](https://docs.python.org/3/library/stdtypes.html#dict.get)
(depending on which behavior you want when your field does not exist).
Order of QSOs in the list is same as in ADIF file.
Secondary result of parsing: The ADIF headers.
This is returned as a Python mapping as well.
Normally, you'd call `adif_io.read_from_file(filename)`. But you can
also provide a string with an ADI-file's content, as follows:
```
import adif_io
qsos, header = adif_io.read_from_string(
"A sample ADIF content for demonstration.\n"
"<adif_ver:5>3.1.0<eoh>\n"
"<QSO_DATE:8>20190714 <time_on:4>1140<CALL:5>LY0HQ"
"<mode:2>CW<BAND:3>40M<RST_SENT:3>599<RST_RCVD:3>599"
"<STX_STRING:2>28<SRX_STRING:4>LRMD<EOR>\n"
"<QSO_DATE:8>20190714<TIME_ON:4>1130<CALL:5>SE9HQ<MODE:2>CW<FREQ:1>7"
"<BAND:3>40M<RST_SENT:3>599<RST_RCVD:3>599"
"<SRX_STRING:3>SSA<DXCC:3>284<EOR>")
```
After this setup, `print(header)` will print out a valid ADIF file start:
> <ADIF_VER:5>3.1.0 <EOH>
(This starts with a blank space, as the ADIF spec demands a header must not
start with the `<` character.)
And
```
for qso in qsos:
print(qso)
```
prints
> <QSO_DATE:8>20190714 <TIME_ON:4>1140 <CALL:5>LY0HQ <MODE:2>CW <BAND:3>40M <RST_RCVD:3>599 <RST_SENT:3>599 <SRX_STRING:4>LRMD <STX_STRING:2>28 <EOR>
>
> <QSO_DATE:8>20190714 <TIME_ON:4>1130 <CALL:5>SE9HQ <FREQ:1>7 <MODE:2>CW <BAND:3>40M <DXCC:3>284 <RST_RCVD:3>599 <RST_SENT:3>599 <SRX_STRING:3>SSA <EOR>
>
So `str(qso)` for a single QSO generates that QSO as an ADIF string.
Fine points:
- The ADIF string of the headers or that of a QSO are each terminated by a `\n`.
- ADIF allows lower- and upper case field names. You can feed either to this software.
- Field names are consistently converted to upper case internally.
- Any non-field text in the header or in a QSO or between QSOs is ignored.
(This may change at some undetermined time in the future.)
- Value content is always a string.
- Fields with zero-length content are treated as non-existent.
- The output of a single QSO has a few important fields first,
then all other fields in alphabetic order.
The details may change over time.
- Some QSO fields, in particular `CALL` and `MODE`, are automatically converted to upper case on output.
This is not done systematically (for other fields that would also benefit from this),
and the details may change.
## Time on and time off
Given one `qso` dict, you can also have the QSO's start time calculated as a Python `datetime.datetime` value:
adif_io.time_on(qsos[0])
If your QSO data also includes `TIME_OFF` fields (and, ideally, though
not required, `QSO_DATE_OFF`), this will also work:
adif_io.time_off(qsos[0])
## Geographic coordinates - to some degree
ADIF uses a somewhat peculiar 11 character `XDDD MM.MMM` format to
code geographic coordinates (fields `LAT` or `LON`). The more common
format these days are simple floats that code degrees. You can convert
from one to the other:
```
adif_io.degrees_from_location("N052 26.592") # Result: 52.4432
adif_io.location_from_degrees(52.4432, True) # Result: "N052 26.592"
```
The additional `bool` argument of `location_from_degrees` should be
`True` for latitudes (N / S) and `False` for longitudes (E / W).
## ADIF version
There is little ADIF-version-specific here. (Everything should work
with ADI-files of ADIF version 3.1.3, if you want to nail it.)
## Not supported: ADIF data types.
This parser knows nothing about ADIF data types or enumerations.
Everything is a string. So in that sense, this parser is fairly simple.
But it does correcly handle things like:
<notes:66>In this QSO, we discussed ADIF and in particular the <eor> marker.
So, in that sense, this parser is _somewhat_ sophisticated.
## Only ADI.
This parser only handles ADI files. It knows nothing of the ADX file format.
## Sample code
Here is some sample code:
```
import adif_io
qsos_raw, adif_header = adif_io.read_from_file("log.adi")
# The QSOs are probably sorted by QSO time already, but make sure:
qsos_raw_sorted = sorted(qsos_raw, key = adif_io.time_on)
```
Pandas / Jupyter users may want to add `import pandas as pd`
up above and continue like this:
```
qsos = pd.DataFrame(qsos_raw_sorted)
qsos.info()
```
Raw data
{
"_id": null,
"home_page": null,
"name": "adif-io",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "ham, amateur radio",
"author": null,
"author_email": "\"Dr. Andreas Kr\u00fcger, DJ3EI\" <dj3ei@famsik.de>",
"download_url": "https://files.pythonhosted.org/packages/6e/5e/aac062bd5ef164f1ed71bd0056b620839d34eae8671f48c55057e6e20ed3/adif_io-0.5.3.tar.gz",
"platform": null,
"description": "# This is an ADIF parser in Python.\n\n## Actual usage\n\nMain result of parsing: List of QSOs:\n\n* Each QSO is represented by a special-purpose Python mapping.\n* Keys in that mapping are ADIF field names in upper case,\n* value for a key is whatever was found in the ADIF, as a string\n (though some values are converted to upper case on output),\n* you can access individual field values via either \n `qso[fieldname]` or [`qso.get(fieldname)`](https://docs.python.org/3/library/stdtypes.html#dict.get)\n (depending on which behavior you want when your field does not exist).\n\nOrder of QSOs in the list is same as in ADIF file.\n\nSecondary result of parsing: The ADIF headers.\nThis is returned as a Python mapping as well.\n\nNormally, you'd call `adif_io.read_from_file(filename)`. But you can\nalso provide a string with an ADI-file's content, as follows:\n\n```\nimport adif_io\n\nqsos, header = adif_io.read_from_string(\n \"A sample ADIF content for demonstration.\\n\"\n \"<adif_ver:5>3.1.0<eoh>\\n\"\n \n \"<QSO_DATE:8>20190714 <time_on:4>1140<CALL:5>LY0HQ\"\n \"<mode:2>CW<BAND:3>40M<RST_SENT:3>599<RST_RCVD:3>599\"\n \"<STX_STRING:2>28<SRX_STRING:4>LRMD<EOR>\\n\"\n\n \"<QSO_DATE:8>20190714<TIME_ON:4>1130<CALL:5>SE9HQ<MODE:2>CW<FREQ:1>7\"\n \"<BAND:3>40M<RST_SENT:3>599<RST_RCVD:3>599\"\n \"<SRX_STRING:3>SSA<DXCC:3>284<EOR>\")\n```\n\nAfter this setup, `print(header)` will print out a valid ADIF file start:\n\n> <ADIF_VER:5>3.1.0 <EOH>\n\n(This starts with a blank space, as the ADIF spec demands a header must not\nstart with the `<` character.)\n\nAnd \n\n```\nfor qso in qsos:\n print(qso)\n```\n\nprints\n\n> <QSO_DATE:8>20190714 <TIME_ON:4>1140 <CALL:5>LY0HQ <MODE:2>CW <BAND:3>40M <RST_RCVD:3>599 <RST_SENT:3>599 <SRX_STRING:4>LRMD <STX_STRING:2>28 <EOR>\n> \n> <QSO_DATE:8>20190714 <TIME_ON:4>1130 <CALL:5>SE9HQ <FREQ:1>7 <MODE:2>CW <BAND:3>40M <DXCC:3>284 <RST_RCVD:3>599 <RST_SENT:3>599 <SRX_STRING:3>SSA <EOR>\n> \n\nSo `str(qso)` for a single QSO generates that QSO as an ADIF string.\n\nFine points:\n\n- The ADIF string of the headers or that of a QSO are each terminated by a `\\n`.\n- ADIF allows lower- and upper case field names. You can feed either to this software.\n- Field names are consistently converted to upper case internally.\n- Any non-field text in the header or in a QSO or between QSOs is ignored.\n (This may change at some undetermined time in the future.)\n- Value content is always a string.\n- Fields with zero-length content are treated as non-existent.\n- The output of a single QSO has a few important fields first, \n then all other fields in alphabetic order.\n The details may change over time.\n- Some QSO fields, in particular `CALL` and `MODE`, are automatically converted to upper case on output.\n This is not done systematically (for other fields that would also benefit from this),\n and the details may change.\n\n\n## Time on and time off\n\nGiven one `qso` dict, you can also have the QSO's start time calculated as a Python `datetime.datetime` value:\n\n adif_io.time_on(qsos[0])\n\nIf your QSO data also includes `TIME_OFF` fields (and, ideally, though\nnot required, `QSO_DATE_OFF`), this will also work:\n\n adif_io.time_off(qsos[0])\n\n## Geographic coordinates - to some degree\n\nADIF uses a somewhat peculiar 11 character `XDDD MM.MMM` format to\ncode geographic coordinates (fields `LAT` or `LON`). The more common\nformat these days are simple floats that code degrees. You can convert\nfrom one to the other:\n\n```\nadif_io.degrees_from_location(\"N052 26.592\") # Result: 52.4432\nadif_io.location_from_degrees(52.4432, True) # Result: \"N052 26.592\"\n```\n\nThe additional `bool` argument of `location_from_degrees` should be\n`True` for latitudes (N / S) and `False` for longitudes (E / W).\n\n## ADIF version\n\nThere is little ADIF-version-specific here. (Everything should work\nwith ADI-files of ADIF version 3.1.3, if you want to nail it.)\n\n## Not supported: ADIF data types.\n\nThis parser knows nothing about ADIF data types or enumerations.\nEverything is a string. So in that sense, this parser is fairly simple.\n\nBut it does correcly handle things like:\n\n <notes:66>In this QSO, we discussed ADIF and in particular the <eor> marker.\n\nSo, in that sense, this parser is _somewhat_ sophisticated.\n\n## Only ADI.\n\nThis parser only handles ADI files. It knows nothing of the ADX file format.\n\n## Sample code\n\nHere is some sample code:\n\n```\nimport adif_io\n\nqsos_raw, adif_header = adif_io.read_from_file(\"log.adi\")\n\n# The QSOs are probably sorted by QSO time already, but make sure:\nqsos_raw_sorted = sorted(qsos_raw, key = adif_io.time_on)\n```\n\nPandas / Jupyter users may want to add `import pandas as pd`\nup above and continue like this:\n\n```\nqsos = pd.DataFrame(qsos_raw_sorted)\nqsos.info()\n```\n",
"bugtrack_url": null,
"license": null,
"summary": "Input and output of ADIF radio amateur log files.",
"version": "0.5.3",
"project_urls": {
"Homepage": "https://gitlab.com/andreas_krueger_py/adif_io",
"Issues": "https://gitlab.com/andreas_krueger_py/adif_io/-/issues",
"Repository": "https://gitlab.com/andreas_krueger_py/adif_io"
},
"split_keywords": [
"ham",
" amateur radio"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "d05128e82a2c1326843f6a836452ccb1e8a3625cbacc641b07d0f4c5a75e6c27",
"md5": "8f73686d58b79d6de610fc8db13c47e0",
"sha256": "681d26adc126de7ce1292861c260733d9a65ca79e12b738b3dc25b5fcdc28c2f"
},
"downloads": -1,
"filename": "adif_io-0.5.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "8f73686d58b79d6de610fc8db13c47e0",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 10985,
"upload_time": "2024-11-28T12:09:27",
"upload_time_iso_8601": "2024-11-28T12:09:27.191854Z",
"url": "https://files.pythonhosted.org/packages/d0/51/28e82a2c1326843f6a836452ccb1e8a3625cbacc641b07d0f4c5a75e6c27/adif_io-0.5.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "6e5eaac062bd5ef164f1ed71bd0056b620839d34eae8671f48c55057e6e20ed3",
"md5": "b54c84bed3eb6a030901cef6380f1767",
"sha256": "d7b923e4347a66c74ab60bf97c672c07e5e5980b787ef5cacf97449ac35f5e71"
},
"downloads": -1,
"filename": "adif_io-0.5.3.tar.gz",
"has_sig": false,
"md5_digest": "b54c84bed3eb6a030901cef6380f1767",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 12345,
"upload_time": "2024-11-28T12:09:28",
"upload_time_iso_8601": "2024-11-28T12:09:28.951209Z",
"url": "https://files.pythonhosted.org/packages/6e/5e/aac062bd5ef164f1ed71bd0056b620839d34eae8671f48c55057e6e20ed3/adif_io-0.5.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-11-28 12:09:28",
"github": false,
"gitlab": true,
"bitbucket": false,
"codeberg": false,
"gitlab_user": "andreas_krueger_py",
"gitlab_project": "adif_io",
"lcname": "adif-io"
}