Repository: xncbf/rcs-pydantic (language: python)

Issue:
pydantic 2.0 migration



Discussion / hints:

Fix patch:
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 23b29b0..5fd06bf 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -17,7 +17,7 @@ jobs:
       - name: Set up Python
         uses: actions/setup-python@v2
         with:
-          python-version: "3.7"
+          python-version: "3.8"
       - uses: actions/cache@v2
         id: cache
         with:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index fa80cdd..377af8f 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,32 +1,26 @@
 repos:
-  - repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v4.3.0
-    hooks:
-      - id: check-yaml
-      - id: end-of-file-fixer
-      - id: trailing-whitespace
-  - repo: https://github.com/psf/black
-    rev: 22.6.0
-    hooks:
-      - id: black
-  - repo: https://github.com/pycqa/autoflake
-    rev: v1.4
-    hooks:
-      - id: autoflake
-        args:
-          - --in-place
-          - --remove-unused-variables
-          - --remove-all-unused-imports
-          - --expand-star-imports
-  - repo: https://github.com/pycqa/flake8
-    rev: 5.0.4
-    hooks:
-      - id: flake8
-        args: [--max-line-length=120]
-  - repo: https://github.com/pycqa/isort
-    rev: 5.10.1
-    hooks:
-      - id: isort
-        name: isort (python)
+- repo: https://github.com/charliermarsh/ruff-pre-commit
+  # Ruff version.
+  rev: 'v0.0.254'
+  hooks:
+    - id: ruff
+      args: [--fix, --exit-non-zero-on-fix]
+- repo: https://github.com/pre-commit/pre-commit-hooks
+  rev: v4.4.0
+  hooks:
+  - id: check-yaml
+    args: [--allow-multiple-documents]
+  - id: end-of-file-fixer
+  - id: trailing-whitespace
+- repo: https://github.com/psf/black
+  rev: 23.11.0
+  hooks:
+  - id: black
+    args: [--line-length=120]
+- repo: https://github.com/pycqa/isort
+  rev: 5.12.0
+  hooks:
+  - id: isort
+    name: isort (python)
 default_language_version:
-  python: python3.10
+  python: python3.11
diff --git a/README.md b/README.md
index 4e325e7..8fb1dc0 100644
--- a/README.md
+++ b/README.md
@@ -43,7 +43,7 @@ pip install rcs-pydantic
 
 ## Dependency
 
-- python3.x (3.7 이상)
+- python3.x (3.8 이상)
 - pydantic
 
 ## Quick start
diff --git a/poetry.lock b/poetry.lock
index c0231a4..f8af70e 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,74 +1,59 @@
 [[package]]
-name = "anyio"
-version = "3.6.1"
-description = "High level compatibility layer for multiple asynchronous event loop implementations"
-category = "dev"
+name = "annotated-types"
+version = "0.6.0"
+description = "Reusable constraint types to use with typing.Annotated"
+category = "main"
 optional = false
-python-versions = ">=3.6.2"
+python-versions = ">=3.8"
 
 [package.dependencies]
-idna = ">=2.8"
-sniffio = ">=1.1"
-typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
-
-[package.extras]
-doc = ["packaging", "sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"]
-test = ["coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "contextlib2", "uvloop (<0.15)", "mock (>=4)", "uvloop (>=0.15)"]
-trio = ["trio (>=0.16)"]
+typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""}
 
 [[package]]
-name = "atomicwrites"
-version = "1.4.1"
-description = "Atomic file writes."
+name = "anyio"
+version = "4.2.0"
+description = "High level compatibility layer for multiple asynchronous event loop implementations"
 category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+python-versions = ">=3.8"
 
-[[package]]
-name = "attrs"
-version = "22.1.0"
-description = "Classes Without Boilerplate"
-category = "dev"
-optional = false
-python-versions = ">=3.5"
+[package.dependencies]
+exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""}
+idna = ">=2.8"
+sniffio = ">=1.1"
+typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""}
 
 [package.extras]
-dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"]
-docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
-tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "zope.interface", "cloudpickle"]
-tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "cloudpickle"]
+doc = ["packaging", "Sphinx (>=7)", "sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"]
+test = ["anyio", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"]
+trio = ["trio (>=0.23)"]
 
 [[package]]
 name = "black"
-version = "21.11b1"
+version = "23.12.1"
 description = "The uncompromising code formatter."
 category = "dev"
 optional = false
-python-versions = ">=3.6.2"
+python-versions = ">=3.8"
 
 [package.dependencies]
-click = ">=7.1.2"
+click = ">=8.0.0"
 mypy-extensions = ">=0.4.3"
-pathspec = ">=0.9.0,<1"
+packaging = ">=22.0"
+pathspec = ">=0.9.0"
 platformdirs = ">=2"
-regex = ">=2021.4.4"
-tomli = ">=0.2.6,<2.0.0"
-typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""}
-typing-extensions = [
-    {version = ">=3.10.0.0", markers = "python_version < \"3.10\""},
-    {version = "!=3.10.0.1", markers = "python_version >= \"3.10\""},
-]
+tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
+typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""}
 
 [package.extras]
 colorama = ["colorama (>=0.4.3)"]
-d = ["aiohttp (>=3.7.4)"]
+d = ["aiohttp (>=3.7.4,!=3.9.0)", "aiohttp (>=3.7.4)"]
 jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
-python2 = ["typed-ast (>=1.4.3)"]
 uvloop = ["uvloop (>=0.15.2)"]
 
 [[package]]
 name = "click"
-version = "8.1.3"
+version = "8.1.7"
 description = "Composable command line interface toolkit"
 category = "dev"
 optional = false
@@ -76,23 +61,22 @@ python-versions = ">=3.7"
 
 [package.dependencies]
 colorama = {version = "*", markers = "platform_system == \"Windows\""}
-importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
 
 [[package]]
 name = "colorama"
-version = "0.4.5"
+version = "0.4.6"
 description = "Cross-platform colored terminal text."
 category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
 
 [[package]]
 name = "coverage"
-version = "6.5.0"
+version = "7.4.0"
 description = "Code coverage measurement for Python"
 category = "dev"
 optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
 
 [package.dependencies]
 tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""}
@@ -100,19 +84,30 @@ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.1
 [package.extras]
 toml = ["tomli"]
 
+[[package]]
+name = "exceptiongroup"
+version = "1.2.0"
+description = "Backport of PEP 654 (exception groups)"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+
+[package.extras]
+test = ["pytest (>=6)"]
+
 [[package]]
 name = "factory-boy"
-version = "3.2.1"
+version = "3.3.0"
 description = "A versatile test fixtures replacement based on thoughtbot's factory_bot for Ruby."
 category = "dev"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
 
 [package.dependencies]
 Faker = ">=0.7.0"
 
 [package.extras]
-dev = ["coverage", "django", "flake8", "isort", "pillow", "sqlalchemy", "mongoengine", "wheel (>=0.32.0)", "tox", "zest.releaser"]
+dev = ["coverage", "django", "flake8", "isort", "pillow", "sqlalchemy", "sqlalchemy-utils", "mongoengine", "wheel (>=0.32.0)", "tox", "zest.releaser"]
 doc = ["sphinx", "sphinx-rtd-theme", "sphinxcontrib-spelling"]
 
 [[package]]
@@ -126,39 +121,22 @@ python-versions = ">=3.6"
 [package.dependencies]
 python-dateutil = ">=2.4"
 text-unidecode = "1.3"
-typing-extensions = {version = ">=3.10.0.2", markers = "python_version < \"3.8\""}
 
 [[package]]
 name = "fastapi"
-version = "0.85.0"
+version = "0.109.0"
 description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
 category = "dev"
 optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
 
 [package.dependencies]
-pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0"
-starlette = "0.20.4"
+pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0"
+starlette = ">=0.35.0,<0.36.0"
+typing-extensions = ">=4.8.0"
 
 [package.extras]
-all = ["email-validator (>=1.1.1,<2.0.0)", "itsdangerous (>=1.1.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "orjson (>=3.2.1,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "requests (>=2.24.0,<3.0.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)", "uvicorn[standard] (>=0.12.0,<0.19.0)"]
-dev = ["autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "pre-commit (>=2.17.0,<3.0.0)", "uvicorn[standard] (>=0.12.0,<0.19.0)"]
-doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer (>=0.4.1,<0.7.0)"]
-test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.8.0)", "databases[sqlite] (>=0.3.2,<0.7.0)", "email-validator (>=1.1.1,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.23.0,<0.24.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.971)", "orjson (>=3.2.1,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "pytest (>=7.1.3,<8.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "requests (>=2.24.0,<3.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "types-orjson (==3.6.2)", "types-ujson (==5.4.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"]
-
-[[package]]
-name = "flake8"
-version = "4.0.1"
-description = "the modular source code checker: pep8 pyflakes and co"
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[package.dependencies]
-importlib-metadata = {version = "<4.3", markers = "python_version < \"3.8\""}
-mccabe = ">=0.6.0,<0.7.0"
-pycodestyle = ">=2.8.0,<2.9.0"
-pyflakes = ">=2.4.0,<2.5.0"
+all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"]
 
 [[package]]
 name = "h11"
@@ -168,214 +146,153 @@ category = "dev"
 optional = false
 python-versions = ">=3.7"
 
-[package.dependencies]
-typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
-
 [[package]]
 name = "idna"
-version = "3.4"
+version = "3.6"
 description = "Internationalized Domain Names in Applications (IDNA)"
 category = "dev"
 optional = false
 python-versions = ">=3.5"
 
-[[package]]
-name = "importlib-metadata"
-version = "4.2.0"
-description = "Read metadata from Python packages"
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[package.dependencies]
-typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""}
-zipp = ">=0.5"
-
-[package.extras]
-docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
-testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
-
 [[package]]
 name = "iniconfig"
-version = "1.1.1"
-description = "iniconfig: brain-dead simple config-ini parsing"
+version = "2.0.0"
+description = "brain-dead simple config-ini parsing"
 category = "dev"
 optional = false
-python-versions = "*"
+python-versions = ">=3.7"
 
 [[package]]
 name = "isort"
-version = "5.10.1"
+version = "5.13.2"
 description = "A Python utility / library to sort Python imports."
 category = "dev"
 optional = false
-python-versions = ">=3.6.1,<4.0"
+python-versions = ">=3.8.0"
 
 [package.extras]
-pipfile_deprecated_finder = ["pipreqs", "requirementslib"]
-requirements_deprecated_finder = ["pipreqs", "pip-api"]
-colors = ["colorama (>=0.4.3,<0.5.0)"]
-plugins = ["setuptools"]
-
-[[package]]
-name = "mccabe"
-version = "0.6.1"
-description = "McCabe checker, plugin for flake8"
-category = "dev"
-optional = false
-python-versions = "*"
+colors = ["colorama (>=0.4.6)"]
 
 [[package]]
 name = "mypy"
-version = "0.931"
+version = "1.8.0"
 description = "Optional static typing for Python"
 category = "dev"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.8"
 
 [package.dependencies]
-mypy-extensions = ">=0.4.3"
-tomli = ">=1.1.0"
-typed-ast = {version = ">=1.4.0,<2", markers = "python_version < \"3.8\""}
-typing-extensions = ">=3.10"
+mypy-extensions = ">=1.0.0"
+tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
+typing-extensions = ">=4.1.0"
 
 [package.extras]
 dmypy = ["psutil (>=4.0)"]
-python2 = ["typed-ast (>=1.4.0,<2)"]
+install-types = ["pip"]
+mypyc = ["setuptools (>=50)"]
+reports = ["lxml"]
 
 [[package]]
 name = "mypy-extensions"
-version = "0.4.3"
-description = "Experimental type system extensions for programs checked with the mypy typechecker."
+version = "1.0.0"
+description = "Type system extensions for programs checked with the mypy type checker."
 category = "dev"
 optional = false
-python-versions = "*"
+python-versions = ">=3.5"
 
 [[package]]
 name = "packaging"
-version = "21.3"
+version = "23.2"
 description = "Core utilities for Python packages"
 category = "dev"
 optional = false
-python-versions = ">=3.6"
-
-[package.dependencies]
-pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
+python-versions = ">=3.7"
 
 [[package]]
 name = "pathspec"
-version = "0.10.1"
+version = "0.12.1"
 description = "Utility library for gitignore style pattern matching of file paths."
 category = "dev"
 optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
 
 [[package]]
 name = "platformdirs"
-version = "2.5.2"
-description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
+version = "4.1.0"
+description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
 category = "dev"
 optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
 
 [package.extras]
-docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"]
-test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"]
+docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx-autodoc-typehints (>=1.24)", "sphinx (>=7.1.1)"]
+test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest (>=7.4)"]
 
 [[package]]
 name = "pluggy"
-version = "1.0.0"
+version = "1.3.0"
 description = "plugin and hook calling mechanisms for python"
 category = "dev"
 optional = false
-python-versions = ">=3.6"
-
-[package.dependencies]
-importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
+python-versions = ">=3.8"
 
 [package.extras]
 dev = ["pre-commit", "tox"]
 testing = ["pytest", "pytest-benchmark"]
 
-[[package]]
-name = "py"
-version = "1.11.0"
-description = "library with cross-python path, ini-parsing, io, code, log facilities"
-category = "dev"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-
-[[package]]
-name = "pycodestyle"
-version = "2.8.0"
-description = "Python style guide checker"
-category = "dev"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-
 [[package]]
 name = "pydantic"
-version = "1.10.2"
-description = "Data validation and settings management using python type hints"
+version = "2.5.3"
+description = "Data validation using Python type hints"
 category = "main"
 optional = false
 python-versions = ">=3.7"
 
 [package.dependencies]
-typing-extensions = ">=4.1.0"
+annotated-types = ">=0.4.0"
+pydantic-core = "2.14.6"
+typing-extensions = ">=4.6.1"
 
 [package.extras]
-dotenv = ["python-dotenv (>=0.10.4)"]
-email = ["email-validator (>=1.0.3)"]
+email = ["email-validator (>=2.0.0)"]
 
 [[package]]
-name = "pyflakes"
-version = "2.4.0"
-description = "passive checker of Python programs"
-category = "dev"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-
-[[package]]
-name = "pyparsing"
-version = "3.0.9"
-description = "pyparsing module - Classes and methods to define and execute parsing grammars"
-category = "dev"
+name = "pydantic-core"
+version = "2.14.6"
+description = ""
+category = "main"
 optional = false
-python-versions = ">=3.6.8"
+python-versions = ">=3.7"
 
-[package.extras]
-diagrams = ["railroad-diagrams", "jinja2"]
+[package.dependencies]
+typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
 
 [[package]]
 name = "pytest"
-version = "6.2.5"
+version = "7.4.4"
 description = "pytest: simple powerful testing with Python"
 category = "dev"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
 
 [package.dependencies]
-atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
-attrs = ">=19.2.0"
 colorama = {version = "*", markers = "sys_platform == \"win32\""}
-importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
+exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
 iniconfig = "*"
 packaging = "*"
 pluggy = ">=0.12,<2.0"
-py = ">=1.8.2"
-toml = "*"
+tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
 
 [package.extras]
-testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
+testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
 
 [[package]]
 name = "pytest-cov"
-version = "3.0.0"
+version = "4.1.0"
 description = "Pytest plugin for measuring coverage."
 category = "dev"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
 
 [package.dependencies]
 coverage = {version = ">=5.2.1", extras = ["toml"]}
@@ -396,12 +313,12 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
 six = ">=1.5"
 
 [[package]]
-name = "regex"
-version = "2022.9.13"
-description = "Alternative regular expression module, to replace re."
+name = "ruff"
+version = "0.1.14"
+description = "An extremely fast Python linter and code formatter, written in Rust."
 category = "dev"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
 
 [[package]]
 name = "six"
@@ -421,18 +338,18 @@ python-versions = ">=3.7"
 
 [[package]]
 name = "starlette"
-version = "0.20.4"
+version = "0.35.1"
 description = "The little ASGI library that shines."
 category = "dev"
 optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
 
 [package.dependencies]
 anyio = ">=3.4.0,<5"
 typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""}
 
 [package.extras]
-full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests"]
+full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyaml"]
 
 [[package]]
 name = "text-unidecode"
@@ -442,37 +359,21 @@ category = "dev"
 optional = false
 python-versions = "*"
 
-[[package]]
-name = "toml"
-version = "0.10.2"
-description = "Python Library for Tom's Obvious, Minimal Language"
-category = "dev"
-optional = false
-python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
-
 [[package]]
 name = "tomli"
-version = "1.2.3"
+version = "2.0.1"
 description = "A lil' TOML parser"
 category = "dev"
 optional = false
-python-versions = ">=3.6"
-
-[[package]]
-name = "typed-ast"
-version = "1.5.4"
-description = "a fork of Python 2 and 3 ast modules with type comment support"
-category = "dev"
-optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
 
 [[package]]
 name = "typing-extensions"
-version = "4.4.0"
-description = "Backported and Experimental Type Hints for Python 3.7+"
+version = "4.9.0"
+description = "Backported and Experimental Type Hints for Python 3.8+"
 category = "main"
 optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
 
 [[package]]
 name = "uvicorn"
@@ -485,68 +386,46 @@ python-versions = ">=3.7"
 [package.dependencies]
 click = ">=7.0"
 h11 = ">=0.8"
-typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
 
 [package.extras]
 standard = ["colorama (>=0.4)", "httptools (>=0.4.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.0)"]
 
-[[package]]
-name = "zipp"
-version = "3.9.0"
-description = "Backport of pathlib-compatible object wrapper for zip files"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-
-[package.extras]
-docs = ["sphinx (>=3.5)", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "furo", "jaraco.tidelift (>=1.4)"]
-testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "flake8 (<5)", "pytest-cov", "pytest-enabler (>=1.3)", "jaraco.itertools", "func-timeout", "jaraco.functools", "more-itertools", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"]
-
 [metadata]
 lock-version = "1.1"
-python-versions = "^3.7"
-content-hash = "932bcf32e8bca5196450bf6100ece0315ac3652effecd2bd07f018dfac42683b"
+python-versions = "^3.8"
+content-hash = "c9b5ce64682863a8122ada94810f2908ac2f5405394896a38719d0abb43b4e9e"
 
 [metadata.files]
+annotated-types = []
 anyio = []
-atomicwrites = []
-attrs = []
 black = []
 click = []
 colorama = []
 coverage = []
+exceptiongroup = []
 factory-boy = []
 faker = []
 fastapi = []
-flake8 = []
 h11 = []
 idna = []
-importlib-metadata = []
 iniconfig = []
 isort = []
-mccabe = []
 mypy = []
 mypy-extensions = []
 packaging = []
 pathspec = []
 platformdirs = []
 pluggy = []
-py = []
-pycodestyle = []
 pydantic = []
-pyflakes = []
-pyparsing = []
+pydantic-core = []
 pytest = []
 pytest-cov = []
 python-dateutil = []
-regex = []
+ruff = []
 six = []
 sniffio = []
 starlette = []
 text-unidecode = []
-toml = []
 tomli = []
-typed-ast = []
 typing-extensions = []
 uvicorn = []
-zipp = []
diff --git a/pyproject.toml b/pyproject.toml
index de33aad..ae962ad 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "rcs-pydantic"
-version = "1.0.0"
+version = "2.0.0"
 description = ""
 authors = ["xncbf <xncbf12@gmail.com>"]
 keywords = ["pydantic", "rcs", "fastapi"]
@@ -10,20 +10,20 @@ license = "MIT"
 readme = "README.md"
 
 [tool.poetry.dependencies]
-python = "^3.7"
-pydantic = "^1.9.0"
+python = "^3.8"
+pydantic = "^2.0.0"
 
 [tool.poetry.dev-dependencies]
-pytest-cov = "^3.0.0"
-pytest = "^6.2.5"
-black = "21.11b1"
-flake8 = "^4.0.1"
-mypy = "^0.931"
-isort = "^5.10.1"
+pytest-cov = "*"
+pytest = "*"
+black = "*"
+mypy = "*"
+isort = "*"
 Faker = "^11.3.0"
 factory-boy = "^3.2.1"
-fastapi = "^0.85.0"
+fastapi = "^0.109.0"
 uvicorn = "^0.18.3"
+ruff = "^0.1.14"
 
 [tool.black]
 line-length = 120
@@ -36,14 +36,87 @@ extend-exclude = '''
 '''
 
 [tool.mypy]
+plugins = [
+  "pydantic.mypy"
+]
 python_version = '3.10'
 ignore_missing_imports = 'True'
 
+follow_imports = "silent"
+warn_redundant_casts = true
+warn_unused_ignores = true
+check_untyped_defs = true
+no_implicit_reexport = true
+
+
+[tool.pydantic-mypy]
+init_forbid_extra = true
+init_typed = true
+warn_required_dynamic_aliases = true
+
 [tool.isort]
 profile = "black"
 line_length = 120
 sections= ["FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"]
 
+[tool.ruff]
+# Enable pycodestyle (`E`) and Pyflakes (`F`) codes by default.
+select = [
+    "E",  # pycodestyle errors
+    "W",  # pycodestyle warnings
+    "F",  # pyflakes
+    "I",  # isort
+    "C",  # flake8-comprehensions
+    "B",  # flake8-bugbear
+]
+ignore = [
+    "B008",  # do not perform function calls in argument defaults
+    "B023",
+    "C901"
+]
+
+# Allow autofix for all enabled rules (when `--fix`) is provided.
+fixable = ["A", "B", "C", "D", "E", "F"]
+unfixable = []
+
+# Exclude a variety of commonly ignored directories.
+exclude = [
+    ".bzr",
+    ".direnv",
+    ".eggs",
+    ".git",
+    ".hg",
+    ".mypy_cache",
+    ".nox",
+    ".pants.d",
+    ".pytype",
+    ".ruff_cache",
+    ".svn",
+    ".tox",
+    ".venv",
+    "__pypackages__",
+    "_build",
+    "buck-out",
+    "build",
+    "dist",
+    "node_modules",
+    "venv",
+    "migrations"
+]
+
+# Same as Black.
+line-length = 120
+
+# Allow unused variables when underscore-prefixed.
+dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
+
+# Assume Python 3.8.
+target-version = "py38"
+
+[tool.ruff.mccabe]
+# Unlike Flake8, default to a complexity level of 10.
+max-complexity = 10
+
 # https://docs.pytest.org/en/6.2.x/reference.html
 [tool.pytest.ini_options]
 minversion = "6.2.5"
diff --git a/rcs_pydantic/enums.py b/rcs_pydantic/enums.py
index 70b12ad..6282bc0 100644
--- a/rcs_pydantic/enums.py
+++ b/rcs_pydantic/enums.py
@@ -43,7 +43,7 @@ class HeaderEnum(Enum):
 
 class ActionEnum(Enum):
     URL_ACTION: str = "urlAction"  # 단말기에 기본 웹 브라우저로 설정된 앱을 통해서, 웹페이지로 이동할 수있습니다
-    LOCAL_BROWSER_ACTION: str = "localBrowserAction"  # 단말기의 메시지 앱 내부 브라우저를 통해 웹페이지로 이동할 수 있습니다
+    LOCAL_BROWSER_ACTION: str = "localBrowserAction"  # 단말기의 메시지 앱 내부 브라우저를 통해 웹페이지로 이동할 수 있습니다  # noqa: E501
     MAP_ACTION: str = "mapAction"  # 미리 지정된 위치를 보여주거나 사용자의 현재 위치를 서버로 전송 할 수 있습니다.
     CALENDAR_ACTION: str = "calendarAction"  # 사용자의 캘린더에 특정 일정을 등록 할 수 있습니다.
     CLIPBOARD_ACTION: str = "clipboardAction"  # 특정 문구를 사용자 단말이 자동으로 복사 할 수 있게 합니다
diff --git a/rcs_pydantic/errors.py b/rcs_pydantic/errors.py
index 0dc10bd..4605a11 100644
--- a/rcs_pydantic/errors.py
+++ b/rcs_pydantic/errors.py
@@ -58,7 +58,10 @@ class ErrorCodeEnum(TupleEnum):
     RCS_USER_NOT_FOUND = (41110, "Message Status Webhook ")
     PROCESS_REVOCATION_REQUEST_FAILED = (41117, "Message Status Webhook ")
     USER_FOR_MESSAGE_RECEIVING_NOT_FOUND = (41200, "")
-    MESSAGE_NOT_ACCEPTABLE = (41201, "Message Session형성과정 중 단말의 SDP에 message송신에 필요한 feature tag가 없는 경우 발생")
+    MESSAGE_NOT_ACCEPTABLE = (
+        41201,
+        "Message Session형성과정 중 단말의 SDP에 message송신에 필요한 feature tag가 없는 경우 발생",
+    )  # noqa: E501
     USER_IS_NOT_CAPABLE_FOR_TEXT = (41210, "Bot이 Text message를 보낼 때 user의 capability에 chat이 없는 경우 발생.")
     USER_IS_NOT_CAPABLE_FOR_FT = (41211, "Bot이 File message를 보낼 때 user의 capability에 fthttp가 없는 경우 발생")
     USER_IS_NOT_CAPABLE_FOR_RICHCARD = (
@@ -73,7 +76,7 @@ class ErrorCodeEnum(TupleEnum):
         41221,
         "clipboardAction, localBrowserAction, messageHeader, messageFooter, openrichcard, geolocationPushMessage,"
         "copyAllowed Bot이 v1.1에 해당하는 Extended message를 보낼 때 user의 capability에 bot, chatbot.sa, xbotmessage "
-        "1.1이 없는 경우 발생. 이 때 xbotmessage는 상위 version이 하위 version을 포함한다. (1.2 version이 있다면 1.1에 해당하는 "
+        "1.1이 없는 경우 발생. 이 때 xbotmessage는 상위 version이 하위 version을 포함한다. (1.2 version이 있다면 1.1에 해당하는 "  # noqa: E501
         "capability를 가진 것으로 간주함)",
     )
     USER_IS_NOT_CAPABLE_FOR_XBOTMESSAGE_1_2 = (
@@ -83,10 +86,16 @@ class ErrorCodeEnum(TupleEnum):
     )
     USER_IS_NOT_CAPABLE_FOR_OPENRICHARD_1_0 = (
         41230,
-        "Bot이 v1.0에 해당하는 Openrichcard를 보낼 때 user의 capability에 bot, chatbot.sa, xbotmessage 1.0이 없는 경우 발생",
+        "Bot이 v1.0에 해당하는 Openrichcard를 보낼 때 user의 capability에 bot, chatbot.sa, xbotmessage 1.0이 없는 경우 발생",  # noqa: E501
     )
-    USER_IS_NOT_CAPABLE_FOR_OPENRICHARD_1_1 = (41231, "v1.1에 해당하는 Openrichcard가 현재 정의 및 사용되지 않으므로, 실제 발생하지 않는 code")
-    USER_IS_NOT_CAPABLE_FOR_OPENRICHARD_1_2 = (41232, "v1.2에 해당하는 Openrichcard가 현재 정의 및 사용되지 않으므로, 실제 발생하지 않는 code")
+    USER_IS_NOT_CAPABLE_FOR_OPENRICHARD_1_1 = (
+        41231,
+        "v1.1에 해당하는 Openrichcard가 현재 정의 및 사용되지 않으므로, 실제 발생하지 않는 code",
+    )  # noqa: E501
+    USER_IS_NOT_CAPABLE_FOR_OPENRICHARD_1_2 = (
+        41232,
+        "v1.2에 해당하는 Openrichcard가 현재 정의 및 사용되지 않으므로, 실제 발생하지 않는 code",
+    )  # noqa: E501
     USER_IS_NOT_CAPABLE_FOR_GEOLOCATION_PUSH_REQUEST = (41240, "User is not capable for GEOLOCATION PUSH REQUEST")
     FAILED_TO_GET_MESSAGE_CONTENT_TYPE = (41250, "Failed to get message content type")
     FILE_DOWNLOAD_FAILED = (41300, "")
@@ -275,7 +284,7 @@ class MaaPErrorCodeEnum(TupleEnum):
     PERSISTENT_MENU_PERMISSION_ERROR = (52009, "Persistent Menu 등록이 허용되지 않습니다.")
     INVALID_PERSISTENT_MENU_DATA = (52010, "Persistent menu JSON 데이터 오류")
     MESSAGE_TRANSMISSION_TIME_EXCEEDING = (52016, "실시간 메시지 인입 후 10초안에 삼성으로 전달되지 못함")
-    MESSAGEBASE_ID_STOPPED_TEMPORARILY = (52023, "메시지 베이스의 상태가 'pause'인 메시지 베이스 메시지로 전문 구성하여 전송 시도 시")
+    MESSAGEBASE_ID_STOPPED_TEMPORARILY = (52023, "메시지 베이스의 상태가 'pause'인 메시지 베이스 메시지로 전문 구성하여 전송 시도 시")  # noqa: E501
     INVALID_WEBHOOK_REQUEST_PARAMETER = (52101, "잘못된 Webhook 중계사 요청 파라미터 입니다.")
     WEBHOOK_HOST_CONNECT_ERROR = (52102, "Webhook 중계 시스템 연결 오류")
     WEBHOOK_HOST_SERVER_REQUEST_FAILURE = (52103, "중계사 Webhook 전송 요청을 실패 했습니다.")
@@ -293,7 +302,7 @@ class MaaPErrorCodeEnum(TupleEnum):
     INVAILD_CONTACT_NUMBER_USER = (54001, "자사 고객이 아닙니다.")
     NO_RCS_CAPABILITY = (54002, "자사 고객이지만, RCS메시지를 수신할 수 있는 가입자가 아닙니다.")
     UNABLE_SENDING_TO_RECIPIENT = (54003, "단말기기로 RCS 메시지를 전송할 수 없습니다.")
-    MAA_P_INTERNAL_ERROR = (54004, "MaaP 시스템 혹은 RCS 프로토콜 상의 이슈로 발송 실패되었음 (삼성 에러 40001 ~ 41100, 42601)")
+    MAA_P_INTERNAL_ERROR = (54004, "MaaP 시스템 혹은 RCS 프로토콜 상의 이슈로 발송 실패되었음 (삼성 에러 40001 ~ 41100, 42601)")  # noqa: E501
     CORP_CONTENT_ERROR = (55001, "기업 정보 내용이 누락된 필수항목이 있습니다.")
     INVALID_PROPERTY = (55002, "필수 파라미터 검증 오류")
     AGENCY_CONTENT_ERROR = (55101, "대행사 정보 내용이 누락된 필수 항목이 있습니다.")
@@ -326,7 +335,10 @@ class MaaPErrorCodeEnum(TupleEnum):
     INVALID_MESSAGEBASEFORM_ID = (55602, "messagebaseformID가 존재하지 않습니다.")
     INVALID_MESSAGE_BASE_PRODUCT_CODE = (55603, "messaegBase의 상품코드 에러")
     PROHIBITED_TEXT_CONTENT = (55701, "(광고) 를 사용할 수 없음")
-    ACTION_BUTTON_PERMISSION_ERROR = (55702, "Action button이 허용되지 않는 messagebaseID에서 Action button을 사용하였음")
+    ACTION_BUTTON_PERMISSION_ERROR = (
+        55702,
+        "Action button이 허용되지 않는 messagebaseID에서 Action button을 사용하였음",
+    )  # noqa: E501
     PROHIBITED_HEADER_VALUE = (55703, "허용되지 않은 header 값 사용")
     PROHIBITED_FOOTER_FIELD = (55704, "header 값과 일치 하지 않은 footer 사용 (ex. header가 0 인데, footer 가 있음)")
     MISSING_FOOTER_CONTENT = (55705, "footer값이 누락되어 있습니다 (ex. header가 1 인데, footer 가 없음)")
@@ -421,10 +433,10 @@ class MaaPErrorCodeEnum(TupleEnum):
     AUTO_REPLY_MESSAGE_SENDING_ERROR = (51933, "자동 응답 메시지 발송 수행 오류가 발생했습니다.")
     NON_SERVICE_SUPPORTED_ERROR = (51934, "처리 미 대상 서비스 입니다.")
     SAMSUNG_MAA_P_CORE_FILE_SERVER_CONNECTION_ERROR = (51935, "삼성 MaaP Core 파일 서버 연결 오류가 발생했습니다.")
-    MESSAGE_FILE_MESSAGE_EVENT_FILE_DOWNLOAD_ERROR_1 = (51936, "파일 메시지 이벤트의 파일 메시지 다운로드 수행 오류가 발생했습니다.")
-    MESSAGE_FILE_MESSAGE_EVENT_FILE_DOWNLOAD_ERROR_2 = (51937, "파일 메시지 이벤트의 파일 메시지 다운로드 수행 오류가 발생했습니다.")
-    MESSAGE_FILE_MESSAGE_REGISTRATION_TO_DB_ERROR = (51938, "파일 메시지 이벤트의 파일 정보 DB 등록 오류가 발생했습니다.")
-    MESSAGE_FILE_MESSAGE_REGISTRATION_TO_DB_FAILURE = (51939, "파일 메시지 이벤트의 파일 정보 DB 등록 작업을 실패 했습니다.")
+    MESSAGE_FILE_MESSAGE_EVENT_FILE_DOWNLOAD_ERROR_1 = (51936, "파일 메시지 이벤트의 파일 메시지 다운로드 수행 오류가 발생했습니다.")  # noqa: E501
+    MESSAGE_FILE_MESSAGE_EVENT_FILE_DOWNLOAD_ERROR_2 = (51937, "파일 메시지 이벤트의 파일 메시지 다운로드 수행 오류가 발생했습니다.")  # noqa: E501
+    MESSAGE_FILE_MESSAGE_REGISTRATION_TO_DB_ERROR = (51938, "파일 메시지 이벤트의 파일 정보 DB 등록 오류가 발생했습니다.")  # noqa: E501
+    MESSAGE_FILE_MESSAGE_REGISTRATION_TO_DB_FAILURE = (51939, "파일 메시지 이벤트의 파일 정보 DB 등록 작업을 실패 했습니다.")  # noqa: E501
     WEBHOOK_SCHEDULER_ASYNC_EXECUTION_ERROR = (51950, "Webhook 스케줄러 비동기 수행 오류.")
     WEBHOOK_SCHEDULER_DB_EXECUTION_ERROR = (51951, "Webhook 스케줄러 DB 수행 오류.")
     WEBHOOK_SCHEDULER_DB_EXECUTION_FAILUER = (51952, "Webhook 스케줄러 DB 수행 실패.")
@@ -567,7 +579,7 @@ class KTErrorCodeEnum(TupleEnum):
     NOT_FOUND_RCS_SUBSCRIBER = (76003, "RCS 가입 정보 없음")
     XROSHOT_SENDER_INTERNAL_ERROR = (76004, "Xroshot Sender 내부 에러")
     XROSHOT_MANAGER_INTERNAL_ERROR = (76005, "Xroshot Manager 내부 에러")
-    EXPIRED_MESSAGE_RECEIVED_TIME = (77001, "Legacy : 레포트 수신 시간 만료 (메시지 전송 후, 24시간 레포트 못받는 경우) RCS  3일")
+    EXPIRED_MESSAGE_RECEIVED_TIME = (77001, "Legacy : 레포트 수신 시간 만료 (메시지 전송 후, 24시간 레포트 못받는 경우) RCS  3일")  # noqa: E501
     INVALIED_MESSAGE_SEQUENCE = (77002, "Message Sequence Number가 틀린 경우")
     NON_EXISTING_WEBHOOK_MESSAGE = (77003, "Webhook 발송 메시지가 존재하지 않습니다")
     INVALID_WEBHOOK_MESSAGE_1 = (77004, "잘못된 Webhook 발송 메시지입니다.")
diff --git a/rcs_pydantic/main.py b/rcs_pydantic/main.py
index 8bd33d5..365e04f 100644
--- a/rcs_pydantic/main.py
+++ b/rcs_pydantic/main.py
@@ -77,17 +77,21 @@ def make_common_info(self, message_info: scheme.MessageInfo) -> dict:
         else:
             msg_service_type = enums.MessageServiceTypeEnum.RCS
 
-        common = {
-            "msgId": str(uuid.uuid4()),
-            "userContact": message_info.userContact,
-            "scheduleType": 0,
-            "msgServiceType": msg_service_type,
-        }
-
         if self.message_group_id:
-            common["msgGroupId"] = self.message_group_id
-
-        return scheme.CommonInfo(**common).dict(exclude_unset=True)
+            return scheme.CommonInfo(
+                msgId=str(uuid.uuid4()),
+                userContact=str(message_info.userContact),
+                scheduleType=enums.ScheduleTypeEnum.IMMEDIATE,
+                msgServiceType=msg_service_type,
+                msgGroupId=self.message_group_id,
+            ).model_dump(exclude_none=True)
+        else:
+            return scheme.CommonInfo(
+                msgId=str(uuid.uuid4()),
+                userContact=str(message_info.userContact),
+                scheduleType=enums.ScheduleTypeEnum.IMMEDIATE,
+                msgServiceType=msg_service_type,
+            ).model_dump(exclude_none=True)
 
     def make_rcs_info(self, message_info: scheme.MessageInfo) -> dict:
         rcs_info = scheme.RcsInfo(
@@ -117,7 +121,4 @@ def make_rcs_info(self, message_info: scheme.MessageInfo) -> dict:
             rcs_info.chipList = self.chips
         if message_info.replyId:
             rcs_info.replyId = message_info.replyId
-        return rcs_info.dict(exclude_unset=True)
-
-    def send(self):
-        self.send_info
+        return rcs_info.model_dump(exclude_none=True)
diff --git a/rcs_pydantic/scheme.py b/rcs_pydantic/scheme.py
index 86cc0c8..c27a5bf 100644
--- a/rcs_pydantic/scheme.py
+++ b/rcs_pydantic/scheme.py
@@ -1,137 +1,124 @@
 from typing import Dict, List, Optional, Union
 
-from pydantic import BaseModel, Field, validator
+from pydantic import BaseModel, ConfigDict, Field, validator
+from typing_extensions import Never
 
 from . import enums
 
 
-class EmptyDict(BaseModel):
-    @classmethod
-    def __get_validators__(cls):
-        yield cls.validate
-
-    @classmethod
-    def validate(cls, v):
-        if not isinstance(v, dict):
-            raise TypeError("dict required")
-        if len(v.keys()) > 0:
-            raise ValueError("dict must be empty")
-        return {}
-
-
 class RcsSMSBody(BaseModel):
-    title: Optional[str] = Field(max_length=30)
+    title: Optional[str] = Field(max_length=30, default=None)
     description: str = Field(max_length=100)
-    media: Optional[str]
+    media: Optional[str] = None
 
 
 class RcsLMSBody(BaseModel):
-    title: Optional[str] = Field(max_length=30)
+    title: Optional[str] = Field(max_length=30, default=None)
     description: str = Field(max_length=1300)
-    media: Optional[str]
+    media: Optional[str] = None
 
 
 class RcsMMSBody(BaseModel):
-    title: Optional[str] = Field(max_length=30)
+    title: Optional[str] = Field(max_length=30, default=None)
     description: str = Field(max_length=1300)
-    media: Optional[str]
+    media: Optional[str] = None
 
 
 class RcsCHATBody(BaseModel):
-    title: Optional[str] = Field(max_length=30)
+    title: Optional[str] = Field(max_length=30, default=None)
     description: str = Field(max_length=1300)
-    media: Optional[str]
+    media: Optional[str] = None
 
 
 class RcsSMSCarouselBody(BaseModel):
-    title1: Optional[str] = Field(max_length=30)
+    title1: Optional[str] = Field(max_length=30, default=None)
     description1: str = Field(max_length=100)
-    media1: Optional[str]
-    title2: Optional[str] = Field(max_length=30)
-    description2: Optional[str] = Field(max_length=100)
-    media2: Optional[str]
+    media1: Optional[str] = None
+    title2: Optional[str] = Field(max_length=30, default=None)
+    description2: Optional[str] = Field(max_length=100, default=None)
+    media2: Optional[str] = None
     title3: Optional[str] = Field(max_length=30)
-    description3: Optional[str] = Field(max_length=100)
-    media3: Optional[str]
+    description3: Optional[str] = Field(max_length=100, default=None)
+    media3: Optional[str] = None
     title4: Optional[str] = Field(max_length=30)
     description4: Optional[str] = Field(max_length=100)
-    media4: Optional[str]
+    media4: Optional[str] = None
     title5: Optional[str] = Field(max_length=30)
     description5: Optional[str] = Field(max_length=100)
-    media5: Optional[str]
+    media5: Optional[str] = None
     title6: Optional[str] = Field(max_length=30)
     description6: Optional[str] = Field(max_length=100)
-    media6: Optional[str]
+    media6: Optional[str] = None
 
 
 class RcsLMSCarouselBody(BaseModel):
     title1: Optional[str] = Field(max_length=30)
     description1: str = Field(max_length=1300)
-    media1: Optional[str]
-    title2: Optional[str] = Field(max_length=30)
-    description2: Optional[str] = Field(max_length=1300)
-    media2: Optional[str]
-    title3: Optional[str] = Field(max_length=30)
-    description3: Optional[str] = Field(max_length=1300)
-    media3: Optional[str]
-    title4: Optional[str] = Field(max_length=30)
-    description4: Optional[str] = Field(max_length=1300)
-    media4: Optional[str]
-    title5: Optional[str] = Field(max_length=30)
-    description5: Optional[str] = Field(max_length=1300)
-    media5: Optional[str]
-    title6: Optional[str] = Field(max_length=30)
-    description6: Optional[str] = Field(max_length=1300)
-    media6: Optional[str]
+    media1: Optional[str] = None
+    title2: Optional[str] = Field(max_length=30, default=None)
+    description2: Optional[str] = Field(max_length=1300, default=None)
+    media2: Optional[str] = None
+    title3: Optional[str] = Field(max_length=30, default=None)
+    description3: Optional[str] = Field(max_length=1300, default=None)
+    media3: Optional[str] = None
+    title4: Optional[str] = Field(max_length=30, default=None)
+    description4: Optional[str] = Field(max_length=1300, default=None)
+    media4: Optional[str] = None
+    title5: Optional[str] = Field(max_length=30, default=None)
+    description5: Optional[str] = Field(max_length=1300, default=None)
+    media5: Optional[str] = None
+    title6: Optional[str] = Field(max_length=30, default=None)
+    description6: Optional[str] = Field(max_length=1300, default=None)
+    media6: Optional[str] = None
 
 
 class RcsMMSCarouselBody(BaseModel):
     title1: Optional[str] = Field(max_length=30)
     description1: str = Field(max_length=1300)
-    media1: Optional[str]
-    title2: Optional[str] = Field(max_length=30)
-    description2: Optional[str] = Field(max_length=1300)
-    media2: Optional[str]
-    title3: Optional[str] = Field(max_length=30)
-    description3: Optional[str] = Field(max_length=1300)
-    media3: Optional[str]
-    title4: Optional[str] = Field(max_length=30)
-    description4: Optional[str] = Field(max_length=1300)
-    media4: Optional[str]
-    title5: Optional[str] = Field(max_length=30)
-    description5: Optional[str] = Field(max_length=1300)
-    media5: Optional[str]
-    title6: Optional[str] = Field(max_length=30)
-    description6: Optional[str] = Field(max_length=1300)
-    media6: Optional[str]
+    media1: Optional[str] = None
+    title2: Optional[str] = Field(max_length=30, default=None)
+    description2: Optional[str] = Field(max_length=1300, default=None)
+    media2: Optional[str] = None
+    title3: Optional[str] = Field(max_length=30, default=None)
+    description3: Optional[str] = Field(max_length=1300, default=None)
+    media3: Optional[str] = None
+    title4: Optional[str] = Field(max_length=30, default=None)
+    description4: Optional[str] = Field(max_length=1300, default=None)
+    media4: Optional[str] = None
+    title5: Optional[str] = Field(max_length=30, default=None)
+    description5: Optional[str] = Field(max_length=1300, default=None)
+    media5: Optional[str] = None
+    title6: Optional[str] = Field(max_length=30, default=None)
+    description6: Optional[str] = Field(max_length=1300, default=None)
+    media6: Optional[str] = None
 
 
 class RcsCHATCarouselBody(BaseModel):
     title1: Optional[str] = Field(max_length=30)
     description1: str = Field(max_length=1300)
-    media1: Optional[str]
-    title2: Optional[str] = Field(max_length=30)
-    description2: Optional[str] = Field(max_length=1300)
-    media2: Optional[str]
-    title3: Optional[str] = Field(max_length=30)
-    description3: Optional[str] = Field(max_length=1300)
-    media3: Optional[str]
-    title4: Optional[str] = Field(max_length=30)
-    description4: Optional[str] = Field(max_length=1300)
-    media4: Optional[str]
-    title5: Optional[str] = Field(max_length=30)
-    description5: Optional[str] = Field(max_length=1300)
-    media5: Optional[str]
-    title6: Optional[str] = Field(max_length=30)
-    description6: Optional[str] = Field(max_length=1300)
-    media6: Optional[str]
+    media1: Optional[str] = None
+    title2: Optional[str] = Field(max_length=30, default=None)
+    description2: Optional[str] = Field(max_length=1300, default=None)
+    media2: Optional[str] = None
+    title3: Optional[str] = Field(max_length=30, default=None)
+    description3: Optional[str] = Field(max_length=1300, default=None)
+    media3: Optional[str] = None
+    title4: Optional[str] = Field(max_length=30, default=None)
+    description4: Optional[str] = Field(max_length=1300, default=None)
+    media4: Optional[str] = None
+    title5: Optional[str] = Field(max_length=30, default=None)
+    description5: Optional[str] = Field(max_length=1300, default=None)
+    media5: Optional[str] = None
+    title6: Optional[str] = Field(max_length=30, default=None)
+    description6: Optional[str] = Field(max_length=1300, default=None)
+    media6: Optional[str] = None
 
 
 class LocationInfo(BaseModel):
-    query: Optional[str]
-    longitude: Optional[float]
-    latitude: Optional[float]
-    label: Optional[str]
+    query: Optional[str] = None
+    longitude: Optional[float] = None
+    latitude: Optional[float] = None
+    label: Optional[str] = None
 
 
 class ShowLocationInfo(BaseModel):
@@ -147,7 +134,7 @@ class PostParameterInfo(BaseModel):
 class OpenUrlInfo(BaseModel):
     url: str
     isHalfView: Optional[str] = Field(default="false")
-    postParameter: Optional[PostParameterInfo]
+    postParameter: Optional[PostParameterInfo] = None
 
 
 class CreateCalendarEventInfo(BaseModel):
@@ -191,8 +178,8 @@ class MapActionInfo(BaseModel):
     미리 지정된 위치를 보여주거나 사용자의 현재 위치를 서버로 전송 할 수 있습니다.
     """
 
-    showLocation: Optional[ShowLocationInfo]
-    requestLocationPush: Optional[Dict]
+    showLocation: Optional[ShowLocationInfo] = None
+    requestLocationPush: Optional[Dict] = None
 
 
 class CalendarActionInfo(BaseModel):
@@ -241,20 +228,20 @@ class ReplyActionInfo(BaseModel):
 
 
 class ActionInfo(BaseModel):
-    urlAction: Optional[UrlActionInfo]
-    localBrowserAction: Optional[LocalBrowserActionInfo]
-    mapAction: Optional[MapActionInfo]
-    calendarAction: Optional[CalendarActionInfo]
-    clipboardAction: Optional[ClipboardActionInfo]
-    composeAction: Optional[ComposeActionInfo]
-    dialerAction: Optional[DialerActionInfo]
+    urlAction: Optional[UrlActionInfo] = None
+    localBrowserAction: Optional[LocalBrowserActionInfo] = None
+    mapAction: Optional[MapActionInfo] = None
+    calendarAction: Optional[CalendarActionInfo] = None
+    clipboardAction: Optional[ClipboardActionInfo] = None
+    composeAction: Optional[ComposeActionInfo] = None
+    dialerAction: Optional[DialerActionInfo] = None
     displayText: str = Field(max_length=200)
     postback: PostbackInfo
 
 
 class SuggestionInfo(BaseModel):
-    action: Optional[ActionInfo]
-    reply: Optional[ReplyActionInfo]
+    action: Optional[ActionInfo] = None
+    reply: Optional[ReplyActionInfo] = None
 
 
 class ButtonInfo(BaseModel):
@@ -271,14 +258,16 @@ class CommonInfo(BaseModel):
 
     msgId: str = Field(max_length=40)
     userContact: str = Field(max_length=40)
-    scheduleType: Optional[enums.ScheduleTypeEnum]
-    msgGroupId: Optional[str] = Field(max_length=20)
+    scheduleType: Optional[enums.ScheduleTypeEnum] = None
+    msgGroupId: Optional[str] = Field(max_length=20, default=None)
     msgServiceType: enums.MessageServiceTypeEnum
 
 
 class RcsInfo(BaseModel):
+    model_config = ConfigDict(arbitrary_types_allowed=True)
+
     chatbotId: str = Field(max_length=40)
-    agencyId: Optional[str] = Field(max_length=20)
+    agencyId: Optional[str] = Field(max_length=20, default=None)
     """
     # agencyId
     대행사 ID
@@ -291,19 +280,21 @@ class RcsInfo(BaseModel):
     """
     # agencyKey
     agencyId (대행사 ID) 와 매핑되는 대행사 Key 값
-    [보안성 강화] agencyId - agencyKey 가 불일치 하는 경우, 통신사에서 실패 처리. 대행사 고객인 경우 필수값. * agencyKey 는 RBC 에서 발급 및 갱신 가능하며,
+    [보안성 강화] agencyId - agencyKey 가 불일치 하는 경우,
+    통신사에서 실패 처리. 대행사 고객인 경우 필수값. * agencyKey 는 RBC 에서 발급 및 갱신 가능하며,
     갱신시 기존(old) agencyKey 는 최대 24 시간 유효함
     """
     brandKey: str
     """
     # brandKey
     chatbotId (챗봇 ID) 소유 brandId (브랜드 ID) 와 매핑되는 브랜드 Key 값
-    [보안성 강화] brandId - brandKey 가 불일치 하는 경우, 통신사에서 실패 처리. 대행사 고객인 경우 필수값. *brandKey 는 기존 RBC 에서 발급, 제공 중인 값
+    [보안성 강화] brandId - brandKey 가 불일치 하는 경우, 통신사에서 실패 처리.
+    대행사 고객인 경우 필수값. *brandKey 는 기존 RBC 에서 발급, 제공 중인 값
     """
 
     messagebaseId: Union[enums.MessageEnum, enums.RCSMessageEnum, str]
     serviceType: enums.ServiceTypeEnum
-    expiryOption: Optional[enums.ExpiryOptionEnum]
+    expiryOption: Optional[enums.ExpiryOptionEnum] = None
     """
     # expiryOption
     메시지 처리 옵션 enum: [1, 2]
@@ -316,7 +307,7 @@ class RcsInfo(BaseModel):
     """
     header: enums.HeaderEnum
 
-    footer: Optional[str] = Field(max_length=20, regex=r"^[\d-]*$")
+    footer: Optional[str] = Field(max_length=20, pattern=r"^[\d-]*$", default=None)
     """
     # footer
     수신거부 전화번호 (숫자, - 만 가능, Max: 20 자리)
@@ -332,7 +323,7 @@ def footer_validator(cls, v, values, **kwargs):
             raise ValueError("If header is 1 then footer should be provided.")
         return v
 
-    cdrId: Optional[str]
+    cdrId: Optional[str] = None
     """
     # cdrId
     청약 ID 기록시 기록한 ID로 과금 처리 된다.
@@ -383,7 +374,7 @@ def footer_validator(cls, v, values, **kwargs):
       - "media" :"maapfile://{fileId}"
     """
 
-    buttons: Optional[List[Union[ButtonInfo, EmptyDict]]]
+    buttons: Optional[List[Union[ButtonInfo, Dict[Never, Never]]]] = None
     """
     # buttons
     GSMA RCC.07의3.6.10.4의 ‘suggestions’ 규격에 준하여 버튼을 구성
@@ -397,7 +388,7 @@ def footer_validator(cls, v, values, **kwargs):
     버튼의 변수부를 등록 하여 사용하며, 해당 필드 허용하지 않음.
     """
 
-    chipList: Optional[List[SuggestionInfo]]
+    chipList: Optional[List[SuggestionInfo]] = None
     """
     # chipList
     GSMA RCC.07의3.6.10.4의 ‘suggestion’ 규격에 따라 chiplist를 구성(RCC.07의 기준 버전 확인 필요)
@@ -405,18 +396,17 @@ def footer_validator(cls, v, values, **kwargs):
     * Chiplist는 최대 11개까지 사용 가능하다
     """
 
-    replyId: Optional[str] = Field(max_length=40)
+    replyId: Optional[str] = Field(max_length=40, default=None)
     """
     # replyId
     양기업의 양방향 momsg를 수신할 때 포함된 replyID를 그대로 넣어서 전송한다
     Maximum : 40Byte
     ㅇRCSCHAT인 경우에 반드시 포함되어야 하며, RCSCHAT이 아닌 경우에는 포함되면 발송이 실패된다
-    *양방향서비스에서 양방향 대화의 세션을 관리하는 기준으로, 고객이 양방향 MO를 수행할 때마다 새롭게 할당되며, 유효시간은 24시간임. 유효시간이 만료된 replyId포함되어 발송되면 실패처리된다
+    *양방향서비스에서 양방향 대화의 세션을 관리하는 기준으로,
+    고객이 양방향 MO를 수행할 때마다 새롭게 할당되며, 유효시간은 24시간임.
+    유효시간이 만료된 replyId포함되어 발송되면 실패처리된다
     """
 
-    class Config:
-        smart_union = True
-
 
 class LegacyInfo(BaseModel):
     """
@@ -429,7 +419,7 @@ class LegacyInfo(BaseModel):
     Fallback은SMS/LMS에 대해서만 제공하고, MMS,CHAT에 대해서는 제공하지 않는다
     """
     callback: str = Field(max_length=20)
-    subject: Optional[str] = Field(max_length=50)
+    subject: Optional[str] = Field(max_length=50, default=None)
     msg: str = Field(max_length=4000)
     """
     SMS : 80Byte
@@ -442,7 +432,7 @@ class LegacyInfo(BaseModel):
     - 0: SMS/LMS인 경우, 미디어파일 없는 경우
     - 1~3 : (TBD) MMS인 경우
     """
-    contentData: Optional[str] = Field(max_length=250)
+    contentData: Optional[str] = Field(max_length=250, default=None)
     """
     (TBD) MMS 에서 사용하는 이미지파일의 정보
     - 컨텐츠위치^컨텐츠타입^컨텐츠서브타입
@@ -456,13 +446,13 @@ class LegacyInfo(BaseModel):
     예) http://10.217.59.209:5084/data/MEDIA/RCS/send/2021/08/09/test004.jpg^1^JPG
     Maximum : 250Byte
     """
-    prefix: Optional[str] = Field(max_length=10)
+    prefix: Optional[str] = Field(max_length=10, default=None)
     """
     RCS 전송성공 가능성 있는 fallback 메시지 전송시 삽입문구
         - 79998(전송성공불확실함), 55820(Revoked Message)... 등
         - SMS 는 msg(본문), LMS/MMS 는 subject(제목)내 문구 삽입 예) 재전송, RE:
     """
-    kisaOrigCode: Optional[int] = Field(ge=0, le=999999999)
+    kisaOrigCode: Optional[int] = Field(ge=0, le=999999999, default=None)
     """
     최초 발신 사업자코드, 9 자리 숫자 형식
     [보안성 강화] 대행사 고객의 경우 (즉, KT 중계가 최초 발신
@@ -496,21 +486,21 @@ class StatusInfo(BaseModel):
     메시지 전송 결과
     """
 
-    rcsId: Optional[str] = Field(max_length=20)
+    rcsId: Optional[str] = Field(max_length=20, default=None)
     msgId: str = Field(max_length=40)
-    userContact: Optional[str] = Field(max_length=40)
+    userContact: Optional[str] = Field(max_length=40, default=None)
     status: enums.MessageStatusEnum
-    serviceType: Union[enums.ServiceTypeEnum, enums.LegacyServiceTypeEnum, None]
-    mnoInfo: Optional[enums.MnoInfoEnum]
-    sentTime: Optional[str] = Field(regex=r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}\+\d{2}$")
-    reason: Optional[ReasonInfo]
-    error: Optional[ErrorInfo]
-    legacyError: Optional[LegacyErrorInfo]
-    timestamp: str = Field(regex=r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}\+\d{2}$")
-    autoReplyMsgId: Optional[str] = Field(max_length=40)
-    postbackId: Optional[str] = Field(max_length=40)
-    chatbotId: Optional[str] = Field(max_length=40)
-    bill: Optional[enums.BillEnum]
+    serviceType: Union[enums.ServiceTypeEnum, enums.LegacyServiceTypeEnum, None] = None
+    mnoInfo: Optional[enums.MnoInfoEnum] = None
+    sentTime: Optional[str] = Field(pattern=r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}\+\d{2}$", default=None)
+    reason: Optional[ReasonInfo] = None
+    error: Optional[ErrorInfo] = None
+    legacyError: Optional[LegacyErrorInfo] = None
+    timestamp: str = Field(pattern=r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}\+\d{2}$")
+    autoReplyMsgId: Optional[str] = Field(max_length=40, default=None)
+    postbackId: Optional[str] = Field(max_length=40, default=None)
+    chatbotId: Optional[str] = Field(max_length=40, default=None)
+    bill: Optional[enums.BillEnum] = None
 
 
 class QuerystatusInfo(BaseModel):
@@ -564,10 +554,10 @@ class MessageInfo(BaseModel):
     고객이 단말 대화방을 최초 진입 시 설정됨
     Maximum : 10Byte
     """
-    postbackId: Optional[str] = Field(max_length=40)
-    postbackData: Optional[str] = Field(max_length=2048)
-    displayText: Optional[str] = Field(max_length=200)
-    messageBody: Union[TextMessageInfo, UserLocationInfo, FileMessageInfo, None]
+    postbackId: Optional[str] = Field(max_length=40, default=None)
+    postbackData: Optional[str] = Field(max_length=2048, default=None)
+    displayText: Optional[str] = Field(max_length=200, default=None)
+    messageBody: Union[TextMessageInfo, UserLocationInfo, FileMessageInfo, None] = None
     """
     eventType이message인 경우에만 설정
     - 텍스트 메시지의 경우 샘플
@@ -607,13 +597,13 @@ def check_message_body(cls, v, values, **kwargs):
 
     userContact: str = Field(max_length=40)
     chatbotId: str = Field(max_length=40)
-    timestamp: str = Field(regex=r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}\+\d{2}$")
+    timestamp: str = Field(pattern=r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}\+\d{2}$")
 
 
 class SendInfo(BaseModel):
     common: CommonInfo
     rcs: RcsInfo
-    legacy: Optional[LegacyInfo]
+    legacy: Optional[LegacyInfo] = None
 
 
 class TokenInfo(BaseModel):
@@ -628,15 +618,15 @@ class FileRegistInfo(BaseModel):
     usageService: enums.FileUsageServiceEnum
     mimeType: str
     file: bytes
-    description: Optional[str]
+    description: Optional[str] = None
 
 
 class FileInfo(BaseModel):
-    fileId: Optional[str]
+    fileId: Optional[str] = None
     usageType: enums.FileUsageTypeEnum
     usageService: enums.FileUsageServiceEnum
     mimeType: str
     status: enums.FileStatusEnum
-    size: Optional[int]
-    expiryDate: str = Field(regex=r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}\+\d{2}$")
+    size: Optional[int] = None
+    expiryDate: str = Field(pattern=r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}\+\d{2}$")
     url: str


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index b8aef59..b8b771c 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -5,10 +5,10 @@ jobs:
     runs-on: ubuntu-latest
     steps:
     - uses: actions/checkout@v1
-    - name: Set up Python 3.7
+    - name: Set up Python 3.8
       uses: actions/setup-python@v2
       with:
-        python-version: 3.7
+        python-version: 3.8
     - name: Install Poetry
       run: |
         python -m pip install poetry
@@ -22,7 +22,7 @@ jobs:
     strategy:
       max-parallel: 8
       matrix:
-        python-version: [3.7, 3.8, 3.9, "3.10", "3.11"]
+        python-version: [3.8, 3.9, "3.10", "3.11", "3.12"]
     steps:
     - uses: actions/checkout@v1
     - name: Set up Python ${{ matrix.python-version }}
diff --git a/scripts/lint-test.sh b/scripts/lint-test.sh
index 0763528..ab5d88a 100644
--- a/scripts/lint-test.sh
+++ b/scripts/lint-test.sh
@@ -4,4 +4,4 @@ set -x
 
 poetry run black rcs_pydantic --check
 poetry run isort --check-only rcs_pydantic
-poetry run flake8
+poetry run ruff check --exit-zero .
diff --git a/tests/factory.py b/tests/factory.py
index 7c9ec42..d71f957 100644
--- a/tests/factory.py
+++ b/tests/factory.py
@@ -247,7 +247,7 @@ class Meta:
         model = scheme.ErrorInfo
 
     code: str = factory.LazyAttribute(
-        lambda n: fake.random_element(elements=[x.value[0] for x in errors.ErrorCodeEnum])
+        lambda n: str(fake.random_element(elements=[x.value[0] for x in errors.ErrorCodeEnum]))
     )
     message: str = factory.LazyAttribute(lambda n: fake.sentence(nb_words=20)[:50])
 
@@ -274,7 +274,6 @@ class Meta:
         model = scheme.ResponseInfo
 
     status: str = "200"
-    data: dict = factory.SubFactory(TokenInfoFactory)
 
 
 class MessageInfoFactory(factory.Factory):
diff --git a/tests/test_factory.py b/tests/test_factory.py
index 0491ec2..0452a51 100644
--- a/tests/test_factory.py
+++ b/tests/test_factory.py
@@ -130,7 +130,7 @@ def test_token_info_factory():
 
 
 def test_response_info_factory():
-    factory.ResponseInfoFactory()
+    factory.ResponseInfoFactory(data=factory.TokenInfoFactory().model_dump())
 
 
 def test_message_info_factory():
diff --git a/tests/test_rcs_pydantic.py b/tests/test_rcs_pydantic.py
index 9cba2d5..ac5b126 100644
--- a/tests/test_rcs_pydantic.py
+++ b/tests/test_rcs_pydantic.py
@@ -1,12 +1,10 @@
 import pytest
 from faker import Faker
-from pydantic import BaseModel
 
 from rcs_pydantic import enums
 from rcs_pydantic.errors import ErrorCodeEnum, KTErrorCodeEnum, MaaPErrorCodeEnum, RcsBizCenterErrorCodeEnum
 from rcs_pydantic.exceptions import MessageException
 from rcs_pydantic.main import RcsMessage
-from rcs_pydantic.scheme import EmptyDict
 
 from . import factory
 
@@ -21,14 +19,14 @@ def test_rcs_message():
         agency_id="abc",
         agency_key="abc",
         brand_key="abc",
-        expiry_option=2,
-        header="1",
+        expiry_option=enums.ExpiryOptionEnum.AFTER_SETTING_TIMES,
+        header=enums.HeaderEnum.ADVERTISE,
         footer="010-0000-0000",
         cdr_id="abc",
         copy_allowed=True,
         message_group_id="abc",
     )
-    rcs_message.send()
+    assert rcs_message.send_info
 
 
 def test_rcs_chat_message():
@@ -39,15 +37,15 @@ def test_rcs_chat_message():
         agency_id="abc",
         agency_key="abc",
         brand_key="abc",
-        expiry_option=2,
-        header="1",
+        expiry_option=enums.ExpiryOptionEnum.AFTER_SETTING_TIMES,
+        header=enums.HeaderEnum.ADVERTISE,
         footer="010-0000-0000",
         cdr_id="abc",
         copy_allowed=True,
         service_type=enums.ServiceTypeEnum.CHAT,
         chips=[factory.SuggestionInfoFactory()],
     )
-    rcs_message.send()
+    assert rcs_message.send_info
 
 
 def test_rcs_message_with_empty_button():
@@ -58,13 +56,13 @@ def test_rcs_message_with_empty_button():
         agency_id="abc",
         agency_key="abc",
         brand_key="abc",
-        expiry_option=2,
-        header="1",
+        expiry_option=enums.ExpiryOptionEnum.AFTER_SETTING_TIMES,
+        header=enums.HeaderEnum.ADVERTISE,
         footer="010-0000-0000",
         cdr_id="abc",
         copy_allowed=True,
     )
-    rcs_message.send()
+    assert rcs_message.send_info
 
 
 def test_tuple_enum_has_value():
@@ -104,22 +102,6 @@ def test_unknown_error_code_message_exception():
         raise MessageException(123)
 
 
-def test_empty_dict():
-    class C(BaseModel):
-        item: EmptyDict
-
-    C(item={})
-
-    with pytest.raises(ValueError):
-        C(item=None)
-
-    with pytest.raises(ValueError):
-        C(item=[])
-
-    with pytest.raises(ValueError):
-        C(item={"a": 1})
-
-
 def test_rcs_legacy_message():
     rcs_message = RcsMessage(
         factory.MessageInfoFactory(),
@@ -128,11 +110,11 @@ def test_rcs_legacy_message():
         agency_id="abc",
         agency_key="abc",
         brand_key="abc",
-        expiry_option=2,
-        header="1",
+        expiry_option=enums.ExpiryOptionEnum.AFTER_SETTING_TIMES,
+        header=enums.HeaderEnum.ADVERTISE,
         footer="010-0000-0000",
         cdr_id="abc",
         copy_allowed=True,
         legacy=factory.LegacyInfoFactory(),
     )
-    rcs_message.send()
+    assert rcs_message.send_info