Skip to content
This repository was archived by the owner on Sep 27, 2024. It is now read-only.

Commit 95ef1b3

Browse files
authored
Make TensorFlow dependencies optional (#275)
1 parent a5ff5df commit 95ef1b3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2158
-1643
lines changed

.github/workflows/ci.yml

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ jobs:
2828
ci:
2929
runs-on: ubuntu-latest
3030
timeout-minutes: 60
31+
strategy:
32+
matrix:
33+
name: [base, all]
34+
include:
35+
- name: base
36+
dependencies: test
37+
tests: model_card_toolkit --ignore-requires-optional-deps
38+
- name: all
39+
dependencies: all
40+
tests: model_card_toolkit --fail-if-skipped
3141

3242
steps:
3343
- uses: actions/checkout@v2
@@ -41,12 +51,12 @@ jobs:
4151
# Cache pip
4252
path: ~/.cache/pip
4353
# Check the cache for a given setup.py + MCT version
44-
key: ${{ runner.os }}-pip-${{ hashFiles('model_card_toolkit/version.py') }}
54+
key: ${{ runner.os }}-pip-${{ matrix.name }}-${{ hashFiles('model_card_toolkit/version.py') }}
4555
restore-keys: |
4656
${{ runner.os }}-pip
4757
- name: Install dependencies
4858
run: |
4959
python -m pip install --upgrade pip wheel
50-
python -m pip install -e ".[test]"
60+
python -m pip install -e ".[${{ matrix.dependencies }}]"
5161
- name: Run tests
52-
run: pytest model_card_toolkit
62+
run: pytest ${{ matrix.tests }}

CODEOWNERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88

99
# PyPI distribution files (Core members)
1010
/model_card_toolkit/__init__.py @rcrowe-google @casassg @hanneshapke @codesue @ahmed-bd @deutranium
11+
/model_card_toolkit/dependencies.py @rcrowe-google @casassg @hanneshapke @codesue @ahmed-bd @deutranium
1112
/model_card_toolkit/version.py @rcrowe-google @casassg @hanneshapke @codesue @ahmed-bd @deutranium
1213
/package_build/ @rcrowe-google @casassg @hanneshapke @codesue @ahmed-bd @deutranium
14+
/proto_build/ @rcrowe-google @casassg @hanneshapke @codesue @ahmed-bd @deutranium
1315
/setup.py @rcrowe-google @casassg @hanneshapke @codesue @ahmed-bd @deutranium
1416
/WORKSPACE @rcrowe-google @casassg @hanneshapke @codesue @ahmed-bd @deutranium
1517
/RELEASE.md @rcrowe-google @casassg @hanneshapke @codesue @ahmed-bd @deutranium

CONTRIBUTING.md

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,14 @@ Follow these steps to install `model-card-toolkit`:
102102
pip install --upgrade pip
103103
```
104104

105-
5. Install the `model-card-toolkit` development package in editable mode:
105+
5. Install the `model-card-toolkit[all]` development package in editable mode:
106+
107+
```sh
108+
pip install -e ".[all]"
109+
```
110+
111+
If you only plan to make changes to parts of the codebase that don't require
112+
optional dependencies, you may install `model-card-toolkit[test]` instead.
106113

107114
```sh
108115
pip install -e ".[test]"
@@ -119,7 +126,7 @@ automatically invoked once when you first install `model-card-toolkit` in
119126
editable mode, but further stub generation requires manual invocation.
120127

121128
```sh
122-
bazel run //model_card_toolkit:move_generated_files
129+
bazel run //proto_build:move_generated_files
123130
```
124131

125132
### Licenses
@@ -142,14 +149,11 @@ with indentation width of 2 spaces.
142149

143150
### Linting your code
144151

145-
Please check your code for linting errors before submitting your PR for review. Pull requests are lint checked using `pre-commit` and `pylint`.
146-
If you want to run the [`pre-commit`](https://pre-commit.com/) checks locally, please install
152+
Please check your code for linting errors before submitting your pull request for review.
153+
Pull requests are lint checked using [`pre-commit`](https://pre-commit.com/) and `pylint`.
154+
If you want to run the `pre-commit` checks locally, run following command
155+
from your local project directory:
147156

148-
```sh
149-
pip install pre-commit
150-
```
151-
152-
When you have `pre-commit` installed, you can run follow command from your local project folder to check for linting errors.
153157
```sh
154158
pre-commit run --all-files
155159
```
@@ -167,6 +171,12 @@ test coverage.
167171
In general, all Python files have at least one corresponding test file. For example,
168172
`awesome.py` should have a corresponding `awesome_test.py`.
169173

174+
If a test suite requires an optional dependency, check [conftest.py](conftest.py)
175+
to verify if it can be automatically ignored with `--ignore-requires-optional-deps`
176+
based on its file pattern. If it can't be automatically ignored, either update
177+
the list of patterns to ignore in `conftest.py` or mark the tests to be skipped
178+
if the dependency is not installed.
179+
170180
#### Running unit tests
171181

172182
To run a specific test suite, e.g. `ModelCardTest`, run its test file:
@@ -175,12 +185,28 @@ To run a specific test suite, e.g. `ModelCardTest`, run its test file:
175185
pytest model_card_toolkit/model_card_test.py
176186
```
177187

178-
Use the following command to run all unit tests:
188+
To run all tests, run:
179189

180190
```sh
181191
pytest model_card_toolkit
182192
```
183193

194+
Use the following command to skip tests that require optional dependencies:
195+
196+
```sh
197+
pytest model_card_toolkit --ignore-requires-optional-deps
198+
```
199+
200+
Use the following command to fail skipped tests:
201+
202+
```sh
203+
pytest model_card_toolkit --fail-if-skipped
204+
```
205+
206+
In general, tests are marked as `skip` if they require optional dependencies
207+
that aren't installed. Failing skipped tests let us catch when tests are skipped
208+
even though all optional dependencies are installed.
209+
184210
## Being a Code Owner
185211

186212
Code owners are automatically requested for review when someone opens a pull

README.md

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
# Model Card Toolkit
22

3-
The Model Card Toolkit (MCT) streamlines and automates generation of [Model Cards](https://modelcards.withgoogle.com/about) [1], machine learning documents that provide context and transparency into a model's development and performance. Integrating the MCT into your ML pipeline enables the sharing model metadata and metrics with researchers, developers, reporters, and more.
3+
[![CI][ci_badge]][ci_link]
4+
[![PyPI][pypi_badge]][pypi_link]
5+
[![Documentation][docs_badge]][docs_link]
6+
7+
The Model Card Toolkit (MCT) streamlines and automates generation of
8+
[Model Cards](https://modelcards.withgoogle.com/about) [1], machine learning documents
9+
that provide context and transparency into a model's development and performance.
10+
Integrating the MCT into your ML pipeline enables you to share model metadata and
11+
metrics with researchers, developers, reporters, and more.
412

513
Some use cases of model cards include:
614

@@ -12,8 +20,27 @@ Some use cases of model cards include:
1220

1321
## Installation
1422

15-
The Model Card Toolkit is hosted on [PyPI](https://pypi.org/project/model-card-toolkit/), and can be installed with `pip install model-card-toolkit` (or `pip install model-card-toolkit
16-
--use-deprecated=legacy-resolver` for versions of pip starting with 20.3). See [the installation guide](model_card_toolkit/documentation/guide/install.md) for more details.
23+
The Model Card Toolkit is hosted on [PyPI](https://pypi.org/project/model-card-toolkit/),
24+
and requires Python 3.7 or later.
25+
26+
Installing the basic, framework agnostic package:
27+
28+
```sh
29+
pip install model-card-toolkit
30+
```
31+
32+
If you are generating model cards for TensorFlow models, install the optional
33+
TensorFlow dependencies to use Model Card Toolkit's TensorFlow utilities:
34+
35+
```sh
36+
pip install model-card-toolkit[tensorflow]
37+
```
38+
39+
You may need to append the `--use-deprecated=legacy-resolver` flag when running
40+
versions of pip starting with 20.3.
41+
42+
See [the installation guide](model_card_toolkit/documentation/guide/install.md)
43+
for more installation options.
1744

1845
## Getting Started
1946

@@ -39,22 +66,34 @@ If you are using [TensorFlow Extended (TFX)](https://www.tensorflow.org/tfx), yo
3966
incorporate model card generation into your TFX pipeline via the `ModelCardGenerator`
4067
component.
4168

42-
The `ModelCardGenerator` component is moving to the
43-
[TFX Addons](https://github.com/tensorflow/tfx-addons) library and will no longer
44-
be packaged in Model Card Toolkit from version 2.0.0. Before you can use the
69+
The `ModelCardGenerator` component has moved to the
70+
[TFX Addons](https://github.com/tensorflow/tfx-addons) library and is no longer
71+
packaged in Model Card Toolkit from version 2.0.0. Before you can use the
4572
component, you will need to install the `tfx-addons` package:
4673

4774
```sh
4875
pip install tfx-addons[model_card_generator]
4976
```
5077

51-
This page will be updated to include the new links for the Model Cards in TFX
52-
guide and the end-to-end demo when the migration is completed.
78+
See the [ModelCardGenerator guide](https://github.com/tensorflow/tfx-addons/blob/main/tfx_addons/model_card_generator/README.md)
79+
and run the [case study notebook](https://github.com/tensorflow/tfx-addons/blob/main/examples/model_card_generator/MLMD_Model_Card_Toolkit_Demo.ipynb)
80+
to learn more about the component.
5381

5482
## Schema
5583

56-
Model cards are stored in proto as an intermediate format. You can see the model card JSON schema in the `schema` directory.
84+
Model cards are stored in proto as an intermediate format. You can see the model
85+
card JSON schema in the `schema` directory.
5786

5887
## References
5988

6089
[1] https://arxiv.org/abs/1810.03993
90+
91+
92+
[ci_badge]: https://github.com/tensorflow/model-card-toolkit/actions/workflows/ci.yml/badge.svg
93+
[ci_link]: https://github.com/tensorflow/model-card-toolkit/actions/workflows/ci.yml
94+
95+
[pypi_badge]: https://badge.fury.io/py/model-card-toolkit.svg
96+
[pypi_link]: https://badge.fury.io/py/model-card-toolkit
97+
98+
[docs_badge]: https://img.shields.io/badge/TensorFow-page-orange
99+
[docs_link]: https://www.tensorflow.org/responsible_ai/model_card_toolkit/guide

conftest.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Copyright 2023 The TensorFlow Authors. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
# ==============================================================================
15+
"""Pytest configuration."""
16+
17+
import fnmatch
18+
import pathlib
19+
20+
import pytest
21+
22+
_REQUIRES_OPTIONAL_DEPS = ['**/tf_*_test.py']
23+
24+
25+
# Adapted from pytest-error-for-skips
26+
# https://github.com/jankatins/pytest-error-for-skips/blob/2.0.0/pytest_error_for_skips.py
27+
@pytest.hookimpl(hookwrapper=True)
28+
def pytest_runtest_makereport(item: pytest.Item, call: pytest.CallInfo[None]):
29+
"""Hook to treat skipped tests as failures."""
30+
outcome = yield
31+
rep = outcome.get_result()
32+
33+
if item.config.getoption('--fail-if-skipped'):
34+
if rep.skipped and call.excinfo.errisinstance(pytest.skip.Exception):
35+
rep.outcome = 'failed'
36+
r = call.excinfo._getreprcrash()
37+
rep.longrepr = f'Fail skipped tests - {r.message}'
38+
39+
40+
@pytest.hookimpl(hookwrapper=True)
41+
def pytest_ignore_collect(
42+
collection_path: pathlib.Path, config: pytest.Config
43+
):
44+
"""Hook to ignore tests that require optional dependencies."""
45+
outcome = yield
46+
if config.getoption('--ignore-requires-optional-deps'):
47+
if any(
48+
fnmatch.fnmatch(str(collection_path), pattern)
49+
for pattern in _REQUIRES_OPTIONAL_DEPS
50+
):
51+
outcome.force_result(True)
52+
53+
54+
def pytest_addoption(parser: pytest.Parser):
55+
parser.addoption(
56+
'--fail-if-skipped', action='store_true', default=False,
57+
help='Treat skipped tests as failures.'
58+
)
59+
60+
parser.addoption(
61+
'--ignore-requires-optional-deps', action='store_true', default=False,
62+
help='Ignore tests that require optional dependencies.'
63+
)

model_card_toolkit/__init__.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,39 @@
1313
# limitations under the License.
1414
"""A module to streamline and automate generation of Model Cards."""
1515
from model_card_toolkit.core import ModelCardToolkit
16-
from model_card_toolkit.model_card import *
16+
from model_card_toolkit.model_card import (
17+
Citation, ConfidenceInterval, Considerations, Dataset, Graphic,
18+
GraphicsCollection, KeyVal, License, Limitation, ModelCard, ModelDetails,
19+
ModelParameters, Owner, PerformanceMetric, QuantitativeAnalysis, Reference,
20+
Risk, SensitiveData, Tradeoff, UseCase, User, Version
21+
)
1722
from model_card_toolkit.tfx.component import ModelCardGenerator
18-
from model_card_toolkit.utils.source import *
1923
from model_card_toolkit.version import __version__
24+
25+
__all__ = [
26+
'__version__',
27+
'Citation',
28+
'ConfidenceInterval',
29+
'Considerations',
30+
'Dataset',
31+
'Graphic',
32+
'GraphicsCollection',
33+
'KeyVal',
34+
'License',
35+
'Limitation',
36+
'ModelCard',
37+
'ModelCardGenerator',
38+
'ModelCardToolkit',
39+
'ModelDetails',
40+
'ModelParameters',
41+
'Owner',
42+
'PerformanceMetric',
43+
'QuantitativeAnalysis',
44+
'Reference',
45+
'Risk',
46+
'SensitiveData',
47+
'Tradeoff',
48+
'UseCase',
49+
'User',
50+
'Version',
51+
]

model_card_toolkit/base_model_card_field.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
from google.protobuf import descriptor, message
2626

27-
from model_card_toolkit.utils import validation
27+
from model_card_toolkit.utils import json_utils
2828

2929

3030
class BaseModelCardField(abc.ABC):
@@ -102,8 +102,9 @@ def _from_proto(self, proto: message.Message) -> "BaseModelCardField":
102102
setattr(self, field_name, [])
103103
for p in getattr(proto, field_name):
104104
# To get the type hint of a list is not easy.
105-
field = \
106-
self.__annotations__[field_name].__args__[0]() # pytype: disable=attribute-error
105+
field = (
106+
self.__annotations__[field_name].__args__[0]() # pytype: disable=attribute-error
107+
)
107108
field._from_proto(p) # pylint: disable=protected-access
108109
getattr(self, field_name).append(field)
109110

@@ -136,7 +137,7 @@ def _from_json(
136137
) -> "BaseModelCardField":
137138
"""Parses a JSON dictionary into the current object."""
138139
for subfield_key, subfield_json_value in json_dict.items():
139-
if subfield_key.startswith(validation.SCHEMA_VERSION_STRING):
140+
if subfield_key.startswith(json_utils.SCHEMA_VERSION_STRING):
140141
continue
141142
elif not hasattr(field, subfield_key):
142143
raise ValueError(
@@ -151,8 +152,9 @@ def _from_json(
151152
subfield_value = []
152153
for item in subfield_json_value:
153154
if isinstance(item, dict):
154-
new_object = \
155-
field.__annotations__[subfield_key].__args__[0]() # pytype: disable=attribute-error
155+
new_object = (
156+
field.__annotations__[subfield_key].__args__[0]() # pytype: disable=attribute-error
157+
)
156158
subfield_value.append(self._from_json(item, new_object))
157159
else: # if primitive
158160
subfield_value.append(item)

0 commit comments

Comments
 (0)