adif-io


Nameadif-io JSON
Version 0.5.3 PyPI version JSON
download
home_pageNone
SummaryInput and output of ADIF radio amateur log files.
upload_time2024-11-28 12:09:28
maintainerNone
docs_urlNone
authorNone
requires_python>=3.9
licenseNone
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:

>  &lt;ADIF_VER:5>3.1.0 &lt;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

> &lt;QSO_DATE:8>20190714 &lt;TIME_ON:4>1140 &lt;CALL:5>LY0HQ &lt;MODE:2>CW &lt;BAND:3>40M &lt;RST_RCVD:3>599 &lt;RST_SENT:3>599 &lt;SRX_STRING:4>LRMD &lt;STX_STRING:2>28 &lt;EOR>
> 
> &lt;QSO_DATE:8>20190714 &lt;TIME_ON:4>1130 &lt;CALL:5>SE9HQ &lt;FREQ:1>7 &lt;MODE:2>CW &lt;BAND:3>40M &lt;DXCC:3>284 &lt;RST_RCVD:3>599 &lt;RST_SENT:3>599 &lt;SRX_STRING:3>SSA &lt;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>  &lt;ADIF_VER:5>3.1.0 &lt;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> &lt;QSO_DATE:8>20190714 &lt;TIME_ON:4>1140 &lt;CALL:5>LY0HQ &lt;MODE:2>CW &lt;BAND:3>40M &lt;RST_RCVD:3>599 &lt;RST_SENT:3>599 &lt;SRX_STRING:4>LRMD &lt;STX_STRING:2>28 &lt;EOR>\n> \n> &lt;QSO_DATE:8>20190714 &lt;TIME_ON:4>1130 &lt;CALL:5>SE9HQ &lt;FREQ:1>7 &lt;MODE:2>CW &lt;BAND:3>40M &lt;DXCC:3>284 &lt;RST_RCVD:3>599 &lt;RST_SENT:3>599 &lt;SRX_STRING:3>SSA &lt;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"
}
        
Elapsed time: 5.03184s