diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000..09b6bc6e9 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,90 @@ +name: Build Documentation + +on: + workflow_dispatch: + workflow_call: + inputs: + publish: + required: true + type: boolean + secrets: + CACHE_VERSION: + required: true + release: + types: [ released ] + + +jobs: + build_docs: + name: Build Documentation + runs-on: ubuntu-latest + steps: + - name: Setup python + uses: actions/setup-python@v2 + with: + python-version: '3.9' + + - name: Checkout repo + uses: actions/checkout@v2 + + - name: Cache pip + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: pip-cache-${{ hashFiles('requirements/*/*.txt') }} + restore-keys: | + pip-cache + + - name: Install patched autodocsumm + # TODO: remove this step once PR is merged + run: | + python3 -m pip install git+https://github.com/theOehrly/autodocsumm.git@fixed-for-prod-0 + + - name: Install python requirements + run: | + python3 -m pip install --upgrade pip setuptools wheel + python3 -m pip install -r requirements-dev.txt + + - name: Create cache directory + run: | + mkdir doc_cache # make sure cache dir exists + + - name: Cache FastF1 + uses: actions/cache@v2 + with: + path: ./doc_cache + key: fastf1-${{ secrets.CACHE_VERSION }}-doc-cache-${{ hashFiles('*.*') }} + restore-keys: | + fastf1-${{ secrets.CACHE_VERSION }}-doc-cache + + - name: Install Fast-F1 from sources + run: | + python3 -m pip install -e . + + - name: Checkout current docs + run: | + mkdir -p docs/build/_html + cd docs/build/_html + git init + git remote add origin "https://$GITHUB_ACTOR:$GITHUB_TOKEN@github.com/$GITHUB_REPOSITORY.git" + git pull origin gh-pages + + - name: Build docs + run: | + mkdir test_cache # not really need but pytest setup relies on it + python setup.py build_sphinx -a -E + + - name: Publish docs + if: (github.event_name == 'release') || inputs.publish + run: | + cd docs/build/_html + git add . + git commit -m "$GITHUB_REF_NAME ($GITHUB_JOB) ci release" + git push origin gh-pages --force + + - name: Upload docs as artifact + uses: actions/upload-artifact@v3 + if: github.event_name != 'release' + with: + name: Documentation Build + path: docs/build/_html \ No newline at end of file diff --git a/.github/workflows/publish_docs.yml b/.github/workflows/publish_docs.yml new file mode 100644 index 000000000..b88b226bc --- /dev/null +++ b/.github/workflows/publish_docs.yml @@ -0,0 +1,13 @@ +name: Publish Documentation from master + +on: + workflow_dispatch: + +jobs: + publish-docs: + name: Build and Publish Docs + uses: ./.github/workflows/docs.yml + with: + publish: true + secrets: + CACHE_VERSION: ${{ secrets.CACHE_VERSION }} \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 697845835..092bea0bb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,7 +7,7 @@ on: jobs: deploy: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -29,7 +29,7 @@ jobs: python setup.py sdist bdist_wheel twine upload dist/* - # if this is a manual dispatch, upload to TestPyPI + # if this is a manual dispatch, upload to TestPyPI - name: Build and publish test release if: github.event_name == 'workflow_dispatch' env: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 427d7440a..c55365f3e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,9 +1,6 @@ name: Run tests -# Controls when the action will run. on: - # run on push, manual dispatch and on a schedule - # when run on schedule, tests will only be run if a new matplotlib release was found workflow_dispatch: push: branches-ignore: @@ -17,7 +14,7 @@ jobs: strategy: matrix: python-version: [ '3.8', '3.9', '3.10' ] - name: Run code tests on ${{ matrix.python-version }} + name: Tests on ${{ matrix.python-version }} steps: - name: Setup python uses: actions/setup-python@v2 @@ -35,7 +32,7 @@ jobs: restore-keys: | pip-cache - - name: Install Python dev dependencies + - name: Install python requirements run: | python3 -m pip install --upgrade pip setuptools wheel python3 -m pip install -r requirements-dev.txt @@ -44,11 +41,21 @@ jobs: run: | python3 -m pip install -e . - - name: Run tests + - name: Create cache directory run: | mkdir test_cache # make sure cache dir exists - pytest -rf + - name: Cache FastF1 + uses: actions/cache@v2 + with: + path: ./test_cache + key: fastf1-${{ secrets.CACHE_VERSION }}-${{ matrix.python-version }}-${{ hashFiles('*.*') }} + restore-keys: | + fastf1-${{ secrets.CACHE_VERSION }}-${{ matrix.python-version }} + + - name: Run tests + run: | + pytest -ra run-lint-checks: runs-on: ubuntu-latest @@ -85,14 +92,14 @@ jobs: pytest -rf --flake8 --lint-only - run-prj-and-doc-tests: - name: Test doc and project structure + run-readme-render-test: + name: Test readme renders on PyPi runs-on: ubuntu-latest steps: - name: Setup python uses: actions/setup-python@v2 with: - python-version: '3.8' + python-version: '3.9' - name: Checkout repo uses: actions/checkout@v2 @@ -105,11 +112,6 @@ jobs: restore-keys: | pip-cache - - name: Install Python dev dependencies - run: | - python3 -m pip install --upgrade pip setuptools wheel - python3 -m pip install -r requirements-dev.txt - - name: Install python requirements run: | python3 -m pip install --upgrade pip setuptools wheel @@ -121,5 +123,13 @@ jobs: - name: Run tests run: | - mkdir test_cache # make sure cache dir exists - pytest -rf --prj-doc \ No newline at end of file + mkdir test_cache # not really need but pytest setup relies on it + pytest -rf --prj-doc + + run-sphinx-build-test: + name: Test Docs + uses: ./.github/workflows/docs.yml + with: + publish: false + secrets: + CACHE_VERSION: ${{ secrets.CACHE_VERSION }} \ No newline at end of file diff --git a/conftest.py b/conftest.py index a9a0abc9b..b9b56c51c 100644 --- a/conftest.py +++ b/conftest.py @@ -1,10 +1,12 @@ +import sys + import pytest def pytest_addoption(parser): parser.addoption( - "--f1-tel-api", action="store_true", default=False, - help="run tests which require connecting to the f1 telemetry api" + "--no-f1-tel-api", action="store_true", default=False, + help="skip tests which require connecting to the f1 telemetry api" ) parser.addoption( "--ergast-api", action="store_true", default=False, @@ -33,8 +35,8 @@ def pytest_configure(config): def pytest_sessionstart(session): - import fastf1.api - fastf1.api.Cache.enable_cache('test_cache') + import fastf1 + fastf1.Cache.enable_cache('test_cache') def pytest_collection_modifyitems(config, items): @@ -47,8 +49,8 @@ def pytest_collection_modifyitems(config, items): # cli conditional skip test that use the cache or connect to the # f1 api directly - if not config.getoption("--f1-tel-api"): - skip_f1_tel = pytest.mark.skip(reason="need --f1-tel-api option to run") + if config.getoption("--no-f1-tel-api"): + skip_f1_tel = pytest.mark.skip(reason="--no-f1-tel-api set") for item in items: if "f1telapi" in item.keywords: item.add_marker(skip_f1_tel) diff --git a/docs/time_explanation.rst b/docs/time_explanation.rst index bdc387685..813c3a0c3 100644 --- a/docs/time_explanation.rst +++ b/docs/time_explanation.rst @@ -40,8 +40,17 @@ For a sample of telemetry data this means, that the sample will always have the Take the following set of example telemetry. Lets assume the variable `tel` holds previously loaded telemetry data for one driver an for a full session (only time data is shown for simplification). -.. code-block:: +.. doctest:: + :hide: + >>> import fastf1 + >>> import pandas + >>> session = fastf1.get_session(2020, 8, 'R') + >>> session.load() + +.. doctest:: + + >>> tel = session.car_data['33'].loc[:, ['Time', 'SessionTime', 'Date']] >>> tel Time SessionTime Date 0 0 days 00:00:02.984000 0 days 00:00:02.984000 2020-09-06 12:40:03.180 @@ -49,19 +58,23 @@ for one driver an for a full session (only time data is shown for simplification 2 0 days 00:00:03.464000 0 days 00:00:03.464000 2020-09-06 12:40:03.660 3 0 days 00:00:03.704000 0 days 00:00:03.704000 2020-09-06 12:40:03.900 4 0 days 00:00:03.944000 0 days 00:00:03.944000 2020-09-06 12:40:04.140 - ... ... ... + ... ... ... ... 35533 0 days 02:23:27.764000 0 days 02:23:27.764000 2020-09-06 15:03:27.960 35534 0 days 02:23:28.004000 0 days 02:23:28.004000 2020-09-06 15:03:28.200 35535 0 days 02:23:28.244000 0 days 02:23:28.244000 2020-09-06 15:03:28.440 35536 0 days 02:23:28.484000 0 days 02:23:28.484000 2020-09-06 15:03:28.680 35537 0 days 02:23:28.724000 0 days 02:23:28.724000 2020-09-06 15:03:28.920 + [35538 rows x 3 columns] -The session (a race in this case) lasted about 2 hours and 23 minutes. `SessionTime` and `Time` are exactly the same -for this set of data. This is how the data looks as it is created by the api functions. +The telemetry comprises approximately 2 hours and 23 minutes of data. +The session (a race in this case) did not last this long, but the data starts +before the beginning of the session and ends after the end. +`SessionTime` and `Time` are exactly the same for this set of data. +This is how the data looks as it is created by the api functions. Next, the data is sliced to only include a subset of the full session. -.. code-block:: +.. doctest:: >>> t1 = pandas.Timedelta(hours=1, minutes=20) >>> t2 = pandas.Timedelta(hours=1, minutes=30) @@ -72,12 +85,13 @@ Next, the data is sliced to only include a subset of the full session. 19813 0 days 00:00:00.676000 0 days 01:20:00.676000 2020-09-06 14:00:00.872 19814 0 days 00:00:00.916000 0 days 01:20:00.916000 2020-09-06 14:00:01.112 19815 0 days 00:00:01.156000 0 days 01:20:01.156000 2020-09-06 14:00:01.352 - ... ... ... + ... ... ... ... 22288 0 days 00:09:59.076000 0 days 01:29:59.076000 2020-09-06 14:09:59.272 22289 0 days 00:09:59.277000 0 days 01:29:59.277000 2020-09-06 14:09:59.473 22290 0 days 00:09:59.517000 0 days 01:29:59.517000 2020-09-06 14:09:59.713 22291 0 days 00:09:59.757000 0 days 01:29:59.757000 2020-09-06 14:09:59.953 22292 0 days 00:09:59.997000 0 days 01:29:59.997000 2020-09-06 14:10:00.193 + [2482 rows x 3 columns] `SessionTime` and `Date` have kept there reference point. But the reference point for `Time` has changed and its new @@ -95,7 +109,7 @@ a common zero point. The relation between `SessionTime` and `Date` is a constant offset. This value is available through the session class. -.. code-block:: +.. doctest:: >>> session.t0_date Timestamp('2020-09-06 12:40:00.196000') @@ -103,7 +117,7 @@ The relation between `SessionTime` and `Date` is a constant offset. This value i As already mentioned above, the zero point of the session time is before the actual start of a session. The session itself officially starts at some later point in time. This value is also available through the session class. -.. code-block:: +.. doctest:: >>> session.session_start_time datetime.timedelta(seconds=2008, microseconds=79000) diff --git a/fastf1/events.py b/fastf1/events.py index 5abb6a768..5889788ae 100644 --- a/fastf1/events.py +++ b/fastf1/events.py @@ -6,7 +6,7 @@ Formula 1 events. An :class:`Event` can be a race weekend or a testing event. Each event -consists of multiple :class:`~fastf1.core.Session`\ s. +consists of multiple :class:`~fastf1.core.Session`. The event schedule objects are built on top of pandas' :class:`pandas.DataFrame` (event schedule) and :class:`pandas.Series` (event). diff --git a/fastf1/tests/test_input_data_handling.py b/fastf1/tests/test_input_data_handling.py index 2b89dbe77..ba64eda3b 100644 --- a/fastf1/tests/test_input_data_handling.py +++ b/fastf1/tests/test_input_data_handling.py @@ -111,7 +111,8 @@ def _mock(*args, **kwargs): fastf1.api.timing_app_data = _mock session = fastf1.get_session(2020, 'Italy', 'R') - session.load(telemetry=False, weather=False) + with fastf1.Cache.disabled(): + session.load(telemetry=False, weather=False) assert 'Failed to load lap data!' not in log_handle.text assert 'No tyre data for driver' in log_handle.text @@ -122,21 +123,11 @@ def _mock(*args, **kwargs): @pytest.mark.f1telapi def test_inlap_added(): - fastf1.testing.run_in_subprocess(_test_inlap_added) - - -def _test_inlap_added(): - # !! API parser test - require running without cache !! - # perez aborted his last q3 run and went straight into the pits - # lap data needs to be added so that telemetry can be loaded - log_handle = fastf1.testing.capture_log(logging.WARNING) - session = fastf1.get_session(2021, 'Mexico City', 'Q') - session.load(telemetry=False) + with fastf1.Cache.disabled(): + session.load(telemetry=False) + last = session.laps.pick_driver('PER').iloc[-1] assert not pd.isnull(last['PitInTime']) assert not pd.isnull(last['Time']) - - # verify that the test was actually run without caching enabled - assert 'NO CACHE' in log_handle.text diff --git a/pytest.ini b/pytest.ini index 60be93b2e..b26a13fc0 100644 --- a/pytest.ini +++ b/pytest.ini @@ -3,8 +3,10 @@ minversion = 6.0 testpaths = fastf1 + docs # the following are only used for 'pytest --flake8' examples scripts python_files = test_*.py +addopts = --doctest-glob="*.rst" --xdoctest --mpl --mpl-baseline-path=fastf1/tests/mpl-baseline --mpl-results-path=mpl-results \ No newline at end of file