Skip to content

Commit

Permalink
Merge branch 'release-2.0.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
Milind220 committed May 4, 2022
2 parents 57530e9 + e7f5843 commit b39187f
Show file tree
Hide file tree
Showing 87 changed files with 7,958 additions and 6,680 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/dependency-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Dependency Review Action
#
# This Action will scan dependency manifest files that change as part of a Pull Reqest, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging.
#
# Source repository: https://github.com/actions/dependency-review-action
# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement
name: 'Dependency Review'
on: [pull_request]

permissions:
contents: read

jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v3
- name: 'Dependency Review'
uses: actions/dependency-review-action@v1
16 changes: 16 additions & 0 deletions .github/workflows/greetings.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: Greetings

on: [pull_request_target, issues]

jobs:
greeting:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/first-interaction@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
issue-message: 'Hey! Thanks for creating your first issue on Ozone!'
pr-message: 'Awesome work with your first PR for Ozone! We will review your PR soon :)'
147 changes: 138 additions & 9 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,23 @@ The following is a set of guidelines for contributing to [Ozone](https://github.
#### Table of Contents

- [How Can I Contribute?](#how-can-i-contribute)

- [Reporting bugs](#reporting-bugs)
- [Suggesting enhancements/features](#suggesting-enhancements/features)
- [Suggesting enhancements/features](#suggesting-enhancementsfeatures)
- [Making a pull request](#making-a-pull-request)
- [Get an issue assigned to you](#get-an-issue-assigned-to-you)

- [Setting Up Local Development Environment](#setting-up-local-development-environment)

- [Getting a local copy](#getting-a-local-copy)
- [Setting up a development environment](#setting-up-a-development-environment)
- [Pushing changes and opening a pull request](#pushing-changes-and-opening-a-pull-request)

- [Test Suite](#test-suite)
- [Setting up and running tests](#setting-up-and-running-tests)
- [Updating tests](#updating-tests)
- [About the cassettes and pytest-recording](#about-the-cassettes-and-pytest-recording)
- [Adding or updating cassettes](#adding-or-updating-cassettes)
- [World Air Quality Index's API](#world-air-quality-indexs-api)

- [Style Guides](#style-guides)

- [Commit message style guide](#git-commit-messages)
- [Git commit messages](#git-commit-messages)
- [Python style guide](#python-style-guide)

- [Github Branching Model](#github-branching-model)


Expand Down Expand Up @@ -145,10 +143,16 @@ Hold my beer, I got this

From this point on, pre-commit hooks will run linters and formatters automatically before every commit. If there's a problem, the commit will abort. You'll need to fix the problem before committing again.

> It's normal for pre-commit to take some time.
> When Black reformats a staged file, the pre-commit will fail. It is normal and expected. See [this discussion](https://github.com/Milind220/Ozone/discussions/85). Just stage the file and commit again, it should pass the second time.
4. Your local development environment is ready to use. Feel free to code away. Make sure to only commit logical changes that are already tested. Don't commit things you just try out and haven't tested.

5. When you're done coding, again, **test out the changes that you've made to the package.** Proceed if all is good.

> See [next section](#test-suite) for instructions about Ozone's test suite.
### Pushing changes and opening a pull request

1. Push the changes to your forked repository.
Expand All @@ -157,6 +161,131 @@ Hold my beer, I got this

3. Describe your PR, submit it and wait for it to be merged! You may be required to do additional work or changes before it is merged.

## Test Suite

Ozone has a test suite that lives in `tests/` directory, which has the following structure within:

Directories:

1. `cassettes/`: Location of vcrpy and pytest-recording cassettes.

Files:

1. `conftest.py`: Location of pytest global and configuration fixtures.
2. `utils.py`: Location of global Python helper objects (i.e. constants and `Ozone` instance) to use in tests.
3. `test_*.py`: Test files, each file is testing one public method.

### Setting up and running tests

After setting development environment as pointed out above, you should already have all necessary testing packages installed. To run all tests, invoke this command from the root directory.

```sh
pytest
```

Some tests are slow and marked accordingly. To skip tests that are marked as "slow", you can use

```sh
pytest --skip-slow
```

If you want to run only specific tests, refer to (pytest documentation)[https://docs.pytest.org/en/7.1.x/how-to/usage.html] for a more complete information. The following is an example for how to run only the test functions starting with the pattern `output_data_format`

```sh
pytest -k "output_data_format"
```

If any of your tests fail because of a VCR error such as `vcr.errors.CannotOverWriteExistingCassetteException` while running the above commands, that could mean the cassette needs to be updated. See [below](#adding-or-updating-cassettes) for information.

### Updating tests

Generally, tests should correspond to the necessary specification/expectation of Ozone users. Tests will help us identify if our code is still in line with such expectations.

Tests should be updated when e.g.:
- There is new expectation on how should Ozone behave. In this case, the tests need to be updated accordingly.
- There is a new functionality. In this case, add necessary tests accordingly.
- There is a new bug or previously unencountered or undocumented behavior. Add them to the existing tests when fixing it, to make sure the same bug will never slip past again in the future.

### About the cassettes and pytest-recording

This test suite is testing Ozone's functionality, therefore interaction with outside sources are mocked. Ozone uses pytest-recording plugin that uses vcrpy under the hood to record request-response pairs.

These request-response pairs are stored as `.yaml` files in `tests/cassettes` directory. When an outbound request is made, pytest-recording will look for that request's response in the tests' `.yaml` file instead of actually letting the request go through to WAQI.

The `tests/cassettes` directory is organized as follows:

- Each folder per one test file.
- Each `.yaml` file per one test function.

For the purposes of this test suite, these request-response pairs are all **assumed** to be complete and correct. In the unlikely event that WAQI API changes their specifications, these request-response pairs need to be re-recorded. See the [next section](#adding-or-updating-cassettes).

### Adding or updating cassettes

By default, pytest-recording will only use existing cassettes for testing, and will raise error if there's a new interaction that is not contained in existing cassettes. This prevents "accidentally" making a request that is not already been mocked.

Cassettes are generally assumed to be complete (covers all the request-response pairs ever needed by the test function) and correct (exactly similar to what WAQI API would send over the live wire). But sometimes, it might not always be the case.

Sometimes when fixing a failing test (or updating a previously passing test), the next runs fail because of a vcr exception `vcr.errors.CannotOverWriteExistingCassetteException`. This is because the test makes a new HTTPS request that's not recorded in the corresponding cassette file. The cassette file thus needs to be updated.

Before doing so, you'll want to test using live connection to confirm that the test actually pass and the failure is caused solely by an outdated cassette:

```sh
pytest --disable-recording
```

If your tests pass when using live connection, it means the cassettes indeed need update. Simply run one of these:

```sh
# Rewrite existing cassettes but disallow creating new cassette files
# For modifying existing tests
pytest --record-mode=rewrite

# Create new cassette files but disallow modifying existing cassettes
# For adding new tests
pytest --record-mode=once
```

Alternatively, you can remove the `tests/cassettes` folder entirely and record from scratch:

```sh
# NOT RECOMMENDED, this is a nuclear option. For "if-all-else-fails"-type situation,
# or when there's very significant change to the test suite file structures.
rm -r tests/cassettes
pytest --record-mode=once
```

After making changes to the cassettes, don't forget to save the cassettes into version control, for example by doing:

```sh
git commit tests/cassettes -m "test: Re-record cassettes for passing test XXX XXX XXX"
```

Note that doing a live request to WAQI requires a token to be supplied. The test suite loads the token from an environment variable. To set this environment variable, you can make a file named `.env` in Ozone root directory with the following content:

```
WAQI_TOKEN=insert_your_token_here
```

Or you can pass the environment variable to the shell environment. For example, in Git Bash you can do this when invoking pytest:

```sh
WAQI_TOKEN=insert_your_token_here pytest --disable-recording
```

Finally, after updating the cassettes, perform the test one more time to confirm that the cassettes don't cause problems:

```sh
# equivalent to just invoking "pytest"
pytest --record-mode=none
```

> To have more confidence that the tests will not go over the wire, the `--block-network` flag can also be passed to block all network access.
For more information:
- [python-decouple homepage](https://github.com/henriquebastos/python-decouple) (used to collect `.env` variables)
- [pytest-recording homepage](https://github.com/kiwicom/pytest-recording)
- [VCRpy documentation about record modes](https://vcrpy.readthedocs.io/en/latest/usage.html#record-modes)



## World Air Quality Index's API
Expand Down
132 changes: 109 additions & 23 deletions FILE_STRUCTURE.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,118 @@
# File Structure
Refer to this file for explanations on the file layout, as well as where to locate certain files.
This document is a reference primer on Ozone's files: what, where, and for what.

- [src/](#src)
- [media/](#media)
- [ozone/](#ozone)
- [ozone.py](#ozonepy)
- [urls.py](#urlspy)
- [historical/](#historical)
- [relevant_funcs.py](#relevant_funcspy)
- [_reverse_engineered.py](#_reverse_engineeredpy)
- [tests/](#tests)
- [cassettes/](#cassettes)
- [conftest.py](#conftestpy)
- [test_*.py](#test_py)
- [utils.py](#utilspy)
- [.pre-commit-config.yaml](#pre-commit-configyaml)
- [pyproject.toml, setup.py, and setup.cfg](#pyprojecttoml-setuppy-and-setupcfg)
- [requirements.txt](#requirementstxt)
- [updateVersion.sh](#updateversionsh)
- [.github/](#github)
- [ISSUE_TEMPLATE/](#issue_template)
- [workflows/](#workflows)
- [lint.yml](#lintyml)
- [package-publish.yml](#package-publishyml)
- [take.yml](#takeyml)

## Source Directory
You can find the source code in the source directory.
```
src/ozone
```
Here, you will find the executable code files and classes. These include files like `__init__.py` (the executable file), `ozone.py` and `urls.py` (refer to **Classes** for more information).
## src/

## Classes
In this repo, there are two main files where the classes are written. `ozone.py`, and `urls.py`. It is important to know the difference between them.
This is the directory where main Ozone source code lives.

### `urls.py`
In this file, the classes stored provide the URL for the other files to use.
### media/

### `ozone.py`
In this file, the classes are stored with the purpose of creating data for the end user. The classes in this file depend on the classes in `urls.py`.
This subdirectory contains media related to Ozone's documentation (README). Included here are demo GIFs and Ozone logo.

This file processes the required token to access the data, makes a request to the API, retrieves the data, and parses it.
### ozone/

## Dependency Management
### `setup.py`
This file is used to set up the project and install the required dependencies.
### `setup.cfg`
This file contains the configuration specification.
### `requirements.txt`
The third-party dependencies are specified in this file.
This module is where core Ozone code lives.

## `src/media`
If you come across `src/media`, you will find that it contains gifs. These are the files for the showcase gifs in the README.md.
#### ozone.py

Main module that contains Ozone's class definition.

#### urls.py

Helper module that contains definitions for WAQI API's URL endpoints.

#### historical/

This subfolder contains Python code relevant for historical data collection feature. It's mostly hack-ish and reverse-engineered from AQI's frontend website.

##### relevant_funcs.py

This file contains relevant JavaScript functions wrapped as one long triple-quoted Python string. These JavaScript functions are excerpted from AQI's frontend and are treated as black box that can convert server-sent data into readable format.

##### _reverse_engineered.py

This file contains most of code required to run the JavaScript functions and convert the result back into Python format that can be used by the rest of Ozone.

## tests/

This is where the test suite lives.

### cassettes/

This folder is where VCR.py cassettes are stored. Each folder here corresponds to one test file. Each file in each folder corresponds to one test function.

### conftest.py

Pytest global and configuration fixtures are defined here.

### test_*.py

These are test files. One test file is responsible for testing one of Ozone's public method.

### utils.py

Constants and objects that are used repeatedly throughout the entire test suite are defined here instead of in each file, to reduce repetitions and make it easier to change things if necessary.

## .pre-commit-config.yaml

Configuration file for pre-commit hooks. Specifies what pre-commit hooks to use, from which repository, and what version.

## pyproject.toml, setup.py, and setup.cfg

Files used for purposes of packaging and installation. Also contains package information for use in PyPI like version information, author name, PyPI category tags, etc.

## requirements.txt

Dependency requirement file for development. Non-developing users won't need to install packages in this file, as the installation process will install the user requirements automatically.

## updateVersion.sh

A custom shell script to automatically increment version. This is purely a convenience script so that each time Ozone needs a new release, we won't need to alter the version numbers in multiple places by hand.

## .github/

This folder is related to GitHub repository and not necessarily part of Ozone package.

### ISSUE_TEMPLATE/

Files in this folder are templates meant for newly opened issues.

### workflows/

This folder contains configuration files for running GitHub actions and workflows, including CI/CD tools.

#### lint.yml

CI/CD tool: linter and style checker.

#### package-publish.yml

CI/CD tool: package and publish a release for each tags.

#### take.yml

GitHub workflow: allow users to claim an issue and get it assigned to themselves without maintainers having to explicitly perform the assigning.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<a href="CONTRIBUTING.md#pull-requests"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" alt="PRs Welcome"></a>
![GitHub](https://img.shields.io/github/license/Milind220/Ozone)
[![Complete Documentation](https://github.com/Milind220/Ozone/actions/workflows/pages/pages-build-deployment/badge.svg)](https://github.com/Milind220/Ozone/actions/workflows/pages/pages-build-deployment)
[![Dependency Review](https://github.com/Milind220/Ozone/actions/workflows/dependency-review.yml/badge.svg)](https://github.com/Milind220/Ozone/actions/workflows/dependency-review.yml)
[![Buy Me a Coffee](https://img.shields.io/badge/buy_me_a_coffee-orange.svg?style=flat)](https://www.buymeacoffee.com/MilindSharma)

## The simplest AQI API
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = ozon3
version = 1.7.5
version = 2.0.0
author = Milind Sharma
author_email = [email protected]
description = A package to get air quality data using the WAQI API
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
description="A package to get air quality data using the WAQI API",
license="GPLv3+",
url="https://github.com/Milind220/Ozone",
version="1.7.5",
download_url="https://github.com/Milind220/Ozone/archive/refs/tags/v1.7.5.tar.gz",
version="2.0.0",
download_url="https://github.com/Milind220/Ozone/archive/refs/tags/v2.0.0.tar.gz",
packages=setuptools.find_packages(),
install_requires=[
"numpy; python_version>='3'",
Expand Down

0 comments on commit b39187f

Please sign in to comment.