Skip to main content

Input and output of ADIF radio amateur log files.

Project description

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).

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()

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

adif_io-0.5.2.tar.gz (11.9 kB view details)

Uploaded Source

Built Distribution

adif_io-0.5.2-py3-none-any.whl (10.8 kB view details)

Uploaded Python 3

File details

Details for the file adif_io-0.5.2.tar.gz.

File metadata

  • Download URL: adif_io-0.5.2.tar.gz
  • Upload date:
  • Size: 11.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.11.2

File hashes

Hashes for adif_io-0.5.2.tar.gz
Algorithm Hash digest
SHA256 18b89ed3bdd0c983a5e40cadb59352f196497727affb7060dde08d600ac49b17
MD5 852721ba6ee8ce57d0dc42f65e045972
BLAKE2b-256 283e42ff77946d0c8c59ff1a6c0523851f9485d6263d5a33b958a894cce01e28

See more details on using hashes here.

File details

Details for the file adif_io-0.5.2-py3-none-any.whl.

File metadata

  • Download URL: adif_io-0.5.2-py3-none-any.whl
  • Upload date:
  • Size: 10.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.11.2

File hashes

Hashes for adif_io-0.5.2-py3-none-any.whl
Algorithm Hash digest
SHA256 37e7d965ed8f8a9474b4e15e77fdb8984f543de72cf4c4ca7b3bc8cd2f0731c7
MD5 80cb4a988c1efae19f4a3be3258d93ba
BLAKE2b-256 a62ea462b57e5599bd4c4e5df4971076c3fbfed7b2dd62963b53fecba84ed2ff

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page