Repository: samuelcolvin/pydantic
Pull request #3112 (2021-08-18 06:54:30)

fix int_validator not catching overflows
<!-- Thank you for your contribution! -->
<!-- Unless your change is trivial, please create an issue to discuss the change before creating a PR -->
<!-- See https://pydantic-docs.helpmanual.io/contributing/ for help on Contributing -->

## Change Summary

`int(value)` can raise an `OverflowError`, for example when called with very large floats.

<!-- Please give a short summary of the changes. -->

## Related issue number

#2345 

<!-- Are there any issues opened that will be resolved by merging this change? -->

## Checklist

* [x] Unit tests for the changes exist
* [ ] Tests pass on CI and coverage remains at 100%
* [ ] Documentation reflects the changes where applicable
* [x] `changes/<pull request or issue id>-<github username>.md` file added describing change
  (see [changes/README.md](https://github.com/samuelcolvin/pydantic/blob/master/changes/README.md) for details)
* [x] My PR is ready to review, **please add a comment including the phrase "please review" to assign reviewers**


ojii: please review
PrettyWood: I reckon it would be better to catch the `OverflowError` in a separate `except` clause with a more explicit error. We could probably do the exact same for `float`
ojii: > I reckon it would be better to catch the `OverflowError` in a separate `except` clause with a more explicit error. 

Sorry, first time contributing to pydantic. Does that mean just changing the `msg` or the `type` of the error? If the latter, is there a way type codes are chosen?

samuelcolvin: please update.
ojii: > This is looking good, just a few things to fix and more test cases to add.

@samuelcolvin i've added more test cases, do you think the error code/msg should be handled different? If so, how are new messages/codes decided?
samuelcolvin: At this stage, breast if you can roughly follow the code from pydantic-core to minimize the incompatibility with v2.
samuelcolvin: https://github.com/samuelcolvin/pydantic-core/blob/fdf42b8b0d0684bc2cac04d34c40fe4b0d33498d/tests/validators/test_int.py#L207
ojii: Since the structure of the error dict is different between v1 and v2 anyway, does it make sense trying to make it v2-like? I feel making it fit in with the rest of v1 makes more sense (eg in v1, error codes seem to always be prefixed with `type_error.` or `value_error.` but in v2 not?)
samuelcolvin: Yes, that's what I meant by roughly follow, e.g. use `value_error.int_nan`?
ojii: > Yes, that's what I meant by roughly follow, e.g. use `value_error.int_nan`?

When I change it to that, interestingly enough `float('nan')` gets caught in the already existing exceptions (`ValueError`). This proposed change (catching `OverflowError`) only catches `float('inf')` or other huge floats, so `int_nan` is probably not the right thing here.
samuelcolvin: Good catch, thanks so much for the PR.

Patch:
diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md
deleted file mode 100644
index b87a10e70..000000000
--- a/.github/ISSUE_TEMPLATE/bug.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: Bug
-about: Create a bug report to help us improve pydantic
-labels: bug
----
-
-### Checks
-
-* [ ] I added a descriptive title to this issue
-* [ ] I have searched (google, github) for similar issues and couldn't find anything
-* [ ] I have read and followed [the docs](https://pydantic-docs.helpmanual.io/) and still think this is a bug
-
-<!-- Sorry to sound so draconian, but every second saved replying to issues is time spend improving pydantic :-) -->
-
-# Bug
-
-Output of `python -c "import pydantic.utils; print(pydantic.utils.version_info())"`:
-```
-...
-```
-<!-- or if you're using pydantic prior to v1.3, manually include: OS, python version and pydantic version -->
-
-<!-- Please read the [docs](https://pydantic-docs.helpmanual.io/) and search through issues to
-confirm your bug hasn't already been reported. -->
-
-<!-- Where possible please include a self-contained code snippet describing your bug: -->
-
-```py
-import pydantic
-
-...
-```
diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml
new file mode 100644
index 000000000..a5e9350a0
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug.yml
@@ -0,0 +1,92 @@
+name: 🐛 Bug
+description: Report a bug or unexpected behavior in pydantic
+labels: [bug, unconfirmed]
+
+body:
+  - type: markdown
+    attributes:
+      value:  Thank you for contributing to pydantic! ✊
+
+  - type: checkboxes
+    id: checks
+    attributes:
+      label: Initial Checks
+      description: |
+        Just a few checks to make sure you need to create a bug report.
+        
+        _Sorry to sound so draconian 👿; but every second spent replying to issues is time not spent improving pydantic 🙇._
+      options:
+        - label: I have searched GitHub for a duplicate issue and I'm sure this is something new
+          required: true
+        - label: I have searched Google & StackOverflow for a solution and couldn't find anything
+          required: true
+        - label: I have read and followed [the docs](https://pydantic-docs.helpmanual.io) and still think this is a bug
+          required: true
+        - label: >
+            I am confident that the issue is with pydantic 
+            (not my code, or another library in the ecosystem like [FastAPI](https://fastapi.tiangolo.com) or
+            [mypy](https://mypy.readthedocs.io/en/stable))
+          required: true
+
+  - type: textarea
+    id: description
+    attributes:
+      label: Description
+      description: |
+        Please explain what you're seeing and what you would expect to see.
+
+        Please provide as much detail as possible to make understanding and solving your problem as quick as possible. 🙏
+    validations:
+      required: true
+
+  - type: textarea
+    id: example
+    attributes:
+      label: Example Code
+      description: >
+        If applicable, please add a self-contained,
+        [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example)
+        demonstrating the bug.
+
+      placeholder: |
+        import pydantic
+
+        ...
+      render: Python
+
+  - type: textarea
+    id: version
+    attributes:
+      label: Python, Pydantic & OS Version
+      description: |
+        Which version of Python & Pydantic are you using, and which Operating System?
+        
+        Please run the following command and copy the output below:
+
+        ```bash
+        python -c "import pydantic.utils; print(pydantic.utils.version_info())"
+        ```
+
+      render: Text
+    validations:
+      required: true
+
+  - type: checkboxes
+    id: affected-components
+    attributes:
+      label: Affected Components
+      description: Which of the following parts of pydantic does this bug affect?
+      # keep this lis in sync with feature_request.yml
+      options:
+        - label: '[Compatibility between releases](https://pydantic-docs.helpmanual.io/changelog/)'
+        - label: '[Data validation/parsing](https://pydantic-docs.helpmanual.io/usage/models/#basic-model-usage)'
+        - label: '[Data serialization](https://pydantic-docs.helpmanual.io/usage/exporting_models/) - `.dict()` and `.json()`'
+        - label: '[JSON Schema](https://pydantic-docs.helpmanual.io/usage/schema/)'
+        - label: '[Dataclasses](https://pydantic-docs.helpmanual.io/usage/dataclasses/)'
+        - label: '[Model Config](https://pydantic-docs.helpmanual.io/usage/model_config/)'
+        - label: '[Field Types](https://pydantic-docs.helpmanual.io/usage/types/) - adding or changing a particular data type'
+        - label: '[Function validation decorator](https://pydantic-docs.helpmanual.io/usage/validation_decorator/)'
+        - label: '[Generic Models](https://pydantic-docs.helpmanual.io/usage/models/#generic-models)'
+        - label: '[Other Model behaviour](https://pydantic-docs.helpmanual.io/usage/models/) - `construct()`, pickling, private attributes, ORM mode'
+        - label: '[Settings Management](https://pydantic-docs.helpmanual.io/usage/settings/)'
+        - label: '[Plugins](https://pydantic-docs.helpmanual.io/) and integration with other tools - mypy, FastAPI, python-devtools, Hypothesis, VS Code, PyCharm, etc.'
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index bf1982bfa..f498e4e2b 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -1,11 +1,5 @@
 blank_issues_enabled: true
 contact_links:
-- name: Question
-  url: 'https://github.com/samuelcolvin/pydantic/discussions/new?category=question'
-  about: Ask a question about how to use pydantic using github discussions
-
-- name: Feature Request
-  url: 'https://github.com/samuelcolvin/pydantic/discussions/new?category=feature-request'
-  about: >
-    If you think we should add a new feature to pydantic, please start a discussion, once it attracts
-    wider support, it can be migrated to an issue
+  - name: 🤔 Ask a Question
+    url: 'https://github.com/samuelcolvin/pydantic/discussions/new?category=question'
+    about: Ask a question about how to use pydantic using github discussions
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 000000000..26273cbf4
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,56 @@
+name: 🚀 Feature request
+description: Suggest a new feature or change to pydantic
+labels: [feature request]
+
+body:
+  - type: markdown
+    attributes:
+      value: Thank you for contributing to pydantic! ✊
+
+  - type: checkboxes
+    id: searched
+    attributes:
+      label: Initial Checks
+      description: |
+        Just a few checks to make sure you need to create a feature request.
+        
+        _Sorry to sound so draconian 👿; but every second spent replying to issues is time not spent improving pydantic 🙇._
+      options:
+        - label: I have searched Google & GitHub for similar requests and couldn't find anything
+          required: true
+        - label: I have read and followed [the docs](https://pydantic-docs.helpmanual.io) and still think this feature is missing
+          required: true
+
+  - type: textarea
+    id: description
+    attributes:
+      label: Description
+      description: |
+        Please give as much detail as possible about the feature you would like to suggest. 🙏
+        
+        You might like to add:
+        * A demo of how code might look when using the feature
+        * Your use case(s) for the feature
+        * Why the feature should be added to pydantic (as opposed to another library or just implemented in your code)
+    validations:
+      required: true
+
+  - type: checkboxes
+    id: affected-components
+    attributes:
+      label: Affected Components
+      description: Which of the following parts of pydantic does this feature affect?
+      # keep this lis in sync with bug.yml
+      options:
+        - label: '[Compatibility between releases](https://pydantic-docs.helpmanual.io/changelog/)'
+        - label: '[Data validation/parsing](https://pydantic-docs.helpmanual.io/usage/models/#basic-model-usage)'
+        - label: '[Data serialization](https://pydantic-docs.helpmanual.io/usage/exporting_models/) - `.dict()` and `.json()`'
+        - label: '[JSON Schema](https://pydantic-docs.helpmanual.io/usage/schema/)'
+        - label: '[Dataclasses](https://pydantic-docs.helpmanual.io/usage/dataclasses/)'
+        - label: '[Model Config](https://pydantic-docs.helpmanual.io/usage/model_config/)'
+        - label: '[Field Types](https://pydantic-docs.helpmanual.io/usage/types/) - adding or changing a particular data type'
+        - label: '[Function validation decorator](https://pydantic-docs.helpmanual.io/usage/validation_decorator/)'
+        - label: '[Generic Models](https://pydantic-docs.helpmanual.io/usage/models/#generic-models)'
+        - label: '[Other Model behaviour](https://pydantic-docs.helpmanual.io/usage/models/) - `construct()`, pickling, private attributes, ORM mode'
+        - label: '[Settings Management](https://pydantic-docs.helpmanual.io/usage/settings/)'
+        - label: '[Plugins](https://pydantic-docs.helpmanual.io/) and integration with other tools - mypy, FastAPI, python-devtools, Hypothesis, VS Code, PyCharm, etc.'
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 998af3f76..508efd759 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,6 +1,7 @@
 <!-- Thank you for your contribution! -->
 <!-- Unless your change is trivial, please create an issue to discuss the change before creating a PR -->
 <!-- See https://pydantic-docs.helpmanual.io/contributing/ for help on Contributing -->
+<!-- PLEASE DO **NOT** put issue ids in the PR title! Instead, add a descriptive title and put ids in the body -->
 
 ## Change Summary
 
diff --git a/.gitignore b/.gitignore
index 55c223952..766bf1e03 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,3 +32,4 @@ pydantic/*.so
 /.ghtopdep_cache/
 /fastapi/
 /codecov.sh
+/worktrees/
diff --git a/changes/3112-ojii.md b/changes/3112-ojii.md
new file mode 100644
index 000000000..a4c6e144d
--- /dev/null
+++ b/changes/3112-ojii.md
@@ -0,0 +1,1 @@
+Catch overflow errors in `int_validator`
\ No newline at end of file
diff --git a/pydantic/validators.py b/pydantic/validators.py
index 2c6565802..897d1bb4a 100644
--- a/pydantic/validators.py
+++ b/pydantic/validators.py
@@ -125,7 +125,7 @@ def int_validator(v: Any) -> int:
 
     try:
         return int(v)
-    except (TypeError, ValueError):
+    except (TypeError, ValueError, OverflowError):
         raise errors.IntegerError()
 
 


Test patch:
diff --git a/tests/test_validators.py b/tests/test_validators.py
index f7d7016f1..e7007ad2a 100644
--- a/tests/test_validators.py
+++ b/tests/test_validators.py
@@ -43,6 +43,18 @@ def test_int_validation():
     assert Model(a=4.5).a == 4
 
 
+@pytest.mark.parametrize('value', [2.2250738585072011e308, float('nan'), float('inf')])
+def test_int_overflow_validation(value):
+    class Model(BaseModel):
+        a: int
+
+    with pytest.raises(ValidationError) as exc_info:
+        Model(a=value)
+    assert exc_info.value.errors() == [
+        {'loc': ('a',), 'msg': 'value is not a valid integer', 'type': 'type_error.integer'}
+    ]
+
+
 def test_frozenset_validation():
     class Model(BaseModel):
         a: frozenset