diff --git a/.coveragerc b/.coveragerc index 6f64402..65319db 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,20 +1,9 @@ +# .coveragerc to control coverage.py [run] -# ignore GUI code atm. -omit = - NanoVNASaver/About.py - NanoVNASaver/Analysis/*.py - NanoVNASaver/Calibration.py - NanoVNASaver/Charts/*.py - NanoVNASaver/Controls/*.py - NanoVNASaver/Hardware/*.py - NanoVNASaver/Inputs.py - NanoVNASaver/Marker/*.py - NanoVNASaver/NanoVNASaver.py - NanoVNASaver/Settings/Bands.py - NanoVNASaver/SweepWorker.py - NanoVNASaver/Windows/*.py - **/__init__.py - NanoVNASaver/__main__.py +branch = True +source = tests +#omit = src/ + [report] fail_under = 90.0 show_missing = True diff --git a/.gitignore b/.gitignore index f5ac704..e9e1e9b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,26 +1,54 @@ -/venv/ -/env/ -.idea/ -.tox/ -.vscode/ -/build/ -/dist/ -/nanovna-saver.spec -*.egg-info/ -*.pyc -*.cal -settings.json -.gitignore -.coverage -.flatpak-builder -/nanovna-saver.exe.spec -/deb_dist/ -*.deb -*.rpm -*.tar.gz +# Temporary and binary files *~ -.*~ -*.bak -*.new -*.old +*.py[cod] +*.so +*.cfg +!.isort.cfg +!setup.cfg *.orig +*.log +*.pot +__pycache__/* +.cache/* +.*.swp +*/.ipynb_checkpoints/* +.DS_Store + +# Project files +.ropeproject +.project +.pydevproject +.settings +.idea +.vscode +tags + +# Package files +*.egg +*.eggs/ +.installed.cfg +*.egg-info + +# Unittest and coverage +htmlcov/* +.coverage +.coverage.* +.tox +junit*.xml +coverage.xml +.pytest_cache/ + +# Build and docs folder/files +build/* +dist/* +sdist/* +docs/api/* +docs/_rst/* +docs/_build/* +cover/* +MANIFEST + +# Per-project virtualenvs +.venv*/ +.conda*/ +.python-version diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 0000000..a2bcab3 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,27 @@ +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: docs/conf.py + +# Build documentation with MkDocs +#mkdocs: +# configuration: mkdocs.yml + +# Optionally build your docs in additional formats such as PDF +formats: + - pdf + +build: + os: ubuntu-22.04 + tools: + python: "3.11" + +python: + install: + - requirements: docs/requirements.txt + - {path: ., method: pip} diff --git a/AUTHORS.rst b/AUTHORS.rst new file mode 100644 index 0000000..4d7cde1 --- /dev/null +++ b/AUTHORS.rst @@ -0,0 +1,42 @@ +============ +Contributors +============ + +* Attilio Panniello +* bicycleGuy +* Carl Tremblay +* cinosh07 +* Dan Halbert +* Daniel Lingvay +* Davide Gerhard +* Denis Bondar +* dhunt1342 +* DiSlord +* Frank Kunz +* Galileo +* Holger Mueller +* ikatkov +* Ishmael Samuel +* James Limbouris +* Jaroslav Škarvada +* Kevin Zembower +* Mark Zachmann +* Martin +* Mauro Gaioni +* Mauro +* mihtjel +* Mike4U <9957897+Mike4U@users.noreply.github.com> +* mss +* Neil Katin +* Ohan Smit +* Olgierd Pilarczyk +* Oscilllator +* Patrick Coleman +* Peter B Marks +* Psynosaur +* RandMental +* Roel Jordans +* Rune B. Broberg +* Sascha Silbe +* sysjoint-tek <63992872+sysjoint-tek@users.noreply.github.com> +* zstadler diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst new file mode 100644 index 0000000..d2c7f18 --- /dev/null +++ b/CONTRIBUTING.rst @@ -0,0 +1,322 @@ +============ +Contributing +============ + +Welcome to ``nanovna-saver`` contributor's guide. + +This document focuses on getting any potential contributor familiarized +with the development processes, but `other kinds of contributions`_ are also +appreciated. + +If you are new to using git_ or have never collaborated in a project previously, +please have a look at `contribution-guide.org`_. Other resources are also +listed in the excellent `guide created by FreeCodeCamp`_ [#contrib1]_. + +Please notice, all users and contributors are expected to be **open, +considerate, reasonable, and respectful**. When in doubt, `Python Software +Foundation's Code of Conduct`_ is a good reference in terms of behavior +guidelines. + + +Issue Reports +============= + +If you experience bugs or general issues with ``nanovna-saver``, please have a look +on the `issue tracker`_. If you don't see anything useful there, please feel +free to fire an issue report. + +.. tip:: + Please don't forget to include the closed issues in your search. + Sometimes a solution was already reported, and the problem is considered + **solved**. + +New issue reports should include information about your programming environment +(e.g., operating system, Python version) and steps to reproduce the problem. +Please try also to simplify the reproduction steps to a very minimal example +that still illustrates the problem you are facing. By removing other factors, +you help us to identify the root cause of the issue. + + +Documentation Improvements +========================== + +You can help improve ``nanovna-saver`` docs by making them more readable and coherent, or +by adding missing information and correcting mistakes. + +``nanovna-saver`` documentation should use Sphinx_ as its main documentation compiler. +This means that the docs are kept in the same repository as the project code, and +that any documentation update is done in the same way was a code contribution. + +.. tip:: + Please notice that the `GitHub web interface`_ provides a quick way of + propose changes in ``nanovna-saver``'s files. While this mechanism can + be tricky for normal code contributions, it works perfectly fine for + contributing to the docs, and can be quite handy. + + If you are interested in trying this method out, please navigate to + the ``docs`` folder in the source repository_, find which file you + would like to propose changes and click in the little pencil icon at the + top, to open `GitHub's code editor`_. Once you finish editing the file, + please write a message in the form at the bottom of the page describing + which changes have you made and what are the motivations behind them and + submit your proposal. + +When working on documentation changes in your local machine, you can +compile them using |tox|_:: + + tox -e docs + +and use Python's built-in web server for a preview in your web browser +(``http://localhost:8000``):: + + python3 -m http.server --directory 'docs/_build/html' + + +Code Contributions +================== + +.. todo:: Please include a reference or explanation about the internals of the project. + + An architecture description, design principles or at least a summary of the + main concepts will make it easy for potential contributors to get started + quickly. + +Submit an issue +--------------- + +Before you work on any non-trivial code contribution it's best to first create +a report in the `issue tracker`_ to start a discussion on the subject. +This often provides additional considerations and avoids unnecessary work. + +Create an environment +--------------------- + +Before you start coding, we recommend creating an isolated `virtual +environment`_ to avoid any problems with your installed Python packages. +This can easily be done via either |virtualenv|_:: + + virtualenv + source /bin/activate + +or Miniconda_:: + + conda create -n nanovna-saver python=3 six virtualenv pytest pytest-cov + conda activate nanovna-saver + +Clone the repository +-------------------- + +#. Create an user account on |the repository service| if you do not already have one. +#. Fork the project repository_: click on the *Fork* button near the top of the + page. This creates a copy of the code under your account on |the repository service|. +#. Clone this copy to your local disk:: + + git clone git@github.com:YourLogin/nanovna-saver.git + cd nanovna-saver + +#. You should run:: + + pip install -U pip setuptools -e . + + to be able to import the package under development in the Python REPL. + + .. todo:: if you are not using pre-commit, please remove the following item: + +#. Install |pre-commit|_:: + + pip install pre-commit + pre-commit install + + ``nanovna-saver`` comes with a lot of hooks configured to automatically help the + developer to check the code being written. + +Implement your changes +---------------------- + +#. Create a branch to hold your changes:: + + git checkout -b my-feature + + and start making changes. Never work on the main branch! + +#. Start your work on this branch. Don't forget to add docstrings_ to new + functions, modules and classes, especially if they are part of public APIs. + +#. Add yourself to the list of contributors in ``AUTHORS.rst``. + +#. When you’re done editing, do:: + + git add + git commit + + to record your changes in git_. + + .. todo:: if you are not using pre-commit, please remove the following item: + + Please make sure to see the validation messages from |pre-commit|_ and fix + any eventual issues. + This should automatically use flake8_/black_ to check/fix the code style + in a way that is compatible with the project. + + .. important:: Don't forget to add unit tests and documentation in case your + contribution adds an additional feature and is not just a bugfix. + + Moreover, writing a `descriptive commit message`_ is highly recommended. + In case of doubt, you can check the commit history with:: + + git log --graph --decorate --pretty=oneline --abbrev-commit --all + + to look for recurring communication patterns. + +#. Please check that your changes don't break any unit tests with:: + + tox + + (after having installed |tox|_ with ``pip install tox`` or ``pipx``). + + You can also use |tox|_ to run several other pre-configured tasks in the + repository. Try ``tox -av`` to see a list of the available checks. + +Submit your contribution +------------------------ + +#. If everything works fine, push your local branch to |the repository service| with:: + + git push -u origin my-feature + +#. Go to the web page of your fork and click |contribute button| + to send your changes for review. + + .. todo:: if you are using GitHub, you can uncomment the following paragraph + + Find more detailed information in `creating a PR`_. You might also want to open + the PR as a draft first and mark it as ready for review after the feedbacks + from the continuous integration (CI) system or any required fixes. + + +Troubleshooting +--------------- + +The following tips can be used when facing problems to build or test the +package: + +#. Make sure to fetch all the tags from the upstream repository_. + The command ``git describe --abbrev=0 --tags`` should return the version you + are expecting. If you are trying to run CI scripts in a fork repository, + make sure to push all the tags. + You can also try to remove all the egg files or the complete egg folder, i.e., + ``.eggs``, as well as the ``*.egg-info`` folders in the ``src`` folder or + potentially in the root of your project. + +#. Sometimes |tox|_ misses out when new dependencies are added, especially to + ``setup.cfg`` and ``docs/requirements.txt``. If you find any problems with + missing dependencies when running a command with |tox|_, try to recreate the + ``tox`` environment using the ``-r`` flag. For example, instead of:: + + tox -e docs + + Try running:: + + tox -r -e docs + +#. Make sure to have a reliable |tox|_ installation that uses the correct + Python version (e.g., 3.7+). When in doubt you can run:: + + tox --version + # OR + which tox + + If you have trouble and are seeing weird errors upon running |tox|_, you can + also try to create a dedicated `virtual environment`_ with a |tox|_ binary + freshly installed. For example:: + + virtualenv .venv + source .venv/bin/activate + .venv/bin/pip install tox + .venv/bin/tox -e all + +#. `Pytest can drop you`_ in an interactive session in the case an error occurs. + In order to do that you need to pass a ``--pdb`` option (for example by + running ``tox -- -k --pdb``). + You can also setup breakpoints manually instead of using the ``--pdb`` option. + + +Maintainer tasks +================ + +Releases +-------- + +.. todo:: This section assumes you are using PyPI to publicly release your package. + + If instead you are using a different/private package index, please update + the instructions accordingly. + +If you are part of the group of maintainers and have correct user permissions +on PyPI_, the following steps can be used to release a new version for +``nanovna-saver``: + +#. Make sure all unit tests are successful. +#. Tag the current commit on the main branch with a release tag, e.g., ``v1.2.3``. +#. Push the new tag to the upstream repository_, e.g., ``git push upstream v1.2.3`` +#. Clean up the ``dist`` and ``build`` folders with ``tox -e clean`` + (or ``rm -rf dist build``) + to avoid confusion with old builds and Sphinx docs. +#. Run ``tox -e build`` and check that the files in ``dist`` have + the correct version (no ``.dirty`` or git_ hash) according to the git_ tag. + Also check the sizes of the distributions, if they are too big (e.g., > + 500KB), unwanted clutter may have been accidentally included. +#. Run ``tox -e publish -- --repository pypi`` and check that everything was + uploaded to PyPI_ correctly. + + + +.. [#contrib1] Even though, these resources focus on open source projects and + communities, the general ideas behind collaborating with other developers + to collectively create software are general and can be applied to all sorts + of environments, including private companies and proprietary code bases. + + +.. <-- start --> +.. todo:: Please review and change the following definitions: + +.. |the repository service| replace:: GitHub +.. |contribute button| replace:: "Create pull request" + +.. _repository: https://github.com//nanovna-saver +.. _issue tracker: https://github.com//nanovna-saver/issues +.. <-- end --> + + +.. |virtualenv| replace:: ``virtualenv`` +.. |pre-commit| replace:: ``pre-commit`` +.. |tox| replace:: ``tox`` + + +.. _black: https://pypi.org/project/black/ +.. _CommonMark: https://commonmark.org/ +.. _contribution-guide.org: https://www.contribution-guide.org/ +.. _creating a PR: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request +.. _descriptive commit message: https://chris.beams.io/posts/git-commit +.. _docstrings: https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html +.. _first-contributions tutorial: https://github.com/firstcontributions/first-contributions +.. _flake8: https://flake8.pycqa.org/en/stable/ +.. _git: https://git-scm.com +.. _GitHub's fork and pull request workflow: https://guides.github.com/activities/forking/ +.. _guide created by FreeCodeCamp: https://github.com/FreeCodeCamp/how-to-contribute-to-open-source +.. _Miniconda: https://docs.conda.io/en/latest/miniconda.html +.. _MyST: https://myst-parser.readthedocs.io/en/latest/syntax/syntax.html +.. _other kinds of contributions: https://opensource.guide/how-to-contribute +.. _pre-commit: https://pre-commit.com/ +.. _PyPI: https://pypi.org/ +.. _PyScaffold's contributor's guide: https://pyscaffold.org/en/stable/contributing.html +.. _Pytest can drop you: https://docs.pytest.org/en/stable/how-to/failures.html#using-python-library-pdb-with-pytest +.. _Python Software Foundation's Code of Conduct: https://www.python.org/psf/conduct/ +.. _reStructuredText: https://www.sphinx-doc.org/en/master/usage/restructuredtext/ +.. _Sphinx: https://www.sphinx-doc.org/en/master/ +.. _tox: https://tox.wiki/en/stable/ +.. _virtual environment: https://realpython.com/python-virtual-environments-a-primer/ +.. _virtualenv: https://virtualenv.pypa.io/en/stable/ + +.. _GitHub web interface: https://docs.github.com/en/repositories/working-with-files/managing-files/editing-files +.. _GitHub's code editor: https://docs.github.com/en/repositories/working-with-files/managing-files/editing-files diff --git a/LICENSE b/LICENSE.txt similarity index 100% rename from LICENSE rename to LICENSE.txt diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 426cdd0..0000000 --- a/Pipfile +++ /dev/null @@ -1,14 +0,0 @@ -[[source]] -name = "pypi" -url = "https://pypi.org/simple" -verify_ssl = true - -[dev-packages] - -[packages] -pyserial = "*" -pyqt5 = "*" -numpy = "*" - -[requires] -python_version = "3.7" diff --git a/README.md b/README.md deleted file mode 100644 index f6107eb..0000000 --- a/README.md +++ /dev/null @@ -1,233 +0,0 @@ -[![Latest Release](https://img.shields.io/github/v/release/NanoVNA-Saver/nanovna-saver.svg)](https://github.com/NanoVNA-Saver/nanovna-saver/releases/latest) -[![License](https://img.shields.io/github/license/NanoVNA-Saver/nanovna-saver.svg)](https://github.com/NanoVNA-Saver/nanovna-saver/blob/master/LICENSE) -[![Downloads](https://img.shields.io/github/downloads/NanoVNA-Saver/nanovna-saver/total.svg)](https://github.com/NanoVNA-Saver/nanovna-saver/releases/) -[![GitHub Releases](https://img.shields.io/github/downloads/NanoVNA-Saver/nanovna-saver/latest/total)](https://github.com/NanoVNA-Saver/nanovna-saver/releases/latest) -[![Donate](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=T8KTGVDQF5K6E&item_name=NanoVNASaver+Development¤cy_code=EUR&source=url) - -# NanoVNASaver - -A multiplatform tool to save Touchstone files from the NanoVNA, -sweep frequency spans in segments to gain more than 101 data -points, and generally display and analyze the resulting data. - -- Copyright 2019, 2020 Rune B. Broberg -- Copyright 2020ff NanoVNA-Saver Authors - - -It's written in __Python 3__ using __PyQt5__ and __scipy__. - -
-Table of Contents - -- [About](#nanovnasaver) - - [Built With](#built-with) -- [Introduction](#introduction) - - [Current Features](#current-features) - - [Screenshot](#screenshot) - - [Binary Releases](#binary-releases) - - [Installation](#installation) - - [Detailed Installation Instructions](docs/INSTALLATION.md) -- [Usage](#using-the-software) - - [Calibration](#calibration) - - [TDR](#tdr) - - [Measuring inductor core permeability](#measuring-inductor-core-permeability) -- [Latest Changes](#latest-changes) -- [Contributing](#contributing) - - [Contribution Guidlines](docs/CONTRIBUTING.md) -- [License](#license) -- [References](#references) -- [Acknowledgements](#acknowledgements) - -
- -## Introduction - -This software connects to a NanoVNA and extracts the data for -display on a computer and allows saving the sweep data to Touchstone files. - - - -### Current features - -- Reading data from a NanoVNA -- Compatible devices: NanoVNA, NanoVNA-H, - NanoVNA-H4, NanoVNA-F, AVNA via Teensy -- Splitting a frequency range into multiple segments to increase resolution - (tried up to >10k points) -- Averaging data for better results particularly at higher frequencies -- Displaying data on multiple chart types, such as Smith, LogMag, Phase and - VSWR-charts, for both S11 and S21 -- Displaying markers, and the impedance, VSWR, Q, equivalent - capacitance/inductance etc. at these locations -- Displaying customizable frequency bands as reference, for example amateur - radio bands -- Exporting and importing 1-port and 2-port Touchstone files -- TDR function (measurement of cable length) - including impedance display -- Filter analysis functions for low-pass, high-pass, band-pass and band-stop - filters -- Display of both an active and a reference trace -- Live updates of data from the NanoVNA, including for multi-segment sweeps -- In-application calibration, including compensation for non-ideal calibration - standards -- Customizable display options, including "dark mode" -- Exporting images of plotted values - -### Screenshot - -![Screenshot of version 0.1.4](https://i.imgur.com/ZoFsV2V.png) - -## Running the application - -The software was written in Python on Windows, using Pycharm, and the modules -PyQT5, numpy, scipy and pyserial. -Main development is currently done on Linux (Mint 21 "Vanessa" Cinnamon) - -## Installation - -### Binary releases - -You can find current binary releases for Windows, Linux and MacOS under - - -The 32bit Windows binaries are somewhat smaller and seems to be a -little bit more stable. - -[Detailed installation instructions](docs/INSTALLATION.md) - -## Using the software - -Connect your NanoVNA to a serial port, and enter this serial port in the serial -port box. If the NanoVNA is connected before the application starts, it should -be automatically detected. Otherwise, click "Rescan". Click "Connect to device" -to connect. - -The app can collect multiple segments to get more accurate measurements. Enter -the number of segments to be done in the "Segments" box. Each segment is 101 -data points, and takes about 1.5 seconds to complete. - -Frequencies are entered in Hz, or suffixed with k or M. Scientific notation -(6.5e6 for 6.5MHz) also works. - -Markers can be manually entered, or controlled using the mouse. For mouse -control, select the active marker using the radio buttons, or hold "shift" -while clicking to drag the nearest marker. The marker readout boxes show the -actual frequency where values are measured. Marker readouts can be hidden -using the "hide data" button when not needed. - -Display settings are available under "Display setup". These allow changing the -chart colours, the application font size and which graphs are displayed. The -settings are saved between program starts. - -### Calibration - -_Before using NanoVNA-Saver, please ensure that the device itself is in a -reasonable calibration state._ - -A calibration of both ports across the entire frequency span, saved to save -slot 0, is sufficient. If the NanoVNA is completely uncalibrated, its readings -may be outside the range accepted by the application. - -In-application calibration is available, either assuming ideal standards or -with relevant standard correction. To manually calibrate, sweep each standard -in turn and press the relevant button in the calibration window. -For assisted calibration, press the "Calibration Assistant" button. If desired, -enter a note in the provided field describing the conditions under which the -calibration was performed. - -Calibration results may be saved and loaded using the provided buttons at the -bottom of the window. Notes are saved and loaded along with the calibration -data. - -![Screenshot of Calibration Window](https://i.imgur.com/p94cxOX.png) - -Users of known characterized calibration standard sets can enter the data for -these, and save the sets. - -After pressing _Apply_, the calibration is immediately applied to the latest -sweep data. - -\! _Currently, load capacitance is unsupported_ \! - -### TDR - -To get accurate TDR measurements, calibrate the device, and attach the cable to -be measured at the calibration plane - i.e. at the same position where the -calibration load would be attached. Open the "Time Domain Reflectometry" -window, and select the correct cable type, or manually enter a propagation -factor. - -### Measuring inductor core permeability - -The permeability (mu) of cores can be measured using a one-port measurement. Put one or more windings on a core of known dimensions and use the "S11 mu" plot from the "Display Setup". The core dimensions (cross section area in mm2, effective length in mm) and number of windings can be set in the context menu for the plot (right click on the plot). - -### Latest Changes - -### Changes in 0.5.5 - -- Measuring inductor core permeability -- Bugfixes for calibration data loading and saving -- Let V2 Devices more time for usb-serial setup -- Make some windows scrollable - -### Changes in 0.5.4 - -- Bugfixes for Python3.11 compatability -- Bugfix for Python3.8 compatability -- use math instead of table for log step calculation -- Support of NanoVNA V2 Plus5 on Windows -- New SI prefixes added - Ronna, Quetta -- addes a Makefile to build a packages -- Simplyfied sweep worker -- Fixed calibration data loading -- Explicit import of scipy functions - #555 -- Refactoring of Analysis modules - -## Contributing - -First off, thanks for taking the time to contribute! Contributions are what -make the open-source community such an amazing place to learn, inspire, and -create. Any contributions you make will benefit everybody else and are -__greatly appreciated__. - -Please read [our contribution guidelines](docs/CONTRIBUTING.md), and thank you -for being involved! - -## License - -This software is licensed under version 3 of the GNU General Public License. It -comes with NO WARRANTY. - -You can use it, commercially as well. You may make changes to the code, but I -(and the license) ask that you give these changes back to the community. - -## References - -- Ohan Smit wrote an introduction to using the application: - [https://zs1sci.com/blog/nanovnasaver/] -- HexAndFlex wrote a 3-part (thus far) series on Getting Started with the NanoVNA: - [https://hexandflex.com/2019/08/31/getting-started-with-the-nanovna-part-1/] - Part 3 is dedicated to NanoVNASaver: - [https://hexandflex.com/2019/09/15/getting-started-with-the-nanovna-part-3-pc-software/] -- Gunthard Kraus did documentation in English and German: - [http://www.gunthard-kraus.de/fertig_NanoVNA/English/] - [http://www.gunthard-kraus.de/fertig_NanoVNA/Deutsch/] - -## Acknowledgements - -Original application by Rune B. Broberg (5Q5R) - -Contributions and changes by Holger Müller (DG5DBH), David Hunt and others. - -TDR inspiration shamelessly stolen from the work of Salil (VU2CWA) at - - -TDR cable types by Larry Goga. - -Bugfixes and Python installation work by Ohan Smit. - -Thanks to everyone who have tested, commented and inspired. Particular thanks -go to the alpha testing crew who suffer the early instability of new versions. - -This software is available free of charge. If you read all this way, and you -_still_ want to support it, you may donate to the developer using the button -below: - -[![Paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=T8KTGVDQF5K6E&item_name=NanoVNASaver+Development¤cy_code=EUR&source=url) diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..8598865 --- /dev/null +++ b/README.rst @@ -0,0 +1,274 @@ +.. role:: raw-html-m2r(raw) + :format: html + + + +.. image:: https://img.shields.io/github/v/release/NanoVNA-Saver/nanovna-saver.svg + :target: https://github.com/NanoVNA-Saver/nanovna-saver/releases/latest + :alt: Latest Release + + +.. image:: https://img.shields.io/github/license/NanoVNA-Saver/nanovna-saver.svg + :target: https://github.com/NanoVNA-Saver/nanovna-saver/blob/master/LICENSE.txt + :alt: License + + +.. image:: https://img.shields.io/github/downloads/NanoVNA-Saver/nanovna-saver/total.svg + :target: https://github.com/NanoVNA-Saver/nanovna-saver/releases/ + :alt: Downloads + + +.. image:: https://img.shields.io/github/downloads/NanoVNA-Saver/nanovna-saver/latest/total + :target: https://github.com/NanoVNA-Saver/nanovna-saver/releases/latest + :alt: GitHub Releases + + +.. image:: https://img.shields.io/badge/paypal-donate-yellow.svg + :target: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=T8KTGVDQF5K6E&item_name=NanoVNASaver+Development¤cy_code=EUR&source=url + :alt: Donate + + +NanoVNASaver +============ + +A multiplatform tool to save Touchstone files from the NanoVNA, +sweep frequency spans in segments to gain more than 101 data +points, and generally display and analyze the resulting data. + + +* Copyright 2019, 2020 Rune B. Broberg +* Copyright 2020ff NanoVNA-Saver Authors + +It's written in **Python 3** using **PyQt5** and **scipy**. + + +Introduction +------------ + +This software connects to a NanoVNA and extracts the data for +display on a computer and allows saving the sweep data to Touchstone files. + +:raw-html-m2r:`` + +Current features +^^^^^^^^^^^^^^^^ + + +* Reading data from a NanoVNA -- Compatible devices: NanoVNA, NanoVNA-H, + NanoVNA-H4, NanoVNA-F, AVNA via Teensy +* Splitting a frequency range into multiple segments to increase resolution + (tried up to >10k points) +* Averaging data for better results particularly at higher frequencies +* Displaying data on multiple chart types, such as Smith, LogMag, Phase and + VSWR-charts, for both S11 and S21 +* Displaying markers, and the impedance, VSWR, Q, equivalent + capacitance/inductance etc. at these locations +* Displaying customizable frequency bands as reference, for example amateur + radio bands +* Exporting and importing 1-port and 2-port Touchstone files +* TDR function (measurement of cable length) - including impedance display +* Filter analysis functions for low-pass, high-pass, band-pass and band-stop + filters +* Display of both an active and a reference trace +* Live updates of data from the NanoVNA, including for multi-segment sweeps +* In-application calibration, including compensation for non-ideal calibration + standards +* Customizable display options, including "dark mode" +* Exporting images of plotted values + +Screenshot +^^^^^^^^^^ + + +.. image:: https://i.imgur.com/ZoFsV2V.png + :target: https://i.imgur.com/ZoFsV2V.png + :alt: Screenshot of version 0.1.4 + + +Running the application +----------------------- + +The software was written in Python on Windows, using Pycharm, and the modules +PyQT5, numpy, scipy and pyserial. +Main development is currently done on Linux (Mint 21 "Vanessa" Cinnamon) + +Installation +------------ + +Binary releases +^^^^^^^^^^^^^^^ + +You can find current binary releases for Windows, Linux and MacOS under +https://github.com/NanoVNA-Saver/nanovna-saver/releases/latest + +The 32bit Windows binaries are somewhat smaller and seems to be a +little bit more stable. + +`Detailed installation instructions `_ + +Using the software +------------------ + +Connect your NanoVNA to a serial port, and enter this serial port in the serial +port box. If the NanoVNA is connected before the application starts, it should +be automatically detected. Otherwise, click "Rescan". Click "Connect to device" +to connect. + +The app can collect multiple segments to get more accurate measurements. Enter +the number of segments to be done in the "Segments" box. Each segment is 101 +data points, and takes about 1.5 seconds to complete. + +Frequencies are entered in Hz, or suffixed with k or M. Scientific notation +(6.5e6 for 6.5MHz) also works. + +Markers can be manually entered, or controlled using the mouse. For mouse +control, select the active marker using the radio buttons, or hold "shift" +while clicking to drag the nearest marker. The marker readout boxes show the +actual frequency where values are measured. Marker readouts can be hidden +using the "hide data" button when not needed. + +Display settings are available under "Display setup". These allow changing the +chart colours, the application font size and which graphs are displayed. The +settings are saved between program starts. + +Calibration +^^^^^^^^^^^ + +*Before using NanoVNA-Saver, please ensure that the device itself is in a +reasonable calibration state.* + +A calibration of both ports across the entire frequency span, saved to save +slot 0, is sufficient. If the NanoVNA is completely uncalibrated, its readings +may be outside the range accepted by the application. + +In-application calibration is available, either assuming ideal standards or +with relevant standard correction. To manually calibrate, sweep each standard +in turn and press the relevant button in the calibration window. +For assisted calibration, press the "Calibration Assistant" button. If desired, +enter a note in the provided field describing the conditions under which the +calibration was performed. + +Calibration results may be saved and loaded using the provided buttons at the +bottom of the window. Notes are saved and loaded along with the calibration +data. + + +.. image:: https://i.imgur.com/p94cxOX.png + :target: https://i.imgur.com/p94cxOX.png + :alt: Screenshot of Calibration Window + + +Users of known characterized calibration standard sets can enter the data for +these, and save the sets. + +After pressing *Apply*\ , the calibration is immediately applied to the latest +sweep data. + +! *Currently, load capacitance is unsupported* ! + +TDR +^^^ + +To get accurate TDR measurements, calibrate the device, and attach the cable to +be measured at the calibration plane - i.e. at the same position where the +calibration load would be attached. Open the "Time Domain Reflectometry" +window, and select the correct cable type, or manually enter a propagation +factor. + +Measuring inductor core permeability +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The permeability (mu) of cores can be measured using a one-port measurement. +Put one or more windings on a core of known dimensions and use the "S11 mu" +plot from the "Display Setup". The core dimensions (cross section area in mm2, +effective length in mm) and number of windings can be set in the context menu +for the plot (right click on the plot). + +Latest Changes +^^^^^^^^^^^^^^ + +Changes in 0.5.5 +^^^^^^^^^^^^^^^^ + + +* Measuring inductor core permeability +* Bugfixes for calibration data loading and saving +* Let V2 Devices more time for usb-serial setup +* Make some windows scrollable + +Changes in 0.5.4 +^^^^^^^^^^^^^^^^ + + +* Bugfixes for Python3.11 compatability +* Bugfix for Python3.8 compatability +* use math instead of table for log step calculation +* Support of NanoVNA V2 Plus5 on Windows +* New SI prefixes added - Ronna, Quetta +* addes a Makefile to build a packages +* Simplyfied sweep worker +* Fixed calibration data loading +* Explicit import of scipy functions - #555 +* Refactoring of Analysis modules + +Contributing +------------ + +First off, thanks for taking the time to contribute! Contributions are what +make the open-source community such an amazing place to learn, inspire, and +create. Any contributions you make will benefit everybody else and are +**greatly appreciated**. + +Please read `our contribution guidelines `_\ , and thank +you for being involved! + +License +------- + +This software is licensed under version 3 of the GNU General Public License. It +comes with NO WARRANTY. + +You can use it, commercially as well. You may make changes to the code, but I +(and the license) ask that you give these changes back to the community. + +References +---------- + + +* Ohan Smit wrote an introduction to using the application: + [https://zs1sci.com/blog/nanovnasaver/] +* HexAndFlex wrote a 3-part (thus far) series on Getting Started with the + NanoVNA: + [https://hexandflex.com/2019/08/31/getting-started-with-the-nanovna-part-1/] + - Part 3 is dedicated to NanoVNASaver: + [https://hexandflex.com/2019/09/15/getting-started-with-the-nanovna-part-3-pc-software/] +* Gunthard Kraus did documentation in English and German: + [http://www.gunthard-kraus.de/fertig_NanoVNA/English/] + [http://www.gunthard-kraus.de/fertig_NanoVNA/Deutsch/] + +Acknowledgements +---------------- + +Original application by Rune B. Broberg (5Q5R) + +Contributions and changes by Holger Müller (DG5DBH), David Hunt and others. + +TDR inspiration shamelessly stolen from the work of Salil (VU2CWA) at +https://nuclearrambo.com/wordpress/accurately-measuring-cable-length-with-nanovna/ + +TDR cable types by Larry Goga. + +Bugfixes and Python installation work by Ohan Smit. + +Thanks to everyone who have tested, commented and inspired. Particular thanks +go to the alpha testing crew who suffer the early instability of new versions. + +This software is available free of charge. If you read all this way, and you +*still* want to support it, you may donate to the developer using the button +below: + + +.. image:: https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif + :target: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=T8KTGVDQF5K6E&item_name=NanoVNASaver+Development¤cy_code=EUR&source=url + :alt: Paypal + diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..31655dd --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,29 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build +AUTODOCDIR = api + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $?), 1) +$(error "The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from https://sphinx-doc.org/") +endif + +.PHONY: help clean Makefile + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +clean: + rm -rf $(BUILDDIR)/* $(AUTODOCDIR) + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/_static/.gitignore b/docs/_static/.gitignore new file mode 100644 index 0000000..3c96363 --- /dev/null +++ b/docs/_static/.gitignore @@ -0,0 +1 @@ +# Empty directory diff --git a/docs/authors.rst b/docs/authors.rst new file mode 100644 index 0000000..cd8e091 --- /dev/null +++ b/docs/authors.rst @@ -0,0 +1,2 @@ +.. _authors: +.. include:: ../AUTHORS.rst diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..8530589 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,286 @@ +# This file is execfile()d with the current directory set to its containing dir. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import os +import sys +import shutil + +# -- Path setup -------------------------------------------------------------- + +__location__ = os.path.dirname(__file__) + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.join(__location__, "../src")) + +# -- Run sphinx-apidoc ------------------------------------------------------- +# This hack is necessary since RTD does not issue `sphinx-apidoc` before running +# `sphinx-build -b html . _build/html`. See Issue: +# https://github.com/readthedocs/readthedocs.org/issues/1139 +# DON'T FORGET: Check the box "Install your project inside a virtualenv using +# setup.py install" in the RTD Advanced Settings. +# Additionally it helps us to avoid running apidoc manually + +try: # for Sphinx >= 1.7 + from sphinx.ext import apidoc +except ImportError: + from sphinx import apidoc + +output_dir = os.path.join(__location__, "api") +module_dir = os.path.join(__location__, "../src/NanoVNASaver") +try: + shutil.rmtree(output_dir) +except FileNotFoundError: + pass + +try: + import sphinx + + cmd_line = f"sphinx-apidoc --implicit-namespaces -f -o {output_dir} {module_dir}" + + args = cmd_line.split(" ") + if tuple(sphinx.__version__.split(".")) >= ("1", "7"): + # This is a rudimentary parse_version to avoid external dependencies + args = args[1:] + + apidoc.main(args) +except Exception as e: + print("Running `sphinx-apidoc` failed!\n{}".format(e)) + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.intersphinx", + "sphinx.ext.todo", + "sphinx.ext.autosummary", + "sphinx.ext.viewcode", + "sphinx.ext.coverage", + "sphinx.ext.doctest", + "sphinx.ext.ifconfig", + "sphinx.ext.mathjax", + "sphinx.ext.napoleon", +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# The suffix of source filenames. +source_suffix = ".rst" + +# The encoding of source files. +# source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = "index" + +# General information about the project. +project = "nanovna-saver" +copyright = "2023, Holger Mueller" + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# version: The short X.Y version. +# release: The full version, including alpha/beta/rc tags. +# If you don’t need the separation provided between version and release, +# just set them both to the same value. +try: + from NanoVNASaver import __version__ as version +except ImportError: + version = "" + +if not version or version.lower() == "unknown": + version = os.getenv("READTHEDOCS_VERSION", "unknown") # automatically set by RTD + +release = version + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# today = '' +# Else, today_fmt is used as the format for a strftime call. +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", ".venv"] + +# The reST default role (used for this markup: `text`) to use for all documents. +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "sphinx" + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# If this is True, todo emits a warning for each TODO entries. The default is False. +todo_emit_warnings = True + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = "alabaster" + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +html_theme_options = { + "sidebar_width": "300px", + "page_width": "1200px" +} + +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +# html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# html_logo = "" + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ["_static"] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +# html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +# html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# html_additional_pages = {} + +# If false, no module index is generated. +# html_domain_indices = True + +# If false, no index is generated. +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +# html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = "nanovna-saver-doc" + + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ("letterpaper" or "a4paper"). + # "papersize": "letterpaper", + # The font size ("10pt", "11pt" or "12pt"). + # "pointsize": "10pt", + # Additional stuff for the LaTeX preamble. + # "preamble": "", +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ("index", "user_guide.tex", "nanovna-saver Documentation", "Holger Mueller", "manual") +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# latex_logo = "" + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +# latex_use_parts = False + +# If true, show page references after internal links. +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# latex_appendices = [] + +# If false, no module index is generated. +# latex_domain_indices = True + +# -- External mapping -------------------------------------------------------- +python_version = ".".join(map(str, sys.version_info[0:2])) +intersphinx_mapping = { + "sphinx": ("https://www.sphinx-doc.org/en/master", None), + "python": ("https://docs.python.org/" + python_version, None), + "matplotlib": ("https://matplotlib.org", None), + "numpy": ("https://numpy.org/doc/stable", None), + "sklearn": ("https://scikit-learn.org/stable", None), + "pandas": ("https://pandas.pydata.org/pandas-docs/stable", None), + "scipy": ("https://docs.scipy.org/doc/scipy/reference", None), + "setuptools": ("https://setuptools.pypa.io/en/stable/", None), + "pyscaffold": ("https://pyscaffold.org/en/stable", None), +} + +print(f"loading configurations for {project} {version} ...", file=sys.stderr) diff --git a/docs/contributing.rst b/docs/contributing.rst new file mode 100644 index 0000000..e582053 --- /dev/null +++ b/docs/contributing.rst @@ -0,0 +1 @@ +.. include:: ../CONTRIBUTING.rst diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..7ddcc32 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,60 @@ +============= +nanovna-saver +============= + +This is the documentation of **nanovna-saver**. + +.. note:: + + This is the main page of your project's `Sphinx`_ documentation. + It is formatted in `reStructuredText`_. Add additional pages + by creating rst-files in ``docs`` and adding them to the `toctree`_ below. + Use then `references`_ in order to link them from this page, e.g. + :ref:`authors` and :ref:`changes`. + + It is also possible to refer to the documentation of other Python packages + with the `Python domain syntax`_. By default you can reference the + documentation of `Sphinx`_, `Python`_, `NumPy`_, `SciPy`_, `matplotlib`_, + `Pandas`_, `Scikit-Learn`_. You can add more by extending the + ``intersphinx_mapping`` in your Sphinx's ``conf.py``. + + The pretty useful extension `autodoc`_ is activated by default and lets + you include documentation from docstrings. Docstrings can be written in + `Google style`_ (recommended!), `NumPy style`_ and `classical style`_. + + +Contents +======== + +.. toctree:: + :maxdepth: 2 + + Overview + Contributions & Help + License + Authors + Module Reference + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + +.. _toctree: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html +.. _reStructuredText: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html +.. _references: https://www.sphinx-doc.org/en/stable/markup/inline.html +.. _Python domain syntax: https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#the-python-domain +.. _Sphinx: https://www.sphinx-doc.org/ +.. _Python: https://docs.python.org/ +.. _Numpy: https://numpy.org/doc/stable +.. _SciPy: https://docs.scipy.org/doc/scipy/reference/ +.. _matplotlib: https://matplotlib.org/contents.html# +.. _Pandas: https://pandas.pydata.org/pandas-docs/stable +.. _Scikit-Learn: https://scikit-learn.org/stable +.. _autodoc: https://www.sphinx-doc.org/en/master/ext/autodoc.html +.. _Google style: https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings +.. _NumPy style: https://numpydoc.readthedocs.io/en/latest/format.html +.. _classical style: https://www.sphinx-doc.org/en/master/domains.html#info-field-lists diff --git a/docs/license.rst b/docs/license.rst new file mode 100644 index 0000000..3989c51 --- /dev/null +++ b/docs/license.rst @@ -0,0 +1,7 @@ +.. _license: + +======= +License +======= + +.. include:: ../LICENSE.txt diff --git a/docs/readme.rst b/docs/readme.rst new file mode 100644 index 0000000..81995ef --- /dev/null +++ b/docs/readme.rst @@ -0,0 +1,2 @@ +.. _readme: +.. include:: ../README.rst diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..2ddf98a --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,5 @@ +# Requirements file for ReadTheDocs, check .readthedocs.yml. +# To build the module reference correctly, make sure every external package +# under `install_requires` in `setup.cfg` is also listed here! +sphinx>=3.2.1 +# sphinx_rtd_theme diff --git a/nanovna-saver.py b/nanovna-saver.py index 9844a07..9204e91 100755 --- a/nanovna-saver.py +++ b/nanovna-saver.py @@ -24,7 +24,13 @@ with suppress(ImportError): # pyright: reportMissingImports=false import pkg_resources.py2_warn -from NanoVNASaver.__main__ import main +try: + from NanoVNASaver.__main__ import main +except ModuleNotFoundError: + import sys + sys.path.append('src') + from NanoVNASaver.__main__ import main + if __name__ == '__main__': main() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..0031989 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,14 @@ +[build-system] +# AVOID CHANGING REQUIRES: IT WILL BE UPDATED BY PYSCAFFOLD! +requires = ["setuptools>=46.1.0", "setuptools_scm[toml]>=5"] +build-backend = "setuptools.build_meta" + +[tool.setuptools_scm] +# For smarter version schemes and other configuration options, +# check out https://github.com/pypa/setuptools_scm +version_scheme = "no-guess-dev" + +[tool.pytest.ini_options] +pythonpath = [ + ".", "src", +] diff --git a/setup.cfg b/setup.cfg index e4a3728..fb3c8db 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,3 +1,8 @@ +# This file is used to configure your project. +# Read more about the various options under: +# https://setuptools.pypa.io/en/latest/userguide/declarative_config.html +# https://setuptools.pypa.io/en/latest/references/keywords.html + [metadata] name = NanoVNASaver author = Rune B. Broberg @@ -5,26 +10,101 @@ author_email= NanoVNA-Saver@users.noreply.github.com license = GNU GPL V3 license_files = LICENSE, description = GUI for the NanoVNA and derivates -long_description = file: README.md +long_description = file: README.rst url = https://github.com/NanoVNA-Saver/nanovna-saver version = attr: NanoVNASaver.About.VERSION platforms= all [options] -# do not use "find_namespace:" because this may recursively include "build" -packages = find: -install_requires= +zip_safe = False +packages = find_namespace: +include_package_data = True +package_dir = + =src + +# Require a min/specific Python version (comma-separated conditions) +python_requires = >=3.8, <4 + +# Add here dependencies of your project (line-separated), e.g. requests>=2.2,<3.0. +# Version specifiers like >=2.2,<3.0 avoid problems due to API changes in +# new major versions. This works if the required packages follow Semantic Versioning. +# For more information, check out https://semver.org/. +install_requires = pyserial>=3.5 PyQt5>=5.15.0 numpy>=1.21.1 scipy>=1.7.1 Cython>=0.29.24 -python_requires = >=3.8, <4 + +[options.packages.find] +where = src +exclude = + tests + +[options.extras_require] +# Add here additional requirements for extra features, to install with: +# `pip install nanovna-saver[PDF]` like: +# PDF = ReportLab; RXP + +# Add here test requirements (semicolon/line-separated) +testing = + setuptools + pytest + pytest-cov [options.entry_points] -console_scripts = - NanoVNASaver = NanoVNASaver.__main__:main +# Add here console scripts like: +# console_scripts = +# script_name = NanoVNASaver.module:function +# For example: +# console_scripts = +# fibonacci = NanoVNASaver.skeleton:run +# And any other entry points, for example: +# pyscaffold.cli = +# awesome = pyscaffoldext.awesome.extension:AwesomeExtension -# without this option the rpm-build includes also the "test" directory -[options.packages.find] -exclude = test +[tool:pytest] +# Specify command line options as you would do when invoking pytest directly. +# e.g. --cov-report html (or xml) for html/xml output or --junitxml junit.xml +# in order to write a coverage file that can be read by Jenkins. +# CAUTION: --cov flags may prohibit setting breakpoints while debugging. +# Comment those flags to avoid this pytest issue. +addopts = + --cov NanoVNASaver --cov-report term-missing + --verbose +norecursedirs = + dist + build + .tox +testpaths = tests +# Use pytest markers to select/deselect specific tests +# markers = +# slow: mark tests as slow (deselect with '-m "not slow"') +# system: mark end-to-end system tests + +[devpi:upload] +# Options for the devpi: PyPI server and packaging tool +# VCS export must be deactivated since we are using setuptools-scm +no_vcs = 1 +formats = bdist_wheel + +[flake8] +# Some sane defaults for the code style checker flake8 +max_line_length = 88 +extend_ignore = E203, W503 +# ^ Black-compatible +# E203 and W503 have edge cases handled by black +exclude = + .tox + build + dist + .eggs + docs/conf.py + +[pyscaffold] +# PyScaffold's parameters when the project was created. +# This will be used when updating. Do not change! +version = 4.4 +package = NanoVNASaver +extensions = + no_skeleton diff --git a/setup.py b/setup.py index b51f5b5..d6cf64a 100644 --- a/setup.py +++ b/setup.py @@ -1,27 +1,21 @@ -# NanoVNASaver -# -# A python program to view and export Touchstone data from a NanoVNA -# Copyright (C) 2019, 2020 Rune B. Broberg -# Copyright (C) 2020,2021 NanoVNA-Saver Authors -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +""" + Setup file for nanovna-saver. + Use setup.cfg to configure your project. + + This file was generated with PyScaffold 4.4. + PyScaffold helps you to put up the scaffold of your new Python project. + Learn more under: https://pyscaffold.org/ +""" from setuptools import setup -setup( - data_files=[ - ("share/doc/nanovnasaver/", ["LICENSE", "README.md", ]), - ("share/applications/", ["NanoVNASaver.desktop", ]), - ("share/icons/hicolor/48x48/apps/", ["NanoVNASaver_48x48.png", ]), - ] -) +if __name__ == "__main__": + try: + setup(use_scm_version={"version_scheme": "no-guess-dev"}) + except: # noqa + print( + "\n\nAn error occurred while building the project, " + "please ensure you have the most updated version of setuptools, " + "setuptools_scm and wheel with:\n" + " pip install -U setuptools setuptools_scm wheel\n\n" + ) + raise diff --git a/NanoVNASaver/About.py b/src/NanoVNASaver/About.py similarity index 98% rename from NanoVNASaver/About.py rename to src/NanoVNASaver/About.py index 29c20ea..5b864fe 100644 --- a/NanoVNASaver/About.py +++ b/src/NanoVNASaver/About.py @@ -17,7 +17,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -VERSION = "0.5.5" +VERSION = "0.6.0-pre" VERSION_URL = ( "https://raw.githubusercontent.com/" "NanoVNA-Saver/nanovna-saver/master/NanoVNASaver/About.py") diff --git a/NanoVNASaver/Analysis/AntennaAnalysis.py b/src/NanoVNASaver/Analysis/AntennaAnalysis.py similarity index 100% rename from NanoVNASaver/Analysis/AntennaAnalysis.py rename to src/NanoVNASaver/Analysis/AntennaAnalysis.py diff --git a/NanoVNASaver/Analysis/BandPassAnalysis.py b/src/NanoVNASaver/Analysis/BandPassAnalysis.py similarity index 100% rename from NanoVNASaver/Analysis/BandPassAnalysis.py rename to src/NanoVNASaver/Analysis/BandPassAnalysis.py diff --git a/NanoVNASaver/Analysis/BandStopAnalysis.py b/src/NanoVNASaver/Analysis/BandStopAnalysis.py similarity index 100% rename from NanoVNASaver/Analysis/BandStopAnalysis.py rename to src/NanoVNASaver/Analysis/BandStopAnalysis.py diff --git a/NanoVNASaver/Analysis/Base.py b/src/NanoVNASaver/Analysis/Base.py similarity index 100% rename from NanoVNASaver/Analysis/Base.py rename to src/NanoVNASaver/Analysis/Base.py diff --git a/NanoVNASaver/Analysis/EFHWAnalysis.py b/src/NanoVNASaver/Analysis/EFHWAnalysis.py similarity index 99% rename from NanoVNASaver/Analysis/EFHWAnalysis.py rename to src/NanoVNASaver/Analysis/EFHWAnalysis.py index e0b9126..2eca1b9 100644 --- a/NanoVNASaver/Analysis/EFHWAnalysis.py +++ b/src/NanoVNASaver/Analysis/EFHWAnalysis.py @@ -47,7 +47,7 @@ class EFHWAnalysis(ResonanceAnalysis): threshold=500)) extended_data = {} logger.info("TO DO: find near data") - for lowest in self.crossing: + for lowest in self.crossings: my_data = self._get_data(lowest) if lowest in extended_data: extended_data[lowest].update(my_data) diff --git a/NanoVNASaver/Analysis/HighPassAnalysis.py b/src/NanoVNASaver/Analysis/HighPassAnalysis.py similarity index 100% rename from NanoVNASaver/Analysis/HighPassAnalysis.py rename to src/NanoVNASaver/Analysis/HighPassAnalysis.py diff --git a/NanoVNASaver/Analysis/LowPassAnalysis.py b/src/NanoVNASaver/Analysis/LowPassAnalysis.py similarity index 100% rename from NanoVNASaver/Analysis/LowPassAnalysis.py rename to src/NanoVNASaver/Analysis/LowPassAnalysis.py diff --git a/NanoVNASaver/Analysis/PeakSearchAnalysis.py b/src/NanoVNASaver/Analysis/PeakSearchAnalysis.py similarity index 100% rename from NanoVNASaver/Analysis/PeakSearchAnalysis.py rename to src/NanoVNASaver/Analysis/PeakSearchAnalysis.py diff --git a/NanoVNASaver/Analysis/ResonanceAnalysis.py b/src/NanoVNASaver/Analysis/ResonanceAnalysis.py similarity index 80% rename from NanoVNASaver/Analysis/ResonanceAnalysis.py rename to src/NanoVNASaver/Analysis/ResonanceAnalysis.py index f75613f..00d8dac 100644 --- a/NanoVNASaver/Analysis/ResonanceAnalysis.py +++ b/src/NanoVNASaver/Analysis/ResonanceAnalysis.py @@ -47,7 +47,7 @@ class ResonanceAnalysis(Analysis): def __init__(self, app): super().__init__(app) - self.crossing: List[int] = [] + self.crossings: List[int] = [] self.filename = "" self._widget = QtWidgets.QWidget() self.layout = QtWidgets.QFormLayout() @@ -94,36 +94,26 @@ class ResonanceAnalysis(Analysis): for _ in range(results_header, self.layout.rowCount()): self.layout.removeRow(self.layout.rowCount() - 1) - self.crossing = at.zero_crossings([d.phase for d in self.app.data.s11]) + self.crossings = sorted( + set(at.zero_crossings([d.phase for d in self.app.data.s11]))) logger.debug("Found %d sections ", - len(self.crossing)) - if not self.crossing: + len(self.crossings)) + if not self.crossings: self.layout.addRow(QtWidgets.QLabel( "No resonance found")) return + self + self.do_resonance_analysis() def do_resonance_analysis(self): extended_data = [] - for m in self.crossing: - start, lowest, end = m - my_data = self._get_data(lowest) - s11_low = self.app.data.s11[lowest] - extended_data.append(my_data) - if start != end: - logger.debug( - "Section from %d to %d, lowest at %d", - start, end, lowest) - self.layout.addRow( - "Resonance", - QtWidgets.QLabel( - f"{format_frequency(s11_low.freq)}" - f" ({format_complex_imp(s11_low.impedance())})")) - else: - self.layout.addRow("Resonance", QtWidgets.QLabel( - format_frequency(self.app.data.s11[lowest].freq))) - self.layout.addWidget(QHLine()) + for crossing in self.crossings: + extended_data.append(self._get_data(crossing)) + self.layout.addRow("Resonance", QtWidgets.QLabel( + format_frequency(self.app.data.s11[crossing].freq))) + self.layout.addWidget(QHLine()) # Remove the final separator line self.layout.removeRow(self.layout.rowCount() - 1) if self.filename and extended_data: diff --git a/NanoVNASaver/Analysis/SimplePeakSearchAnalysis.py b/src/NanoVNASaver/Analysis/SimplePeakSearchAnalysis.py similarity index 100% rename from NanoVNASaver/Analysis/SimplePeakSearchAnalysis.py rename to src/NanoVNASaver/Analysis/SimplePeakSearchAnalysis.py diff --git a/NanoVNASaver/Analysis/VSWRAnalysis.py b/src/NanoVNASaver/Analysis/VSWRAnalysis.py similarity index 100% rename from NanoVNASaver/Analysis/VSWRAnalysis.py rename to src/NanoVNASaver/Analysis/VSWRAnalysis.py diff --git a/NanoVNASaver/Analysis/__init__.py b/src/NanoVNASaver/Analysis/__init__.py similarity index 100% rename from NanoVNASaver/Analysis/__init__.py rename to src/NanoVNASaver/Analysis/__init__.py diff --git a/NanoVNASaver/AnalyticTools.py b/src/NanoVNASaver/AnalyticTools.py similarity index 100% rename from NanoVNASaver/AnalyticTools.py rename to src/NanoVNASaver/AnalyticTools.py diff --git a/NanoVNASaver/Calibration.py b/src/NanoVNASaver/Calibration.py similarity index 100% rename from NanoVNASaver/Calibration.py rename to src/NanoVNASaver/Calibration.py diff --git a/NanoVNASaver/Charts/CLogMag.py b/src/NanoVNASaver/Charts/CLogMag.py similarity index 100% rename from NanoVNASaver/Charts/CLogMag.py rename to src/NanoVNASaver/Charts/CLogMag.py diff --git a/NanoVNASaver/Charts/Capacitance.py b/src/NanoVNASaver/Charts/Capacitance.py similarity index 100% rename from NanoVNASaver/Charts/Capacitance.py rename to src/NanoVNASaver/Charts/Capacitance.py diff --git a/NanoVNASaver/Charts/Chart.py b/src/NanoVNASaver/Charts/Chart.py similarity index 100% rename from NanoVNASaver/Charts/Chart.py rename to src/NanoVNASaver/Charts/Chart.py diff --git a/NanoVNASaver/Charts/Frequency.py b/src/NanoVNASaver/Charts/Frequency.py similarity index 100% rename from NanoVNASaver/Charts/Frequency.py rename to src/NanoVNASaver/Charts/Frequency.py diff --git a/NanoVNASaver/Charts/GroupDelay.py b/src/NanoVNASaver/Charts/GroupDelay.py similarity index 100% rename from NanoVNASaver/Charts/GroupDelay.py rename to src/NanoVNASaver/Charts/GroupDelay.py diff --git a/NanoVNASaver/Charts/Inductance.py b/src/NanoVNASaver/Charts/Inductance.py similarity index 100% rename from NanoVNASaver/Charts/Inductance.py rename to src/NanoVNASaver/Charts/Inductance.py diff --git a/NanoVNASaver/Charts/LogMag.py b/src/NanoVNASaver/Charts/LogMag.py similarity index 100% rename from NanoVNASaver/Charts/LogMag.py rename to src/NanoVNASaver/Charts/LogMag.py diff --git a/NanoVNASaver/Charts/Magnitude.py b/src/NanoVNASaver/Charts/Magnitude.py similarity index 100% rename from NanoVNASaver/Charts/Magnitude.py rename to src/NanoVNASaver/Charts/Magnitude.py diff --git a/NanoVNASaver/Charts/MagnitudeZ.py b/src/NanoVNASaver/Charts/MagnitudeZ.py similarity index 100% rename from NanoVNASaver/Charts/MagnitudeZ.py rename to src/NanoVNASaver/Charts/MagnitudeZ.py diff --git a/NanoVNASaver/Charts/MagnitudeZSeries.py b/src/NanoVNASaver/Charts/MagnitudeZSeries.py similarity index 100% rename from NanoVNASaver/Charts/MagnitudeZSeries.py rename to src/NanoVNASaver/Charts/MagnitudeZSeries.py diff --git a/NanoVNASaver/Charts/MagnitudeZShunt.py b/src/NanoVNASaver/Charts/MagnitudeZShunt.py similarity index 100% rename from NanoVNASaver/Charts/MagnitudeZShunt.py rename to src/NanoVNASaver/Charts/MagnitudeZShunt.py diff --git a/NanoVNASaver/Charts/Permeability.py b/src/NanoVNASaver/Charts/Permeability.py similarity index 100% rename from NanoVNASaver/Charts/Permeability.py rename to src/NanoVNASaver/Charts/Permeability.py diff --git a/NanoVNASaver/Charts/Phase.py b/src/NanoVNASaver/Charts/Phase.py similarity index 100% rename from NanoVNASaver/Charts/Phase.py rename to src/NanoVNASaver/Charts/Phase.py diff --git a/NanoVNASaver/Charts/Polar.py b/src/NanoVNASaver/Charts/Polar.py similarity index 100% rename from NanoVNASaver/Charts/Polar.py rename to src/NanoVNASaver/Charts/Polar.py diff --git a/NanoVNASaver/Charts/QFactor.py b/src/NanoVNASaver/Charts/QFactor.py similarity index 100% rename from NanoVNASaver/Charts/QFactor.py rename to src/NanoVNASaver/Charts/QFactor.py diff --git a/NanoVNASaver/Charts/RI.py b/src/NanoVNASaver/Charts/RI.py similarity index 100% rename from NanoVNASaver/Charts/RI.py rename to src/NanoVNASaver/Charts/RI.py diff --git a/NanoVNASaver/Charts/RIMu.py b/src/NanoVNASaver/Charts/RIMu.py similarity index 100% rename from NanoVNASaver/Charts/RIMu.py rename to src/NanoVNASaver/Charts/RIMu.py diff --git a/NanoVNASaver/Charts/RIZ.py b/src/NanoVNASaver/Charts/RIZ.py similarity index 100% rename from NanoVNASaver/Charts/RIZ.py rename to src/NanoVNASaver/Charts/RIZ.py diff --git a/NanoVNASaver/Charts/RIZSeries.py b/src/NanoVNASaver/Charts/RIZSeries.py similarity index 100% rename from NanoVNASaver/Charts/RIZSeries.py rename to src/NanoVNASaver/Charts/RIZSeries.py diff --git a/NanoVNASaver/Charts/RIZShunt.py b/src/NanoVNASaver/Charts/RIZShunt.py similarity index 100% rename from NanoVNASaver/Charts/RIZShunt.py rename to src/NanoVNASaver/Charts/RIZShunt.py diff --git a/NanoVNASaver/Charts/SParam.py b/src/NanoVNASaver/Charts/SParam.py similarity index 100% rename from NanoVNASaver/Charts/SParam.py rename to src/NanoVNASaver/Charts/SParam.py diff --git a/NanoVNASaver/Charts/Smith.py b/src/NanoVNASaver/Charts/Smith.py similarity index 100% rename from NanoVNASaver/Charts/Smith.py rename to src/NanoVNASaver/Charts/Smith.py diff --git a/NanoVNASaver/Charts/Square.py b/src/NanoVNASaver/Charts/Square.py similarity index 100% rename from NanoVNASaver/Charts/Square.py rename to src/NanoVNASaver/Charts/Square.py diff --git a/NanoVNASaver/Charts/TDR.py b/src/NanoVNASaver/Charts/TDR.py similarity index 100% rename from NanoVNASaver/Charts/TDR.py rename to src/NanoVNASaver/Charts/TDR.py diff --git a/NanoVNASaver/Charts/VSWR.py b/src/NanoVNASaver/Charts/VSWR.py similarity index 100% rename from NanoVNASaver/Charts/VSWR.py rename to src/NanoVNASaver/Charts/VSWR.py diff --git a/NanoVNASaver/Charts/__init__.py b/src/NanoVNASaver/Charts/__init__.py similarity index 61% rename from NanoVNASaver/Charts/__init__.py rename to src/NanoVNASaver/Charts/__init__.py index 087d7ca..80076a3 100644 --- a/NanoVNASaver/Charts/__init__.py +++ b/src/NanoVNASaver/Charts/__init__.py @@ -23,3 +23,30 @@ from .Smith import SmithChart from .SParam import SParameterChart from .TDR import TDRChart from .VSWR import VSWRChart +__all__ = [ + 'Chart', + 'FrequencyChart', + 'PolarChart', + 'SquareChart', + 'CapacitanceChart', + 'InductanceChart', + 'GroupDelayChart', + 'LogMagChart', + 'CombinedLogMagChart', + 'MagnitudeChart', + 'MagnitudeZChart', + 'MagnitudeZShuntChart', + 'MagnitudeZSeriesChart', + 'PermeabilityChart', + 'PhaseChart', + 'QualityFactorChart', + 'RealImaginaryChart', + 'RealImaginaryMuChart', + 'RealImaginaryZChart', + 'RealImaginaryZShuntChart', + 'RealImaginaryZSeriesChart', + 'SmithChart', + 'SParameterChart', + 'TDRChart', + 'VSWRChart', +] diff --git a/NanoVNASaver/Controls/Control.py b/src/NanoVNASaver/Controls/Control.py similarity index 100% rename from NanoVNASaver/Controls/Control.py rename to src/NanoVNASaver/Controls/Control.py diff --git a/NanoVNASaver/Controls/MarkerControl.py b/src/NanoVNASaver/Controls/MarkerControl.py similarity index 100% rename from NanoVNASaver/Controls/MarkerControl.py rename to src/NanoVNASaver/Controls/MarkerControl.py diff --git a/NanoVNASaver/Controls/SerialControl.py b/src/NanoVNASaver/Controls/SerialControl.py similarity index 100% rename from NanoVNASaver/Controls/SerialControl.py rename to src/NanoVNASaver/Controls/SerialControl.py diff --git a/NanoVNASaver/Controls/SweepControl.py b/src/NanoVNASaver/Controls/SweepControl.py similarity index 100% rename from NanoVNASaver/Controls/SweepControl.py rename to src/NanoVNASaver/Controls/SweepControl.py diff --git a/NanoVNASaver/Controls/__init__.py b/src/NanoVNASaver/Controls/__init__.py similarity index 100% rename from NanoVNASaver/Controls/__init__.py rename to src/NanoVNASaver/Controls/__init__.py diff --git a/NanoVNASaver/Defaults.py b/src/NanoVNASaver/Defaults.py similarity index 100% rename from NanoVNASaver/Defaults.py rename to src/NanoVNASaver/Defaults.py diff --git a/NanoVNASaver/Formatting.py b/src/NanoVNASaver/Formatting.py similarity index 100% rename from NanoVNASaver/Formatting.py rename to src/NanoVNASaver/Formatting.py diff --git a/NanoVNASaver/Hardware/AVNA.py b/src/NanoVNASaver/Hardware/AVNA.py similarity index 100% rename from NanoVNASaver/Hardware/AVNA.py rename to src/NanoVNASaver/Hardware/AVNA.py diff --git a/NanoVNASaver/Hardware/Hardware.py b/src/NanoVNASaver/Hardware/Hardware.py similarity index 100% rename from NanoVNASaver/Hardware/Hardware.py rename to src/NanoVNASaver/Hardware/Hardware.py diff --git a/NanoVNASaver/Hardware/NanoVNA.py b/src/NanoVNASaver/Hardware/NanoVNA.py similarity index 100% rename from NanoVNASaver/Hardware/NanoVNA.py rename to src/NanoVNASaver/Hardware/NanoVNA.py diff --git a/NanoVNASaver/Hardware/NanoVNA_F.py b/src/NanoVNASaver/Hardware/NanoVNA_F.py similarity index 100% rename from NanoVNASaver/Hardware/NanoVNA_F.py rename to src/NanoVNASaver/Hardware/NanoVNA_F.py diff --git a/NanoVNASaver/Hardware/NanoVNA_F_V2.py b/src/NanoVNASaver/Hardware/NanoVNA_F_V2.py similarity index 100% rename from NanoVNASaver/Hardware/NanoVNA_F_V2.py rename to src/NanoVNASaver/Hardware/NanoVNA_F_V2.py diff --git a/NanoVNASaver/Hardware/NanoVNA_H.py b/src/NanoVNASaver/Hardware/NanoVNA_H.py similarity index 100% rename from NanoVNASaver/Hardware/NanoVNA_H.py rename to src/NanoVNASaver/Hardware/NanoVNA_H.py diff --git a/NanoVNASaver/Hardware/NanoVNA_H4.py b/src/NanoVNASaver/Hardware/NanoVNA_H4.py similarity index 100% rename from NanoVNASaver/Hardware/NanoVNA_H4.py rename to src/NanoVNASaver/Hardware/NanoVNA_H4.py diff --git a/NanoVNASaver/Hardware/NanoVNA_V2.py b/src/NanoVNASaver/Hardware/NanoVNA_V2.py similarity index 100% rename from NanoVNASaver/Hardware/NanoVNA_V2.py rename to src/NanoVNASaver/Hardware/NanoVNA_V2.py diff --git a/NanoVNASaver/Hardware/Serial.py b/src/NanoVNASaver/Hardware/Serial.py similarity index 100% rename from NanoVNASaver/Hardware/Serial.py rename to src/NanoVNASaver/Hardware/Serial.py diff --git a/NanoVNASaver/Hardware/TinySA.py b/src/NanoVNASaver/Hardware/TinySA.py similarity index 100% rename from NanoVNASaver/Hardware/TinySA.py rename to src/NanoVNASaver/Hardware/TinySA.py diff --git a/NanoVNASaver/Hardware/VNA.py b/src/NanoVNASaver/Hardware/VNA.py similarity index 100% rename from NanoVNASaver/Hardware/VNA.py rename to src/NanoVNASaver/Hardware/VNA.py diff --git a/NanoVNASaver/Hardware/__init__.py b/src/NanoVNASaver/Hardware/__init__.py similarity index 100% rename from NanoVNASaver/Hardware/__init__.py rename to src/NanoVNASaver/Hardware/__init__.py diff --git a/NanoVNASaver/Inputs.py b/src/NanoVNASaver/Inputs.py similarity index 100% rename from NanoVNASaver/Inputs.py rename to src/NanoVNASaver/Inputs.py diff --git a/NanoVNASaver/Marker/Delta.py b/src/NanoVNASaver/Marker/Delta.py similarity index 100% rename from NanoVNASaver/Marker/Delta.py rename to src/NanoVNASaver/Marker/Delta.py diff --git a/NanoVNASaver/Marker/Values.py b/src/NanoVNASaver/Marker/Values.py similarity index 100% rename from NanoVNASaver/Marker/Values.py rename to src/NanoVNASaver/Marker/Values.py diff --git a/NanoVNASaver/Marker/Widget.py b/src/NanoVNASaver/Marker/Widget.py similarity index 100% rename from NanoVNASaver/Marker/Widget.py rename to src/NanoVNASaver/Marker/Widget.py diff --git a/NanoVNASaver/Marker/__init__.py b/src/NanoVNASaver/Marker/__init__.py similarity index 100% rename from NanoVNASaver/Marker/__init__.py rename to src/NanoVNASaver/Marker/__init__.py diff --git a/NanoVNASaver/NanoVNASaver.py b/src/NanoVNASaver/NanoVNASaver.py similarity index 98% rename from NanoVNASaver/NanoVNASaver.py rename to src/NanoVNASaver/NanoVNASaver.py index c80a0d7..fb41e31 100644 --- a/NanoVNASaver/NanoVNASaver.py +++ b/src/NanoVNASaver/NanoVNASaver.py @@ -425,16 +425,19 @@ class NanoVNASaver(QtWidgets.QWidget): logger.debug("Finished building interface") + def _sweep_control(self, start: bool = True) -> None: + self.sweep_control.progress_bar.setValue(0 if start else 100) + self.sweep_control.btn_start.setDisabled(start) + self.sweep_control.btn_stop.setDisabled(not start) + self.sweep_control.toggle_settings(start) + def sweep_start(self): # Run the device data update if not self.vna.connected(): return self.worker.stopped = False - self.sweep_control.progress_bar.setValue(0) - self.sweep_control.btn_start.setDisabled(True) - self.sweep_control.btn_stop.setDisabled(False) - self.sweep_control.toggle_settings(True) + self._sweep_control(start=True) for m in self.markers: m.resetLabels() @@ -545,10 +548,7 @@ class NanoVNASaver(QtWidgets.QWidget): self.dataAvailable.emit() def sweepFinished(self): - self.sweep_control.progress_bar.setValue(100) - self.sweep_control.btn_start.setDisabled(False) - self.sweep_control.btn_stop.setDisabled(True) - self.sweep_control.toggle_settings(False) + self._sweep_control(start=False) for marker in self.markers: marker.frequencyInput.textEdited.emit( diff --git a/NanoVNASaver/RFTools.py b/src/NanoVNASaver/RFTools.py similarity index 100% rename from NanoVNASaver/RFTools.py rename to src/NanoVNASaver/RFTools.py diff --git a/NanoVNASaver/SITools.py b/src/NanoVNASaver/SITools.py similarity index 100% rename from NanoVNASaver/SITools.py rename to src/NanoVNASaver/SITools.py diff --git a/NanoVNASaver/Settings/Bands.py b/src/NanoVNASaver/Settings/Bands.py similarity index 100% rename from NanoVNASaver/Settings/Bands.py rename to src/NanoVNASaver/Settings/Bands.py diff --git a/NanoVNASaver/Settings/Sweep.py b/src/NanoVNASaver/Settings/Sweep.py similarity index 100% rename from NanoVNASaver/Settings/Sweep.py rename to src/NanoVNASaver/Settings/Sweep.py diff --git a/NanoVNASaver/Settings/__init__.py b/src/NanoVNASaver/Settings/__init__.py similarity index 100% rename from NanoVNASaver/Settings/__init__.py rename to src/NanoVNASaver/Settings/__init__.py diff --git a/NanoVNASaver/SweepWorker.py b/src/NanoVNASaver/SweepWorker.py similarity index 100% rename from NanoVNASaver/SweepWorker.py rename to src/NanoVNASaver/SweepWorker.py diff --git a/NanoVNASaver/Touchstone.py b/src/NanoVNASaver/Touchstone.py similarity index 100% rename from NanoVNASaver/Touchstone.py rename to src/NanoVNASaver/Touchstone.py diff --git a/NanoVNASaver/Version.py b/src/NanoVNASaver/Version.py similarity index 95% rename from NanoVNASaver/Version.py rename to src/NanoVNASaver/Version.py index 97c9a49..84b4c37 100644 --- a/NanoVNASaver/Version.py +++ b/src/NanoVNASaver/Version.py @@ -47,11 +47,11 @@ class Version: logger.error("Unable to parse version: %s", vstring) def __gt__(self, other: "Version") -> bool: - l, r = self.data, other.data + left, right = self.data, other.data for name in ("major", "minor", "revision"): - if l[name] > r[name]: + if left[name] > right[name]: return True - if l[name] < r[name]: + if left[name] < right[name]: return False return False diff --git a/NanoVNASaver/Windows/About.py b/src/NanoVNASaver/Windows/About.py similarity index 100% rename from NanoVNASaver/Windows/About.py rename to src/NanoVNASaver/Windows/About.py diff --git a/NanoVNASaver/Windows/AnalysisWindow.py b/src/NanoVNASaver/Windows/AnalysisWindow.py similarity index 100% rename from NanoVNASaver/Windows/AnalysisWindow.py rename to src/NanoVNASaver/Windows/AnalysisWindow.py diff --git a/NanoVNASaver/Windows/Bands.py b/src/NanoVNASaver/Windows/Bands.py similarity index 100% rename from NanoVNASaver/Windows/Bands.py rename to src/NanoVNASaver/Windows/Bands.py diff --git a/NanoVNASaver/Windows/CalibrationSettings.py b/src/NanoVNASaver/Windows/CalibrationSettings.py similarity index 100% rename from NanoVNASaver/Windows/CalibrationSettings.py rename to src/NanoVNASaver/Windows/CalibrationSettings.py diff --git a/NanoVNASaver/Windows/Defaults.py b/src/NanoVNASaver/Windows/Defaults.py similarity index 100% rename from NanoVNASaver/Windows/Defaults.py rename to src/NanoVNASaver/Windows/Defaults.py diff --git a/NanoVNASaver/Windows/DeviceSettings.py b/src/NanoVNASaver/Windows/DeviceSettings.py similarity index 100% rename from NanoVNASaver/Windows/DeviceSettings.py rename to src/NanoVNASaver/Windows/DeviceSettings.py diff --git a/NanoVNASaver/Windows/DisplaySettings.py b/src/NanoVNASaver/Windows/DisplaySettings.py similarity index 100% rename from NanoVNASaver/Windows/DisplaySettings.py rename to src/NanoVNASaver/Windows/DisplaySettings.py diff --git a/NanoVNASaver/Windows/Files.py b/src/NanoVNASaver/Windows/Files.py similarity index 100% rename from NanoVNASaver/Windows/Files.py rename to src/NanoVNASaver/Windows/Files.py diff --git a/NanoVNASaver/Windows/MarkerSettings.py b/src/NanoVNASaver/Windows/MarkerSettings.py similarity index 100% rename from NanoVNASaver/Windows/MarkerSettings.py rename to src/NanoVNASaver/Windows/MarkerSettings.py diff --git a/NanoVNASaver/Windows/Screenshot.py b/src/NanoVNASaver/Windows/Screenshot.py similarity index 100% rename from NanoVNASaver/Windows/Screenshot.py rename to src/NanoVNASaver/Windows/Screenshot.py diff --git a/NanoVNASaver/Windows/SweepSettings.py b/src/NanoVNASaver/Windows/SweepSettings.py similarity index 100% rename from NanoVNASaver/Windows/SweepSettings.py rename to src/NanoVNASaver/Windows/SweepSettings.py diff --git a/NanoVNASaver/Windows/TDR.py b/src/NanoVNASaver/Windows/TDR.py similarity index 100% rename from NanoVNASaver/Windows/TDR.py rename to src/NanoVNASaver/Windows/TDR.py diff --git a/NanoVNASaver/Windows/__init__.py b/src/NanoVNASaver/Windows/__init__.py similarity index 62% rename from NanoVNASaver/Windows/__init__.py rename to src/NanoVNASaver/Windows/__init__.py index 73e5138..24b6db6 100644 --- a/NanoVNASaver/Windows/__init__.py +++ b/src/NanoVNASaver/Windows/__init__.py @@ -9,3 +9,16 @@ from .MarkerSettings import MarkerSettingsWindow from .Screenshot import ScreenshotWindow from .SweepSettings import SweepSettingsWindow from .TDR import TDRWindow +__all__ = [ + 'AboutWindow', + 'AnalysisWindow', + 'BandsWindow', + 'CalibrationWindow', + 'DeviceSettingsWindow', + 'DisplaySettingsWindow', + 'FilesWindow', + 'MarkerSettingsWindow', + 'ScreenshotWindow', + 'SweepSettingsWindow', + 'TDRWindow', +] diff --git a/src/NanoVNASaver/__init__.py b/src/NanoVNASaver/__init__.py new file mode 100644 index 0000000..5ad22a2 --- /dev/null +++ b/src/NanoVNASaver/__init__.py @@ -0,0 +1,16 @@ +import sys + +if sys.version_info[:2] >= (3, 8): + # TODO: Import directly (no need for conditional) when `python_requires = >= 3.8` + from importlib.metadata import PackageNotFoundError, version # pragma: no cover +else: + from importlib_metadata import PackageNotFoundError, version # pragma: no cover + +try: + # Change here if project is renamed and does not equal the package name + dist_name = "nanovna-saver" + __version__ = version(dist_name) +except PackageNotFoundError: # pragma: no cover + __version__ = "unknown" +finally: + del version, PackageNotFoundError diff --git a/NanoVNASaver/__main__.py b/src/NanoVNASaver/__main__.py similarity index 100% rename from NanoVNASaver/__main__.py rename to src/NanoVNASaver/__main__.py diff --git a/test/__init__.py b/test/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/NanoVNASaver/__init__.py b/tests/__init__.py similarity index 100% rename from NanoVNASaver/__init__.py rename to tests/__init__.py diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..4b6fac8 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,10 @@ +""" + Dummy conftest.py for NanoVNASaver. + + If you don't know what this is for, just leave it empty. + Read more about conftest.py under: + - https://docs.pytest.org/en/stable/fixture.html + - https://docs.pytest.org/en/stable/writing_plugins.html +""" + +# import pytest diff --git a/test/data/attenuator-0643_DB.s2p b/tests/data/attenuator-0643_DB.s2p similarity index 100% rename from test/data/attenuator-0643_DB.s2p rename to tests/data/attenuator-0643_DB.s2p diff --git a/test/data/attenuator-0643_MA.s2p b/tests/data/attenuator-0643_MA.s2p similarity index 100% rename from test/data/attenuator-0643_MA.s2p rename to tests/data/attenuator-0643_MA.s2p diff --git a/test/data/attenuator-0643_RI.s2p b/tests/data/attenuator-0643_RI.s2p similarity index 100% rename from test/data/attenuator-0643_RI.s2p rename to tests/data/attenuator-0643_RI.s2p diff --git a/test/data/broken_pair.s2p b/tests/data/broken_pair.s2p similarity index 100% rename from test/data/broken_pair.s2p rename to tests/data/broken_pair.s2p diff --git a/test/data/bug_159.s1p b/tests/data/bug_159.s1p similarity index 100% rename from test/data/bug_159.s1p rename to tests/data/bug_159.s1p diff --git a/test/data/bug_455.s1p b/tests/data/bug_455.s1p similarity index 100% rename from test/data/bug_455.s1p rename to tests/data/bug_455.s1p diff --git a/test/data/db.s2p b/tests/data/db.s2p similarity index 100% rename from test/data/db.s2p rename to tests/data/db.s2p diff --git a/test/data/ferrit_1.s1p b/tests/data/ferrit_1.s1p similarity index 100% rename from test/data/ferrit_1.s1p rename to tests/data/ferrit_1.s1p diff --git a/test/data/ft240-43.s1p b/tests/data/ft240-43.s1p similarity index 100% rename from test/data/ft240-43.s1p rename to tests/data/ft240-43.s1p diff --git a/test/data/full_v2_200_300.cal b/tests/data/full_v2_200_300.cal similarity index 100% rename from test/data/full_v2_200_300.cal rename to tests/data/full_v2_200_300.cal diff --git a/test/data/ma.s2p b/tests/data/ma.s2p similarity index 100% rename from test/data/ma.s2p rename to tests/data/ma.s2p diff --git a/test/data/missing_pair.s2p b/tests/data/missing_pair.s2p similarity index 100% rename from test/data/missing_pair.s2p rename to tests/data/missing_pair.s2p diff --git a/test/data/scikit_unordered.s2p b/tests/data/scikit_unordered.s2p similarity index 100% rename from test/data/scikit_unordered.s2p rename to tests/data/scikit_unordered.s2p diff --git a/test/data/sol_27_30.cal b/tests/data/sol_27_30.cal similarity index 100% rename from test/data/sol_27_30.cal rename to tests/data/sol_27_30.cal diff --git a/test/data/t130-2.s1p b/tests/data/t130-2.s1p similarity index 100% rename from test/data/t130-2.s1p rename to tests/data/t130-2.s1p diff --git a/test/data/test_1port_broken.cal b/tests/data/test_1port_broken.cal similarity index 100% rename from test/data/test_1port_broken.cal rename to tests/data/test_1port_broken.cal diff --git a/test/data/test_1port_fixed.cal b/tests/data/test_1port_fixed.cal similarity index 100% rename from test/data/test_1port_fixed.cal rename to tests/data/test_1port_fixed.cal diff --git a/test/data/test_2port_long.cal b/tests/data/test_2port_long.cal similarity index 100% rename from test/data/test_2port_long.cal rename to tests/data/test_2port_long.cal diff --git a/test/data/unordered.s1p b/tests/data/unordered.s1p similarity index 100% rename from test/data/unordered.s1p rename to tests/data/unordered.s1p diff --git a/test/data/valid.s1p b/tests/data/valid.s1p similarity index 100% rename from test/data/valid.s1p rename to tests/data/valid.s1p diff --git a/test/data/valid.s2p b/tests/data/valid.s2p similarity index 100% rename from test/data/valid.s2p rename to tests/data/valid.s2p diff --git a/test/data/valid_with_datacomment.s1p b/tests/data/valid_with_datacomment.s1p similarity index 100% rename from test/data/valid_with_datacomment.s1p rename to tests/data/valid_with_datacomment.s1p diff --git a/tests/data/wire-200-300.s1p b/tests/data/wire-200-300.s1p new file mode 100644 index 0000000..cfe5dc0 --- /dev/null +++ b/tests/data/wire-200-300.s1p @@ -0,0 +1,102 @@ +# HZ S RI R 50 +200000000 0.9983237454747583 0.054252976433478324 +201000000 0.9981801449420438 0.05325111954956431 +202000000 0.9980356021533138 0.05375931392995528 +203000000 0.99816818249912 0.05588720166124264 +204000000 0.9978661942161071 0.055359539190008966 +205000000 0.997625987232743 0.05525710052998494 +206000000 0.9976668205216893 0.05506673420475188 +207000000 0.9989507832819968 0.0557989539143409 +208000000 0.9985269616633635 0.056020179477492084 +209000000 0.9977812467167855 0.056716034278600294 +210000000 0.9975467678052998 0.05694157627109465 +211000000 0.998838138052381 0.057146819999689444 +212000000 0.9979938454488549 0.057062020301186414 +213000000 0.9983719536316094 0.05803133459329076 +214000000 0.9989306458703168 0.05865589172592955 +215000000 0.9967457900102514 0.057374340412010116 +216000000 0.99795756976149 0.05896061271980533 +217000000 0.9995489723928674 0.059285069106537906 +218000000 0.9986176525607264 0.05965992568323054 +219000000 0.9974635281662345 0.05891807878823223 +220000000 0.9984295126791514 0.05919002916126207 +221000000 0.9979993998237353 0.05923190865495068 +222000000 0.9974118553142552 0.059871021438485085 +223000000 0.9972372933751866 0.059815402945971353 +224000000 0.997348039704881 0.059974492493209845 +225000000 0.9972252773528719 0.0608135350500931 +226000000 0.9977965431684596 0.058841997329592825 +227000000 0.9976348377647214 0.0615024286955781 +228000000 0.9978230367810327 0.06077716268240004 +229000000 0.9983166166328095 0.06359616554565174 +230000000 0.9980011028223256 0.06176080522759875 +231000000 0.9982795135018049 0.06234733692646284 +232000000 0.9987615600243828 0.06266607029618809 +233000000 0.9978001662559638 0.06211170942585016 +234000000 0.99876048956477 0.06210825459040856 +235000000 0.9964660418661756 0.06293198810260658 +236000000 0.9974171173902692 0.06117167472758814 +237000000 0.9977257155926429 0.06277772702464698 +238000000 0.9982886207124259 0.06315906820940645 +239000000 0.9973045310061558 0.06341170788629184 +240000000 0.9977023234753631 0.06378781858423106 +241000000 0.9988012038778653 0.06496372930678161 +242000000 0.9972823885902345 0.06440208696898513 +243000000 0.9980249526213418 0.06452464815408565 +244000000 0.998364379133989 0.06504029259696895 +245000000 0.9976309685403584 0.0638937469810314 +246000000 0.9977291804120059 0.06440966593219502 +247000000 0.9983528962572561 0.06599727752389983 +248000000 0.9976340381123913 0.06543078115576723 +249000000 0.9983224537253816 0.0660935108528695 +250000000 0.9984320564889841 0.06807892281068366 +251000000 0.9977596975236899 0.06537261274874938 +252000000 0.9981260952033183 0.06829950832821408 +253000000 0.9978263564463402 0.06742329481503007 +254000000 0.9984799902529107 0.06877628598433144 +255000000 0.9981253202358327 0.06725851566776965 +256000000 0.9983459524052654 0.06790858806797255 +257000000 0.9972157499261518 0.06889284850826684 +258000000 0.9982761290481796 0.06803423544296625 +259000000 0.9970468070203565 0.06799061085170678 +260000000 0.9975964676224909 0.06776586302973409 +261000000 0.9969310982862624 0.06795234797555347 +262000000 0.9977527924538838 0.06946811579375953 +263000000 0.9969326617275697 0.07072745891211477 +264000000 0.9976459163733019 0.06973236148434601 +265000000 0.9964090591584315 0.06907864255022102 +266000000 0.9983550455082911 0.07214699120942897 +267000000 0.9966799528056401 0.07122926921544041 +268000000 0.9978489587683784 0.07149916626088745 +269000000 0.9985697211944131 0.07107198819670679 +270000000 0.9956547552164912 0.0712580748171368 +271000000 0.9976410015120722 0.07310416379534193 +272000000 0.9986071743130795 0.07199830706275298 +273000000 0.9980433639168048 0.07213110065295612 +274000000 0.9968273004559505 0.07235716432542226 +275000000 0.9967617446861382 0.07400010460229783 +276000000 0.9964163219348253 0.07312685780443444 +277000000 0.9970678474474282 0.07382864583834665 +278000000 0.9968082785597264 0.07461888612083849 +279000000 0.9961371886616062 0.0737209786781675 +280000000 0.9970554795163619 0.07431087692471942 +281000000 0.9965609868241296 0.07545802143616995 +282000000 0.9981694408813551 0.07421363422611986 +283000000 0.9982620288819636 0.0752504023659176 +284000000 0.9962435606529738 0.07671863784891594 +285000000 0.9977334582397902 0.07579089912471189 +286000000 0.9952016077978535 0.07595736762740875 +287000000 0.9962370447943562 0.07601588195068226 +288000000 0.99693667613338 0.07869397919346535 +289000000 0.9962205288538121 0.0771779022069723 +290000000 0.9955771122718405 0.07635957685945759 +291000000 0.997463785190588 0.07820970038185741 +292000000 0.9975133810558902 0.0777757093747184 +293000000 0.9978613389840202 0.07908395724958518 +294000000 0.9976897714433687 0.07859764245295639 +295000000 0.9954560158572916 0.07730151914600736 +296000000 0.9957845917945681 0.08018856925137306 +297000000 0.9986408212450184 0.08013819579467844 +298000000 0.995538080855166 0.08025111100814115 +299000000 0.9975393003316874 0.07989425072869846 +300000000 0.9958569643338128 0.08008514891869226 diff --git a/test/test_analytics.py b/tests/test_analytics.py similarity index 100% rename from test/test_analytics.py rename to tests/test_analytics.py diff --git a/test/test_formatSweepFrequency.py b/tests/test_formatSweepFrequency.py similarity index 100% rename from test/test_formatSweepFrequency.py rename to tests/test_formatSweepFrequency.py diff --git a/test/test_formatting.py b/tests/test_formatting.py similarity index 100% rename from test/test_formatting.py rename to tests/test_formatting.py diff --git a/test/test_parseFrequency.py b/tests/test_parseFrequency.py similarity index 100% rename from test/test_parseFrequency.py rename to tests/test_parseFrequency.py diff --git a/test/test_rftools.py b/tests/test_rftools.py similarity index 100% rename from test/test_rftools.py rename to tests/test_rftools.py diff --git a/test/test_settings.py b/tests/test_settings.py similarity index 100% rename from test/test_settings.py rename to tests/test_settings.py diff --git a/test/test_sitools.py b/tests/test_sitools.py similarity index 100% rename from test/test_sitools.py rename to tests/test_sitools.py diff --git a/test/test_sweep.py b/tests/test_sweep.py similarity index 100% rename from test/test_sweep.py rename to tests/test_sweep.py diff --git a/test/test_touchstone.py b/tests/test_touchstone.py similarity index 90% rename from test/test_touchstone.py rename to tests/test_touchstone.py index 02b59c0..6e1e62d 100644 --- a/test/test_touchstone.py +++ b/tests/test_touchstone.py @@ -61,14 +61,14 @@ class TestTouchstoneOptions(unittest.TestCase): class TestTouchstoneTouchstone(unittest.TestCase): def test_load(self): - ts = Touchstone("./test/data/valid.s1p") + ts = Touchstone("./tests/data/valid.s1p") ts.load() self.assertEqual(str(ts.opts), "# HZ S RI R 50") self.assertEqual(len(ts.s11), 1010) self.assertEqual(len(ts.s21), 0) self.assertEqual(ts.r, 50) - ts = Touchstone("./test/data/valid.s2p") + ts = Touchstone("./tests/data/valid.s2p") ts.load() ts.gen_interpolation() self.assertEqual(str(ts.opts), "# HZ S RI R 50") @@ -85,31 +85,31 @@ class TestTouchstoneTouchstone(unittest.TestCase): Datapoint(750000, -0.3331754099382822, 0.00032433255669243524)) - ts = Touchstone("./test/data/ma.s2p") + ts = Touchstone("./tests/data/ma.s2p") ts.load() self.assertEqual(str(ts.opts), "# MHZ S MA R 50") - ts = Touchstone("./test/data/db.s2p") + ts = Touchstone("./tests/data/db.s2p") ts.load() self.assertEqual(str(ts.opts), "# HZ S DB R 50") - ts = Touchstone("./test/data/broken_pair.s2p") + ts = Touchstone("./tests/data/broken_pair.s2p") with self.assertLogs(level=logging.ERROR) as cm: ts.load() self.assertRegex(cm.output[0], "Data values aren't pairs") - ts = Touchstone("./test/data/missing_pair.s2p") + ts = Touchstone("./tests/data/missing_pair.s2p") with self.assertLogs(level=logging.ERROR) as cm: ts.load() self.assertRegex(cm.output[0], "Inconsistent number") - ts = Touchstone("./test/data/nonexistent.s2p") + ts = Touchstone("./tests/data/nonexistent.s2p") with self.assertLogs(level=logging.ERROR) as cm: ts.load() self.assertRegex(cm.output[0], "No such file or directory") def test_swap(self): - ts = Touchstone("./test/data/valid.s2p") + ts = Touchstone("./tests/data/valid.s2p") ts.load() s11, s21, s12, s22 = ts.sdata ts.swap() @@ -117,11 +117,11 @@ class TestTouchstoneTouchstone(unittest.TestCase): self.assertEqual([s11_, s21_, s12_, s22_], [s22, s12, s21, s11]) def test_db_conversation(self): - ts_db = Touchstone("./test/data/attenuator-0643_DB.s2p") + ts_db = Touchstone("./tests/data/attenuator-0643_DB.s2p") ts_db.load() - ts_ri = Touchstone("./test/data/attenuator-0643_RI.s2p") + ts_ri = Touchstone("./tests/data/attenuator-0643_RI.s2p") ts_ri.load() - ts_ma = Touchstone("./test/data/attenuator-0643_MA.s2p") + ts_ma = Touchstone("./tests/data/attenuator-0643_MA.s2p") ts_ma.load() self.assertEqual(len(ts_db.s11), len(ts_ri.s11)) for dps_db, dps_ri in zip(ts_db.s11, ts_ri.s11): @@ -132,7 +132,7 @@ class TestTouchstoneTouchstone(unittest.TestCase): self.assertAlmostEqual(dps_db.z, dps_ma.z, places=5) def test_load_scikit(self): - ts = Touchstone("./test/data/scikit_unordered.s2p") + ts = Touchstone("./tests/data/scikit_unordered.s2p") with self.assertLogs(level=logging.WARNING) as cm: ts.load() self.assertEqual(cm.output, [ @@ -167,7 +167,7 @@ class TestTouchstoneTouchstone(unittest.TestCase): self.assertEqual(ts.s_freq("11", 2), Datapoint(2, 0.5, 0.5)) def test_save(self): - ts = Touchstone("./test/data/valid.s2p") + ts = Touchstone("./tests/data/valid.s2p") self.assertEqual(ts.saves(), "# HZ S RI R 50\n") ts.load() lines = ts.saves().splitlines() @@ -184,7 +184,7 @@ class TestTouchstoneTouchstone(unittest.TestCase): self.assertEqual(lines[-1], '900000000 -0.127646 0.31969 0.596287 -0.503453' ' 0.599076 -0.50197 -0.122713 0.326965') - ts.filename = "./test/data/output.s2p" + ts.filename = "./tests/data/output.s2p" ts.save(4) os.remove(ts.filename) ts.filename = "" diff --git a/test/test_version.py b/tests/test_version.py similarity index 100% rename from test/test_version.py rename to tests/test_version.py diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..add5d8a --- /dev/null +++ b/tox.ini @@ -0,0 +1,92 @@ +# Tox configuration file +# Read more under https://tox.wiki/ + +[tox] +minversion = 3.24 +envlist = default +isolated_build = True + + +[testenv] +description = Invoke pytest to run automated tests +setenv = + TOXINIDIR = {toxinidir} +passenv = + HOME + SETUPTOOLS_* +extras = + testing +commands = + pytest {posargs} +deps = -Ur./requirements.txt + +# # To run `tox -e lint` you need to make sure you have a +# # `.pre-commit-config.yaml` file. See https://pre-commit.com +# [testenv:lint] +# description = Perform static analysis and style checks +# skip_install = True +# deps = pre-commit +# passenv = +# HOMEPATH +# PROGRAMDATA +# SETUPTOOLS_* +# commands = +# pre-commit run --all-files {posargs:--show-diff-on-failure} + + +[testenv:{build,clean}] +description = + build: Build the package in isolation according to PEP517, see https://github.com/pypa/build + clean: Remove old distribution files and temporary build artifacts (./build and ./dist) +# https://setuptools.pypa.io/en/stable/build_meta.html#how-to-use-it +skip_install = True +changedir = {toxinidir} +deps = + build: build[virtualenv] +passenv = + SETUPTOOLS_* +commands = + clean: python -c 'import shutil; [shutil.rmtree(p, True) for p in ("build", "dist", "docs/_build")]' + clean: python -c 'import pathlib, shutil; [shutil.rmtree(p, True) for p in pathlib.Path("src").glob("*.egg-info")]' + build: python -m build {posargs} +# By default, both `sdist` and `wheel` are built. If your sdist is too big or you don't want +# to make it available, consider running: `tox -e build -- --wheel` + + +[testenv:{docs,doctests,linkcheck}] +description = + docs: Invoke sphinx-build to build the docs + doctests: Invoke sphinx-build to run doctests + linkcheck: Check for broken links in the documentation +passenv = + SETUPTOOLS_* +setenv = + DOCSDIR = {toxinidir}/docs + BUILDDIR = {toxinidir}/docs/_build + docs: BUILD = html + doctests: BUILD = doctest + linkcheck: BUILD = linkcheck +deps = + -r {toxinidir}/docs/requirements.txt + # ^ requirements.txt shared with Read The Docs +commands = + sphinx-build --color -b {env:BUILD} -d "{env:BUILDDIR}/doctrees" "{env:DOCSDIR}" "{env:BUILDDIR}/{env:BUILD}" {posargs} + + +[testenv:publish] +description = + Publish the package you have been developing to a package index server. + By default, it uses testpypi. If you really want to publish your package + to be publicly accessible in PyPI, use the `-- --repository pypi` option. +skip_install = True +changedir = {toxinidir} +passenv = + # See: https://twine.readthedocs.io/en/latest/ + TWINE_USERNAME + TWINE_PASSWORD + TWINE_REPOSITORY + TWINE_REPOSITORY_URL +deps = twine +commands = + python -m twine check dist/* + python -m twine upload {posargs:--repository {env:TWINE_REPOSITORY:testpypi}} dist/*