Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #1610 unexpected field-error related to a well-formatted value example of a schema's boolean field using frictionless validate #1615

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4833b85
TDD: Add test cases for boolean field
amelie-rondot Jan 4, 2024
581279b
TDD: tests passe: fix Field with boolean type creation from descripto…
amelie-rondot Jan 5, 2024
17f74c1
TDD: Add test cases for boolean field customised with 'trueValues' an…
amelie-rondot Jan 5, 2024
7aa1cde
TDD: test pass, fix BooleanField creation from a schema descriptor to…
amelie-rondot Jan 5, 2024
e1c5965
Refactoring
amelie-rondot Jan 5, 2024
e77e416
Add many test cases for test boolean field from schema descriptor rea…
amelie-rondot Jan 5, 2024
a93c035
Fix test cases to expected behavior
amelie-rondot Jan 15, 2024
c539d67
Fix failed tests
amelie-rondot Jan 15, 2024
7107b8d
TDD: add test case to fix example value in boolean field with customi…
amelie-rondot Jan 15, 2024
3c7cd54
TDD: test passes: edit 'field.true_values' and 'field.false_values' t…
amelie-rondot Jan 16, 2024
e26d533
Refacto: sort and remove useless imports
amelie-rondot Jan 16, 2024
8e7c1f9
Refacto: factorize test cases
amelie-rondot Jan 16, 2024
0e0aa0e
Refacto and add test cases corresponding to issue 1610
amelie-rondot Jan 16, 2024
151c81f
Add test case for invalid value example in schema descriptor to fix i…
amelie-rondot Jan 16, 2024
9e08f2d
Refacto: reformat file
amelie-rondot Jan 16, 2024
cdea802
Linting: lint and format files
amelie-rondot Jan 25, 2024
07eefdc
Refacto: rmove useless lines
amelie-rondot Jan 29, 2024
c2b8faf
Refacto: remove useless lines 2
amelie-rondot Jan 29, 2024
a7a01b4
🔵 typo
pierrecamilleri Apr 23, 2024
42b14fa
fix: from_descriptor not possible
pierrecamilleri May 3, 2024
f127067
fix: lint
pierrecamilleri Aug 30, 2024
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
64 changes: 62 additions & 2 deletions frictionless/fields/__spec__/test_boolean.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import pytest

from frictionless import Field
from frictionless import Field, Schema
from frictionless.errors.metadata import SchemaError
from frictionless.exception import FrictionlessException

# General

Expand Down Expand Up @@ -32,12 +34,70 @@
("default", "3.14", None, {}),
("default", "", None, {}),
("default", "Yes", None, {"trueValues": ["yes"]}),
("default", "true", None, {"trueValues": ["yes"]}),
("default", "True", None, {"trueValues": ["yes"]}),
("default", "TRUE", None, {"trueValues": ["yes"]}),
("default", "1", None, {"trueValues": ["yes"]}),
("default", "No", None, {"falseValues": ["no"]}),
("default", "false", None, {"falseValues": ["no"]}),
("default", "False", None, {"falseValues": ["no"]}),
("default", "FALSE", None, {"falseValues": ["no"]}),
("default", "0", None, {"falseValues": ["no"]}),
],
)
def test_boolean_read_cell(format, source, target, options):
descriptor = {"name": "name", "type": "boolean", "format": format}
descriptor.update(options)
field = Field.from_descriptor(descriptor)
cell, notes = field.read_cell(source)
cell, _ = field.read_cell(source)
assert cell == target

schema_descriptor = {"fields": [{"name": "IsTrue", "type": "boolean"}]}
schema_descriptor["fields"][0].update(options)
schema = Schema.from_descriptor(schema_descriptor)
fields = schema.fields
cell, _ = fields[0].read_cell(source)
assert cell == target


@pytest.mark.parametrize(
"source, target, options",
[
(True, True, {"trueValues": ["yes"], "example": "yes"}),
("yes", True, {"trueValues": ["yes"], "example": "yes"}),
("true", None, {"trueValues": ["yes"], "example": "yes"}),
(False, False, {"falseValues": ["no"], "example": "no"}),
("no", False, {"falseValues": ["no"], "example": "no"}),
("false", None, {"falseValues": ["no"], "example": "no"}),
],
)
def test_boolean_from_schema_descriptor_with_valid_example_fix_issue_1610(
source, target, options
):
schema_descriptor = {
"$schema": "https://frictionlessdata.io/schemas/table-schema.json",
"fields": [{"name": "IsTrue", "type": "boolean"}],
}
schema_descriptor["fields"][0].update(options)
schema = Schema.from_descriptor(schema_descriptor)
fields = schema.fields
cell, _ = fields[0].read_cell(source)
assert cell == target


def test_boolean_from_schema_descriptor_with_invalid_example_fix_issue_1610():
schema_descriptor = {
"$schema": "https://frictionlessdata.io/schemas/table-schema.json",
"fields": [
{
"name": "IsTrue",
"type": "boolean",
"falseValues": ["no"],
"example": "invalid",
}
],
}
with pytest.raises(FrictionlessException) as excinfo:
Schema.from_descriptor(schema_descriptor)
err = excinfo.value.error
assert isinstance(err, SchemaError)
20 changes: 16 additions & 4 deletions frictionless/schema/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ class Field(Metadata):
For example: "default","array" etc.
"""

missing_values: List[str] = attrs.field(factory=settings.DEFAULT_MISSING_VALUES.copy)
missing_values: List[str] = attrs.field(
factory=settings.DEFAULT_MISSING_VALUES.copy
)
"""
List of string values to be set as missing values in the field. If any of string in missing values
is found in the field value then it is set as None.
Expand Down Expand Up @@ -260,13 +262,23 @@ def metadata_validate(cls, descriptor: IDescriptor): # type: ignore
if example:
type = descriptor.get("type")
Class = system.select_field_class(type)

field = Class(
pdelboca marked this conversation as resolved.
Show resolved Hide resolved
name=descriptor.get("name", "example"),
format=descriptor.get("format", "default"), # type: ignore
name=descriptor.get("name"), # type: ignore
format=descriptor.get("format", "default"),
)

if type == "boolean":
# 'example' value must be compared to customized 'trueValues' and 'falseValues'
if "trueValues" in descriptor.keys():
field.true_values = descriptor["trueValues"]
if "falseValues" in descriptor.keys():
field.false_values = descriptor["falseValues"]
_, notes = field.read_cell(example)
if notes is not None:
note = f'example value "{example}" for field "{field.name}" is not valid'
note = (
f'example value "{example}" for field "{field.name}" is not valid'
)
yield errors.FieldError(note=note)

# Misleading
Expand Down
Loading