Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/validate_samples.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Validate-Samples

on:
push:
paths:
- 'samples/*/TIDES/*'
- 'spec/*'
pull_request:
paths:
- 'samples/*/TIDES/*'
- 'spec/*'
workflow_dispatch:
create:

jobs:
validate:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Validate sample data
uses: frictionlessdata/repository@v2

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any way to pass --schema-sync to this action? Otherwise it will fail when option fields are left out of the csvs.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking into it

with:
packages: "samples/*/TIDES/datapackage.json"

11 changes: 9 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
.DS_Store*
.vscode*
/__pycache__/*
.env
/venv*
/site
/__pycache__
/site/*
# pages that are copied in from main repo
/docs/CONTRIBUTING.md
/docs/CODE_OF_CONDUCT.md
/docs/README.md
# pages that are generated from templates
/docs/tables.md
/docs/architecture.md
6 changes: 6 additions & 0 deletions .markdownlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,11 @@ MD007:
# Remove line length limit
MD013: false

# Remove "fenced code blocks should have language specified"
MD040: false

# Remove "no inline HTML"
MD033: false

# Remove "no emphasis as heading"
MD036: false
33 changes: 32 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,43 @@ This repository provides data schemas and tools to support the access, managemen

## TIDES specification

The TIDES specification is maintained in the `/spec` sub-directory as a series of JSON tables compatible with the [frictionless data](https://specs.frictionlessdata.io/table-schema/) table schema standards.
The TIDES specification is maintained in the `/spec` sub-directory as a series of JSON tables compatible with the [frictionless data](https://specs.frictionlessdata.io/table-schema/) table schema and [data package](https://specs.frictionlessdata.io/data-package) standards.
Human-friendlier documentation is auto-generated and available at:

- [Architecture](architecture.md)
- [Table Schemas](tables.md)

## Example Data

Sample data can be found in the `/samples` directory, with one directory for each example.

## Validating TIDES data

TIDES data with a valid [`datapackage.json`](#data-package) can be easily validated using the [frictionless framework](https://framework.frictionlessdata.io/), which can be installed and invoke as follows:

```bash
pip install frictionless
frictionless validate path/to/your/datapackage.json
```

### Data Package

To validate a package of TIDES data, you must add a frictionless-compliant [`datapackage.json`](https://specs.frictionlessdata.io/data-package/) alongside your data which describes which files should be validated to which schemas. Most of this can be copied from [`/data/template/datapackage.json`](https://raw.githubusercontent.com/TIDES-transit/TIDES/main/data/template/datapackage.json).

Once this is created, mapping the data files to the schema, simply run:

```sh
frictionless validate datapackage.json
```

### Specific files

Specific files can be validated by running the frictionless framework against them and their corresponding schemas as follows:

```sh
frictionless validate vehicles.csv --schema https://raw.githubusercontent.com/TIDES-transit/TIDES/main/spec/schema.vehicles.json
```

## Contributing to TIDES

Those who want to help with the development of the TIDES specification should review the guidance in <CONTRIBUTING.md>.
Expand Down
2 changes: 1 addition & 1 deletion contributors.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
# Contributors
# Contributors
4 changes: 3 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
{{ include_file('README.md', downshift_h1= False) }}
# TIDES Transit Specification Suite

{{ include_file('README.md', start_line = 2, downshift_h1= False) }}
9 changes: 9 additions & 0 deletions docs/samples.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Sample Data

Sample data can be found in the `/samples` directory, with one directory for each data sample.

{{ include_file('samples/README.md')}}

## Data List

{{ list_samples('samples') }}
92 changes: 81 additions & 11 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"tables.md": "tables",
}


def define_env(env):
"""
This is the hook for defining variables, macros and filters
Expand All @@ -26,15 +27,42 @@ def define_env(env):
"""

@env.macro
def include_file(filename: str, downshift_h1 = True, start_line: int = 0, end_line: int = None):
def list_samples(data_dir: str) -> str:
"""Outputs a simple list of the directories in a folder in markdown.
Args:
data_dir (str):directory to search in
Returns:
str: markdown-formatted list
"""

fields = ["Sample", "Agency", "Resources", "Vendors"]

data_dir = os.path.join(env.project_dir, data_dir)
samples = [
d for d in os.listdir(data_dir) if os.path.isdir(os.path.join(data_dir, d))
]

md_table = (
"| *" + "** | **".join(fields) + "* |\n| " + " ----- |" * len(fields) + "\n"
)

for s in samples:
md_table += datapackage_to_row(os.path.join(data_dir, s), fields)
return md_table

@env.macro
def include_file(
filename: str, downshift_h1=True, start_line: int = 0, end_line: int = None
):
"""
Include a file, optionally indicating start_line and end_line.

Will create redirects if specified in FIND_REPLACE in main.py.

args:
filename: file to include, relative to the top directory of the documentation project.
downshift_h1: If true, will downshift headings by 1 if h1 heading found. Defaults to True.
downshift_h1: If true, will downshift headings by 1 if h1 heading found.
Defaults to True.
start_line (Optional): if included, will start including the file from this line
(indexed to 0)
end_line (Optional): if included, will stop including at this line (indexed to 0)
Expand All @@ -53,20 +81,19 @@ def include_file(filename: str, downshift_h1 = True, start_line: int = 0, end_li
4: re.compile(r"(#{4}\s)(.*)"),
5: re.compile(r"(#{5}\s)(.*)"),
}
print(f"???before downshifting! {full_filename}")

if md_heading_re[1].search(content) and downshift_h1:
print("!!!downshifting!")
content = re.sub(md_heading_re[5],r'#\1\2',content)
content = re.sub(md_heading_re[4],r'#\1\2',content)
content = re.sub(md_heading_re[3],r'#\1\2',content)
content = re.sub(md_heading_re[2],r'#\1\2',content)
content = re.sub(md_heading_re[1],r'#\1\2',content)
content = re.sub(md_heading_re[5], r"#\1\2", content)
content = re.sub(md_heading_re[4], r"#\1\2", content)
content = re.sub(md_heading_re[3], r"#\1\2", content)
content = re.sub(md_heading_re[2], r"#\1\2", content)
content = re.sub(md_heading_re[1], r"#\1\2", content)

_filenamebase = env.page.file.url
for _find, _replace in FIND_REPLACE.items():
if _filenamebase in _replace:
_replace = _replace.replace(_filenamebase, "")

content = content.replace(_find, _replace)
return content

Expand Down Expand Up @@ -95,7 +122,7 @@ def frictionless_spec(
columns=["fullpath", "fullpath_schema", "path", "schema", "name"]
).reset_index()
spec_df["name"] = spec_df["name"].apply(
lambda x: f"[`{x}`](tables.md#{x})".replace("_","-")
lambda x: f"[`{x}`](tables.md#{x})".replace("_", "-")
)

return spec_df.to_markdown(index=False)
Expand Down Expand Up @@ -133,6 +160,49 @@ def frictionless_schemas(
TABLE_TYPES = ["Event", "Summary", "Supporting"]


def datapackage_to_row(dir: str, fields: list) -> str:
"""Reads datapackage and translates key metadata to a row in a markdown table.

Right now, only works for fields: "Sample", "Agency", "Resources", "Vendors"

Args:
dir (str): fully qualified directory for sample data
fields (list): list of fields to return

Returns:
str: row in a markdown table with name, agency, resources, vendors
"""
dp_filename = os.path.join(dir, "datapackage.json")
if not os.path.isfile(dp_filename):
raise ValueError(f"Can't find datapackage file:\n {dp_filename}.")
with open(dp_filename, "r") as dp_file:
dp = json.loads(dp_file.read())

_vendors = [
s.get("vendor", None) for r in dp["resources"] for s in r.get("sources", [])
]
_vendors = list(set(_vendors) - set([None]))

_md_cells = {
"Sample": _to_sample_readme_link(dp["name"], dir),
"Agency": dp["agency"],
"Resources": (
"<ul><li>`"
+ "`</li><li>`".join([r["name"] for r in dp["resources"]])
+ "`</li></ul>"
),
"Vendors": "<ul><li>`" + "`</li><li>`".join(_vendors) + "`</li></ul>",
}

md_row = "| " + " | ".join([_md_cells[f] for f in fields]) + " |\n"

return md_row


def _to_sample_readme_link(sample_name, folder_dir):
return f"[{sample_name.capitalize()}]({folder_dir}/README.md)"


def _document_frictionless_schema(schema_filename: str) -> dict:
"""Documents a single frictionless schema.

Expand Down
12 changes: 12 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,19 @@ plugins:
theme: |
^(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) ? 'dark' : 'light'
securityLevel: 'loose'
- mike:
version_selector: true
- redirects:
redirect_maps: #original relative to /docs : redirect target
'../CODE_OF_CONDUCT.md': 'CODE_OF_CONDUCT.md'
'../CONTRIBUTING.md': 'CONTRIBUTING.md'
'../contributors.md': 'contributors.md'
- search

extra:
version:
provider: mike

watch:
- CONTRIBUTING.md
- CODE_OF_CONDUCT.md
Expand Down Expand Up @@ -72,4 +83,5 @@ nav:
- Home: index.md
- Architecture: architecture.md
- Table Schemas: tables.md
- Sample Data: samples.md
- Development: development.md
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
-r docs/requirements.txt
pre-commit
-r docs/requirements.txt
76 changes: 76 additions & 0 deletions samples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Data Directory Organization

Each TIDES Data Package example should follow the following directory structure, consistent with the structure of the [Frictionless Data Package specification](https://specs.frictionlessdata.io/data-package/), including:

```
unique-example-name
\TIDES # Required. Data to be validated against the TIDES specification
\datapackage.json # Required. Data package metadata per https://specs.frictionlessdata.io/data-package/
\raw # Optional. Data which the agency uses to create TIDES data
\scripts # Optional. Scripts used to transform raw --> TIDES
```

## Adding Examples

We encourage the addition of examples, but please follow the following guidelines:

1. *No large files* This isn't the place to store your data, rather to document some minimal examples. The recommended size is 100-1000 records per file, more if absolutely required to reproduce an issue with the spec. All individual files should be well under 50 MB.
2. *Include Metadata* as specified in [`datapackage.json`](#data-package).
3. *Include a README.md* in the base folder of your example with an overview so that it can be included in the documentation.

## Data Package

TIDES data packages must include a [`datapackage.json`](https://specs.frictionlessdata.io/data-package/). Key information to include in [`datapackage.json`](https://specs.frictionlessdata.io/data-package/) includes:

| **Field** | **Description** | **Required** |
| --------- | --------------- | ------------ |
| `title` | A human-readable title. | Required |
| `name` | Identifier string as a URL-friendly slug. | Required |
| `description` | Short description of data package. | Recommended |
| `agency` | Transit agency name. | Recommended |
| `ntd_id` | ID for the National Transit Database. | Recommended |
| `profile` | Should be `tabular-data-package` | Required |
| `licenses` | Should be `[{"name": "Apache-2.0"}]` to be consistent with this repository | Required |
| `contributors` | Array of data contributors `[{"title": "My Name", "github": "my_handle", "email": "me@myself.com"}]` | Recommended |
| `maintainers` | Array of data maintainers `[{"title": "My Name", "github": "my_handle", "email": "me@myself.com"}]` | Recommended |
| `resources` | Array of data files included in your package, formated as a [`tabular-data-resource`](#data-resource)| Required |

### Data Resource

Key fields for each [`tabular-data-resource`](https://specs.frictionlessdata.io/tabular-data-resource/) are as follows:

| **Field** | **Description** | **Required** |
| --------- | --------------- | ------------ |
| `name` | Short sluggable name used to refer to data in this file. | Required |
| `path` | Path of the data resource file relative to the `datapackage.json` | Required |
| `schema` | Data schema to use to valdiate the data resource to | Required |
| `sources` | Array of data sources formatted as a [`source`](#data-source) | Recommended |

### Data Source

| **Field** | **Description** | **Required** |
| --------- | --------------- | ------------ |
| `title` | Description of the data source. | Required |
| `component` | What technology component was used to generate this data (directly or indirectly)? Examples include `AVL`, `APC`, `AFC`, etc. | Recommended |
| `product` | What product was used to generate this data (directly or indirectly)? | Recommended |
| `vendor` | What company makes this product? | Recommended |

## Data validation

Data with a valid [`datapackage.json`](#data-package) can be easily validated using the [frictionless framework](https://framework.frictionlessdata.io/), which can be installed and invoke as follows:

```bash
pip install frictionless
frictionless validate path/to/your/datapackage.json
```

### Specific files

Specific files can be validated by running the frictionless framework against them and their corresponding schemas as follows:

```sh
frictionless validate vehicles.csv --schema https://raw.githubusercontent.com/TIDES-transit/TIDES/main/spec/vehicles.schema.json
```
### Continuous Data Validation

Example data in the `\TIDES` subdirectories is validated upon a push action to the main repository according to the `TIDES` schema posted to the `main` branch.