Skip to content

Commit

Permalink
Merge pull request #2 from mnbf9rca/chore/add_workflows
Browse files Browse the repository at this point in the history
Chore/add workflows
  • Loading branch information
mnbf9rca authored Jul 9, 2024
2 parents d8bfb99 + fbaf138 commit 87c3ec9
Show file tree
Hide file tree
Showing 6 changed files with 240 additions and 24 deletions.
75 changes: 75 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"

on:
push:
branches: ["*", "*/*"]
pull_request:
# The branches below must be a subset of the branches above
branches: ["*", "*/*"]
schedule:
- cron: "43 4 * * 3"

jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write

strategy:
fail-fast: false
matrix:
language: ["python"]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Use only 'java' to analyze code written in Java, Kotlin or both
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support

steps:
- name: Checkout repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.

# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality

# Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3

# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun

# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.

# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3
with:
category: "/language:${{matrix.language}}"
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 Request, 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@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
- name: 'Dependency Review'
uses: actions/dependency-review-action@72eb03d02c7872a771aacd928f3123ac62ad6d3a # v4
53 changes: 53 additions & 0 deletions .github/workflows/run_pytest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: Python package

on:
push:
branches-ignore:
- main
pull_request:
branches:
- main

jobs:
test:
strategy:
matrix:
python-version: ["3.12"]
runs-on: ubuntu-latest
container: ubuntu:latest@sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc436217b30
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5
with:
python-version: ${{ matrix.python-version }}
- name: Install OS dependencies for snok/install-poetry
run: |
DEBIAN_FRONTEND=noninteractive apt update
DEBIAN_FRONTEND=noninteractive apt install curl sqlite3 -y
- uses: snok/install-poetry@93ada01c735cc8a383ce0ce2ae205a21c415379b # v1
with:
version: 1.8.3 # pin the version as they keep changing their APIs
virtualenvs-create: false
virtualenvs-in-project: false
- name: Install dependencies
run: |
python -m venv venv
. venv/bin/activate
poetry install --with dev --no-interaction --sync
python -c "import os; print(os.environ['VIRTUAL_ENV'])"
- name: Lint with flake8
run: |
. venv/bin/activate
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
run: |
. venv/bin/activate
pytest --cov pydantic_tfl_api --cov-report=xml
# - name: Upload coverage reports to Codecov
# uses: codecov/codecov-action@0cfda1dd0a4ad9efc75517f399d859cd1ea4ced1 # v4
# env:
# CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,21 @@ pip install pydantic-tfl-api

## Usage

Uses Pydantic so you can use the `model_dump_json()` method to see the data returned by the API. See [Pydantic documentation](https://docs.pydantic.dev/latest/) for more help
Uses Pydantic so you can use the `model_dump_json()` method to fully expand all the objects in the result. See [Pydantic documentation](https://docs.pydantic.dev/latest/) for more help.

```python
from tfl.client import Client
from tfl.api_token import ApiToken
from pydantic_tfl_api.client import Client, ApiToken

app_id = 'APPLICATION ID'
app_key = 'APPLICATION KEY'

token = ApiToken(app_id, app_key)

client = Client(token)
print (client.get_line_meta_modes().model_dump_json())
print (client.get_line_meta_modes())
print (client.get_lines(mode="bus")[0].model_dump_json())
print (client.get_lines(line_id="victoria")[0].model_dump_json())
print (client.get_route_by_line_id_with_direction(line_id="northern", direction="all").model_dump_json())
```
## Class structure

Expand Down
66 changes: 46 additions & 20 deletions pydantic_tfl_api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from .api_token import ApiToken
from .rest_client import RestClient
from importlib import import_module
from typing import Any, Literal
from typing import Any, Literal, List
from requests import Response
import pkgutil
from pydantic import BaseModel
Expand Down Expand Up @@ -77,7 +77,9 @@ def _deserialize_error(self, response: Response) -> models.ApiError:
message=response.text,
)

def get_stop_points_by_line_id(self, line_id: str) -> models.StopPoint | models.ApiError:
def get_stop_points_by_line_id(
self, line_id: str
) -> models.StopPoint | List[models.StopPoint] | models.ApiError:
response = self.client.send_request(
endpoints["stopPointsByLineId"].format(line_id)
)
Expand All @@ -91,7 +93,9 @@ def get_line_meta_modes(self) -> models.Mode | models.ApiError:
return self._deserialize_error(response)
return self._deserialize("Mode", response)

def get_lines(self, line_id: str | None =None, mode: str | None =None) -> models.Line | models.ApiError:
def get_lines(
self, line_id: str | None = None, mode: str | None = None
) -> models.Line | List[models.Line] | models.ApiError:
if line_id is None and mode is None:
raise Exception(
"Either the --line_id argument or the --mode argument needs to be specified."
Expand All @@ -105,85 +109,107 @@ def get_lines(self, line_id: str | None =None, mode: str | None =None) -> models
return self._deserialize_error(response)
return self._deserialize("Line", response)

def get_line_status(self, line: str, include_details: bool=None) -> models.Line | models.ApiError:
def get_line_status(
self, line: str, include_details: bool = None
) -> models.Line | List[models.Line] | models.ApiError:
response = self.client.send_request(
endpoints["lineStatus"].format(line), {"detail": include_details is True}
)
if response.status_code != 200:
return self._deserialize_error(response)
return self._deserialize("Line", response)

def get_line_status_severity(self, severity: str) -> models.Line | models.ApiError:
def get_line_status_severity(
self, severity: str
) -> models.Line | List[models.Line] | models.ApiError:
response = self.client.send_request(
endpoints["lineStatusBySeverity"].format(severity)
)
if response.status_code != 200:
return self._deserialize_error(response)
return self._deserialize("Line", response)
def get_line_status_by_mode(self, mode: str) -> models.Line | models.ApiError:
response = self.client.send_request(
endpoints["lineStatusByMode"].format(mode)
)

def get_line_status_by_mode(
self, mode: str
) -> models.Line | List[models.Line] | models.ApiError:
response = self.client.send_request(endpoints["lineStatusByMode"].format(mode))
if response.status_code != 200:
return self._deserialize_error(response)
return self._deserialize("Line", response)

def get_route_by_line_id(self, line_id: str) -> models.Line | models.ApiError:
def get_route_by_line_id(
self, line_id: str
) -> models.Line | List[models.Line] | models.ApiError:
response = self.client.send_request(endpoints["routeByLineId"].format(line_id))
if response.status_code != 200:
return self._deserialize_error(response)
return self._deserialize("Line", response)

def get_route_by_mode(self, mode: str) -> models.Line | models.ApiError:
def get_route_by_mode(
self, mode: str
) -> models.Line | List[models.Line] | models.ApiError:
response = self.client.send_request(endpoints["routeByMode"].format(mode))
if response.status_code != 200:
return self._deserialize_error(response)
return self._deserialize("Line", response)

def get_route_by_line_id_with_direction(self, line_id: str, direction: Literal['inbound', 'outbound', 'all']) -> models.Line | models.ApiError:

def get_route_by_line_id_with_direction(
self, line_id: str, direction: Literal["inbound", "outbound", "all"]
) -> models.RouteSequence | List[models.RouteSequence] | models.ApiError:
response = self.client.send_request(
endpoints["routeByLineIdWithDirection"].format(line_id, direction)
)
if response.status_code != 200:
return self._deserialize_error(response)
return self._deserialize("RouteSequence", response)

def get_line_disruptions_by_line_id(self, line_id: str) -> models.Disruption | models.ApiError:
def get_line_disruptions_by_line_id(
self, line_id: str
) -> models.Disruption | List[models.Disruption] | models.ApiError:
response = self.client.send_request(
endpoints["lineDisruptionsByLineId"].format(line_id)
)
if response.status_code != 200:
return self._deserialize_error(response)
return self._deserialize("Disruption", response)

def get_line_disruptions_by_mode(self, mode: str) -> models.Disruption | models.ApiError:
def get_line_disruptions_by_mode(
self, mode: str
) -> models.Disruption | List[models.Disruption] | models.ApiError:
response = self.client.send_request(
endpoints["lineDisruptionsByMode"].format(mode)
)
if response.status_code != 200:
return self._deserialize_error(response)
return self._deserialize("Disruption", response)

def get_stop_points_by_id(self, id: str) -> models.StopPoint | models.ApiError:
def get_stop_points_by_id(
self, id: str
) -> models.StopPoint | List[models.StopPoint] | models.ApiError:
response = self.client.send_request(endpoints["stopPointById"].format(id))
if response.status_code != 200:
return self._deserialize_error(response)
return self._deserialize("StopPoint", response)

def get_stop_points_by_mode(self, mode: str) -> models.StopPointsResponse | models.ApiError:
def get_stop_points_by_mode(
self, mode: str
) -> models.StopPointsResponse | List[models.StopPointsResponse] | models.ApiError:
response = self.client.send_request(endpoints["stopPointByMode"].format(mode))
if response.status_code != 200:
return self._deserialize_error(response)
return self._deserialize("StopPointsResponse", response)

def get_stop_point_meta_modes(self) -> models.Mode | models.ApiError:
def get_stop_point_meta_modes(
self,
) -> models.Mode | List[models.Mode] | models.ApiError:
response = self.client.send_request(endpoints["stopPointMetaModes"])
if response.status_code != 200:
return self._deserialize_error(response)
return self._deserialize("Mode", response)

def get_arrivals_by_line_id(self, line_id: str) -> models.Prediction | models.ApiError:
def get_arrivals_by_line_id(
self, line_id: str
) -> models.Prediction | List[models.Prediction] | models.ApiError:
response = self.client.send_request(
endpoints["arrivalsByLineId"].format(line_id)
)
Expand Down
42 changes: 42 additions & 0 deletions renovate.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:best-practices"
],
"automerge": true,
"automergeType": "pr",
"ignoreTests": false,
"lockFileMaintenance": {
"enabled": true,
"extends": [
"schedule:weekly"
],
"automerge": true
},
"minor": {
"automerge": true,
"extends": [
"schedule:automergeDaily"
]
},
"patch": {
"automerge": true,
"extends": [
"schedule:automergeDaily"
]
},
"pin": {
"automerge": true,
"extends": [
"schedule:automergeDaily"
]
},
"vulnerabilityAlerts": {
"enabled": true,
"extends": [
"schedule:daily"
]
},
"rebaseWhen": "behind-base-branch",
"updateNotScheduled": true
}

0 comments on commit 87c3ec9

Please sign in to comment.