From 9151d55bc5eead345720a2c486fdfa759cd6a9f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Kr=C3=BCger?= Date: Sun, 24 Nov 2019 00:56:56 +0100 Subject: [PATCH] Two bugfixes and some polish. (#3) * Copyright of contributed material belongs to contributor. * The text in (e.g.) a SOAPBOX: line can contain another ":". * The last character of a good ADIF log should be a newline. * Merge multiple OPERATOR: lines. * Between START-OF-LOG and END-OF-LOG, other tags can be in any order. * Make things easier for contributors and others who want to run the tests. * Bump version to 0.0.4. --- .build.yml | 1 - .gitignore | 2 ++ .travis.yml | 1 - LICENSE | 2 +- README.md | 22 ++++++++++++++++++++++ cabrillo/parser.py | 15 +++++++++------ setup.py | 2 +- tests/CQWPX.log | 3 ++- tests/CQWPX_bad_style.log | 14 +++++++++----- tests/path_helper.py | 9 +++++++++ tests/test_cabrillo.py | 2 ++ tests/test_parser_log.py | 7 +++++-- tests/test_parser_qso.py | 1 + tests/test_qso.py | 2 ++ 14 files changed, 65 insertions(+), 18 deletions(-) create mode 100644 tests/path_helper.py diff --git a/.build.yml b/.build.yml index 1db4e95..9680b42 100644 --- a/.build.yml +++ b/.build.yml @@ -8,7 +8,6 @@ environment: tasks: - pytest: | cd ${project} - export PYTHONPATH=$PYTHONPATH:$(pwd) sudo pip3 install -r requirements_test.txt py.test --cov-report term-missing --cov cabrillo -v diff --git a/.gitignore b/.gitignore index d8a72af..df3e6f9 100644 --- a/.gitignore +++ b/.gitignore @@ -79,6 +79,8 @@ ipython_config.py # pyenv .python-version +# Virtual env as proposed in README +python-venv # celery beat schedule file celerybeat-schedule diff --git a/.travis.yml b/.travis.yml index dec37d9..c322d09 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,6 @@ python: - "3.6" cache: pip install: - - "export PYTHONPATH=$PYTHONPATH:$(pwd)" - pip install -r requirements_test.txt script: - py.test --cov-report term-missing --cov cabrillo -v \ No newline at end of file diff --git a/LICENSE b/LICENSE index a442d28..92aeb41 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright 2018 Howard Xiao +Copyright 2018-2019 Howard Xiao and contributors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/README.md b/README.md index 35a41d5..d3b22a6 100644 --- a/README.md +++ b/README.md @@ -93,3 +93,25 @@ class Cabrillo(builtins.object) | dx_exch: Received exchange incl. RST. List of each component. | t: Transmitter ID for multi-transmitter categories in int. 0/1. ``` + +## Contributors + +Pull requests are appreciated! + +The following instructions show how to obtain the sourcecode and execute the tests. +They assume Python 3.3 or later. + +For Posix plattforms (which includes Mac and Linux): + +``` +git clone https://github.com/thxo/cabrillo.git +cd cabrillo +python3 -m venv python-venv +source python-venv/bin/activate +pip install -r requirements_test.txt +py.test --cov-report term-missing --cov cabrillo -v +``` + +On a Windows machine, using `cmd.exe`, substitute +`python-venv/Scripts/activate` for +`source python-venv/bin/activate`. diff --git a/cabrillo/parser.py b/cabrillo/parser.py index 3e6deec..3d58c90 100644 --- a/cabrillo/parser.py +++ b/cabrillo/parser.py @@ -5,6 +5,7 @@ from cabrillo.errors import InvalidQSOException, InvalidLogException from cabrillo.data import KEYWORD_MAP +import re def parse_qso(text): """Parse a single line of QSO into a QSO object. @@ -74,12 +75,14 @@ def parse_log_text(text, ignore_unknown_key=False, check_categories=True): results = dict() results['x_anything'] = dict() + key_colon_value = re.compile(r'^\s*([^:]+?)\s*:\s*(.*?)\s*$') for line in text.split('\n'): - try: - key, value = [x.replace('\r', '').strip() for x in line.split(':')] - except ValueError: - raise InvalidLogException('Line not delimited by `:`, ' - 'got {}.'.format(line)) + match = key_colon_value.fullmatch(line) + if match: + key, value = match.group(1), match.group(2) + else: + raise InvalidLogException('Line does not start with `:`-delimited key, ' + 'got `{}`.'.format(line)) if key == 'END-OF-LOG': break @@ -98,7 +101,7 @@ def parse_log_text(text, ignore_unknown_key=False, check_categories=True): results.setdefault(inverse_keywords[key], list()).append( parse_qso(value)) elif key == 'OPERATORS': - results[inverse_keywords[key]] = value.replace(',', ' ').split() + results.setdefault(inverse_keywords[key], list()).extend(value.replace(',', ' ').split()) elif key in ['ADDRESS', 'SOAPBOX']: results.setdefault(inverse_keywords[key], list()).append(value) elif key in inverse_keywords.keys(): diff --git a/setup.py b/setup.py index 30c5dfb..8cb6c33 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name="cabrillo", - version="0.0.3", + version="0.0.4", author="Howard Xiao", author_email="thx@thxo.org", description="A Python library to parse Cabrillo-format amateur radio " diff --git a/tests/CQWPX.log b/tests/CQWPX.log index a5a6215..3e1db8b 100644 --- a/tests/CQWPX.log +++ b/tests/CQWPX.log @@ -21,6 +21,7 @@ ADDRESS-COUNTRY: USA OPERATORS: AA1XXX AA2XXX AA3XXX SOAPBOX: Put your comments here. SOAPBOX: Use multiple lines if needed. +SOAPBOX: Once you said "SOAPBOX:", the rest of the line is free-form. QSO: 7005 CW 2009-05-30 0002 AA1ZZZ 599 1 S50A 599 4 QSO: 7006 CW 2009-05-30 0015 AA1ZZZ 599 2 EF8M 599 34 -END-OF-LOG: \ No newline at end of file +END-OF-LOG: diff --git a/tests/CQWPX_bad_style.log b/tests/CQWPX_bad_style.log index 213045c..bdd110b 100644 --- a/tests/CQWPX_bad_style.log +++ b/tests/CQWPX_bad_style.log @@ -1,4 +1,5 @@ START-OF-LOG: 3.0 +QSO: 7005 CW 2009-05-30 0002 AA1ZZZ 599 1 S50A 599 4 CALLSIGN: AA1ZZZ CONTEST:CQ-WPX-CW CATEGORY-OPERATOR: SINGLE-OP @@ -17,12 +18,15 @@ ADDRESS: 11 Hollis Street ADDRESS-CITY: Uxbridge ADDRESS-STATE-PROVINCE: MA ADDRESS-POSTALCODE: 01569 -ADDRESS-COUNTRY: USA -OPERATORS: AA1XXX, AA2XXX, AA3XXX, -SOAPBOX: Put your comments here. -SOAPBOX: Use multiple lines if needed. -QSO: 7005 CW 2009-05-30 0002 AA1ZZZ 599 1 S50A 599 4 QSO: 7006 CW 2009-05-30 0015 AA1ZZZ 599 2 EF8M 599 34 +ADDRESS-COUNTRY: USA +OPERATORS: AA1XXX, AA2XXX, +OPERATORS: +OPERATORS: +OPERATORS: AA3XXX, +SOAPBOX: Put your comments here. +SOAPBOX: Use multiple lines if needed. +SOAPBOX: Once you said "SOAPBOX:", the rest of the line is free-form. END-OF-LOG: diff --git a/tests/path_helper.py b/tests/path_helper.py new file mode 100644 index 0000000..ed60538 --- /dev/null +++ b/tests/path_helper.py @@ -0,0 +1,9 @@ +import sys +import os.path + +"""Make the cabrillo module importable from the tests' point of view.""" + +project_root_dir = os.path.dirname(os.path.dirname(__file__)) + +if not project_root_dir in sys.path: + sys.path.append(project_root_dir) diff --git a/tests/test_cabrillo.py b/tests/test_cabrillo.py index 7befcab..852b1b2 100644 --- a/tests/test_cabrillo.py +++ b/tests/test_cabrillo.py @@ -4,6 +4,8 @@ import pytest +import path_helper + from cabrillo import Cabrillo, QSO from cabrillo.data import VALID_CATEGORIES_MAP from cabrillo.errors import InvalidLogException diff --git a/tests/test_parser_log.py b/tests/test_parser_log.py index a16f357..fbb6b34 100644 --- a/tests/test_parser_log.py +++ b/tests/test_parser_log.py @@ -3,6 +3,8 @@ import pytest +import path_helper + from cabrillo import QSO from cabrillo.errors import InvalidLogException from cabrillo.parser import parse_log_file, parse_log_text @@ -35,10 +37,11 @@ def test_parse_cqwpx(): assert cab.address_country == 'USA' assert cab.operators == ['AA1XXX', 'AA2XXX', 'AA3XXX'] assert cab.soapbox == ['Put your comments here.', - 'Use multiple lines if needed.'] + 'Use multiple lines if needed.', + 'Once you said "SOAPBOX:", the rest of the line is free-form.'] out_lines = cab.write_text().split('\n') - correct_lines = open('tests/CQWPX.log').read().split('\n') + correct_lines = open('tests/CQWPX.log').read().strip().split('\n') assert len(out_lines) == len(correct_lines) and sorted( out_lines) == sorted(correct_lines) diff --git a/tests/test_parser_qso.py b/tests/test_parser_qso.py index 84fd051..90bb407 100644 --- a/tests/test_parser_qso.py +++ b/tests/test_parser_qso.py @@ -2,6 +2,7 @@ from datetime import datetime import pytest +import path_helper from cabrillo.errors import InvalidQSOException from cabrillo.parser import parse_qso diff --git a/tests/test_qso.py b/tests/test_qso.py index c81a834..e7d6eb9 100644 --- a/tests/test_qso.py +++ b/tests/test_qso.py @@ -3,6 +3,8 @@ import pytest +import path_helper + from cabrillo import QSO from cabrillo.qso import frequency_to_band from cabrillo.errors import InvalidQSOException