From 624a2142bf8779ae734621260613a187aebc274c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 30 Jan 2023 11:49:56 +0100 Subject: [PATCH 01/85] =?UTF-8?q?=F0=9F=94=A7=20Add=20template=20for=20Git?= =?UTF-8?q?Hub=20Discussion=20questions=20and=20update=20issues=20template?= =?UTF-8?q?=20(#544)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/DISCUSSION_TEMPLATE/questions.yml | 160 ++++++++++++++++++++++ .github/ISSUE_TEMPLATE/question.yml | 20 +-- 2 files changed, 170 insertions(+), 10 deletions(-) create mode 100644 .github/DISCUSSION_TEMPLATE/questions.yml diff --git a/.github/DISCUSSION_TEMPLATE/questions.yml b/.github/DISCUSSION_TEMPLATE/questions.yml new file mode 100644 index 0000000..97902a6 --- /dev/null +++ b/.github/DISCUSSION_TEMPLATE/questions.yml @@ -0,0 +1,160 @@ +labels: [question] +body: + - type: markdown + attributes: + value: | + Thanks for your interest in SQLModel! πŸš€ + + Please follow these instructions, fill every question, and do every step. πŸ™ + + I'm asking this because answering questions and solving problems in GitHub is what consumes most of the time. + + I end up not being able to add new features, fix bugs, review pull requests, etc. as fast as I wish because I have to spend too much time handling questions. + + All that, on top of all the incredible help provided by a bunch of community members that give a lot of their time to come here and help others. + + If more SQLModel users came to help others like them just a little bit more, it would be much less effort for them (and you and me πŸ˜…). + + By asking questions in a structured way (following this) it will be much easier to help you. + + And there's a high chance that you will find the solution along the way and you won't even have to submit it and wait for an answer. 😎 + + As there are too many questions, I'll have to discard and close the incomplete ones. That will allow me (and others) to focus on helping people like you that follow the whole process and help us help you. πŸ€“ + - type: checkboxes + id: checks + attributes: + label: First Check + description: Please confirm and check all the following options. + options: + - label: I added a very descriptive title here. + required: true + - label: I used the GitHub search to find a similar question and didn't find it. + required: true + - label: I searched the SQLModel documentation, with the integrated search. + required: true + - label: I already searched in Google "How to X in SQLModel" and didn't find any information. + required: true + - label: I already read and followed all the tutorial in the docs and didn't find an answer. + required: true + - label: I already checked if it is not related to SQLModel but to [Pydantic](https://github.com/samuelcolvin/pydantic). + required: true + - label: I already checked if it is not related to SQLModel but to [SQLAlchemy](https://github.com/sqlalchemy/sqlalchemy). + required: true + - type: checkboxes + id: help + attributes: + label: Commit to Help + description: | + After submitting this, I commit to one of: + + * Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there. + * I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future. + * Review one Pull Request by downloading the code and following all the review process](https://sqlmodel.tiangolo.com/help/#review-pull-requests). + + options: + - label: I commit to help with one of those options πŸ‘† + required: true + - type: textarea + id: example + attributes: + label: Example Code + description: | + Please add a self-contained, [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) with your use case. + + If I (or someone) can copy it, run it, and see it right away, there's a much higher chance I (or someone) will be able to help you. + + placeholder: | + from typing import Optional + + from sqlmodel import Field, Session, SQLModel, create_engine + + + class Hero(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str + secret_name: str + age: Optional[int] = None + + + hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") + + engine = create_engine("sqlite:///database.db") + + + SQLModel.metadata.create_all(engine) + + with Session(engine) as session: + session.add(hero_1) + session.commit() + session.refresh(hero_1) + print(hero_1) + render: python + validations: + required: true + - type: textarea + id: description + attributes: + label: Description + description: | + What is the problem, question, or error? + + Write a short description telling me what you are doing, what you expect to happen, and what is currently happening. + placeholder: | + * Create a Hero model. + * Create a Hero instance. + * Save it to a SQLite database. + * Check the data with DB Browser for SQLite. + * There's only one hero there, but I expected it to include many others recruited by the first one. + validations: + required: true + - type: dropdown + id: os + attributes: + label: Operating System + description: What operating system are you on? + multiple: true + options: + - Linux + - Windows + - macOS + - Other + validations: + required: true + - type: textarea + id: os-details + attributes: + label: Operating System Details + description: You can add more details about your operating system here, in particular if you chose "Other". + - type: input + id: sqlmodel-version + attributes: + label: SQLModel Version + description: | + What SQLModel version are you using? + + You can find the SQLModel version with: + + ```bash + python -c "import sqlmodel; print(sqlmodel.__version__)" + ``` + validations: + required: true + - type: input + id: python-version + attributes: + label: Python Version + description: | + What Python version are you using? + + You can find the Python version with: + + ```bash + python --version + ``` + validations: + required: true + - type: textarea + id: context + attributes: + label: Additional Context + description: Add any additional context information or screenshots you think are useful. diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml index a574467..dfdc25d 100644 --- a/.github/ISSUE_TEMPLATE/question.yml +++ b/.github/ISSUE_TEMPLATE/question.yml @@ -8,29 +8,29 @@ body: Thanks for your interest in SQLModel! πŸš€ Please follow these instructions, fill every question, and do every step. πŸ™ - - I'm asking this because answering questions and solving problems in GitHub issues is what consumes most of the time. - - I end up not being able to add new features, fix bugs, review pull requests, etc. as fast as I wish because I have to spend too much time handling issues. + + I'm asking this because answering questions and solving problems in GitHub is what consumes most of the time. + + I end up not being able to add new features, fix bugs, review pull requests, etc. as fast as I wish because I have to spend too much time handling questions. All that, on top of all the incredible help provided by a bunch of community members that give a lot of their time to come here and help others. If more SQLModel users came to help others like them just a little bit more, it would be much less effort for them (and you and me πŸ˜…). By asking questions in a structured way (following this) it will be much easier to help you. - + And there's a high chance that you will find the solution along the way and you won't even have to submit it and wait for an answer. 😎 - As there are too many issues with questions, I'll have to close the incomplete ones. That will allow me (and others) to focus on helping people like you that follow the whole process and help us help you. πŸ€“ + As there are too many questions, I'll have to discard and close the incomplete ones. That will allow me (and others) to focus on helping people like you that follow the whole process and help us help you. πŸ€“ - type: checkboxes id: checks attributes: label: First Check description: Please confirm and check all the following options. options: - - label: I added a very descriptive title to this issue. + - label: I added a very descriptive title here. required: true - - label: I used the GitHub search to find a similar issue and didn't find it. + - label: I used the GitHub search to find a similar question and didn't find it. required: true - label: I searched the SQLModel documentation, with the integrated search. required: true @@ -48,10 +48,10 @@ body: label: Commit to Help description: | After submitting this, I commit to one of: - + * Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there. * I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future. - * Implement a Pull Request for a confirmed bug. + * Review one Pull Request by downloading the code and following all the review process](https://sqlmodel.tiangolo.com/help/#review-pull-requests). options: - label: I commit to help with one of those options πŸ‘† From c47a54df918191fda75dd5f3a397f29740f7419a Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 30 Jan 2023 10:50:32 +0000 Subject: [PATCH 02/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 4a4788f..9a680bc 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ”§ Add template for GitHub Discussion questions and update issues template. PR [#544](https://github.com/tiangolo/sqlmodel/pull/544) by [@tiangolo](https://github.com/tiangolo). * πŸ‘· Refactor CI artifact upload/download for docs previews. PR [#514](https://github.com/tiangolo/sqlmodel/pull/514) by [@tiangolo](https://github.com/tiangolo). * ✏️ Fix typo in internal function name `get_sqlachemy_type()`. PR [#496](https://github.com/tiangolo/sqlmodel/pull/496) by [@cmarqu](https://github.com/cmarqu). * ⬆ Bump actions/cache from 2 to 3. PR [#497](https://github.com/tiangolo/sqlmodel/pull/497) by [@dependabot[bot]](https://github.com/apps/dependabot). From 1c294ddeb6ec83c79c38239eb43112225db17731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 31 Jan 2023 15:14:16 +0100 Subject: [PATCH 03/85] =?UTF-8?q?=F0=9F=94=A7=20Update=20new=20issue=20cho?= =?UTF-8?q?oser=20to=20point=20to=20GitHub=20Discussions=20(#546)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/ISSUE_TEMPLATE/config.yml | 9 + .github/ISSUE_TEMPLATE/feature-request.yml | 214 --------------------- .github/ISSUE_TEMPLATE/privileged.yml | 22 +++ .github/ISSUE_TEMPLATE/question.yml | 162 ---------------- 4 files changed, 31 insertions(+), 376 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/feature-request.yml create mode 100644 .github/ISSUE_TEMPLATE/privileged.yml delete mode 100644 .github/ISSUE_TEMPLATE/question.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 5574939..46a5c2c 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -2,3 +2,12 @@ blank_issues_enabled: false contact_links: - name: Security Contact about: Please report security vulnerabilities to security@tiangolo.com + - name: Question or Problem + about: Ask a question or ask about a problem in GitHub Discussions. + url: https://github.com/tiangolo/sqlmodel/discussions/categories/questions + - name: Feature Request + about: To suggest an idea or ask about a feature, please start with a question saying what you would like to achieve. There might be a way to do it already. + url: https://github.com/tiangolo/sqlmodel/discussions/categories/questions + - name: Show and tell + about: Show what you built with SQLModel or to be used with SQLModel. + url: https://github.com/tiangolo/sqlmodel/discussions/categories/show-and-tell diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml deleted file mode 100644 index 5f18e8d..0000000 --- a/.github/ISSUE_TEMPLATE/feature-request.yml +++ /dev/null @@ -1,214 +0,0 @@ -name: Feature Request -description: Suggest an idea or ask for a feature that you would like to have in SQLModel -labels: [enhancement] -body: - - type: markdown - attributes: - value: | - Thanks for your interest in SQLModel! πŸš€ - - Please follow these instructions, fill every question, and do every step. πŸ™ - - I'm asking this because answering questions and solving problems in GitHub issues is what consumes most of the time. - - I end up not being able to add new features, fix bugs, review pull requests, etc. as fast as I wish because I have to spend too much time handling issues. - - All that, on top of all the incredible help provided by a bunch of community members that give a lot of their time to come here and help others. - - If more SQLModel users came to help others like them just a little bit more, it would be much less effort for them (and you and me πŸ˜…). - - By asking questions in a structured way (following this) it will be much easier to help you. - - And there's a high chance that you will find the solution along the way and you won't even have to submit it and wait for an answer. 😎 - - As there are too many issues with questions, I'll have to close the incomplete ones. That will allow me (and others) to focus on helping people like you that follow the whole process and help us help you. πŸ€“ - - type: checkboxes - id: checks - attributes: - label: First Check - description: Please confirm and check all the following options. - options: - - label: I added a very descriptive title to this issue. - required: true - - label: I used the GitHub search to find a similar issue and didn't find it. - required: true - - label: I searched the SQLModel documentation, with the integrated search. - required: true - - label: I already searched in Google "How to X in SQLModel" and didn't find any information. - required: true - - label: I already read and followed all the tutorial in the docs and didn't find an answer. - required: true - - label: I already checked if it is not related to SQLModel but to [Pydantic](https://github.com/samuelcolvin/pydantic). - required: true - - label: I already checked if it is not related to SQLModel but to [SQLAlchemy](https://github.com/sqlalchemy/sqlalchemy). - required: true - - type: checkboxes - id: help - attributes: - label: Commit to Help - description: | - After submitting this, I commit to one of: - - * Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there. - * I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future. - * Implement a Pull Request for a confirmed bug. - - options: - - label: I commit to help with one of those options πŸ‘† - required: true - - type: textarea - id: example - attributes: - label: Example Code - description: | - Please add a self-contained, [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) with your use case. - - If I (or someone) can copy it, run it, and see it right away, there's a much higher chance I (or someone) will be able to help you. - - placeholder: | - from typing import Optional - - from sqlmodel import Field, Session, SQLModel, create_engine - - - class Hero(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) - name: str - secret_name: str - age: Optional[int] = None - - - hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") - - engine = create_engine("sqlite:///database.db") - - - SQLModel.metadata.create_all(engine) - - with Session(engine) as session: - session.add(hero_1) - session.commit() - session.refresh(hero_1) - print(hero_1) - render: python - validations: - required: true - - type: textarea - id: description - attributes: - label: Description - description: | - What is your feature request? - - Write a short description telling me what you are trying to solve and what you are currently doing. - placeholder: | - * Create a Hero model. - * Create a Hero instance. - * Save it to a SQLite database. - * I would like it to also automatically send me an email with all the SQL code executed. - validations: - required: true - - type: textarea - id: wanted-solution - attributes: - label: Wanted Solution - description: | - Tell me what's the solution you would like. - placeholder: | - I would like it to have a `send_email` configuration that defaults to `False`, and can be set to `True` to send me an email. - validations: - required: true - - type: textarea - id: wanted-code - attributes: - label: Wanted Code - description: Show me an example of how you would want the code to look like. - placeholder: | - from typing import Optional - - from sqlmodel import Field, Session, SQLModel, create_engine - - - class Hero(SQLModel, table=True, send_email=True): - id: Optional[int] = Field(default=None, primary_key=True) - name: str - secret_name: str - age: Optional[int] = None - - - hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") - - engine = create_engine("sqlite:///database.db") - - - SQLModel.metadata.create_all(engine) - - with Session(engine) as session: - session.add(hero_1) - session.commit() - session.refresh(hero_1) - print(hero_1) - - - render: python - validations: - required: true - - type: textarea - id: alternatives - attributes: - label: Alternatives - description: | - Tell me about alternatives you've considered. - placeholder: | - To hire someone to look at the logs, write the SQL in paper, and then send me a letter by post with it. - - type: dropdown - id: os - attributes: - label: Operating System - description: What operating system are you on? - multiple: true - options: - - Linux - - Windows - - macOS - - Other - validations: - required: true - - type: textarea - id: os-details - attributes: - label: Operating System Details - description: You can add more details about your operating system here, in particular if you chose "Other". - - type: input - id: sqlmodel-version - attributes: - label: SQLModel Version - description: | - What SQLModel version are you using? - - You can find the SQLModel version with: - - ```bash - python -c "import sqlmodel; print(sqlmodel.__version__)" - ``` - validations: - required: true - - type: input - id: python-version - attributes: - label: Python Version - description: | - What Python version are you using? - - You can find the Python version with: - - ```bash - python --version - ``` - validations: - required: true - - type: textarea - id: context - attributes: - label: Additional Context - description: Add any additional context information or screenshots you think are useful. diff --git a/.github/ISSUE_TEMPLATE/privileged.yml b/.github/ISSUE_TEMPLATE/privileged.yml new file mode 100644 index 0000000..da11e71 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/privileged.yml @@ -0,0 +1,22 @@ +name: Privileged +description: You are @tiangolo or he asked you directly to create an issue here. If not, check the other options. πŸ‘‡ +body: + - type: markdown + attributes: + value: | + Thanks for your interest in SQLModel! πŸš€ + + If you are not @tiangolo or he didn't ask you directly to create an issue here, please start the conversation in a [Question in GitHub Discussions](https://github.com/tiangolo/sqlmodel/discussions/categories/questions) instead. + - type: checkboxes + id: privileged + attributes: + label: Privileged issue + description: Confirm that you are allowed to create an issue here. + options: + - label: I'm @tiangolo or he asked me directly to create an issue here. + required: true + - type: textarea + id: content + attributes: + label: Issue Content + description: Add the content of the issue here. diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml deleted file mode 100644 index dfdc25d..0000000 --- a/.github/ISSUE_TEMPLATE/question.yml +++ /dev/null @@ -1,162 +0,0 @@ -name: Question or Problem -description: Ask a question or ask about a problem -labels: [question] -body: - - type: markdown - attributes: - value: | - Thanks for your interest in SQLModel! πŸš€ - - Please follow these instructions, fill every question, and do every step. πŸ™ - - I'm asking this because answering questions and solving problems in GitHub is what consumes most of the time. - - I end up not being able to add new features, fix bugs, review pull requests, etc. as fast as I wish because I have to spend too much time handling questions. - - All that, on top of all the incredible help provided by a bunch of community members that give a lot of their time to come here and help others. - - If more SQLModel users came to help others like them just a little bit more, it would be much less effort for them (and you and me πŸ˜…). - - By asking questions in a structured way (following this) it will be much easier to help you. - - And there's a high chance that you will find the solution along the way and you won't even have to submit it and wait for an answer. 😎 - - As there are too many questions, I'll have to discard and close the incomplete ones. That will allow me (and others) to focus on helping people like you that follow the whole process and help us help you. πŸ€“ - - type: checkboxes - id: checks - attributes: - label: First Check - description: Please confirm and check all the following options. - options: - - label: I added a very descriptive title here. - required: true - - label: I used the GitHub search to find a similar question and didn't find it. - required: true - - label: I searched the SQLModel documentation, with the integrated search. - required: true - - label: I already searched in Google "How to X in SQLModel" and didn't find any information. - required: true - - label: I already read and followed all the tutorial in the docs and didn't find an answer. - required: true - - label: I already checked if it is not related to SQLModel but to [Pydantic](https://github.com/samuelcolvin/pydantic). - required: true - - label: I already checked if it is not related to SQLModel but to [SQLAlchemy](https://github.com/sqlalchemy/sqlalchemy). - required: true - - type: checkboxes - id: help - attributes: - label: Commit to Help - description: | - After submitting this, I commit to one of: - - * Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there. - * I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future. - * Review one Pull Request by downloading the code and following all the review process](https://sqlmodel.tiangolo.com/help/#review-pull-requests). - - options: - - label: I commit to help with one of those options πŸ‘† - required: true - - type: textarea - id: example - attributes: - label: Example Code - description: | - Please add a self-contained, [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) with your use case. - - If I (or someone) can copy it, run it, and see it right away, there's a much higher chance I (or someone) will be able to help you. - - placeholder: | - from typing import Optional - - from sqlmodel import Field, Session, SQLModel, create_engine - - - class Hero(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) - name: str - secret_name: str - age: Optional[int] = None - - - hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") - - engine = create_engine("sqlite:///database.db") - - - SQLModel.metadata.create_all(engine) - - with Session(engine) as session: - session.add(hero_1) - session.commit() - session.refresh(hero_1) - print(hero_1) - render: python - validations: - required: true - - type: textarea - id: description - attributes: - label: Description - description: | - What is the problem, question, or error? - - Write a short description telling me what you are doing, what you expect to happen, and what is currently happening. - placeholder: | - * Create a Hero model. - * Create a Hero instance. - * Save it to a SQLite database. - * Check the data with DB Browser for SQLite. - * There's only one hero there, but I expected it to include many others recruited by the first one. - validations: - required: true - - type: dropdown - id: os - attributes: - label: Operating System - description: What operating system are you on? - multiple: true - options: - - Linux - - Windows - - macOS - - Other - validations: - required: true - - type: textarea - id: os-details - attributes: - label: Operating System Details - description: You can add more details about your operating system here, in particular if you chose "Other". - - type: input - id: sqlmodel-version - attributes: - label: SQLModel Version - description: | - What SQLModel version are you using? - - You can find the SQLModel version with: - - ```bash - python -c "import sqlmodel; print(sqlmodel.__version__)" - ``` - validations: - required: true - - type: input - id: python-version - attributes: - label: Python Version - description: | - What Python version are you using? - - You can find the Python version with: - - ```bash - python --version - ``` - validations: - required: true - - type: textarea - id: context - attributes: - label: Additional Context - description: Add any additional context information or screenshots you think are useful. From dc44d2e2c43d302bd9dbc9248365ec81efc498d0 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 31 Jan 2023 14:14:55 +0000 Subject: [PATCH 04/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 9a680bc..7b59117 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ”§ Update new issue chooser to point to GitHub Discussions. PR [#546](https://github.com/tiangolo/sqlmodel/pull/546) by [@tiangolo](https://github.com/tiangolo). * πŸ”§ Add template for GitHub Discussion questions and update issues template. PR [#544](https://github.com/tiangolo/sqlmodel/pull/544) by [@tiangolo](https://github.com/tiangolo). * πŸ‘· Refactor CI artifact upload/download for docs previews. PR [#514](https://github.com/tiangolo/sqlmodel/pull/514) by [@tiangolo](https://github.com/tiangolo). * ✏️ Fix typo in internal function name `get_sqlachemy_type()`. PR [#496](https://github.com/tiangolo/sqlmodel/pull/496) by [@cmarqu](https://github.com/cmarqu). From 5c9a3b3b2181ee274be1cdf424ff9da26e377cbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 3 Feb 2023 18:52:25 +0100 Subject: [PATCH 05/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20help=20SQLModel?= =?UTF-8?q?=20docs=20(#548)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/help.md | 150 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 143 insertions(+), 7 deletions(-) diff --git a/docs/help.md b/docs/help.md index 6cde4c6..d0d2308 100644 --- a/docs/help.md +++ b/docs/help.md @@ -58,26 +58,125 @@ You can: I love to hear about how **SQLModel** is being used, what you have liked in it, in which project/company are you using it, etc. -## Help others with issues in GitHub +## Help others with questions in GitHub -You can see existing issues and try and help others, most of the times they are questions that you might already know the answer for. πŸ€“ +You can try and help others with their questions in: + +* GitHub Discussions +* GitHub Issues + +In many cases you might already know the answer for those questions. πŸ€“ + +Just remember, the most important point is: try to be kind. People come with their frustrations and in many cases don't ask in the best way, but try as best as you can to be kind. πŸ€— + +The idea is for the **SQLModel** community to be kind and welcoming. At the same time, don't accept bullying or disrespectful behavior towards others. We have to take care of each other. + +--- + +Here's how to help others with questions (in discussions or issues): + +### Understand the question + +* Check if you can understand what is the **purpose** and use case of the person asking. + +* Then check if the question (the vast majority are questions) is **clear**. + +* In many cases the question asked is about an imaginary solution from the user, but there might be a **better** one. If you can understand the problem and use case better, you might be able to suggest a better **alternative solution**. + +* If you can't understand the question, ask for more **details**. + +### Reproduce the problem + +For most of the cases and most of the questions there's something related to the person's **original code**. + +In many cases they will only copy a fragment of the code, but that's not enough to **reproduce the problem**. + +* You can ask them to provide a minimal, reproducible, example, that you can **copy-paste** and run locally to see the same error or behavior they are seeing, or to understand their use case better. + +* If you are feeling too generous, you can try to **create an example** like that yourself, just based on the description of the problem. Just have in mind that this might take a lot of time and it might be better to ask them to clarify the problem first. + +### Suggest solutions + +* After being able to understand the question, you can give them a possible **answer**. + +* In many cases, it's better to understand their **underlying problem or use case**, because there might be a better way to solve it than what they are trying to do. + +### Ask to close + +If they reply, there's a high chance you would have solved their problem, congrats, **you're a hero**! 🦸 + +* Now, if that solved their problem, you can ask them to: + + * In GitHub Discussions: mark the comment as the **answer**. + * In GitHub Issues: **close** the issue**. ## Watch the GitHub repository You can "watch" SQLModel in GitHub (clicking the "watch" button at the top right): https://github.com/tiangolo/sqlmodel. πŸ‘€ -If you select "Watching" instead of "Releases only" you will receive notifications when someone creates a new issue. +If you select "Watching" instead of "Releases only" you will receive notifications when someone creates a new issue or question. You can also specify that you only want to be notified about new issues, or discussions, or PRs, etc. -Then you can try and help them solve those issues. +Then you can try and help them solve those questions. -## Create issues +## Ask Questions -You can create a new issue in the GitHub repository, for example to: +You can create a new question in the GitHub repository, for example to: * Ask a **question** or ask about a **problem**. * Suggest a new **feature**. -**Note**: if you create an issue, then I'm going to ask you to also help others. πŸ˜‰ +**Note**: if you do it, then I'm going to ask you to also help others. πŸ˜‰ + +## Review Pull Requests + +You can help me review pull requests from others. + +Again, please try your best to be kind. πŸ€— + +--- + +Here's what to have in mind and how to review a pull request: + +### Understand the problem + +* First, make sure you **understand the problem** that the pull request is trying to solve. It might have a longer discussion in a GitHub Discussion or issue. + +* There's also a good chance that the pull request is not actually needed because the problem can be solved in a **different way**. Then you can suggest or ask about that. + +### Don't worry about style + +* Don't worry too much about things like commit message styles, I will squash and merge customizing the commit manually. + +* Also don't worry about style rules, there are already automatized tools checking that. + +And if there's any other style or consistency need, I'll ask directly for that, or I'll add commits on top with the needed changes. + +### Check the code + +* Check and read the code, see if it makes sense, **run it locally** and see if it actually solves the problem. + +* Then **comment** saying that you did that, that's how I will know you really checked it. + +!!! info + Unfortunately, I can't simply trust PRs that just have several approvals. + + Several times it has happened that there are PRs with 3, 5 or more approvals, probably because the description is appealing, but when I check the PRs, they are actually broken, have a bug, or don't solve the problem they claim to solve. πŸ˜… + + So, it's really important that you actually read and run the code, and let me know in the comments that you did. πŸ€“ + +* If the PR can be simplified in a way, you can ask for that, but there's no need to be too picky, there might be a lot of subjective points of view (and I will have my own as well πŸ™ˆ), so it's better if you can focus on the fundamental things. + +### Tests + +* Help me check that the PR has **tests**. + +* Check that the tests **fail** before the PR. 🚨 + +* Then check that the tests **pass** after the PR. βœ… + +* Many PRs don't have tests, you can **remind** them to add tests, or you can even **suggest** some tests yourself. That's one of the things that consume most time and you can help a lot with that. + +* Then also comment what you tried, that way I'll know that you checked it. πŸ€“ ## Create a Pull Request @@ -86,7 +185,44 @@ You can [contribute](contributing.md){.internal-link target=_blank} to the sourc * To fix a typo you found on the documentation. * To propose new documentation sections. * To fix an existing issue/bug. + * Make sure to add tests. * To add a new feature. + * Make sure to add tests. + * Make sure to add documentation if it's relevant. + +## Help Maintain SQLModel + +Help me maintain **SQLModel**! πŸ€“ + +There's a lot of work to do, and for most of it, **YOU** can do it. + +The main tasks that you can do right now are: + +* [Help others with questions in GitHub](#help-others-with-questions-in-github){.internal-link target=_blank} (see the section above). +* [Review Pull Requests](#review-pull-requests){.internal-link target=_blank} (see the section above). + +Those two tasks are what **consume time the most**. That's the main work of maintaining SQLModel. + +If you can help me with that, **you are helping me maintain SQLModel** and making sure it keeps **advancing faster and better**. πŸš€ + +## Join the chat + +Join the πŸ‘₯ FastAPI and Friends Discord chat server πŸ‘₯ and hang out with others in the community. There's a `#sqlmodel` channel. + +!!! tip + For questions, ask them in GitHub Discussions, there's a much better chance you will receive help there. + + Use the chat only for other general conversations. + +### Don't use the chat for questions + +Have in mind that as chats allow more "free conversation", it's easy to ask questions that are too general and more difficult to answer, so, you might not receive answers. + +In GitHub, the template will guide you to write the right question so that you can more easily get a good answer, or even solve the problem yourself even before asking. And in GitHub I can make sure I always answer everything, even if it takes some time. I can't personally do that with the chat. πŸ˜… + +Conversations in the chat are also not as easily searchable as in GitHub, so questions and answers might get lost in the conversation. + +On the other side, there are thousands of users in the chat, so there's a high chance you'll find someone to talk to there, almost all the time. πŸ˜„ ## Sponsor the author From 33e00c3ab3ed2143c583f94ed0b6bfdde0d72c07 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 3 Feb 2023 17:53:01 +0000 Subject: [PATCH 06/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 7b59117..9f8ce2a 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ“ Update help SQLModel docs. PR [#548](https://github.com/tiangolo/sqlmodel/pull/548) by [@tiangolo](https://github.com/tiangolo). * πŸ”§ Update new issue chooser to point to GitHub Discussions. PR [#546](https://github.com/tiangolo/sqlmodel/pull/546) by [@tiangolo](https://github.com/tiangolo). * πŸ”§ Add template for GitHub Discussion questions and update issues template. PR [#544](https://github.com/tiangolo/sqlmodel/pull/544) by [@tiangolo](https://github.com/tiangolo). * πŸ‘· Refactor CI artifact upload/download for docs previews. PR [#514](https://github.com/tiangolo/sqlmodel/pull/514) by [@tiangolo](https://github.com/tiangolo). From 810236c26c6d46a2d2b008e1640a3f41f0c6a77e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 21 Feb 2023 12:02:18 +0100 Subject: [PATCH 07/85] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Upgrade=20analytics?= =?UTF-8?q?=20(#558)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index a27bbde..646af7c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -110,7 +110,7 @@ markdown_extensions: extra: analytics: provider: google - property: UA-205713594-2 + property: G-J8HVTT936W social: - icon: fontawesome/brands/github-alt link: https://github.com/tiangolo/sqlmodel From 43a689d369f52b72aac60efd71111aba7d84714d Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 21 Feb 2023 11:02:54 +0000 Subject: [PATCH 08/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 9f8ce2a..0ea7801 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆️ Upgrade analytics. PR [#558](https://github.com/tiangolo/sqlmodel/pull/558) by [@tiangolo](https://github.com/tiangolo). * πŸ“ Update help SQLModel docs. PR [#548](https://github.com/tiangolo/sqlmodel/pull/548) by [@tiangolo](https://github.com/tiangolo). * πŸ”§ Update new issue chooser to point to GitHub Discussions. PR [#546](https://github.com/tiangolo/sqlmodel/pull/546) by [@tiangolo](https://github.com/tiangolo). * πŸ”§ Add template for GitHub Discussion questions and update issues template. PR [#544](https://github.com/tiangolo/sqlmodel/pull/544) by [@tiangolo](https://github.com/tiangolo). From 02bd7ebffdeda14110cff3f1bb7472a77a17f73b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 29 Jul 2023 12:32:47 +0200 Subject: [PATCH 09/85] =?UTF-8?q?=F0=9F=97=91=EF=B8=8F=20Deprecate=20Pytho?= =?UTF-8?q?n=203.6=20and=20upgrade=20Poetry=20and=20Poetry=20Version=20Plu?= =?UTF-8?q?gin=20(#627)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build-docs.yml | 32 +++++++++++------------ .github/workflows/publish.yml | 16 +++++------- .github/workflows/test.yml | 42 ++++++++++++++++++++----------- README.md | 2 +- docs/contributing.md | 4 --- docs/features.md | 2 +- docs/index.md | 2 +- docs/tutorial/index.md | 6 +---- pyproject.toml | 12 ++++----- scripts/lint.sh | 2 -- scripts/test.sh | 1 + sqlmodel/main.py | 3 ++- sqlmodel/sql/expression.py | 37 ++++++--------------------- sqlmodel/sql/expression.py.jinja2 | 40 ++++++----------------------- 14 files changed, 77 insertions(+), 124 deletions(-) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index 6400691..3bcc78d 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -4,26 +4,28 @@ on: branches: - main pull_request: - types: [opened, synchronize] + types: + - opened + - synchronize workflow_dispatch: inputs: debug_enabled: - description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)' + description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)' required: false default: false jobs: build-docs: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: Dump GitHub context env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - uses: actions/checkout@v3.1.0 + - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 with: - python-version: "3.7" + python-version: "3.11" # Allow debugging with tmate - name: Setup tmate session uses: mxschmitt/action-tmate@v3 @@ -34,34 +36,30 @@ jobs: id: cache with: path: ${{ env.pythonLocation }} - key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-root-docs + key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-root-docs-v2 - name: Install poetry if: steps.cache.outputs.cache-hit != 'true' - # TODO: remove python -m pip install --force git+https://github.com/python-poetry/poetry-core.git@ad33bc2 - # once there's a release of Poetry 1.2.x including poetry-core > 1.1.0a6 - # Ref: https://github.com/python-poetry/poetry-core/pull/188 run: | python -m pip install --upgrade pip - python -m pip install --force git+https://github.com/python-poetry/poetry-core.git@ad33bc2 - python -m pip install "poetry==1.2.0a2" - python -m poetry plugin add poetry-version-plugin + python -m pip install "poetry" + python -m poetry self add poetry-version-plugin - name: Configure poetry run: python -m poetry config virtualenvs.create false - name: Install Dependencies if: steps.cache.outputs.cache-hit != 'true' run: python -m poetry install - name: Install Material for MkDocs Insiders - if: github.event.pull_request.head.repo.fork == false && steps.cache.outputs.cache-hit != 'true' - run: python -m poetry run pip install git+https://${{ secrets.ACTIONS_TOKEN }}@github.com/squidfunk/mkdocs-material-insiders.git + if: ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false ) && steps.cache.outputs.cache-hit != 'true' + run: python -m poetry run pip install git+https://${{ secrets.SQLMODEL_MKDOCS_MATERIAL_INSIDERS }}@github.com/squidfunk/mkdocs-material-insiders.git - uses: actions/cache@v3 with: key: mkdocs-cards-${{ github.ref }} path: .cache - name: Build Docs - if: github.event.pull_request.head.repo.fork == true + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true run: python -m poetry run mkdocs build - name: Build Docs with Insiders - if: github.event.pull_request.head.repo.fork == false + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false run: python -m poetry run mkdocs build --config-file mkdocs.insiders.yml - name: Zip docs run: python -m poetry run bash ./scripts/zip-docs.sh @@ -70,7 +68,7 @@ jobs: name: docs-zip path: ./site/docs.zip - name: Deploy to Netlify - uses: nwtgck/actions-netlify@v1.1.5 + uses: nwtgck/actions-netlify@v2.0.0 with: publish-dir: './site' production-branch: main diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f3c1e98..d788411 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -7,15 +7,15 @@ on: workflow_dispatch: inputs: debug_enabled: - description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)' + description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)' required: false default: false jobs: publish: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3.1.0 + - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 with: @@ -30,17 +30,13 @@ jobs: id: cache with: path: ${{ env.pythonLocation }} - key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-root + key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-root-v2 - name: Install poetry if: steps.cache.outputs.cache-hit != 'true' - # TODO: remove python -m pip install --force git+https://github.com/python-poetry/poetry-core.git@ad33bc2 - # once there's a release of Poetry 1.2.x including poetry-core > 1.1.0a6 - # Ref: https://github.com/python-poetry/poetry-core/pull/188 run: | python -m pip install --upgrade pip - python -m pip install --force git+https://github.com/python-poetry/poetry-core.git@ad33bc2 - python -m pip install "poetry==1.2.0a2" - python -m poetry plugin add poetry-version-plugin + python -m pip install "poetry" + python -m poetry self add poetry-version-plugin - name: Configure poetry run: python -m poetry config virtualenvs.create false - name: Install Dependencies diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 585ffc0..c743532 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,24 +5,30 @@ on: branches: - main pull_request: - types: [opened, synchronize] + types: + - opened + - synchronize workflow_dispatch: inputs: debug_enabled: - description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)' + description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)' required: false default: false jobs: test: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.6.15", "3.7", "3.8", "3.9", "3.10"] + python-version: + - "3.7" + - "3.8" + - "3.9" + - "3.10" fail-fast: false steps: - - uses: actions/checkout@v3.1.0 + - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 with: @@ -37,24 +43,19 @@ jobs: id: cache with: path: ${{ env.pythonLocation }} - key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-root + key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-root-v2 - name: Install poetry if: steps.cache.outputs.cache-hit != 'true' - # TODO: remove python -m pip install --force git+https://github.com/python-poetry/poetry-core.git@ad33bc2 - # once there's a release of Poetry 1.2.x including poetry-core > 1.1.0a6 - # Ref: https://github.com/python-poetry/poetry-core/pull/188 run: | python -m pip install --upgrade pip - python -m pip install --force git+https://github.com/python-poetry/poetry-core.git@ad33bc2 - python -m pip install "poetry==1.2.0a2" - python -m poetry plugin add poetry-version-plugin + python -m pip install "poetry" + python -m poetry self add poetry-version-plugin - name: Configure poetry run: python -m poetry config virtualenvs.create false - name: Install Dependencies if: steps.cache.outputs.cache-hit != 'true' run: python -m poetry install - name: Lint - if: ${{ matrix.python-version != '3.6.15' }} run: python -m poetry run bash scripts/lint.sh - run: mkdir coverage - name: Test @@ -68,7 +69,8 @@ jobs: name: coverage path: coverage coverage-combine: - needs: [test] + needs: + - test runs-on: ubuntu-latest steps: @@ -96,3 +98,15 @@ jobs: with: name: coverage-html path: htmlcov + + # https://github.com/marketplace/actions/alls-green#why + alls-green: # This job does nothing and is only used for the branch protection + if: always() + needs: + - coverage-combine + runs-on: ubuntu-latest + steps: + - name: Decide whether the needed jobs succeeded or failed + uses: re-actors/alls-green@release/v1 + with: + jobs: ${{ toJSON(needs) }} diff --git a/README.md b/README.md index 5721f1c..f85bb97 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ It combines SQLAlchemy and Pydantic and tries to simplify the code you write as ## Requirements -A recent and currently supported version of Python (right now, Python supports versions 3.6 and above). +A recent and currently supported version of Python Python. As **SQLModel** is based on **Pydantic** and **SQLAlchemy**, it requires them. They will be automatically installed when you install SQLModel. diff --git a/docs/contributing.md b/docs/contributing.md index f2964fb..1cd62d4 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -6,10 +6,6 @@ First, you might want to see the basic ways to [help SQLModel and get help](help If you already cloned the repository and you know that you need to deep dive in the code, here are some guidelines to set up your environment. -### Python - -SQLModel supports Python 3.6 and above, but for development you should have at least **Python 3.7**. - ### Poetry **SQLModel** uses Poetry to build, package, and publish the project. diff --git a/docs/features.md b/docs/features.md index 09de0c1..102edef 100644 --- a/docs/features.md +++ b/docs/features.md @@ -12,7 +12,7 @@ Nevertheless, SQLModel is completely **independent** of FastAPI and can be used ## Just Modern Python -It's all based on standard modern **Python** type annotations. No new syntax to learn. Just standard modern Python. +It's all based on standard modern **Python** type annotations. No new syntax to learn. Just standard modern Python. If you need a 2 minute refresher of how to use Python types (even if you don't use SQLModel or FastAPI), check the FastAPI tutorial section: Python types intro. diff --git a/docs/index.md b/docs/index.md index 5721f1c..f85bb97 100644 --- a/docs/index.md +++ b/docs/index.md @@ -50,7 +50,7 @@ It combines SQLAlchemy and Pydantic and tries to simplify the code you write as ## Requirements -A recent and currently supported version of Python (right now, Python supports versions 3.6 and above). +A recent and currently supported version of Python Python. As **SQLModel** is based on **Pydantic** and **SQLAlchemy**, it requires them. They will be automatically installed when you install SQLModel. diff --git a/docs/tutorial/index.md b/docs/tutorial/index.md index 33cf622..79fa670 100644 --- a/docs/tutorial/index.md +++ b/docs/tutorial/index.md @@ -64,15 +64,13 @@ $ cd sqlmodel-tutorial Make sure you have an officially supported version of Python. -Currently it is **Python 3.6** and above (Python 3.5 was already deprecated). - You can check which version you have with:
```console $ python3 --version -Python 3.6.9 +Python 3.11 ```
@@ -84,8 +82,6 @@ You might want to try with the specific versions, for example with: * `python3.10` * `python3.9` * `python3.8` -* `python3.7` -* `python3.6` The code would look like this: diff --git a/pyproject.toml b/pyproject.toml index e3b1d3c..e402727 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,10 +17,10 @@ classifiers = [ "Intended Audience :: System Administrators", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", "Topic :: Database", "Topic :: Database :: Database Engines/Servers", "Topic :: Internet", @@ -30,7 +30,7 @@ classifiers = [ ] [tool.poetry.dependencies] -python = "^3.6.1" +python = "^3.7" SQLAlchemy = ">=1.4.17,<=1.4.41" pydantic = "^1.8.2" sqlalchemy2-stubs = {version = "*", allow-prereleases = true} @@ -39,19 +39,17 @@ sqlalchemy2-stubs = {version = "*", allow-prereleases = true} pytest = "^7.0.1" mypy = "0.971" flake8 = "^5.0.4" -black = {version = "^22.10.0", python = "^3.7"} +black = "^22.10.0" mkdocs = "^1.2.1" mkdocs-material = "^8.1.4" -pillow = {version = "^9.3.0", python = "^3.7"} -cairosvg = {version = "^2.5.2", python = "^3.7"} +pillow = "^9.3.0" +cairosvg = "^2.5.2" mdx-include = "^1.4.1" coverage = {extras = ["toml"], version = "^6.2"} fastapi = "^0.68.1" requests = "^2.26.0" autoflake = "^1.4" isort = "^5.9.3" -async_generator = {version = "*", python = "~3.6"} -async-exit-stack = {version = "*", python = "~3.6"} [build-system] requires = ["poetry-core"] diff --git a/scripts/lint.sh b/scripts/lint.sh index 02568cd..4191d90 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -7,5 +7,3 @@ mypy sqlmodel flake8 sqlmodel tests docs_src black sqlmodel tests docs_src --check isort sqlmodel tests docs_src scripts --check-only -# TODO: move this to test.sh after deprecating Python 3.6 -CHECK_JINJA=1 python scripts/generate_select.py diff --git a/scripts/test.sh b/scripts/test.sh index 9b758bd..1460a9c 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -3,6 +3,7 @@ set -e set -x +CHECK_JINJA=1 python scripts/generate_select.py coverage run -m pytest tests coverage combine coverage report --show-missing diff --git a/sqlmodel/main.py b/sqlmodel/main.py index d95c498..5b5950a 100644 --- a/sqlmodel/main.py +++ b/sqlmodel/main.py @@ -11,6 +11,7 @@ from typing import ( Callable, ClassVar, Dict, + ForwardRef, List, Mapping, Optional, @@ -29,7 +30,7 @@ from pydantic.fields import SHAPE_SINGLETON from pydantic.fields import FieldInfo as PydanticFieldInfo from pydantic.fields import ModelField, Undefined, UndefinedType from pydantic.main import ModelMetaclass, validate_model -from pydantic.typing import ForwardRef, NoArgAnyCallable, resolve_annotations +from pydantic.typing import NoArgAnyCallable, resolve_annotations from pydantic.utils import ROOT_KEY, Representation from sqlalchemy import Boolean, Column, Date, DateTime from sqlalchemy import Enum as sa_Enum diff --git a/sqlmodel/sql/expression.py b/sqlmodel/sql/expression.py index 31c0bc1..264e39c 100644 --- a/sqlmodel/sql/expression.py +++ b/sqlmodel/sql/expression.py @@ -1,6 +1,5 @@ # WARNING: do not modify this code, it is generated by expression.py.jinja2 -import sys from datetime import datetime from typing import ( TYPE_CHECKING, @@ -12,7 +11,6 @@ from typing import ( Type, TypeVar, Union, - cast, overload, ) from uuid import UUID @@ -24,36 +22,17 @@ from sqlalchemy.sql.expression import Select as _Select _TSelect = TypeVar("_TSelect") -# Workaround Generics incompatibility in Python 3.6 -# Ref: https://github.com/python/typing/issues/449#issuecomment-316061322 -if sys.version_info.minor >= 7: - class Select(_Select, Generic[_TSelect]): - inherit_cache = True +class Select(_Select, Generic[_TSelect]): + inherit_cache = True - # This is not comparable to sqlalchemy.sql.selectable.ScalarSelect, that has a different - # purpose. This is the same as a normal SQLAlchemy Select class where there's only one - # entity, so the result will be converted to a scalar by default. This way writing - # for loops on the results will feel natural. - class SelectOfScalar(_Select, Generic[_TSelect]): - inherit_cache = True -else: - from typing import GenericMeta # type: ignore - - class GenericSelectMeta(GenericMeta, _Select.__class__): # type: ignore - pass - - class _Py36Select(_Select, Generic[_TSelect], metaclass=GenericSelectMeta): - inherit_cache = True - - class _Py36SelectOfScalar(_Select, Generic[_TSelect], metaclass=GenericSelectMeta): - inherit_cache = True - - # Cast them for editors to work correctly, from several tricks tried, this works - # for both VS Code and PyCharm - Select = cast("Select", _Py36Select) # type: ignore - SelectOfScalar = cast("SelectOfScalar", _Py36SelectOfScalar) # type: ignore +# This is not comparable to sqlalchemy.sql.selectable.ScalarSelect, that has a different +# purpose. This is the same as a normal SQLAlchemy Select class where there's only one +# entity, so the result will be converted to a scalar by default. This way writing +# for loops on the results will feel natural. +class SelectOfScalar(_Select, Generic[_TSelect]): + inherit_cache = True if TYPE_CHECKING: # pragma: no cover diff --git a/sqlmodel/sql/expression.py.jinja2 b/sqlmodel/sql/expression.py.jinja2 index 51f04a2..26d12a0 100644 --- a/sqlmodel/sql/expression.py.jinja2 +++ b/sqlmodel/sql/expression.py.jinja2 @@ -1,4 +1,3 @@ -import sys from datetime import datetime from typing import ( TYPE_CHECKING, @@ -10,7 +9,6 @@ from typing import ( Type, TypeVar, Union, - cast, overload, ) from uuid import UUID @@ -22,37 +20,15 @@ from sqlalchemy.sql.expression import Select as _Select _TSelect = TypeVar("_TSelect") -# Workaround Generics incompatibility in Python 3.6 -# Ref: https://github.com/python/typing/issues/449#issuecomment-316061322 -if sys.version_info.minor >= 7: - - class Select(_Select, Generic[_TSelect]): - inherit_cache = True - - # This is not comparable to sqlalchemy.sql.selectable.ScalarSelect, that has a different - # purpose. This is the same as a normal SQLAlchemy Select class where there's only one - # entity, so the result will be converted to a scalar by default. This way writing - # for loops on the results will feel natural. - class SelectOfScalar(_Select, Generic[_TSelect]): - inherit_cache = True - -else: - from typing import GenericMeta # type: ignore - - class GenericSelectMeta(GenericMeta, _Select.__class__): # type: ignore - pass - - class _Py36Select(_Select, Generic[_TSelect], metaclass=GenericSelectMeta): - inherit_cache = True - - class _Py36SelectOfScalar(_Select, Generic[_TSelect], metaclass=GenericSelectMeta): - inherit_cache = True - - # Cast them for editors to work correctly, from several tricks tried, this works - # for both VS Code and PyCharm - Select = cast("Select", _Py36Select) # type: ignore - SelectOfScalar = cast("SelectOfScalar", _Py36SelectOfScalar) # type: ignore +class Select(_Select, Generic[_TSelect]): + inherit_cache = True +# This is not comparable to sqlalchemy.sql.selectable.ScalarSelect, that has a different +# purpose. This is the same as a normal SQLAlchemy Select class where there's only one +# entity, so the result will be converted to a scalar by default. This way writing +# for loops on the results will feel natural. +class SelectOfScalar(_Select, Generic[_TSelect]): + inherit_cache = True if TYPE_CHECKING: # pragma: no cover from ..main import SQLModel From a21d5c85a3b5131a2c9eb9fedcc6013796fa1063 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 31 Jul 2023 17:15:43 +0200 Subject: [PATCH 10/85] =?UTF-8?q?=F0=9F=91=B7=E2=80=8D=E2=99=82=EF=B8=8F?= =?UTF-8?q?=20Upgrade=20CI=20for=20docs=20(#628)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/actions/watch-previews/Dockerfile | 7 -- .github/actions/watch-previews/action.yml | 10 -- .github/actions/watch-previews/app/main.py | 102 ------------------ .github/workflows/build-docs.yml | 69 +++++++----- .../{preview-docs.yml => deploy-docs.yml} | 31 +++--- 5 files changed, 59 insertions(+), 160 deletions(-) delete mode 100644 .github/actions/watch-previews/Dockerfile delete mode 100644 .github/actions/watch-previews/action.yml delete mode 100644 .github/actions/watch-previews/app/main.py rename .github/workflows/{preview-docs.yml => deploy-docs.yml} (57%) diff --git a/.github/actions/watch-previews/Dockerfile b/.github/actions/watch-previews/Dockerfile deleted file mode 100644 index b8cc64d..0000000 --- a/.github/actions/watch-previews/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM python:3.7 - -RUN pip install httpx PyGithub "pydantic==1.5.1" - -COPY ./app /app - -CMD ["python", "/app/main.py"] diff --git a/.github/actions/watch-previews/action.yml b/.github/actions/watch-previews/action.yml deleted file mode 100644 index a9c4b3f..0000000 --- a/.github/actions/watch-previews/action.yml +++ /dev/null @@ -1,10 +0,0 @@ -name: Watch docs previews in PRs -description: Check PRs and trigger new docs deploys -author: "SebastiΓ‘n RamΓ­rez " -inputs: - token: - description: 'Token for the repo. Can be passed in using {{ secrets.GITHUB_TOKEN }}' - required: true -runs: - using: docker - image: Dockerfile diff --git a/.github/actions/watch-previews/app/main.py b/.github/actions/watch-previews/app/main.py deleted file mode 100644 index 8a6d4a2..0000000 --- a/.github/actions/watch-previews/app/main.py +++ /dev/null @@ -1,102 +0,0 @@ -import logging -from datetime import datetime -from pathlib import Path -from typing import List, Optional - -import httpx -from github import Github -from github.NamedUser import NamedUser -from pydantic import BaseModel, BaseSettings, SecretStr - -github_api = "https://api.github.com" -netlify_api = "https://api.netlify.com" -main_branch = "main" - - -class Settings(BaseSettings): - input_token: SecretStr - github_repository: str - github_event_path: Path - github_event_name: Optional[str] = None - - -class Artifact(BaseModel): - id: int - node_id: str - name: str - size_in_bytes: int - url: str - archive_download_url: str - expired: bool - created_at: datetime - updated_at: datetime - - -class ArtifactResponse(BaseModel): - total_count: int - artifacts: List[Artifact] - - -def get_message(commit: str) -> str: - return f"Docs preview for commit {commit} at" - - -if __name__ == "__main__": - logging.basicConfig(level=logging.INFO) - settings = Settings() - logging.info(f"Using config: {settings.json()}") - g = Github(settings.input_token.get_secret_value()) - repo = g.get_repo(settings.github_repository) - owner: NamedUser = repo.owner - headers = {"Authorization": f"token {settings.input_token.get_secret_value()}"} - prs = list(repo.get_pulls(state="open")) - response = httpx.get( - f"{github_api}/repos/{settings.github_repository}/actions/artifacts", - headers=headers, - ) - data = response.json() - artifacts_response = ArtifactResponse.parse_obj(data) - for pr in prs: - logging.info("-----") - logging.info(f"Processing PR #{pr.number}: {pr.title}") - pr_comments = list(pr.get_issue_comments()) - pr_commits = list(pr.get_commits()) - last_commit = pr_commits[0] - for pr_commit in pr_commits: - if pr_commit.commit.author.date > last_commit.commit.author.date: - last_commit = pr_commit - commit = last_commit.commit.sha - logging.info(f"Last commit: {commit}") - message = get_message(commit) - notified = False - for pr_comment in pr_comments: - if message in pr_comment.body: - notified = True - logging.info(f"Docs preview was notified: {notified}") - if not notified: - artifact_name = f"docs-zip-{commit}" - use_artifact: Optional[Artifact] = None - for artifact in artifacts_response.artifacts: - if artifact.name == artifact_name: - use_artifact = artifact - break - if not use_artifact: - logging.info("Artifact not available") - else: - logging.info(f"Existing artifact: {use_artifact.name}") - response = httpx.post( - f"{github_api}/repos/{settings.github_repository}/actions/workflows/preview-docs.yml/dispatches", - headers=headers, - json={ - "ref": main_branch, - "inputs": { - "pr": f"{pr.number}", - "name": artifact_name, - "commit": commit, - }, - }, - ) - logging.info( - f"Trigger sent, response status: {response.status_code} - content: {response.content}" - ) - logging.info("Finished") diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index 3bcc78d..cf5295a 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -7,14 +7,34 @@ on: types: - opened - synchronize - workflow_dispatch: - inputs: - debug_enabled: - description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)' - required: false - default: false jobs: + changes: + runs-on: ubuntu-latest + # Required permissions + permissions: + pull-requests: read + # Set job outputs to values from filter step + outputs: + docs: ${{ steps.filter.outputs.docs }} + steps: + - uses: actions/checkout@v3 + # For pull requests it's not necessary to checkout the code but for the main branch it is + - uses: dorny/paths-filter@v2 + id: filter + with: + filters: | + docs: + - README.md + - docs/** + - docs_src/** + - pyproject.toml + - mkdocs.yml + - mkdocs.insiders.yml + build-docs: + needs: + - changes + if: ${{ needs.changes.outputs.docs == 'true' }} runs-on: ubuntu-latest steps: - name: Dump GitHub context @@ -26,18 +46,12 @@ jobs: uses: actions/setup-python@v4 with: python-version: "3.11" - # Allow debugging with tmate - - name: Setup tmate session - uses: mxschmitt/action-tmate@v3 - if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }} - with: - limit-access-to-actor: true - uses: actions/cache@v3 id: cache with: path: ${{ env.pythonLocation }} - key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-root-docs-v2 - - name: Install poetry + key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-v01 + - name: Install Poetry if: steps.cache.outputs.cache-hit != 'true' run: | python -m pip install --upgrade pip @@ -61,19 +75,20 @@ jobs: - name: Build Docs with Insiders if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false run: python -m poetry run mkdocs build --config-file mkdocs.insiders.yml - - name: Zip docs - run: python -m poetry run bash ./scripts/zip-docs.sh - uses: actions/upload-artifact@v3 with: - name: docs-zip - path: ./site/docs.zip - - name: Deploy to Netlify - uses: nwtgck/actions-netlify@v2.0.0 + name: docs-site + path: ./site/** + + # https://github.com/marketplace/actions/alls-green#why + docs-all-green: # This job does nothing and is only used for the branch protection + if: always() + needs: + - build-docs + runs-on: ubuntu-latest + steps: + - name: Decide whether the needed jobs succeeded or failed + uses: re-actors/alls-green@release/v1 with: - publish-dir: './site' - production-branch: main - github-token: ${{ secrets.GITHUB_TOKEN }} - enable-commit-comment: false - env: - NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} - NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} + jobs: ${{ toJSON(needs) }} + allowed-skips: build-docs diff --git a/.github/workflows/preview-docs.yml b/.github/workflows/deploy-docs.yml similarity index 57% rename from .github/workflows/preview-docs.yml rename to .github/workflows/deploy-docs.yml index 3550a9b..6fb0c01 100644 --- a/.github/workflows/preview-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -1,45 +1,48 @@ -name: Preview Docs +name: Deploy Docs on: workflow_run: workflows: - Build Docs - types: + types: - completed jobs: - preview-docs: - runs-on: ubuntu-20.04 + deploy-docs: + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3.1.0 + - name: Dump GitHub context + env: + GITHUB_CONTEXT: ${{ toJson(github) }} + run: echo "$GITHUB_CONTEXT" + - uses: actions/checkout@v3 - name: Clean site run: | rm -rf ./site mkdir ./site - name: Download Artifact Docs - uses: dawidd6/action-download-artifact@v2.24.2 + id: download + uses: dawidd6/action-download-artifact@v2.27.0 with: + if_no_artifact_found: ignore github_token: ${{ secrets.GITHUB_TOKEN }} workflow: build-docs.yml run_id: ${{ github.event.workflow_run.id }} - name: docs-zip + name: docs-site path: ./site/ - - name: Unzip docs - run: | - cd ./site - unzip docs.zip - rm -f docs.zip - name: Deploy to Netlify + if: steps.download.outputs.found_artifact == 'true' id: netlify - uses: nwtgck/actions-netlify@v1.1.5 + uses: nwtgck/actions-netlify@v2.0.0 with: publish-dir: './site' - production-deploy: false + production-deploy: ${{ github.event.workflow_run.head_repository.full_name == github.repository && github.event.workflow_run.head_branch == 'main' }} github-token: ${{ secrets.GITHUB_TOKEN }} enable-commit-comment: false env: NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} - name: Comment Deploy + if: steps.netlify.outputs.deploy-url != '' uses: ./.github/actions/comment-docs-preview-in-pr with: token: ${{ secrets.GITHUB_TOKEN }} From 73fa81af74a47e02acb2afacf93a714fa66d32e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 31 Jul 2023 21:38:43 +0200 Subject: [PATCH 11/85] =?UTF-8?q?=F0=9F=91=B7=20Update=20latest=20changes?= =?UTF-8?q?=20token=20(#616)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/latest-changes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/latest-changes.yml b/.github/workflows/latest-changes.yml index 9c3edcc..dd59e85 100644 --- a/.github/workflows/latest-changes.yml +++ b/.github/workflows/latest-changes.yml @@ -23,7 +23,7 @@ jobs: - uses: actions/checkout@v3.1.0 with: # To allow latest-changes to commit to the main branch - token: ${{ secrets.ACTIONS_TOKEN }} + token: ${{ secrets.SQLMODEL_LATEST_CHANGES }} # Allow debugging with tmate - name: Setup tmate session uses: mxschmitt/action-tmate@v3 From aaa54492c1646e0b0942e980db5a871b7ce0c420 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 31 Jul 2023 19:39:15 +0000 Subject: [PATCH 12/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 0ea7801..fef2a4e 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ‘· Update latest changes token. PR [#616](https://github.com/tiangolo/sqlmodel/pull/616) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Upgrade analytics. PR [#558](https://github.com/tiangolo/sqlmodel/pull/558) by [@tiangolo](https://github.com/tiangolo). * πŸ“ Update help SQLModel docs. PR [#548](https://github.com/tiangolo/sqlmodel/pull/548) by [@tiangolo](https://github.com/tiangolo). * πŸ”§ Update new issue chooser to point to GitHub Discussions. PR [#546](https://github.com/tiangolo/sqlmodel/pull/546) by [@tiangolo](https://github.com/tiangolo). From e246ae88647ff096aff79f64e08cf9ef565c91d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 31 Jul 2023 21:48:21 +0200 Subject: [PATCH 13/85] =?UTF-8?q?=F0=9F=91=B7=20Update=20CI=20debug=20mode?= =?UTF-8?q?=20with=20Tmate=20(#629)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/latest-changes.yml | 8 ++++---- .github/workflows/publish.yml | 4 ++-- .github/workflows/test.yml | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/latest-changes.yml b/.github/workflows/latest-changes.yml index dd59e85..357767b 100644 --- a/.github/workflows/latest-changes.yml +++ b/.github/workflows/latest-changes.yml @@ -12,22 +12,22 @@ on: description: PR number required: true debug_enabled: - description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)' + description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)' required: false - default: false + default: 'false' jobs: latest-changes: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3.1.0 + - uses: actions/checkout@v3 with: # To allow latest-changes to commit to the main branch token: ${{ secrets.SQLMODEL_LATEST_CHANGES }} # Allow debugging with tmate - name: Setup tmate session uses: mxschmitt/action-tmate@v3 - if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }} + if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }} with: limit-access-to-actor: true - uses: docker://tiangolo/latest-changes:0.0.3 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d788411..1c21cd4 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -9,7 +9,7 @@ on: debug_enabled: description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)' required: false - default: false + default: 'false' jobs: publish: @@ -23,7 +23,7 @@ jobs: # Allow debugging with tmate - name: Setup tmate session uses: mxschmitt/action-tmate@v3 - if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }} + if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }} with: limit-access-to-actor: true - uses: actions/cache@v3 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c743532..871557a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,7 @@ on: debug_enabled: description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)' required: false - default: false + default: 'false' jobs: test: @@ -36,7 +36,7 @@ jobs: # Allow debugging with tmate - name: Setup tmate session uses: mxschmitt/action-tmate@v3 - if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }} + if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }} with: limit-access-to-actor: true - uses: actions/cache@v3 From 40007c80da32edd9698f7bd063cc5d3496b60b60 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 31 Jul 2023 19:48:54 +0000 Subject: [PATCH 14/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index fef2a4e..f7b4b08 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ‘· Update CI debug mode with Tmate. PR [#629](https://github.com/tiangolo/sqlmodel/pull/629) by [@tiangolo](https://github.com/tiangolo). * πŸ‘· Update latest changes token. PR [#616](https://github.com/tiangolo/sqlmodel/pull/616) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Upgrade analytics. PR [#558](https://github.com/tiangolo/sqlmodel/pull/558) by [@tiangolo](https://github.com/tiangolo). * πŸ“ Update help SQLModel docs. PR [#548](https://github.com/tiangolo/sqlmodel/pull/548) by [@tiangolo](https://github.com/tiangolo). From da29f7940d99f73eecb85cdc2caead7b163fdfe5 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 31 Jul 2023 19:52:51 +0000 Subject: [PATCH 15/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index f7b4b08..d09e0ba 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ—‘οΈ Deprecate Python 3.6 and upgrade Poetry and Poetry Version Plugin. PR [#627](https://github.com/tiangolo/sqlmodel/pull/627) by [@tiangolo](https://github.com/tiangolo). * πŸ‘· Update CI debug mode with Tmate. PR [#629](https://github.com/tiangolo/sqlmodel/pull/629) by [@tiangolo](https://github.com/tiangolo). * πŸ‘· Update latest changes token. PR [#616](https://github.com/tiangolo/sqlmodel/pull/616) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Upgrade analytics. PR [#558](https://github.com/tiangolo/sqlmodel/pull/558) by [@tiangolo](https://github.com/tiangolo). From 30a9c23a348ede2f0b1c000f5e2b80517b2495cd Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 31 Jul 2023 19:53:00 +0000 Subject: [PATCH 16/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index d09e0ba..231e821 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ‘·β€β™‚οΈ Upgrade CI for docs. PR [#628](https://github.com/tiangolo/sqlmodel/pull/628) by [@tiangolo](https://github.com/tiangolo). * πŸ—‘οΈ Deprecate Python 3.6 and upgrade Poetry and Poetry Version Plugin. PR [#627](https://github.com/tiangolo/sqlmodel/pull/627) by [@tiangolo](https://github.com/tiangolo). * πŸ‘· Update CI debug mode with Tmate. PR [#629](https://github.com/tiangolo/sqlmodel/pull/629) by [@tiangolo](https://github.com/tiangolo). * πŸ‘· Update latest changes token. PR [#616](https://github.com/tiangolo/sqlmodel/pull/616) by [@tiangolo](https://github.com/tiangolo). From 1e2fd100478943b7a8c8dda72f851ce39df18ee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 1 Aug 2023 11:18:53 +0200 Subject: [PATCH 17/85] =?UTF-8?q?=F0=9F=91=B7=20Update=20docs=20deployment?= =?UTF-8?q?s=20to=20Cloudflare=20(#630)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/deploy-docs.yml | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 6fb0c01..25cd1ff 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -29,21 +29,20 @@ jobs: run_id: ${{ github.event.workflow_run.id }} name: docs-site path: ./site/ - - name: Deploy to Netlify + - name: Deploy to Cloudflare Pages if: steps.download.outputs.found_artifact == 'true' - id: netlify - uses: nwtgck/actions-netlify@v2.0.0 + id: deploy + uses: cloudflare/pages-action@v1 with: - publish-dir: './site' - production-deploy: ${{ github.event.workflow_run.head_repository.full_name == github.repository && github.event.workflow_run.head_branch == 'main' }} - github-token: ${{ secrets.GITHUB_TOKEN }} - enable-commit-comment: false - env: - NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} - NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + projectName: sqlmodel + directory: './site' + gitHubToken: ${{ secrets.GITHUB_TOKEN }} + branch: ${{ ( github.event.workflow_run.head_repository.full_name == github.repository && github.event.workflow_run.head_branch == 'main' && 'main' ) || ( github.event.workflow_run.head_sha ) }} - name: Comment Deploy - if: steps.netlify.outputs.deploy-url != '' + if: steps.deploy.outputs.url != '' uses: ./.github/actions/comment-docs-preview-in-pr with: token: ${{ secrets.GITHUB_TOKEN }} - deploy_url: "${{ steps.netlify.outputs.deploy-url }}" + deploy_url: "${{ steps.deploy.outputs.url }}" From 088164ef2aa30a21a168f511a998f85c469bba1c Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 1 Aug 2023 09:19:41 +0000 Subject: [PATCH 18/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 231e821..8b0cf52 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ‘· Update docs deployments to Cloudflare. PR [#630](https://github.com/tiangolo/sqlmodel/pull/630) by [@tiangolo](https://github.com/tiangolo). * πŸ‘·β€β™‚οΈ Upgrade CI for docs. PR [#628](https://github.com/tiangolo/sqlmodel/pull/628) by [@tiangolo](https://github.com/tiangolo). * πŸ—‘οΈ Deprecate Python 3.6 and upgrade Poetry and Poetry Version Plugin. PR [#627](https://github.com/tiangolo/sqlmodel/pull/627) by [@tiangolo](https://github.com/tiangolo). * πŸ‘· Update CI debug mode with Tmate. PR [#629](https://github.com/tiangolo/sqlmodel/pull/629) by [@tiangolo](https://github.com/tiangolo). From 89c356cb77b92728ed5962b17c9b19a17abc0af9 Mon Sep 17 00:00:00 2001 From: Sugato Ray Date: Sun, 22 Oct 2023 05:02:53 -0500 Subject: [PATCH 19/85] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8F=20Add=20`CITATION.c?= =?UTF-8?q?ff`=20file=20for=20academic=20citations=20(#13)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SebastiΓ‘n RamΓ­rez --- CITATION.cff | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 CITATION.cff diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000..978031d --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,24 @@ +# This CITATION.cff file was generated with cffinit. +# Visit https://bit.ly/cffinit to generate yours today! + +cff-version: 1.2.0 +title: SQLModel +message: >- + If you use this software, please cite it using the + metadata from this file. +type: software +authors: + - given-names: SebastiΓ‘n + family-names: RamΓ­rez + email: tiangolo@gmail.com +identifiers: +repository-code: 'https://github.com/tiangolo/sqlmodel' +url: 'https://sqlmodel.tiangolo.com' +abstract: >- + SQLModel, SQL databases in Python, designed for + simplicity, compatibility, and robustness. +keywords: + - fastapi + - pydantic + - sqlalchemy +license: MIT From aa7169b93b2b06030da0a3e0ee86b4932be9415c Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 22 Oct 2023 10:03:26 +0000 Subject: [PATCH 20/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 8b0cf52..1f52793 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ› οΈ Add `CITATION.cff` file for academic citations. PR [#13](https://github.com/tiangolo/sqlmodel/pull/13) by [@sugatoray](https://github.com/sugatoray). * πŸ‘· Update docs deployments to Cloudflare. PR [#630](https://github.com/tiangolo/sqlmodel/pull/630) by [@tiangolo](https://github.com/tiangolo). * πŸ‘·β€β™‚οΈ Upgrade CI for docs. PR [#628](https://github.com/tiangolo/sqlmodel/pull/628) by [@tiangolo](https://github.com/tiangolo). * πŸ—‘οΈ Deprecate Python 3.6 and upgrade Poetry and Poetry Version Plugin. PR [#627](https://github.com/tiangolo/sqlmodel/pull/627) by [@tiangolo](https://github.com/tiangolo). From d5219aa3c55c5cb1ed2c0b1a665ef2ad10da425c Mon Sep 17 00:00:00 2001 From: byrman Date: Sun, 22 Oct 2023 14:01:51 +0200 Subject: [PATCH 21/85] =?UTF-8?q?=F0=9F=90=9B=20Fix=20SQLAlchemy=20version?= =?UTF-8?q?=201.4.36=20breaks=20SQLModel=20relationships=20(#315)=20(#461)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SebastiΓ‘n RamΓ­rez --- sqlmodel/main.py | 1 + tests/test_main.py | 39 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/sqlmodel/main.py b/sqlmodel/main.py index 5b5950a..caae8cf 100644 --- a/sqlmodel/main.py +++ b/sqlmodel/main.py @@ -333,6 +333,7 @@ class SQLModelMetaclass(ModelMetaclass, DeclarativeMeta): # There's a SQLAlchemy relationship declared, that takes precedence # over anything else, use that and continue with the next attribute dict_used[rel_name] = rel_info.sa_relationship + setattr(cls, rel_name, rel_info.sa_relationship) # Fix #315 continue ann = cls.__annotations__[rel_name] temp_field = ModelField.infer( diff --git a/tests/test_main.py b/tests/test_main.py index 22c6232..72465cd 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,8 +1,9 @@ -from typing import Optional +from typing import List, Optional import pytest from sqlalchemy.exc import IntegrityError -from sqlmodel import Field, Session, SQLModel, create_engine +from sqlalchemy.orm import RelationshipProperty +from sqlmodel import Field, Relationship, Session, SQLModel, create_engine def test_should_allow_duplicate_row_if_unique_constraint_is_not_passed(clear_sqlmodel): @@ -91,3 +92,37 @@ def test_should_raise_exception_when_try_to_duplicate_row_if_unique_constraint_i session.add(hero_2) session.commit() session.refresh(hero_2) + + +def test_sa_relationship_property(clear_sqlmodel): + """Test https://github.com/tiangolo/sqlmodel/issues/315#issuecomment-1272122306""" + + class Team(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(unique=True) + heroes: List["Hero"] = Relationship( # noqa: F821 + sa_relationship=RelationshipProperty("Hero", back_populates="team") + ) + + class Hero(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(unique=True) + team_id: Optional[int] = Field(default=None, foreign_key="team.id") + team: Optional[Team] = Relationship( + sa_relationship=RelationshipProperty("Team", back_populates="heroes") + ) + + team_preventers = Team(name="Preventers") + hero_rusty_man = Hero(name="Rusty-Man", team=team_preventers) + + engine = create_engine("sqlite://", echo=True) + + SQLModel.metadata.create_all(engine) + + with Session(engine) as session: + session.add(hero_rusty_man) + session.commit() + session.refresh(hero_rusty_man) + # The next statement should not raise an AttributeError + assert hero_rusty_man.team + assert hero_rusty_man.team.name == "Preventers" From d939b7c45c394fb60d04e9f3554cb11519914b5d Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 22 Oct 2023 12:02:24 +0000 Subject: [PATCH 22/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 1f52793..5808054 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ› Fix SQLAlchemy version 1.4.36 breaks SQLModel relationships (#315). PR [#461](https://github.com/tiangolo/sqlmodel/pull/461) by [@byrman](https://github.com/byrman). * πŸ› οΈ Add `CITATION.cff` file for academic citations. PR [#13](https://github.com/tiangolo/sqlmodel/pull/13) by [@sugatoray](https://github.com/sugatoray). * πŸ‘· Update docs deployments to Cloudflare. PR [#630](https://github.com/tiangolo/sqlmodel/pull/630) by [@tiangolo](https://github.com/tiangolo). * πŸ‘·β€β™‚οΈ Upgrade CI for docs. PR [#628](https://github.com/tiangolo/sqlmodel/pull/628) by [@tiangolo](https://github.com/tiangolo). From bdcf11bca62889710678913e7fc7ae30e067d0ae Mon Sep 17 00:00:00 2001 From: Jorge Alvarado Date: Sun, 22 Oct 2023 09:03:51 -0300 Subject: [PATCH 23/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20instructions=20ab?= =?UTF-8?q?out=20how=20to=20make=20a=20foreign=20key=20required=20in=20`do?= =?UTF-8?q?cs/tutorial/relationship-attributes/define-relationships-attrib?= =?UTF-8?q?utes.md`=20(#474)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SebastiΓ‘n RamΓ­rez --- .../define-relationships-attributes.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/tutorial/relationship-attributes/define-relationships-attributes.md b/docs/tutorial/relationship-attributes/define-relationships-attributes.md index 0531ec5..b6e77d9 100644 --- a/docs/tutorial/relationship-attributes/define-relationships-attributes.md +++ b/docs/tutorial/relationship-attributes/define-relationships-attributes.md @@ -115,9 +115,7 @@ This means that this attribute could be `None`, or it could be a full `Team` obj This is because the related **`team_id` could also be `None`** (or `NULL` in the database). -If it was required for a `Hero` instance to belong to a `Team`, then the `team_id` would be `int` instead of `Optional[int]`. - -And the `team` attribute would be a `Team` instead of `Optional[Team]`. +If it was required for a `Hero` instance to belong to a `Team`, then the `team_id` would be `int` instead of `Optional[int]`, its `Field` would be `Field(foreign_key="team.id")` instead of `Field(default=None, foreign_key="team.id")` and the `team` attribute would be a `Team` instead of `Optional[Team]`. ## Relationship Attributes With Lists From b7d6a0a3c39d6ddddb8eb7e3d9d8c90f47b954fc Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 22 Oct 2023 12:04:24 +0000 Subject: [PATCH 24/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 5808054..6b8e3ff 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ“ Update instructions about how to make a foreign key required in `docs/tutorial/relationship-attributes/define-relationships-attributes.md`. PR [#474](https://github.com/tiangolo/sqlmodel/pull/474) by [@jalvaradosegura](https://github.com/jalvaradosegura). * πŸ› Fix SQLAlchemy version 1.4.36 breaks SQLModel relationships (#315). PR [#461](https://github.com/tiangolo/sqlmodel/pull/461) by [@byrman](https://github.com/byrman). * πŸ› οΈ Add `CITATION.cff` file for academic citations. PR [#13](https://github.com/tiangolo/sqlmodel/pull/13) by [@sugatoray](https://github.com/sugatoray). * πŸ‘· Update docs deployments to Cloudflare. PR [#630](https://github.com/tiangolo/sqlmodel/pull/630) by [@tiangolo](https://github.com/tiangolo). From a2e2942aadba6caea9a34461cd48fe89cdfe2cf1 Mon Sep 17 00:00:00 2001 From: Ben Rapaport <89947784+br-follow@users.noreply.github.com> Date: Sun, 22 Oct 2023 08:26:37 -0400 Subject: [PATCH 25/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes,?= =?UTF-8?q?=20add=20second=20author=20to=20PR=20(#429)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SebastiΓ‘n RamΓ­rez --- docs/release-notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/release-notes.md b/docs/release-notes.md index 6b8e3ff..b6ee0be 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -40,7 +40,7 @@ ### Fixes -* πŸ› Fix auto detecting and setting `nullable`, allowing overrides in field. PR [#423](https://github.com/tiangolo/sqlmodel/pull/423) by [@JonasKs](https://github.com/JonasKs). +* πŸ› Fix auto detecting and setting `nullable`, allowing overrides in field. PR [#423](https://github.com/tiangolo/sqlmodel/pull/423) by [@JonasKs](https://github.com/JonasKs) and [@br-follow](https://github.com/br-follow). * ♻️ Update `expresion.py`, sync from Jinja2 template, implement `inherit_cache` to solve errors like: `SAWarning: Class SelectOfScalar will not make use of SQL compilation caching`. PR [#422](https://github.com/tiangolo/sqlmodel/pull/422) by [@tiangolo](https://github.com/tiangolo). ### Docs From 2799303f6c39f4d1ae35a4c90adf4654c21392b9 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 22 Oct 2023 12:27:13 +0000 Subject: [PATCH 26/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index b6ee0be..32a8569 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ“ Update release notes, add second author to PR. PR [#429](https://github.com/tiangolo/sqlmodel/pull/429) by [@br-follow](https://github.com/br-follow). * πŸ“ Update instructions about how to make a foreign key required in `docs/tutorial/relationship-attributes/define-relationships-attributes.md`. PR [#474](https://github.com/tiangolo/sqlmodel/pull/474) by [@jalvaradosegura](https://github.com/jalvaradosegura). * πŸ› Fix SQLAlchemy version 1.4.36 breaks SQLModel relationships (#315). PR [#461](https://github.com/tiangolo/sqlmodel/pull/461) by [@byrman](https://github.com/byrman). * πŸ› οΈ Add `CITATION.cff` file for academic citations. PR [#13](https://github.com/tiangolo/sqlmodel/pull/13) by [@sugatoray](https://github.com/sugatoray). From 893d64fd3127b1737922629cb3b7803fdb370947 Mon Sep 17 00:00:00 2001 From: Dipendra Raj Panta <49410574+Mr-DRP@users.noreply.github.com> Date: Sun, 22 Oct 2023 18:31:52 +0545 Subject: [PATCH 27/85] =?UTF-8?q?=F0=9F=93=9D=20Fix=20typos=20(duplication?= =?UTF-8?q?)=20in=20main=20page=20(#631)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update README.md * Update index.md --- README.md | 2 +- docs/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f85bb97..a9387c5 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ It combines SQLAlchemy and Pydantic and tries to simplify the code you write as ## Requirements -A recent and currently supported version of Python Python. +A recent and currently supported version of Python. As **SQLModel** is based on **Pydantic** and **SQLAlchemy**, it requires them. They will be automatically installed when you install SQLModel. diff --git a/docs/index.md b/docs/index.md index f85bb97..a9387c5 100644 --- a/docs/index.md +++ b/docs/index.md @@ -50,7 +50,7 @@ It combines SQLAlchemy and Pydantic and tries to simplify the code you write as ## Requirements -A recent and currently supported version of Python Python. +A recent and currently supported version of Python. As **SQLModel** is based on **Pydantic** and **SQLAlchemy**, it requires them. They will be automatically installed when you install SQLModel. From 357417e6d581dd66adfbe4efa667b5139ef161ff Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 22 Oct 2023 12:47:27 +0000 Subject: [PATCH 28/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 32a8569..d15ce97 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ“ Fix typos (duplication) in main page. PR [#631](https://github.com/tiangolo/sqlmodel/pull/631) by [@Mr-DRP](https://github.com/Mr-DRP). * πŸ“ Update release notes, add second author to PR. PR [#429](https://github.com/tiangolo/sqlmodel/pull/429) by [@br-follow](https://github.com/br-follow). * πŸ“ Update instructions about how to make a foreign key required in `docs/tutorial/relationship-attributes/define-relationships-attributes.md`. PR [#474](https://github.com/tiangolo/sqlmodel/pull/474) by [@jalvaradosegura](https://github.com/jalvaradosegura). * πŸ› Fix SQLAlchemy version 1.4.36 breaks SQLModel relationships (#315). PR [#461](https://github.com/tiangolo/sqlmodel/pull/461) by [@byrman](https://github.com/byrman). From 1568bad01ec1d5f7edada00e49c18ce44ba0a334 Mon Sep 17 00:00:00 2001 From: Kian-Meng Ang Date: Sun, 22 Oct 2023 20:50:44 +0800 Subject: [PATCH 29/85] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Fix=20typos=20found?= =?UTF-8?q?=20with=20codespell=20(#520)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found via `codespell -S *.svg,*.css,*.js,*.drawio -L pullrequest,sesion` --- docs/tutorial/automatic-id-none-refresh.md | 14 +++++++------- docs/tutorial/code-structure.md | 2 +- docs/tutorial/connect/create-connected-tables.md | 2 +- .../create-db-and-table-with-db-browser.md | 2 +- docs/tutorial/fastapi/tests.md | 2 +- docs/tutorial/index.md | 4 ++-- docs/tutorial/insert.md | 2 +- docs/tutorial/many-to-many/create-data.md | 2 +- docs/tutorial/one.md | 2 +- .../relationship-attributes/back-populates.md | 2 +- .../relationship-attributes/read-relationships.md | 2 +- docs/tutorial/select.md | 4 ++-- docs/tutorial/where.md | 4 ++-- .../annotations/en/tutorial002.md | 2 +- .../tutorial/update/annotations/en/tutorial004.md | 2 +- sqlmodel/default.py | 4 ++-- tests/test_validation.py | 2 +- 17 files changed, 27 insertions(+), 27 deletions(-) diff --git a/docs/tutorial/automatic-id-none-refresh.md b/docs/tutorial/automatic-id-none-refresh.md index bbf74dd..d41cd14 100644 --- a/docs/tutorial/automatic-id-none-refresh.md +++ b/docs/tutorial/automatic-id-none-refresh.md @@ -36,7 +36,7 @@ When we create a new `Hero` instance, we don't set the `id`: {!./docs_src/tutorial/automatic_id_none_refresh/tutorial001.py[ln:23-26]!} -# Code below ommitted πŸ‘‡ +# Code below omitted πŸ‘‡ ```
@@ -125,7 +125,7 @@ We can verify by creating a session using a `with` block and adding the objects. {!./docs_src/tutorial/automatic_id_none_refresh/tutorial001.py[ln:23-41]!} -# Code below ommitted πŸ‘‡ +# Code below omitted πŸ‘‡ ```
@@ -238,7 +238,7 @@ To confirm and understand how this **automatic expiration and refresh** of data {!./docs_src/tutorial/automatic_id_none_refresh/tutorial001.py[ln:33-58]!} -# Code below ommitted πŸ‘‡ +# Code below omitted πŸ‘‡ ```
@@ -271,7 +271,7 @@ Let's see how it works: ```console $ python app.py -// Output above ommitted πŸ‘† +// Output above omitted πŸ‘† // After committing, the objects are expired and have no values After committing the session @@ -335,7 +335,7 @@ You can do that too with `session.refresh(object)`: {!./docs_src/tutorial/automatic_id_none_refresh/tutorial001.py[ln:33-67]!} -# Code below ommitted πŸ‘‡ +# Code below omitted πŸ‘‡ ```
@@ -362,7 +362,7 @@ Here's how the output would look like: ```console $ python app.py -// Output above ommitted πŸ‘† +// Output above omitted πŸ‘† // The first refresh INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age @@ -427,7 +427,7 @@ And the output shows again the same data: ```console $ python app.py -// Output above ommitted πŸ‘† +// Output above omitted πŸ‘† // By finishing the with block, the Session is closed, including a rollback of any pending transaction that could have been there and was not committed INFO Engine ROLLBACK diff --git a/docs/tutorial/code-structure.md b/docs/tutorial/code-structure.md index 59a9e4b..502c8bf 100644 --- a/docs/tutorial/code-structure.md +++ b/docs/tutorial/code-structure.md @@ -168,7 +168,7 @@ Let's assume that now the file structure is: ### Circular Imports and Type Annotations -The problem with circular imports is that Python can't resolve them at *runtime*. +The problem with circular imports is that Python can't resolve them at *runtime*. But when using Python **type annotations** it's very common to need to declare the type of some variables with classes imported from other files. diff --git a/docs/tutorial/connect/create-connected-tables.md b/docs/tutorial/connect/create-connected-tables.md index 452c904..14a310f 100644 --- a/docs/tutorial/connect/create-connected-tables.md +++ b/docs/tutorial/connect/create-connected-tables.md @@ -106,7 +106,7 @@ This is the same model we have been using up to now, we are just adding the new Most of that should look familiar: -The column will be named `team_id`. It will be an integer, and it could be `NULL` in the database (or `None` in Python), becase there could be some heroes that don't belong to any team. +The column will be named `team_id`. It will be an integer, and it could be `NULL` in the database (or `None` in Python), because there could be some heroes that don't belong to any team. We add a default of `None` to the `Field()` so we don't have to explicitly pass `team_id=None` when creating a hero. diff --git a/docs/tutorial/create-db-and-table-with-db-browser.md b/docs/tutorial/create-db-and-table-with-db-browser.md index a1bb394..4437f15 100644 --- a/docs/tutorial/create-db-and-table-with-db-browser.md +++ b/docs/tutorial/create-db-and-table-with-db-browser.md @@ -164,6 +164,6 @@ Of course, you can also go and take a full SQL course or read a book about SQL, We saw how to interact with SQLite databases in files using **DB Browser for SQLite** in a visual user interface. -We also saw how to use it to write some SQL directly to the SQLite database. This will be useful to verify the data in the database is looking correclty, to debug, etc. +We also saw how to use it to write some SQL directly to the SQLite database. This will be useful to verify the data in the database is looking correctly, to debug, etc. In the next chapters we will start using **SQLModel** to interact with the database, and we will continue to use **DB Browser for SQLite** at the same time to look at the database underneath. πŸ” diff --git a/docs/tutorial/fastapi/tests.md b/docs/tutorial/fastapi/tests.md index f817a88..cc6ad65 100644 --- a/docs/tutorial/fastapi/tests.md +++ b/docs/tutorial/fastapi/tests.md @@ -82,7 +82,7 @@ But now, we need to deal with a bit of logistics and details we are not paying a This test looks fine, but there's a problem. -If we run it, it will use the same **production database** that we are using to store our very important **heroes**, and we will end up adding unnecesary data to it, or even worse, in future tests we could end up removing production data. +If we run it, it will use the same **production database** that we are using to store our very important **heroes**, and we will end up adding unnecessary data to it, or even worse, in future tests we could end up removing production data. So, we should use an independent **testing database**, just for the tests. diff --git a/docs/tutorial/index.md b/docs/tutorial/index.md index 79fa670..e859414 100644 --- a/docs/tutorial/index.md +++ b/docs/tutorial/index.md @@ -135,7 +135,7 @@ Here are the commands you could use: // Remember that you might need to use python3.9 or similar πŸ’‘ // Create the virtual environment using the module "venv" $ python3 -m venv env - // ...here it creates the virtual enviroment in the directory "env" + // ...here it creates the virtual environment in the directory "env" // Activate the virtual environment $ source ./env/bin/activate // Verify that the virtual environment is active @@ -157,7 +157,7 @@ Here are the commands you could use: ```console // Create the virtual environment using the module "venv" # >$ python3 -m venv env - // ...here it creates the virtual enviroment in the directory "env" + // ...here it creates the virtual environment in the directory "env" // Activate the virtual environment # >$ .\env\Scripts\Activate.ps1 // Verify that the virtual environment is active diff --git a/docs/tutorial/insert.md b/docs/tutorial/insert.md index 5947e1e..ecf87ad 100644 --- a/docs/tutorial/insert.md +++ b/docs/tutorial/insert.md @@ -171,7 +171,7 @@ The first step is to import the `Session` class: ```Python hl_lines="3" {!./docs_src/tutorial/insert/tutorial001.py[ln:1-3]!} -# Code below ommitted πŸ‘‡ +# Code below omitted πŸ‘‡ ```
diff --git a/docs/tutorial/many-to-many/create-data.md b/docs/tutorial/many-to-many/create-data.md index 22afb7c..2a51f5a 100644 --- a/docs/tutorial/many-to-many/create-data.md +++ b/docs/tutorial/many-to-many/create-data.md @@ -179,4 +179,4 @@ INFO Engine ROLLBACK ## Recap -After setting up the model link, using it with **relationship attributes** is fairly straighforward, just Python objects. ✨ +After setting up the model link, using it with **relationship attributes** is fairly straightforward, just Python objects. ✨ diff --git a/docs/tutorial/one.md b/docs/tutorial/one.md index 3b60653..f06343f 100644 --- a/docs/tutorial/one.md +++ b/docs/tutorial/one.md @@ -12,7 +12,7 @@ Let's see the utilities to read a single row. ## Continue From Previous Code -We'll continue with the same examples we have been using in the previous chapters to create and select data and we'll keep udpating them. +We'll continue with the same examples we have been using in the previous chapters to create and select data and we'll keep updating them.
πŸ‘€ Full file preview diff --git a/docs/tutorial/relationship-attributes/back-populates.md b/docs/tutorial/relationship-attributes/back-populates.md index 86a4c2a..27129a0 100644 --- a/docs/tutorial/relationship-attributes/back-populates.md +++ b/docs/tutorial/relationship-attributes/back-populates.md @@ -123,7 +123,7 @@ Now let's update **Spider-Boy**, removing him from the team by setting `hero_spi
-The first important thing is, we *haven't commited* the hero yet, so accessing the list of heroes would not trigger an automatic refresh. +The first important thing is, we *haven't committed* the hero yet, so accessing the list of heroes would not trigger an automatic refresh. But in our code, in this exact point in time, we already said that **Spider-Boy** is no longer part of the **Preventers**. πŸ”₯ diff --git a/docs/tutorial/relationship-attributes/read-relationships.md b/docs/tutorial/relationship-attributes/read-relationships.md index 181b229..c970b5e 100644 --- a/docs/tutorial/relationship-attributes/read-relationships.md +++ b/docs/tutorial/relationship-attributes/read-relationships.md @@ -52,7 +52,7 @@ With what we have learned **up to now**, we could use a `select()` statement, th ## Get Relationship Team - New Way -But now that we have the **relationship attributes**, we can just access them, and **SQLModel** (actually SQLAlchemy) will go and fetch the correspoinding data from the database, and make it available in the attribute. ✨ +But now that we have the **relationship attributes**, we can just access them, and **SQLModel** (actually SQLAlchemy) will go and fetch the corresponding data from the database, and make it available in the attribute. ✨ So, the highlighted block above, has the same results as the block below: diff --git a/docs/tutorial/select.md b/docs/tutorial/select.md index fb638c1..5de32db 100644 --- a/docs/tutorial/select.md +++ b/docs/tutorial/select.md @@ -190,7 +190,7 @@ First we have to import `select` from `sqlmodel` at the top of the file: ```Python hl_lines="3" {!./docs_src/tutorial/select/tutorial001.py[ln:1-3]!} -# More code below ommitted πŸ‘‡ +# More code below omitted πŸ‘‡ ```
@@ -472,7 +472,7 @@ SQLAlchemy's own `Session` has a method `session.execute()`. It doesn't have a ` If you see SQLAlchemy tutorials, they will always use `session.execute()`. -**SQLModel**'s own `Session` inherits directly from SQLAlchemy's `Session`, and adds this additonal method `session.exec()`. Underneath, it uses the same `session.execute()`. +**SQLModel**'s own `Session` inherits directly from SQLAlchemy's `Session`, and adds this additional method `session.exec()`. Underneath, it uses the same `session.execute()`. But `session.exec()` does several **tricks** combined with the tricks in `session()` to give you the **best editor support**, with **autocompletion** and **inline errors** everywhere, even after getting data from a select. ✨ diff --git a/docs/tutorial/where.md b/docs/tutorial/where.md index ca85a4d..47f1b9b 100644 --- a/docs/tutorial/where.md +++ b/docs/tutorial/where.md @@ -206,7 +206,7 @@ We care specially about the **select** statement: ## Filter Rows Using `WHERE` with **SQLModel** -Now, the same way that we add `WHERE` to a SQL statement to filter rows, we can add a `.where()` to a **SQLModel** `select()` statment to filter rows, which will filter the objects returned: +Now, the same way that we add `WHERE` to a SQL statement to filter rows, we can add a `.where()` to a **SQLModel** `select()` statement to filter rows, which will filter the objects returned: ```Python hl_lines="5" # Code above omitted πŸ‘† @@ -748,7 +748,7 @@ FROM hero WHERE hero.age >= ? AND hero.age < ? INFO Engine [no key 0.00014s] (35, 40) -// The two heros printed +// The two heroes printed age=35 id=5 name='Black Lion' secret_name='Trevor Challa' age=36 id=6 name='Dr. Weird' secret_name='Steve Weird' diff --git a/docs_src/tutorial/automatic_id_none_refresh/annotations/en/tutorial002.md b/docs_src/tutorial/automatic_id_none_refresh/annotations/en/tutorial002.md index fd33fec..8306d9b 100644 --- a/docs_src/tutorial/automatic_id_none_refresh/annotations/en/tutorial002.md +++ b/docs_src/tutorial/automatic_id_none_refresh/annotations/en/tutorial002.md @@ -157,7 +157,7 @@ Hero 3: ``` -21. Print the line `"After commiting the session, show IDs"`. +21. Print the line `"After committing the session, show IDs"`. Generates the output: diff --git a/docs_src/tutorial/update/annotations/en/tutorial004.md b/docs_src/tutorial/update/annotations/en/tutorial004.md index 55755cd..3fcf104 100644 --- a/docs_src/tutorial/update/annotations/en/tutorial004.md +++ b/docs_src/tutorial/update/annotations/en/tutorial004.md @@ -132,7 +132,7 @@ !!! tip SQLAlchemy is still using the previous transaction, so it doesn't have to create a new one. -18. Print the first hero, now udpated. +18. Print the first hero, now updated. This generates the output: diff --git a/sqlmodel/default.py b/sqlmodel/default.py index bb44972..e8e37a5 100644 --- a/sqlmodel/default.py +++ b/sqlmodel/default.py @@ -6,7 +6,7 @@ class _DefaultPlaceholder: You shouldn't use this class directly. It's used internally to recognize when a default value has been overwritten, even - if the overriden default value was truthy. + if the overridden default value was truthy. """ def __init__(self, value: Any): @@ -27,6 +27,6 @@ def Default(value: _TDefaultType) -> _TDefaultType: You shouldn't use this function directly. It's used internally to recognize when a default value has been overwritten, even - if the overriden default value was truthy. + if the overridden default value was truthy. """ return _DefaultPlaceholder(value) # type: ignore diff --git a/tests/test_validation.py b/tests/test_validation.py index a3ff6e3..ad60fcb 100644 --- a/tests/test_validation.py +++ b/tests/test_validation.py @@ -7,7 +7,7 @@ from sqlmodel import SQLModel def test_validation(clear_sqlmodel): - """Test validation of implicit and explict None values. + """Test validation of implicit and explicit None values. # For consistency with pydantic, validators are not to be called on # arguments that are not explicitly provided. From 5231c8b6bb748906fbd6cf490ad477ff898ec8f0 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 22 Oct 2023 12:51:20 +0000 Subject: [PATCH 30/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index d15ce97..033a8ce 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏️ Fix typos found with codespell. PR [#520](https://github.com/tiangolo/sqlmodel/pull/520) by [@kianmeng](https://github.com/kianmeng). * πŸ“ Fix typos (duplication) in main page. PR [#631](https://github.com/tiangolo/sqlmodel/pull/631) by [@Mr-DRP](https://github.com/Mr-DRP). * πŸ“ Update release notes, add second author to PR. PR [#429](https://github.com/tiangolo/sqlmodel/pull/429) by [@br-follow](https://github.com/br-follow). * πŸ“ Update instructions about how to make a foreign key required in `docs/tutorial/relationship-attributes/define-relationships-attributes.md`. PR [#474](https://github.com/tiangolo/sqlmodel/pull/474) by [@jalvaradosegura](https://github.com/jalvaradosegura). From 8970833b147e998b5e5d0c52421a979d4ac81cf8 Mon Sep 17 00:00:00 2001 From: Matvey Fedoseev <41521530+MatveyF@users.noreply.github.com> Date: Sun, 22 Oct 2023 13:54:36 +0100 Subject: [PATCH 31/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20outdated=20link?= =?UTF-8?q?=20in=20`docs/db-to-code.md`=20(#649)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SebastiΓ‘n RamΓ­rez --- docs/db-to-code.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/db-to-code.md b/docs/db-to-code.md index 2e0fb1b..980c457 100644 --- a/docs/db-to-code.md +++ b/docs/db-to-code.md @@ -111,7 +111,7 @@ DROP TABLE hero; That is how you tell the database in SQL to delete the entire table `hero`. -Nooooo! We lost all the data in the `hero` table! πŸ’₯😱 +Nooooo! We lost all the data in the `hero` table! πŸ’₯😱 ### SQL Sanitization @@ -305,4 +305,4 @@ You will see **your own code** a lot more than the internal table names, so it's So, to keep things consistent, I'll keep using the same table names that **SQLModel** would have generated. !!! tip - You can also override the table name. You can read about it in the Advanced User Guide. \ No newline at end of file + You can also override the table name. You can read about it in the Advanced User Guide. From a8a792e3c0c43f8c0ff443d54c3353c05c7c437b Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 22 Oct 2023 12:55:08 +0000 Subject: [PATCH 32/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 033a8ce..f5660af 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ“ Update outdated link in `docs/db-to-code.md`. PR [#649](https://github.com/tiangolo/sqlmodel/pull/649) by [@MatveyF](https://github.com/MatveyF). * ✏️ Fix typos found with codespell. PR [#520](https://github.com/tiangolo/sqlmodel/pull/520) by [@kianmeng](https://github.com/kianmeng). * πŸ“ Fix typos (duplication) in main page. PR [#631](https://github.com/tiangolo/sqlmodel/pull/631) by [@Mr-DRP](https://github.com/Mr-DRP). * πŸ“ Update release notes, add second author to PR. PR [#429](https://github.com/tiangolo/sqlmodel/pull/429) by [@br-follow](https://github.com/br-follow). From 840fd08ab2f803d4e8fb67c7587a59621473c715 Mon Sep 17 00:00:00 2001 From: David Danier Date: Mon, 23 Oct 2023 08:42:30 +0200 Subject: [PATCH 33/85] =?UTF-8?q?=E2=9C=A8=20Raise=20a=20more=20clear=20er?= =?UTF-8?q?ror=20when=20a=20type=20is=20not=20valid=20(#425)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SebastiΓ‘n RamΓ­rez --- sqlmodel/main.py | 79 ++++++++++++++-------------- tests/test_sqlalchemy_type_errors.py | 28 ++++++++++ 2 files changed, 68 insertions(+), 39 deletions(-) create mode 100644 tests/test_sqlalchemy_type_errors.py diff --git a/sqlmodel/main.py b/sqlmodel/main.py index caae8cf..7dec60d 100644 --- a/sqlmodel/main.py +++ b/sqlmodel/main.py @@ -374,45 +374,46 @@ class SQLModelMetaclass(ModelMetaclass, DeclarativeMeta): def get_sqlalchemy_type(field: ModelField) -> Any: - if issubclass(field.type_, str): - if field.field_info.max_length: - return AutoString(length=field.field_info.max_length) - return AutoString - if issubclass(field.type_, float): - return Float - if issubclass(field.type_, bool): - return Boolean - if issubclass(field.type_, int): - return Integer - if issubclass(field.type_, datetime): - return DateTime - if issubclass(field.type_, date): - return Date - if issubclass(field.type_, timedelta): - return Interval - if issubclass(field.type_, time): - return Time - if issubclass(field.type_, Enum): - return sa_Enum(field.type_) - if issubclass(field.type_, bytes): - return LargeBinary - if issubclass(field.type_, Decimal): - return Numeric( - precision=getattr(field.type_, "max_digits", None), - scale=getattr(field.type_, "decimal_places", None), - ) - if issubclass(field.type_, ipaddress.IPv4Address): - return AutoString - if issubclass(field.type_, ipaddress.IPv4Network): - return AutoString - if issubclass(field.type_, ipaddress.IPv6Address): - return AutoString - if issubclass(field.type_, ipaddress.IPv6Network): - return AutoString - if issubclass(field.type_, Path): - return AutoString - if issubclass(field.type_, uuid.UUID): - return GUID + if isinstance(field.type_, type) and field.shape == SHAPE_SINGLETON: + if issubclass(field.type_, str): + if field.field_info.max_length: + return AutoString(length=field.field_info.max_length) + return AutoString + if issubclass(field.type_, float): + return Float + if issubclass(field.type_, bool): + return Boolean + if issubclass(field.type_, int): + return Integer + if issubclass(field.type_, datetime): + return DateTime + if issubclass(field.type_, date): + return Date + if issubclass(field.type_, timedelta): + return Interval + if issubclass(field.type_, time): + return Time + if issubclass(field.type_, Enum): + return sa_Enum(field.type_) + if issubclass(field.type_, bytes): + return LargeBinary + if issubclass(field.type_, Decimal): + return Numeric( + precision=getattr(field.type_, "max_digits", None), + scale=getattr(field.type_, "decimal_places", None), + ) + if issubclass(field.type_, ipaddress.IPv4Address): + return AutoString + if issubclass(field.type_, ipaddress.IPv4Network): + return AutoString + if issubclass(field.type_, ipaddress.IPv6Address): + return AutoString + if issubclass(field.type_, ipaddress.IPv6Network): + return AutoString + if issubclass(field.type_, Path): + return AutoString + if issubclass(field.type_, uuid.UUID): + return GUID raise ValueError(f"The field {field.name} has no matching SQLAlchemy type") diff --git a/tests/test_sqlalchemy_type_errors.py b/tests/test_sqlalchemy_type_errors.py new file mode 100644 index 0000000..e211c46 --- /dev/null +++ b/tests/test_sqlalchemy_type_errors.py @@ -0,0 +1,28 @@ +from typing import Any, Dict, List, Optional, Union + +import pytest +from sqlmodel import Field, SQLModel + + +def test_type_list_breaks() -> None: + with pytest.raises(ValueError): + + class Hero(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + tags: List[str] + + +def test_type_dict_breaks() -> None: + with pytest.raises(ValueError): + + class Hero(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + tags: Dict[str, Any] + + +def test_type_union_breaks() -> None: + with pytest.raises(ValueError): + + class Hero(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + tags: Union[int, str] From 9ba303910639a446d428aa9e1a4a4b54d79ca19c Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Oct 2023 06:43:04 +0000 Subject: [PATCH 34/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index f5660af..8ba2f57 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Raise a more clear error when a type is not valid. PR [#425](https://github.com/tiangolo/sqlmodel/pull/425) by [@ddanier](https://github.com/ddanier). * πŸ“ Update outdated link in `docs/db-to-code.md`. PR [#649](https://github.com/tiangolo/sqlmodel/pull/649) by [@MatveyF](https://github.com/MatveyF). * ✏️ Fix typos found with codespell. PR [#520](https://github.com/tiangolo/sqlmodel/pull/520) by [@kianmeng](https://github.com/kianmeng). * πŸ“ Fix typos (duplication) in main page. PR [#631](https://github.com/tiangolo/sqlmodel/pull/631) by [@Mr-DRP](https://github.com/Mr-DRP). From 065fcdc8280ab333a0e165eec9124b727d2a92e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 23 Oct 2023 11:34:50 +0400 Subject: [PATCH 35/85] =?UTF-8?q?=F0=9F=91=B7=20Move=20to=20Ruff=20and=20a?= =?UTF-8?q?dd=20pre-commit=20(#661)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * πŸ‘· Add pre-commit * πŸ”§ Add pyproject.toml config for Ruff * βž• Replace isort, flake8, autoflake with Ruff * πŸ”¨ Update lint and format scripts * 🎨 Format with Ruff * πŸ”§ Update Poetry config --- .pre-commit-config.yaml | 35 ++++++++++++++++++++++ pyproject.toml | 49 ++++++++++++++++++------------- scripts/format.sh | 5 ++-- scripts/lint.sh | 3 +- sqlmodel/__init__.py | 64 ++++++++++++++++++++--------------------- sqlmodel/main.py | 29 ++++++++++++------- 6 files changed, 117 insertions(+), 68 deletions(-) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..9f7085f --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,35 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +default_language_version: + python: python3.10 +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: check-added-large-files + - id: check-toml + - id: check-yaml + args: + - --unsafe + - id: end-of-file-fixer + - id: trailing-whitespace +- repo: https://github.com/asottile/pyupgrade + rev: v3.7.0 + hooks: + - id: pyupgrade + args: + - --py3-plus + - --keep-runtime-typing +- repo: https://github.com/charliermarsh/ruff-pre-commit + rev: v0.0.275 + hooks: + - id: ruff + args: + - --fix +- repo: https://github.com/psf/black + rev: 23.3.0 + hooks: + - id: black +ci: + autofix_commit_msg: 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks + autoupdate_commit_msg: ⬆ [pre-commit.ci] pre-commit autoupdate diff --git a/pyproject.toml b/pyproject.toml index e402727..73d8b3a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,10 +35,9 @@ SQLAlchemy = ">=1.4.17,<=1.4.41" pydantic = "^1.8.2" sqlalchemy2-stubs = {version = "*", allow-prereleases = true} -[tool.poetry.dev-dependencies] +[tool.poetry.group.dev.dependencies] pytest = "^7.0.1" mypy = "0.971" -flake8 = "^5.0.4" black = "^22.10.0" mkdocs = "^1.2.1" mkdocs-material = "^8.1.4" @@ -48,8 +47,7 @@ mdx-include = "^1.4.1" coverage = {extras = ["toml"], version = "^6.2"} fastapi = "^0.68.1" requests = "^2.26.0" -autoflake = "^1.4" -isort = "^5.9.3" +ruff = "^0.1.1" [build-system] requires = ["poetry-core"] @@ -75,27 +73,19 @@ exclude_lines = [ "if TYPE_CHECKING:", ] -[tool.isort] -profile = "black" -known_third_party = ["sqlmodel"] -skip_glob = [ - "sqlmodel/__init__.py", - ] - - [tool.mypy] # --strict disallow_any_generics = true -disallow_subclassing_any = true -disallow_untyped_calls = true +disallow_subclassing_any = true +disallow_untyped_calls = true disallow_untyped_defs = true -disallow_incomplete_defs = true -check_untyped_defs = true -disallow_untyped_decorators = true +disallow_incomplete_defs = true +check_untyped_defs = true +disallow_untyped_decorators = true no_implicit_optional = true -warn_redundant_casts = true +warn_redundant_casts = true warn_unused_ignores = true -warn_return_any = true +warn_return_any = true implicit_reexport = false strict_equality = true # --strict end @@ -104,4 +94,23 @@ strict_equality = true module = "sqlmodel.sql.expression" warn_unused_ignores = false -# invalidate CI cache: 1 +[tool.ruff] +select = [ + "E", # pycodestyle errors + "W", # pycodestyle warnings + "F", # pyflakes + "I", # isort + "C", # flake8-comprehensions + "B", # flake8-bugbear +] +ignore = [ + "E501", # line too long, handled by black + "B008", # do not perform function calls in argument defaults + "C901", # too complex +] + +[tool.ruff.per-file-ignores] +# "__init__.py" = ["F401"] + +[tool.ruff.isort] +known-third-party = ["sqlmodel", "sqlalchemy", "pydantic", "fastapi"] diff --git a/scripts/format.sh b/scripts/format.sh index 0d45639..b6aebd1 100755 --- a/scripts/format.sh +++ b/scripts/format.sh @@ -1,6 +1,5 @@ #!/bin/sh -e set -x -autoflake --remove-all-unused-imports --recursive --remove-unused-variables --in-place sqlmodel docs_src tests --exclude=__init__.py -black sqlmodel tests docs_src -isort sqlmodel tests docs_src +ruff sqlmodel tests docs_src scripts --fix +black sqlmodel tests docs_src scripts diff --git a/scripts/lint.sh b/scripts/lint.sh index 4191d90..b328e3d 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -4,6 +4,5 @@ set -e set -x mypy sqlmodel -flake8 sqlmodel tests docs_src +ruff sqlmodel tests docs_src scripts black sqlmodel tests docs_src --check -isort sqlmodel tests docs_src scripts --check-only diff --git a/sqlmodel/__init__.py b/sqlmodel/__init__.py index 720aa8c..3aa6e0d 100644 --- a/sqlmodel/__init__.py +++ b/sqlmodel/__init__.py @@ -5,12 +5,12 @@ from sqlalchemy.engine import create_mock_engine as create_mock_engine from sqlalchemy.engine import engine_from_config as engine_from_config from sqlalchemy.inspection import inspect as inspect from sqlalchemy.schema import BLANK_SCHEMA as BLANK_SCHEMA +from sqlalchemy.schema import DDL as DDL from sqlalchemy.schema import CheckConstraint as CheckConstraint from sqlalchemy.schema import Column as Column from sqlalchemy.schema import ColumnDefault as ColumnDefault from sqlalchemy.schema import Computed as Computed from sqlalchemy.schema import Constraint as Constraint -from sqlalchemy.schema import DDL as DDL from sqlalchemy.schema import DefaultClause as DefaultClause from sqlalchemy.schema import FetchedValue as FetchedValue from sqlalchemy.schema import ForeignKey as ForeignKey @@ -23,6 +23,14 @@ from sqlalchemy.schema import Sequence as Sequence from sqlalchemy.schema import Table as Table from sqlalchemy.schema import ThreadLocalMetaData as ThreadLocalMetaData from sqlalchemy.schema import UniqueConstraint as UniqueConstraint +from sqlalchemy.sql import LABEL_STYLE_DEFAULT as LABEL_STYLE_DEFAULT +from sqlalchemy.sql import ( + LABEL_STYLE_DISAMBIGUATE_ONLY as LABEL_STYLE_DISAMBIGUATE_ONLY, +) +from sqlalchemy.sql import LABEL_STYLE_NONE as LABEL_STYLE_NONE +from sqlalchemy.sql import ( + LABEL_STYLE_TABLENAME_PLUS_COL as LABEL_STYLE_TABLENAME_PLUS_COL, +) from sqlalchemy.sql import alias as alias from sqlalchemy.sql import all_ as all_ from sqlalchemy.sql import and_ as and_ @@ -48,14 +56,6 @@ from sqlalchemy.sql import insert as insert from sqlalchemy.sql import intersect as intersect from sqlalchemy.sql import intersect_all as intersect_all from sqlalchemy.sql import join as join -from sqlalchemy.sql import LABEL_STYLE_DEFAULT as LABEL_STYLE_DEFAULT -from sqlalchemy.sql import ( - LABEL_STYLE_DISAMBIGUATE_ONLY as LABEL_STYLE_DISAMBIGUATE_ONLY, -) -from sqlalchemy.sql import LABEL_STYLE_NONE as LABEL_STYLE_NONE -from sqlalchemy.sql import ( - LABEL_STYLE_TABLENAME_PLUS_COL as LABEL_STYLE_TABLENAME_PLUS_COL, -) from sqlalchemy.sql import lambda_stmt as lambda_stmt from sqlalchemy.sql import lateral as lateral from sqlalchemy.sql import literal as literal @@ -85,55 +85,53 @@ from sqlalchemy.sql import values as values from sqlalchemy.sql import within_group as within_group from sqlalchemy.types import ARRAY as ARRAY from sqlalchemy.types import BIGINT as BIGINT -from sqlalchemy.types import BigInteger as BigInteger from sqlalchemy.types import BINARY as BINARY from sqlalchemy.types import BLOB as BLOB from sqlalchemy.types import BOOLEAN as BOOLEAN -from sqlalchemy.types import Boolean as Boolean from sqlalchemy.types import CHAR as CHAR from sqlalchemy.types import CLOB as CLOB from sqlalchemy.types import DATE as DATE -from sqlalchemy.types import Date as Date from sqlalchemy.types import DATETIME as DATETIME -from sqlalchemy.types import DateTime as DateTime from sqlalchemy.types import DECIMAL as DECIMAL -from sqlalchemy.types import Enum as Enum from sqlalchemy.types import FLOAT as FLOAT -from sqlalchemy.types import Float as Float from sqlalchemy.types import INT as INT from sqlalchemy.types import INTEGER as INTEGER -from sqlalchemy.types import Integer as Integer -from sqlalchemy.types import Interval as Interval from sqlalchemy.types import JSON as JSON -from sqlalchemy.types import LargeBinary as LargeBinary from sqlalchemy.types import NCHAR as NCHAR from sqlalchemy.types import NUMERIC as NUMERIC -from sqlalchemy.types import Numeric as Numeric from sqlalchemy.types import NVARCHAR as NVARCHAR -from sqlalchemy.types import PickleType as PickleType from sqlalchemy.types import REAL as REAL from sqlalchemy.types import SMALLINT as SMALLINT +from sqlalchemy.types import TEXT as TEXT +from sqlalchemy.types import TIME as TIME +from sqlalchemy.types import TIMESTAMP as TIMESTAMP +from sqlalchemy.types import VARBINARY as VARBINARY +from sqlalchemy.types import VARCHAR as VARCHAR +from sqlalchemy.types import BigInteger as BigInteger +from sqlalchemy.types import Boolean as Boolean +from sqlalchemy.types import Date as Date +from sqlalchemy.types import DateTime as DateTime +from sqlalchemy.types import Enum as Enum +from sqlalchemy.types import Float as Float +from sqlalchemy.types import Integer as Integer +from sqlalchemy.types import Interval as Interval +from sqlalchemy.types import LargeBinary as LargeBinary +from sqlalchemy.types import Numeric as Numeric +from sqlalchemy.types import PickleType as PickleType from sqlalchemy.types import SmallInteger as SmallInteger from sqlalchemy.types import String as String -from sqlalchemy.types import TEXT as TEXT from sqlalchemy.types import Text as Text -from sqlalchemy.types import TIME as TIME from sqlalchemy.types import Time as Time -from sqlalchemy.types import TIMESTAMP as TIMESTAMP from sqlalchemy.types import TypeDecorator as TypeDecorator from sqlalchemy.types import Unicode as Unicode from sqlalchemy.types import UnicodeText as UnicodeText -from sqlalchemy.types import VARBINARY as VARBINARY -from sqlalchemy.types import VARCHAR as VARCHAR -# Extensions and modifications of SQLAlchemy in SQLModel +# From SQLModel, modifications of SQLAlchemy or equivalents of Pydantic from .engine.create import create_engine as create_engine -from .orm.session import Session as Session -from .sql.expression import select as select -from .sql.expression import col as col -from .sql.sqltypes import AutoString as AutoString - -# Export SQLModel specifics (equivalent to Pydantic) -from .main import SQLModel as SQLModel from .main import Field as Field from .main import Relationship as Relationship +from .main import SQLModel as SQLModel +from .orm.session import Session as Session +from .sql.expression import col as col +from .sql.expression import select as select +from .sql.sqltypes import AutoString as AutoString diff --git a/sqlmodel/main.py b/sqlmodel/main.py index 7dec60d..d5a7302 100644 --- a/sqlmodel/main.py +++ b/sqlmodel/main.py @@ -26,15 +26,24 @@ from typing import ( from pydantic import BaseConfig, BaseModel from pydantic.errors import ConfigError, DictError -from pydantic.fields import SHAPE_SINGLETON +from pydantic.fields import SHAPE_SINGLETON, ModelField, Undefined, UndefinedType from pydantic.fields import FieldInfo as PydanticFieldInfo -from pydantic.fields import ModelField, Undefined, UndefinedType from pydantic.main import ModelMetaclass, validate_model from pydantic.typing import NoArgAnyCallable, resolve_annotations from pydantic.utils import ROOT_KEY, Representation -from sqlalchemy import Boolean, Column, Date, DateTime +from sqlalchemy import ( + Boolean, + Column, + Date, + DateTime, + Float, + ForeignKey, + Integer, + Interval, + Numeric, + inspect, +) from sqlalchemy import Enum as sa_Enum -from sqlalchemy import Float, ForeignKey, Integer, Interval, Numeric, inspect from sqlalchemy.orm import RelationshipProperty, declared_attr, registry, relationship from sqlalchemy.orm.attributes import set_attribute from sqlalchemy.orm.decl_api import DeclarativeMeta @@ -305,9 +314,9 @@ class SQLModelMetaclass(ModelMetaclass, DeclarativeMeta): config_registry = cast(registry, config_registry) # If it was passed by kwargs, ensure it's also set in config new_cls.__config__.registry = config_table - setattr(new_cls, "_sa_registry", config_registry) - setattr(new_cls, "metadata", config_registry.metadata) - setattr(new_cls, "__abstract__", True) + setattr(new_cls, "_sa_registry", config_registry) # noqa: B010 + setattr(new_cls, "metadata", config_registry.metadata) # noqa: B010 + setattr(new_cls, "__abstract__", True) # noqa: B010 return new_cls # Override SQLAlchemy, allow both SQLAlchemy and plain Pydantic models @@ -320,7 +329,7 @@ class SQLModelMetaclass(ModelMetaclass, DeclarativeMeta): # triggers an error base_is_table = False for base in bases: - config = getattr(base, "__config__") + config = getattr(base, "__config__") # noqa: B009 if config and getattr(config, "table", False): base_is_table = True break @@ -351,7 +360,7 @@ class SQLModelMetaclass(ModelMetaclass, DeclarativeMeta): rel_kwargs["back_populates"] = rel_info.back_populates if rel_info.link_model: ins = inspect(rel_info.link_model) - local_table = getattr(ins, "local_table") + local_table = getattr(ins, "local_table") # noqa: B009 if local_table is None: raise RuntimeError( "Couldn't find the secondary table for " @@ -430,7 +439,7 @@ def get_column_from_field(field: ModelField) -> Column: # type: ignore # Override derived nullability if the nullable property is set explicitly # on the field if hasattr(field.field_info, "nullable"): - field_nullable = getattr(field.field_info, "nullable") + field_nullable = getattr(field.field_info, "nullable") # noqa: B009 if field_nullable != Undefined: nullable = field_nullable args = [] From 7f72c60ae44dc20e42e22b322afa08e31d4553ea Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Oct 2023 07:35:25 +0000 Subject: [PATCH 36/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 8ba2f57..5e79cf0 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ‘· Move to Ruff and add pre-commit. PR [#661](https://github.com/tiangolo/sqlmodel/pull/661) by [@tiangolo](https://github.com/tiangolo). * ✨ Raise a more clear error when a type is not valid. PR [#425](https://github.com/tiangolo/sqlmodel/pull/425) by [@ddanier](https://github.com/ddanier). * πŸ“ Update outdated link in `docs/db-to-code.md`. PR [#649](https://github.com/tiangolo/sqlmodel/pull/649) by [@MatveyF](https://github.com/MatveyF). * ✏️ Fix typos found with codespell. PR [#520](https://github.com/tiangolo/sqlmodel/pull/520) by [@kianmeng](https://github.com/kianmeng). From 27a81b2112d7cd160c2f2de38430e91ae9ca6158 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 23 Oct 2023 11:46:31 +0400 Subject: [PATCH 37/85] =?UTF-8?q?=F0=9F=8E=A8=20Run=20pre-commit=20on=20al?= =?UTF-8?q?l=20files=20and=20autoformat=20(#666)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../comment-docs-preview-in-pr/app/main.py | 4 +- docs/img/databases/external-server.drawio | 2 +- docs/img/databases/external-server.svg | 2 +- docs/img/databases/multiple-servers.drawio | 2 +- docs/img/databases/multiple-servers.svg | 2 +- docs/img/databases/relationships.drawio | 2 +- docs/img/databases/relationships.svg | 2 +- docs/img/databases/same-server.drawio | 2 +- docs/img/databases/same-server.svg | 2 +- docs/img/databases/single-file.drawio | 2 +- docs/img/databases/single-file.svg | 2 +- docs/img/db-to-code/mapper.drawio | 2 +- docs/img/db-to-code/mapper.svg | 2 +- .../img/tutorial/indexes/dictionary001.drawio | 2 +- docs/img/tutorial/indexes/dictionary001.svg | 2 +- .../img/tutorial/indexes/dictionary002.drawio | 2 +- docs/img/tutorial/indexes/dictionary002.svg | 2 +- .../img/tutorial/indexes/dictionary003.drawio | 2 +- docs/img/tutorial/indexes/dictionary003.svg | 2 +- .../img/tutorial/indexes/dictionary004.drawio | 2 +- docs/img/tutorial/indexes/dictionary004.svg | 2 +- .../img/tutorial/indexes/dictionary005.drawio | 2 +- docs/img/tutorial/indexes/dictionary005.svg | 2 +- .../img/tutorial/indexes/dictionary006.drawio | 2 +- docs/img/tutorial/indexes/dictionary006.svg | 2 +- .../img/tutorial/indexes/dictionary007.drawio | 2 +- docs/img/tutorial/indexes/dictionary007.svg | 2 +- .../img/tutorial/indexes/dictionary008.drawio | 2 +- docs/img/tutorial/indexes/dictionary008.svg | 2 +- docs/img/tutorial/indexes/techbook001.drawio | 2 +- docs/img/tutorial/indexes/techbook001.svg | 2 +- .../tutorial/many-to-many/many-to-many.drawio | 2 +- .../tutorial/many-to-many/many-to-many.svg | 2 +- .../tutorial/offset-and-limit/limit.drawio | 2 +- docs/img/tutorial/offset-and-limit/limit.svg | 2 +- .../tutorial/offset-and-limit/limit2.drawio | 2 +- docs/img/tutorial/offset-and-limit/limit2.svg | 2 +- .../tutorial/offset-and-limit/limit3.drawio | 2 +- docs/img/tutorial/offset-and-limit/limit3.svg | 2 +- .../attributes/back-populates.drawio | 2 +- .../attributes/back-populates.svg | 2 +- .../attributes/back-populates2.drawio | 2 +- .../attributes/back-populates2.svg | 2 +- .../select/relationships2.drawio | 2 +- .../relationships/select/relationships2.svg | 2 +- docs/js/termynal.js | 14 ++-- docs/overrides/main.html | 8 +- docs/tutorial/automatic-id-none-refresh.md | 76 +++++++++--------- .../tutorial/connect/create-connected-rows.md | 22 +++--- .../connect/create-connected-tables.md | 40 +++++----- docs/tutorial/connect/read-connected-data.md | 16 ++-- .../connect/remove-data-connections.md | 6 +- .../connect/update-data-connections.md | 6 +- docs/tutorial/create-db-and-table.md | 10 +-- docs/tutorial/delete.md | 8 +- docs/tutorial/index.md | 2 +- docs/tutorial/indexes.md | 12 +-- docs/tutorial/limit-and-offset.md | 12 +-- docs/tutorial/many-to-many/create-data.md | 24 +++--- .../many-to-many/create-models-with-link.md | 28 +++---- .../many-to-many/link-with-extra-fields.md | 78 +++++++++---------- .../update-remove-relationships.md | 28 +++---- docs/tutorial/one.md | 28 +++---- .../relationship-attributes/back-populates.md | 24 +++--- .../read-relationships.md | 4 +- docs/tutorial/select.md | 4 +- docs/tutorial/update.md | 8 +- docs/tutorial/where.md | 16 ++-- .../annotations/en/tutorial002.md | 24 +++--- .../delete/annotations/en/tutorial002.md | 8 +- .../select/annotations/en/tutorial002.md | 2 +- .../update/annotations/en/tutorial002.md | 8 +- .../update/annotations/en/tutorial004.md | 16 ++-- sqlmodel/sql/sqltypes.py | 1 - .../test_delete/test_tutorial001.py | 1 - .../test_limit_and_offset/test_tutorial001.py | 1 - .../test_multiple_models/test_tutorial001.py | 1 - .../test_multiple_models/test_tutorial002.py | 1 - .../test_read_one/test_tutorial001.py | 1 - .../test_response_model/test_tutorial001.py | 1 - .../test_tutorial001.py | 1 - .../test_simple_hero_api/test_tutorial001.py | 1 - .../test_teams/test_tutorial001.py | 1 - .../test_update/test_tutorial001.py | 1 - 84 files changed, 311 insertions(+), 324 deletions(-) diff --git a/.github/actions/comment-docs-preview-in-pr/app/main.py b/.github/actions/comment-docs-preview-in-pr/app/main.py index 3b10e0e..c9fb7cb 100644 --- a/.github/actions/comment-docs-preview-in-pr/app/main.py +++ b/.github/actions/comment-docs-preview-in-pr/app/main.py @@ -48,9 +48,7 @@ if __name__ == "__main__": use_pr = pr break if not use_pr: - logging.error( - f"No PR found for hash: {event.workflow_run.head_commit.id}" - ) + logging.error(f"No PR found for hash: {event.workflow_run.head_commit.id}") sys.exit(0) github_headers = { "Authorization": f"token {settings.input_token.get_secret_value()}" diff --git a/docs/img/databases/external-server.drawio b/docs/img/databases/external-server.drawio index 4af8e30..7631d02 100644 --- a/docs/img/databases/external-server.drawio +++ b/docs/img/databases/external-server.drawio @@ -90,4 +90,4 @@ - \ No newline at end of file + diff --git a/docs/img/databases/external-server.svg b/docs/img/databases/external-server.svg index cf0f541..4a85c58 100644 --- a/docs/img/databases/external-server.svg +++ b/docs/img/databases/external-server.svg @@ -1 +1 @@ -
Machine / Computer
Machine / Computer
Database application
Database application
File
File
Data
Data
File
File
Data
Data
File
File
Data
Data
Machine / Computer
Machine / Computer
Your code
Your code
Viewer does not support full SVG 1.1
\ No newline at end of file +
Machine / Computer
Machine / Computer
Database application
Database application
File
File
Data
Data
File
File
Data
Data
File
File
Data
Data
Machine / Computer
Machine / Computer
Your code
Your code
Viewer does not support full SVG 1.1
diff --git a/docs/img/databases/multiple-servers.drawio b/docs/img/databases/multiple-servers.drawio index efceed9..9a4fd54 100644 --- a/docs/img/databases/multiple-servers.drawio +++ b/docs/img/databases/multiple-servers.drawio @@ -202,4 +202,4 @@ - \ No newline at end of file + diff --git a/docs/img/databases/multiple-servers.svg b/docs/img/databases/multiple-servers.svg index 039260a..083d0e7 100644 --- a/docs/img/databases/multiple-servers.svg +++ b/docs/img/databases/multiple-servers.svg @@ -1 +1 @@ -
Machine / Computer
Machine / Computer
Database application
Database application
File
File
Data
Data
File
File
Data
Data
Machine / Computer
Machine / Computer
Your code
Your code
Machine / Computer
Machine / Computer
Database application
Database application
File
File
Data
Data
File
File
Data
Data
Machine / Computer
Machine / Computer
Database application
Database application
File
File
Data
Data
File
File
Data
Data
Viewer does not support full SVG 1.1
\ No newline at end of file +
Machine / Computer
Machine / Computer
Database application
Database application
File
File
Data
Data
File
File
Data
Data
Machine / Computer
Machine / Computer
Your code
Your code
Machine / Computer
Machine / Computer
Database application
Database application
File
File
Data
Data
File
File
Data
Data
Machine / Computer
Machine / Computer
Database application
Database application
File
File
Data
Data
File
File
Data
Data
Viewer does not support full SVG 1.1
diff --git a/docs/img/databases/relationships.drawio b/docs/img/databases/relationships.drawio index 9ae668c..fb8ef8d 100644 --- a/docs/img/databases/relationships.drawio +++ b/docs/img/databases/relationships.drawio @@ -148,4 +148,4 @@ - \ No newline at end of file + diff --git a/docs/img/databases/relationships.svg b/docs/img/databases/relationships.svg index fbecdac..0557275 100644 --- a/docs/img/databases/relationships.svg +++ b/docs/img/databases/relationships.svg @@ -54,4 +54,4 @@ src: url("https://fonts.gstatic.com/s/roboto/v27/KFOmCnqEu92Fr1Mu4mxK.woff2") format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } -
hero
hero
id
id
name
name
secret_name
secret_name
age
age
team_id
team_id
1
1
Deadpond
Deadpond
Dive Wilson
Dive Wilson
null
null
2
2
2
2
Spider-Boy
Spider-Boy
Pedro Parqueador
Pedro Parqueador
null
null
1
1
3
3
Rusty-Man
Rusty-Man
Tommy Sharp
Tommy Sharp
48
48
1
1
team
team
id
id
name
name
headquarters
headquarters
1
1
Preventers
Preventers
Sharp Tower
Sharp Tower
2
2
Z-Force
Z-Force

Sister Margaret’s Bar

Sister Margaret’s Bar
Viewer does not support full SVG 1.1 \ No newline at end of file +
hero
hero
id
id
name
name
secret_name
secret_name
age
age
team_id
team_id
1
1
Deadpond
Deadpond
Dive Wilson
Dive Wilson
null
null
2
2
2
2
Spider-Boy
Spider-Boy
Pedro Parqueador
Pedro Parqueador
null
null
1
1
3
3
Rusty-Man
Rusty-Man
Tommy Sharp
Tommy Sharp
48
48
1
1
team
team
id
id
name
name
headquarters
headquarters
1
1
Preventers
Preventers
Sharp Tower
Sharp Tower
2
2
Z-Force
Z-Force

Sister Margaret’s Bar

Sister Margaret’s Bar
Viewer does not support full SVG 1.1 diff --git a/docs/img/databases/same-server.drawio b/docs/img/databases/same-server.drawio index 596c649..4f43be4 100644 --- a/docs/img/databases/same-server.drawio +++ b/docs/img/databases/same-server.drawio @@ -81,4 +81,4 @@ - \ No newline at end of file + diff --git a/docs/img/databases/same-server.svg b/docs/img/databases/same-server.svg index 7f2a77b..a3f6dff 100644 --- a/docs/img/databases/same-server.svg +++ b/docs/img/databases/same-server.svg @@ -1 +1 @@ -
Machine / Computer
Machine / Computer
Database application
Database application
File
File
Data
Data
File
File
Data
Data
File
File
Data
Data
Your code
Your code
Viewer does not support full SVG 1.1
\ No newline at end of file +
Machine / Computer
Machine / Computer
Database application
Database application
File
File
Data
Data
File
File
Data
Data
File
File
Data
Data
Your code
Your code
Viewer does not support full SVG 1.1
diff --git a/docs/img/databases/single-file.drawio b/docs/img/databases/single-file.drawio index 52ce703..c379f71 100644 --- a/docs/img/databases/single-file.drawio +++ b/docs/img/databases/single-file.drawio @@ -34,4 +34,4 @@ - \ No newline at end of file + diff --git a/docs/img/databases/single-file.svg b/docs/img/databases/single-file.svg index f2526d9..52c91e5 100644 --- a/docs/img/databases/single-file.svg +++ b/docs/img/databases/single-file.svg @@ -1 +1 @@ -
Machine / Computer
Machine / Computer
Your code
Your code
File: heroes.db
File: heroes.db
Data
Data
Viewer does not support full SVG 1.1
\ No newline at end of file +
Machine / Computer
Machine / Computer
Your code
Your code
File: heroes.db
File: heroes.db
Data
Data
Viewer does not support full SVG 1.1
diff --git a/docs/img/db-to-code/mapper.drawio b/docs/img/db-to-code/mapper.drawio index 072b629..3b002eb 100644 --- a/docs/img/db-to-code/mapper.drawio +++ b/docs/img/db-to-code/mapper.drawio @@ -61,4 +61,4 @@ - \ No newline at end of file + diff --git a/docs/img/db-to-code/mapper.svg b/docs/img/db-to-code/mapper.svg index 496c907..e31a464 100644 --- a/docs/img/db-to-code/mapper.svg +++ b/docs/img/db-to-code/mapper.svg @@ -1 +1 @@ -
Set of triangles
Set of triangles
Set of squares
Set of squares
Squares to Triangles Mapper
Squares to Triangles Mapp...
Viewer does not support full SVG 1.1
\ No newline at end of file +
Set of triangles
Set of triangles
Set of squares
Set of squares
Squares to Triangles Mapper
Squares to Triangles Mapp...
Viewer does not support full SVG 1.1
diff --git a/docs/img/tutorial/indexes/dictionary001.drawio b/docs/img/tutorial/indexes/dictionary001.drawio index 659f6b5..84992d0 100644 --- a/docs/img/tutorial/indexes/dictionary001.drawio +++ b/docs/img/tutorial/indexes/dictionary001.drawio @@ -94,4 +94,4 @@ - \ No newline at end of file + diff --git a/docs/img/tutorial/indexes/dictionary001.svg b/docs/img/tutorial/indexes/dictionary001.svg index b543793..59fc392 100644 --- a/docs/img/tutorial/indexes/dictionary001.svg +++ b/docs/img/tutorial/indexes/dictionary001.svg @@ -54,4 +54,4 @@ src: url("https://fonts.gstatic.com/s/roboto/v29/KFOmCnqEu92Fr1Mu4mxK.woff2") format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } -
A
A
B
B
C
C
D
D
E
E
F
F
G
G
H
H
I
I
J
J
K
K
L
L
M
M
N
N
O
O
P
P
Q
Q
R
R
S
S
T
T
U
U
V
V
W
W
X
X
Y
Y
Z
Z
Dictionary
Dictionary
M
M
Viewer does not support full SVG 1.1 \ No newline at end of file +
A
A
B
B
C
C
D
D
E
E
F
F
G
G
H
H
I
I
J
J
K
K
L
L
M
M
N
N
O
O
P
P
Q
Q
R
R
S
S
T
T
U
U
V
V
W
W
X
X
Y
Y
Z
Z
Dictionary
Dictionary
M
M
Viewer does not support full SVG 1.1 diff --git a/docs/img/tutorial/indexes/dictionary002.drawio b/docs/img/tutorial/indexes/dictionary002.drawio index cb1857b..52544ab 100644 --- a/docs/img/tutorial/indexes/dictionary002.drawio +++ b/docs/img/tutorial/indexes/dictionary002.drawio @@ -94,4 +94,4 @@ - \ No newline at end of file + diff --git a/docs/img/tutorial/indexes/dictionary002.svg b/docs/img/tutorial/indexes/dictionary002.svg index 677687d..d612925 100644 --- a/docs/img/tutorial/indexes/dictionary002.svg +++ b/docs/img/tutorial/indexes/dictionary002.svg @@ -1 +1 @@ -
A
A
B
B
C
C
D
D
E
E
F
F
G
G
H
H
I
I
J
J
K
K
L
L
M
M
N
N
O
O
P
P
Q
Q
R
R
S
S
T
T
U
U
V
V
W
W
X
X
Y
Y
Z
Z
Dictionary
Dictionary
M
M
Viewer does not support full SVG 1.1
\ No newline at end of file +
A
A
B
B
C
C
D
D
E
E
F
F
G
G
H
H
I
I
J
J
K
K
L
L
M
M
N
N
O
O
P
P
Q
Q
R
R
S
S
T
T
U
U
V
V
W
W
X
X
Y
Y
Z
Z
Dictionary
Dictionary
M
M
Viewer does not support full SVG 1.1
diff --git a/docs/img/tutorial/indexes/dictionary003.drawio b/docs/img/tutorial/indexes/dictionary003.drawio index 845eb06..d373533 100644 --- a/docs/img/tutorial/indexes/dictionary003.drawio +++ b/docs/img/tutorial/indexes/dictionary003.drawio @@ -94,4 +94,4 @@ - \ No newline at end of file + diff --git a/docs/img/tutorial/indexes/dictionary003.svg b/docs/img/tutorial/indexes/dictionary003.svg index d667a68..0eafd5c 100644 --- a/docs/img/tutorial/indexes/dictionary003.svg +++ b/docs/img/tutorial/indexes/dictionary003.svg @@ -1 +1 @@ -
A
A
B
B
C
C
D
D
E
E
F
F
G
G
H
H
I
I
J
J
K
K
L
L
M
M
N
N
O
O
P
P
Q
Q
R
R
S
S
T
T
U
U
V
V
W
W
X
X
Y
Y
Z
Z
Dictionary
Dictionary
Viewer does not support full SVG 1.1
\ No newline at end of file +
A
A
B
B
C
C
D
D
E
E
F
F
G
G
H
H
I
I
J
J
K
K
L
L
M
M
N
N
O
O
P
P
Q
Q
R
R
S
S
T
T
U
U
V
V
W
W
X
X
Y
Y
Z
Z
Dictionary
Dictionary
Viewer does not support full SVG 1.1
diff --git a/docs/img/tutorial/indexes/dictionary004.drawio b/docs/img/tutorial/indexes/dictionary004.drawio index 14bbb1e..6c8590d 100644 --- a/docs/img/tutorial/indexes/dictionary004.drawio +++ b/docs/img/tutorial/indexes/dictionary004.drawio @@ -97,4 +97,4 @@ - \ No newline at end of file + diff --git a/docs/img/tutorial/indexes/dictionary004.svg b/docs/img/tutorial/indexes/dictionary004.svg index f881d6c..dcfcfc5 100644 --- a/docs/img/tutorial/indexes/dictionary004.svg +++ b/docs/img/tutorial/indexes/dictionary004.svg @@ -1 +1 @@ -
A
A
B
B
C
C
D
D
E
E
F
F
G
G
H
H
I
I
J
J
K
K
L
L
M
M
N
N
O
O
P
P
Q
Q
R
R
S
S
T
T
U
U
V
V
W
W
X
X
Y
Y
Z
Z
Dictionary
Dictionary
F
F
Viewer does not support full SVG 1.1
\ No newline at end of file +
A
A
B
B
C
C
D
D
E
E
F
F
G
G
H
H
I
I
J
J
K
K
L
L
M
M
N
N
O
O
P
P
Q
Q
R
R
S
S
T
T
U
U
V
V
W
W
X
X
Y
Y
Z
Z
Dictionary
Dictionary
F
F
Viewer does not support full SVG 1.1
diff --git a/docs/img/tutorial/indexes/dictionary005.drawio b/docs/img/tutorial/indexes/dictionary005.drawio index 9e339c1..33e21c6 100644 --- a/docs/img/tutorial/indexes/dictionary005.drawio +++ b/docs/img/tutorial/indexes/dictionary005.drawio @@ -94,4 +94,4 @@ - \ No newline at end of file + diff --git a/docs/img/tutorial/indexes/dictionary005.svg b/docs/img/tutorial/indexes/dictionary005.svg index 9d37624..4bfa8c0 100644 --- a/docs/img/tutorial/indexes/dictionary005.svg +++ b/docs/img/tutorial/indexes/dictionary005.svg @@ -1 +1 @@ -
A
A
B
B
C
C
D
D
E
E
F
F
G
G
H
H
I
I
J
J
K
K
L
L
M
M
N
N
O
O
P
P
Q
Q
R
R
S
S
T
T
U
U
V
V
W
W
X
X
Y
Y
Z
Z
Dictionary
Dictionary
Viewer does not support full SVG 1.1
\ No newline at end of file +
A
A
B
B
C
C
D
D
E
E
F
F
G
G
H
H
I
I
J
J
K
K
L
L
M
M
N
N
O
O
P
P
Q
Q
R
R
S
S
T
T
U
U
V
V
W
W
X
X
Y
Y
Z
Z
Dictionary
Dictionary
Viewer does not support full SVG 1.1
diff --git a/docs/img/tutorial/indexes/dictionary006.drawio b/docs/img/tutorial/indexes/dictionary006.drawio index 3c669d3..84366e8 100644 --- a/docs/img/tutorial/indexes/dictionary006.drawio +++ b/docs/img/tutorial/indexes/dictionary006.drawio @@ -97,4 +97,4 @@ - \ No newline at end of file + diff --git a/docs/img/tutorial/indexes/dictionary006.svg b/docs/img/tutorial/indexes/dictionary006.svg index 30be80e..f893ca4 100644 --- a/docs/img/tutorial/indexes/dictionary006.svg +++ b/docs/img/tutorial/indexes/dictionary006.svg @@ -1 +1 @@ -
A
A
B
B
C
C
D
D
E
E
F
F
G
G
H
H
I
I
J
J
K
K
L
L
M
M
N
N
O
O
P
P
Q
Q
R
R
S
S
T
T
U
U
V
V
W
W
X
X
Y
Y
Z
Z
Dictionary
Dictionary
C
C
Viewer does not support full SVG 1.1
\ No newline at end of file +
A
A
B
B
C
C
D
D
E
E
F
F
G
G
H
H
I
I
J
J
K
K
L
L
M
M
N
N
O
O
P
P
Q
Q
R
R
S
S
T
T
U
U
V
V
W
W
X
X
Y
Y
Z
Z
Dictionary
Dictionary
C
C
Viewer does not support full SVG 1.1
diff --git a/docs/img/tutorial/indexes/dictionary007.drawio b/docs/img/tutorial/indexes/dictionary007.drawio index 89b32ca..62ad844 100644 --- a/docs/img/tutorial/indexes/dictionary007.drawio +++ b/docs/img/tutorial/indexes/dictionary007.drawio @@ -97,4 +97,4 @@ - \ No newline at end of file + diff --git a/docs/img/tutorial/indexes/dictionary007.svg b/docs/img/tutorial/indexes/dictionary007.svg index 79e7950..8f71aa8 100644 --- a/docs/img/tutorial/indexes/dictionary007.svg +++ b/docs/img/tutorial/indexes/dictionary007.svg @@ -1 +1 @@ -
A
A
B
B
C
C
D
D
E
E
F
F
G
G
H
H
I
I
J
J
K
K
L
L
M
M
N
N
O
O
P
P
Q
Q
R
R
S
S
T
T
U
U
V
V
W
W
X
X
Y
Y
Z
Z
Dictionary
Dictionary
Viewer does not support full SVG 1.1
\ No newline at end of file +
A
A
B
B
C
C
D
D
E
E
F
F
G
G
H
H
I
I
J
J
K
K
L
L
M
M
N
N
O
O
P
P
Q
Q
R
R
S
S
T
T
U
U
V
V
W
W
X
X
Y
Y
Z
Z
Dictionary
Dictionary
Viewer does not support full SVG 1.1
diff --git a/docs/img/tutorial/indexes/dictionary008.drawio b/docs/img/tutorial/indexes/dictionary008.drawio index ac08ad0..30a1f66 100644 --- a/docs/img/tutorial/indexes/dictionary008.drawio +++ b/docs/img/tutorial/indexes/dictionary008.drawio @@ -100,4 +100,4 @@ - \ No newline at end of file + diff --git a/docs/img/tutorial/indexes/dictionary008.svg b/docs/img/tutorial/indexes/dictionary008.svg index 013a4d6..5a48e18 100644 --- a/docs/img/tutorial/indexes/dictionary008.svg +++ b/docs/img/tutorial/indexes/dictionary008.svg @@ -1 +1 @@ -
A
A
B
B
C
C
D
D
E
E
F
F
G
G
H
H
I
I
J
J
K
K
L
L
M
M
N
N
O
O
P
P
Q
Q
R
R
S
S
T
T
U
U
V
V
W
W
X
X
Y
Y
Z
Z
Dictionary
Dictionary
D
D
Viewer does not support full SVG 1.1
\ No newline at end of file +
A
A
B
B
C
C
D
D
E
E
F
F
G
G
H
H
I
I
J
J
K
K
L
L
M
M
N
N
O
O
P
P
Q
Q
R
R
S
S
T
T
U
U
V
V
W
W
X
X
Y
Y
Z
Z
Dictionary
Dictionary
D
D
Viewer does not support full SVG 1.1
diff --git a/docs/img/tutorial/indexes/techbook001.drawio b/docs/img/tutorial/indexes/techbook001.drawio index de1c256..5fffe3c 100644 --- a/docs/img/tutorial/indexes/techbook001.drawio +++ b/docs/img/tutorial/indexes/techbook001.drawio @@ -89,4 +89,4 @@ - \ No newline at end of file + diff --git a/docs/img/tutorial/indexes/techbook001.svg b/docs/img/tutorial/indexes/techbook001.svg index 8b0c09d..3f44f50 100644 --- a/docs/img/tutorial/indexes/techbook001.svg +++ b/docs/img/tutorial/indexes/techbook001.svg @@ -1 +1 @@ -
Technical Book
Technical Book
Chapter 1
Chapter 1
Chapter 2
Chapter 2
Chapter 3
Chapter 3
Chapter 4
Chapter 4
Chapter 5
Chapter 5
Chapter 6
Chapter 6
Chapter 7
Chapter 7
Book Index
Book Index
Database
Database
Python
Python
Files
Files
Editors
Editors
Viewer does not support full SVG 1.1
\ No newline at end of file +
Technical Book
Technical Book
Chapter 1
Chapter 1
Chapter 2
Chapter 2
Chapter 3
Chapter 3
Chapter 4
Chapter 4
Chapter 5
Chapter 5
Chapter 6
Chapter 6
Chapter 7
Chapter 7
Book Index
Book Index
Database
Database
Python
Python
Files
Files
Editors
Editors
Viewer does not support full SVG 1.1
diff --git a/docs/img/tutorial/many-to-many/many-to-many.drawio b/docs/img/tutorial/many-to-many/many-to-many.drawio index d585e5e..bbe1176 100644 --- a/docs/img/tutorial/many-to-many/many-to-many.drawio +++ b/docs/img/tutorial/many-to-many/many-to-many.drawio @@ -217,4 +217,4 @@ - \ No newline at end of file + diff --git a/docs/img/tutorial/many-to-many/many-to-many.svg b/docs/img/tutorial/many-to-many/many-to-many.svg index d35c280..aa0c6cc 100644 --- a/docs/img/tutorial/many-to-many/many-to-many.svg +++ b/docs/img/tutorial/many-to-many/many-to-many.svg @@ -54,4 +54,4 @@ src: url("https://fonts.gstatic.com/s/roboto/v27/KFOmCnqEu92Fr1Mu4mxK.woff2") format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } -
hero
hero
id
id
name
name
secret_name
secret_name
age
age
1
1
Deadpond
Deadpond
Dive Wilson
Dive Wilson
null
null
2
2
Spider-Boy
Spider-Boy
Pedro Parqueador
Pedro Parqueador
null
null
3
3
Rusty-Man
Rusty-Man
Tommy Sharp
Tommy Sharp
48
48
team
team
id
id
name
name
headquarters
headquarters
1
1
Preventers
Preventers
Sharp Tower
Sharp Tower
2
2
Z-Force
Z-Force

Sister Margaret’s Bar

Sister Margaret’s Bar
heroteamlink
heroteamlink
hero_id
hero_id
team_id
team_id
1
1
1
1
1
1
2
2
2
2
1
1
3
3
1
1
Viewer does not support full SVG 1.1 \ No newline at end of file +
hero
hero
id
id
name
name
secret_name
secret_name
age
age
1
1
Deadpond
Deadpond
Dive Wilson
Dive Wilson
null
null
2
2
Spider-Boy
Spider-Boy
Pedro Parqueador
Pedro Parqueador
null
null
3
3
Rusty-Man
Rusty-Man
Tommy Sharp
Tommy Sharp
48
48
team
team
id
id
name
name
headquarters
headquarters
1
1
Preventers
Preventers
Sharp Tower
Sharp Tower
2
2
Z-Force
Z-Force

Sister Margaret’s Bar

Sister Margaret’s Bar
heroteamlink
heroteamlink
hero_id
hero_id
team_id
team_id
1
1
1
1
1
1
2
2
2
2
1
1
3
3
1
1
Viewer does not support full SVG 1.1 diff --git a/docs/img/tutorial/offset-and-limit/limit.drawio b/docs/img/tutorial/offset-and-limit/limit.drawio index 569dfc5..da7f17c 100644 --- a/docs/img/tutorial/offset-and-limit/limit.drawio +++ b/docs/img/tutorial/offset-and-limit/limit.drawio @@ -130,4 +130,4 @@ - \ No newline at end of file + diff --git a/docs/img/tutorial/offset-and-limit/limit.svg b/docs/img/tutorial/offset-and-limit/limit.svg index 3e31086..d05669e 100644 --- a/docs/img/tutorial/offset-and-limit/limit.svg +++ b/docs/img/tutorial/offset-and-limit/limit.svg @@ -54,4 +54,4 @@ src: url("https://fonts.gstatic.com/s/roboto/v27/KFOmCnqEu92Fr1Mu4mxK.woff2") format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } -
hero
hero
id
id
name
name
secret_name
secret_name
age
age
1
1
Deadpond
Deadpond
Dive Wilson
Dive Wilson
null
null
2
2
Spider-Boy
Spider-Boy
Pedro Parqueador
Pedro Parqueador
null
null
3
3
Rusty-Man
Rusty-Man
Tommy Sharp
Tommy Sharp
48
48
4
4
Tarantula
Tarantula
Natalia Roman-on
Natalia Roman-on
32
32
5
5
Black Lion
Black Lion
Trevor Challa
Trevor Challa
35
35
6
6
Dr. Weird
Dr. Weird
Steve Weird
Steve Weird
36
36
7
7
Captain North America
Captain North America
Esteban Rogelios
Esteban Rogelios
93
93
Viewer does not support full SVG 1.1 \ No newline at end of file +
hero
hero
id
id
name
name
secret_name
secret_name
age
age
1
1
Deadpond
Deadpond
Dive Wilson
Dive Wilson
null
null
2
2
Spider-Boy
Spider-Boy
Pedro Parqueador
Pedro Parqueador
null
null
3
3
Rusty-Man
Rusty-Man
Tommy Sharp
Tommy Sharp
48
48
4
4
Tarantula
Tarantula
Natalia Roman-on
Natalia Roman-on
32
32
5
5
Black Lion
Black Lion
Trevor Challa
Trevor Challa
35
35
6
6
Dr. Weird
Dr. Weird
Steve Weird
Steve Weird
36
36
7
7
Captain North America
Captain North America
Esteban Rogelios
Esteban Rogelios
93
93
Viewer does not support full SVG 1.1 diff --git a/docs/img/tutorial/offset-and-limit/limit2.drawio b/docs/img/tutorial/offset-and-limit/limit2.drawio index a329235..68f9817 100644 --- a/docs/img/tutorial/offset-and-limit/limit2.drawio +++ b/docs/img/tutorial/offset-and-limit/limit2.drawio @@ -130,4 +130,4 @@ - \ No newline at end of file + diff --git a/docs/img/tutorial/offset-and-limit/limit2.svg b/docs/img/tutorial/offset-and-limit/limit2.svg index a3a7e81..f574f13 100644 --- a/docs/img/tutorial/offset-and-limit/limit2.svg +++ b/docs/img/tutorial/offset-and-limit/limit2.svg @@ -54,4 +54,4 @@ src: url("https://fonts.gstatic.com/s/roboto/v27/KFOmCnqEu92Fr1Mu4mxK.woff2") format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } -
hero
hero
id
id
name
name
secret_name
secret_name
age
age
1
1
Deadpond
Deadpond
Dive Wilson
Dive Wilson
null
null
2
2
Spider-Boy
Spider-Boy
Pedro Parqueador
Pedro Parqueador
null
null
3
3
Rusty-Man
Rusty-Man
Tommy Sharp
Tommy Sharp
48
48
4
4
Tarantula
Tarantula
Natalia Roman-on
Natalia Roman-on
32
32
5
5
Black Lion
Black Lion
Trevor Challa
Trevor Challa
35
35
6
6
Dr. Weird
Dr. Weird
Steve Weird
Steve Weird
36
36
7
7
Captain North America
Captain North America
Esteban Rogelios
Esteban Rogelios
93
93
Viewer does not support full SVG 1.1 \ No newline at end of file +
hero
hero
id
id
name
name
secret_name
secret_name
age
age
1
1
Deadpond
Deadpond
Dive Wilson
Dive Wilson
null
null
2
2
Spider-Boy
Spider-Boy
Pedro Parqueador
Pedro Parqueador
null
null
3
3
Rusty-Man
Rusty-Man
Tommy Sharp
Tommy Sharp
48
48
4
4
Tarantula
Tarantula
Natalia Roman-on
Natalia Roman-on
32
32
5
5
Black Lion
Black Lion
Trevor Challa
Trevor Challa
35
35
6
6
Dr. Weird
Dr. Weird
Steve Weird
Steve Weird
36
36
7
7
Captain North America
Captain North America
Esteban Rogelios
Esteban Rogelios
93
93
Viewer does not support full SVG 1.1 diff --git a/docs/img/tutorial/offset-and-limit/limit3.drawio b/docs/img/tutorial/offset-and-limit/limit3.drawio index 2b2b20d..93e4c2d 100644 --- a/docs/img/tutorial/offset-and-limit/limit3.drawio +++ b/docs/img/tutorial/offset-and-limit/limit3.drawio @@ -130,4 +130,4 @@ - \ No newline at end of file + diff --git a/docs/img/tutorial/offset-and-limit/limit3.svg b/docs/img/tutorial/offset-and-limit/limit3.svg index 5858359..8a1a560 100644 --- a/docs/img/tutorial/offset-and-limit/limit3.svg +++ b/docs/img/tutorial/offset-and-limit/limit3.svg @@ -54,4 +54,4 @@ src: url("https://fonts.gstatic.com/s/roboto/v27/KFOmCnqEu92Fr1Mu4mxK.woff2") format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } -
hero
hero
id
id
name
name
secret_name
secret_name
age
age
1
1
Deadpond
Deadpond
Dive Wilson
Dive Wilson
null
null
2
2
Spider-Boy
Spider-Boy
Pedro Parqueador
Pedro Parqueador
null
null
3
3
Rusty-Man
Rusty-Man
Tommy Sharp
Tommy Sharp
48
48
4
4
Tarantula
Tarantula
Natalia Roman-on
Natalia Roman-on
32
32
5
5
Black Lion
Black Lion
Trevor Challa
Trevor Challa
35
35
6
6
Dr. Weird
Dr. Weird
Steve Weird
Steve Weird
36
36
7
7
Captain North America
Captain North America
Esteban Rogelios
Esteban Rogelios
93
93
Viewer does not support full SVG 1.1 \ No newline at end of file +
hero
hero
id
id
name
name
secret_name
secret_name
age
age
1
1
Deadpond
Deadpond
Dive Wilson
Dive Wilson
null
null
2
2
Spider-Boy
Spider-Boy
Pedro Parqueador
Pedro Parqueador
null
null
3
3
Rusty-Man
Rusty-Man
Tommy Sharp
Tommy Sharp
48
48
4
4
Tarantula
Tarantula
Natalia Roman-on
Natalia Roman-on
32
32
5
5
Black Lion
Black Lion
Trevor Challa
Trevor Challa
35
35
6
6
Dr. Weird
Dr. Weird
Steve Weird
Steve Weird
36
36
7
7
Captain North America
Captain North America
Esteban Rogelios
Esteban Rogelios
93
93
Viewer does not support full SVG 1.1 diff --git a/docs/img/tutorial/relationships/attributes/back-populates.drawio b/docs/img/tutorial/relationships/attributes/back-populates.drawio index 5ef9c03..5fc8c6f 100644 --- a/docs/img/tutorial/relationships/attributes/back-populates.drawio +++ b/docs/img/tutorial/relationships/attributes/back-populates.drawio @@ -38,4 +38,4 @@ - \ No newline at end of file + diff --git a/docs/img/tutorial/relationships/attributes/back-populates.svg b/docs/img/tutorial/relationships/attributes/back-populates.svg index dabf36d..631f73c 100644 --- a/docs/img/tutorial/relationships/attributes/back-populates.svg +++ b/docs/img/tutorial/relationships/attributes/back-populates.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/docs/img/tutorial/relationships/attributes/back-populates2.drawio b/docs/img/tutorial/relationships/attributes/back-populates2.drawio index 7313c46..c5d283f 100644 --- a/docs/img/tutorial/relationships/attributes/back-populates2.drawio +++ b/docs/img/tutorial/relationships/attributes/back-populates2.drawio @@ -49,4 +49,4 @@ - \ No newline at end of file + diff --git a/docs/img/tutorial/relationships/attributes/back-populates2.svg b/docs/img/tutorial/relationships/attributes/back-populates2.svg index 83ed815..929cb0a 100644 --- a/docs/img/tutorial/relationships/attributes/back-populates2.svg +++ b/docs/img/tutorial/relationships/attributes/back-populates2.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/docs/img/tutorial/relationships/select/relationships2.drawio b/docs/img/tutorial/relationships/select/relationships2.drawio index 0086af5..afd77f4 100644 --- a/docs/img/tutorial/relationships/select/relationships2.drawio +++ b/docs/img/tutorial/relationships/select/relationships2.drawio @@ -139,4 +139,4 @@ - \ No newline at end of file + diff --git a/docs/img/tutorial/relationships/select/relationships2.svg b/docs/img/tutorial/relationships/select/relationships2.svg index e2f987e..c0987c7 100644 --- a/docs/img/tutorial/relationships/select/relationships2.svg +++ b/docs/img/tutorial/relationships/select/relationships2.svg @@ -54,4 +54,4 @@ src: url("https://fonts.gstatic.com/s/roboto/v27/KFOmCnqEu92Fr1Mu4mxK.woff2") format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } -
hero
hero
id
id
name
name
secret_name
secret_name
age
age
team_id
team_id
1
1
Deadpond
Deadpond
Dive Wilson
Dive Wilson
null
null
2
2
2
2
Spider-Boy
Spider-Boy
Pedro Parqueador
Pedro Parqueador
null
null
null
null
3
3
Rusty-Man
Rusty-Man
Tommy Sharp
Tommy Sharp
48
48
1
1
team
team
id
id
name
name
headquarters
headquarters
1
1
Preventers
Preventers
Sharp Tower
Sharp Tower
2
2
Z-Force
Z-Force

Sister Margaret’s Bar

Sister Margaret’s Bar
Viewer does not support full SVG 1.1 \ No newline at end of file +
hero
hero
id
id
name
name
secret_name
secret_name
age
age
team_id
team_id
1
1
Deadpond
Deadpond
Dive Wilson
Dive Wilson
null
null
2
2
2
2
Spider-Boy
Spider-Boy
Pedro Parqueador
Pedro Parqueador
null
null
null
null
3
3
Rusty-Man
Rusty-Man
Tommy Sharp
Tommy Sharp
48
48
1
1
team
team
id
id
name
name
headquarters
headquarters
1
1
Preventers
Preventers
Sharp Tower
Sharp Tower
2
2
Z-Force
Z-Force

Sister Margaret’s Bar

Sister Margaret’s Bar
Viewer does not support full SVG 1.1 diff --git a/docs/js/termynal.js b/docs/js/termynal.js index c21e437..45bb371 100644 --- a/docs/js/termynal.js +++ b/docs/js/termynal.js @@ -72,14 +72,14 @@ class Termynal { * Initialise the widget, get lines, clear container and start animation. */ init() { - /** + /** * Calculates width and height of Termynal container. * If container is empty and lines are dynamically loaded, defaults to browser `auto` or CSS. - */ + */ const containerStyle = getComputedStyle(this.container); - this.container.style.width = containerStyle.width !== '0px' ? + this.container.style.width = containerStyle.width !== '0px' ? containerStyle.width : undefined; - this.container.style.minHeight = containerStyle.height !== '0px' ? + this.container.style.minHeight = containerStyle.height !== '0px' ? containerStyle.height : undefined; this.container.setAttribute('data-termynal', ''); @@ -138,7 +138,7 @@ class Termynal { restart.innerHTML = "restart ↻" return restart } - + generateFinish() { const finish = document.createElement('a') finish.onclick = (e) => { @@ -215,7 +215,7 @@ class Termynal { /** * Converts line data objects into line elements. - * + * * @param {Object[]} lineData - Dynamically loaded lines. * @param {Object} line - Line data object. * @returns {Element[]} - Array of line elements. @@ -231,7 +231,7 @@ class Termynal { /** * Helper function for generating attributes string. - * + * * @param {Object} line - Line data object. * @returns {string} - String of attributes. */ diff --git a/docs/overrides/main.html b/docs/overrides/main.html index fc5bce8..7440b08 100644 --- a/docs/overrides/main.html +++ b/docs/overrides/main.html @@ -12,9 +12,9 @@ }); }); - -{%- endblock %} \ No newline at end of file +{%- endblock %} diff --git a/docs/tutorial/automatic-id-none-refresh.md b/docs/tutorial/automatic-id-none-refresh.md index d41cd14..c7cf975 100644 --- a/docs/tutorial/automatic-id-none-refresh.md +++ b/docs/tutorial/automatic-id-none-refresh.md @@ -198,9 +198,9 @@ INFO Engine COMMIT // And now our prints After committing the session -Hero 1: -Hero 2: -Hero 3: +Hero 1: +Hero 2: +Hero 3: // What is happening here? 😱 ``` @@ -275,17 +275,17 @@ $ python app.py // After committing, the objects are expired and have no values After committing the session -Hero 1: -Hero 2: -Hero 3: +Hero 1: +Hero 2: +Hero 3: // Now we will access an attribute like the ID, this is the first print After committing the session, show IDs // Notice that before printing the first ID, the Session makes the Engine go to the database to refresh the data πŸ€“ INFO Engine BEGIN (implicit) -INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age -FROM hero +INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age +FROM hero WHERE hero.id = ? INFO Engine [generated in 0.00017s] (1,) @@ -293,8 +293,8 @@ INFO Engine [generated in 0.00017s] (1,) Hero 1 ID: 1 // Before the next print, refresh the data for the second object -INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age -FROM hero +INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age +FROM hero WHERE hero.id = ? INFO Engine [cached since 0.001245s ago] (2,) @@ -302,8 +302,8 @@ INFO Engine [cached since 0.001245s ago] (2,) Hero 2 ID: 2 // Before the third print, refresh its data -INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age -FROM hero +INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age +FROM hero WHERE hero.id = ? INFO Engine [cached since 0.002215s ago] (3,) @@ -365,20 +365,20 @@ $ python app.py // Output above omitted πŸ‘† // The first refresh -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.id = ? INFO Engine [generated in 0.00024s] (1,) // The second refresh -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.id = ? INFO Engine [cached since 0.001487s ago] (2,) // The third refresh -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.id = ? INFO Engine [cached since 0.002377s ago] (3,) @@ -468,12 +468,12 @@ INFO Engine PRAGMA main.table_info("hero") INFO Engine [raw sql] () INFO Engine PRAGMA temp.table_info("hero") INFO Engine [raw sql] () -INFO Engine +INFO Engine CREATE TABLE hero ( - id INTEGER, - name VARCHAR NOT NULL, - secret_name VARCHAR NOT NULL, - age INTEGER, + id INTEGER, + name VARCHAR NOT NULL, + secret_name VARCHAR NOT NULL, + age INTEGER, PRIMARY KEY (id) ) @@ -497,23 +497,23 @@ INFO Engine INSERT INTO hero (name, secret_name, age) VALUES (?, ?, ?) INFO Engine [cached since 0.001483s ago] ('Rusty-Man', 'Tommy Sharp', 48) INFO Engine COMMIT After committing the session -Hero 1: -Hero 2: -Hero 3: +Hero 1: +Hero 2: +Hero 3: After committing the session, show IDs INFO Engine BEGIN (implicit) -INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age -FROM hero +INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age +FROM hero WHERE hero.id = ? INFO Engine [generated in 0.00029s] (1,) Hero 1 ID: 1 -INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age -FROM hero +INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age +FROM hero WHERE hero.id = ? INFO Engine [cached since 0.002132s ago] (2,) Hero 2 ID: 2 -INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age -FROM hero +INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age +FROM hero WHERE hero.id = ? INFO Engine [cached since 0.003367s ago] (3,) Hero 3 ID: 3 @@ -521,16 +521,16 @@ After committing the session, show names Hero 1 name: Deadpond Hero 2 name: Spider-Boy Hero 3 name: Rusty-Man -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.id = ? INFO Engine [generated in 0.00025s] (1,) -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.id = ? INFO Engine [cached since 0.001583s ago] (2,) -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.id = ? INFO Engine [cached since 0.002722s ago] (3,) After refreshing the heroes diff --git a/docs/tutorial/connect/create-connected-rows.md b/docs/tutorial/connect/create-connected-rows.md index 657edbd..beda24a 100644 --- a/docs/tutorial/connect/create-connected-rows.md +++ b/docs/tutorial/connect/create-connected-rows.md @@ -159,7 +159,7 @@ As the `Hero` class model now has a field (column, attribute) `team_id`, we can We haven't committed this hero to the database yet, but there are already a couple of things to pay **attention** to. -If the database already had some teams, we wouldn't even know **what is the ID** that is going to be automatically assigned to each team by the database, for example, we couldn't just guess `1` or `2`. +If the database already had some teams, we wouldn't even know **what is the ID** that is going to be automatically assigned to each team by the database, for example, we couldn't just guess `1` or `2`. But once the team is created and committed to the database, we can access the object's `id` field to get that ID. @@ -171,8 +171,8 @@ That line alone would generate an output of: ``` INFO Engine BEGIN (implicit) -INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters -FROM team +INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters +FROM team WHERE team.id = ? INFO Engine [generated in 0.00025s] (2,) ``` @@ -199,8 +199,8 @@ Let's now create two more heroes: When creating `hero_rusty_man`, we are accessing `team_preventers.id`, so that will also trigger a refresh of its data, generating an output of: ``` -INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters -FROM team +INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters +FROM team WHERE team.id = ? INFO Engine [cached since 0.001795s ago] (1,) ``` @@ -256,18 +256,18 @@ $ python app.py INFO Engine BEGIN (implicit) // Refresh the first hero -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id +FROM hero WHERE hero.id = ? INFO Engine [generated in 0.00021s] (1,) // Refresh the second hero -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id +FROM hero WHERE hero.id = ? INFO Engine [cached since 0.001575s ago] (2,) // Refresh the third hero -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id +FROM hero WHERE hero.id = ? INFO Engine [cached since 0.002518s ago] (3,) diff --git a/docs/tutorial/connect/create-connected-tables.md b/docs/tutorial/connect/create-connected-tables.md index 14a310f..5a9a420 100644 --- a/docs/tutorial/connect/create-connected-tables.md +++ b/docs/tutorial/connect/create-connected-tables.md @@ -191,24 +191,24 @@ INFO Engine PRAGMA temp.table_info("hero") INFO Engine [raw sql] () // Create the tables -INFO Engine +INFO Engine CREATE TABLE team ( - id INTEGER, - name VARCHAR NOT NULL, - headquarters VARCHAR NOT NULL, + id INTEGER, + name VARCHAR NOT NULL, + headquarters VARCHAR NOT NULL, PRIMARY KEY (id) ) INFO Engine [no key 0.00010s] () -INFO Engine +INFO Engine CREATE TABLE hero ( - id INTEGER, - name VARCHAR NOT NULL, - secret_name VARCHAR NOT NULL, - age INTEGER, - team_id INTEGER, - PRIMARY KEY (id), + id INTEGER, + name VARCHAR NOT NULL, + secret_name VARCHAR NOT NULL, + age INTEGER, + team_id INTEGER, + PRIMARY KEY (id), FOREIGN KEY(team_id) REFERENCES team (id) ) @@ -229,9 +229,9 @@ So, the first SQL could also be written as: ```SQL CREATE TABLE team ( - id INTEGER, - name TEXT NOT NULL, - headquarters TEXT NOT NULL, + id INTEGER, + name TEXT NOT NULL, + headquarters TEXT NOT NULL, PRIMARY KEY (id) ) ``` @@ -240,12 +240,12 @@ And the second table could be written as: ```SQL hl_lines="8" CREATE TABLE hero ( - id INTEGER, - name TEXT NOT NULL, - secret_name TEXT NOT NULL, - age INTEGER, - team_id INTEGER, - PRIMARY KEY (id), + id INTEGER, + name TEXT NOT NULL, + secret_name TEXT NOT NULL, + age INTEGER, + team_id INTEGER, + PRIMARY KEY (id), FOREIGN KEY(team_id) REFERENCES team (id) ) ``` diff --git a/docs/tutorial/connect/read-connected-data.md b/docs/tutorial/connect/read-connected-data.md index 88cd754..0ef3bcc 100644 --- a/docs/tutorial/connect/read-connected-data.md +++ b/docs/tutorial/connect/read-connected-data.md @@ -203,8 +203,8 @@ $ python app.py // Previous output omitted πŸ˜‰ // Get the heroes with their teams -2021-08-09 08:55:50,682 INFO sqlalchemy.engine.Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id, team.id AS id_1, team.name AS name_1, team.headquarters -FROM hero, team +2021-08-09 08:55:50,682 INFO sqlalchemy.engine.Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id, team.id AS id_1, team.name AS name_1, team.headquarters +FROM hero, team WHERE hero.team_id = team.id 2021-08-09 08:55:50,682 INFO sqlalchemy.engine.Engine [no key 0.00015s] () @@ -323,7 +323,7 @@ $ python app.py // Previous output omitted πŸ˜‰ // Select using a JOIN with automatic ON -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id, team.id AS id_1, team.name AS name_1, team.headquarters +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id, team.id AS id_1, team.name AS name_1, team.headquarters FROM hero JOIN team ON team.id = hero.team_id INFO Engine [no key 0.00032s] () @@ -458,7 +458,7 @@ $ python app.py // Previous output omitted πŸ˜‰ // SELECT using LEFT OUTER JOIN -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id, team.id AS id_1, team.name AS name_1, team.headquarters +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id, team.id AS id_1, team.name AS name_1, team.headquarters FROM hero LEFT OUTER JOIN team ON team.id = hero.team_id INFO Engine [no key 0.00051s] () @@ -522,9 +522,9 @@ If we run that, it would output: $ python app.py // Select only the hero data -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id // But still join with the team table -FROM hero JOIN team ON team.id = hero.team_id +FROM hero JOIN team ON team.id = hero.team_id // And filter with WHERE to get only the Preventers WHERE team.name = ? INFO Engine [no key 0.00066s] ('Preventers',) @@ -564,9 +564,9 @@ And if we run that, it will output: $ python app.py // Select the hero and the team data -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id, team.id AS id_1, team.name AS name_1, team.headquarters +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id, team.id AS id_1, team.name AS name_1, team.headquarters // Join the hero with the team table -FROM hero JOIN team ON team.id = hero.team_id +FROM hero JOIN team ON team.id = hero.team_id // Filter with WHERE to get only Preventers WHERE team.name = ? INFO Engine [no key 0.00018s] ('Preventers',) diff --git a/docs/tutorial/connect/remove-data-connections.md b/docs/tutorial/connect/remove-data-connections.md index f44559b..940a09f 100644 --- a/docs/tutorial/connect/remove-data-connections.md +++ b/docs/tutorial/connect/remove-data-connections.md @@ -56,7 +56,7 @@ We can simply set the `team_id` to `None`, and now it doesn't have a connection # Code above omitted πŸ‘† {!./docs_src/tutorial/connect/delete/tutorial001.py[ln:31-32]!} - + # Previous code here omitted πŸ‘ˆ {!./docs_src/tutorial/connect/delete/tutorial001.py[ln:68-72]!} @@ -94,8 +94,8 @@ INFO Engine COMMIT // Automatically start a new transaction INFO Engine BEGIN (implicit) // Refresh the hero -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id +FROM hero WHERE hero.id = ? INFO Engine [cached since 0.1661s ago] (3,) diff --git a/docs/tutorial/connect/update-data-connections.md b/docs/tutorial/connect/update-data-connections.md index b7c8b0d..ccc430d 100644 --- a/docs/tutorial/connect/update-data-connections.md +++ b/docs/tutorial/connect/update-data-connections.md @@ -56,7 +56,7 @@ Doing it is just like updating any other field: # Code above omitted πŸ‘† {!./docs_src/tutorial/connect/update/tutorial001.py[ln:31-32]!} - + # Previous code here omitted πŸ‘ˆ {!./docs_src/tutorial/connect/update/tutorial001.py[ln:62-66]!} @@ -94,8 +94,8 @@ INFO Engine COMMIT // Automatically start a new transaction INFO Engine BEGIN (implicit) // Refresh the hero data -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id +FROM hero WHERE hero.id = ? INFO Engine [cached since 0.08837s ago] (3,) diff --git a/docs/tutorial/create-db-and-table.md b/docs/tutorial/create-db-and-table.md index abd73cb..52a12fa 100644 --- a/docs/tutorial/create-db-and-table.md +++ b/docs/tutorial/create-db-and-table.md @@ -422,15 +422,15 @@ INFO Engine PRAGMA main.table_info("hero") INFO Engine [raw sql] () INFO Engine PRAGMA temp.table_info("hero") INFO Engine [raw sql] () -INFO Engine +INFO Engine // Finally, the glorious SQL to create the table ✨ CREATE TABLE hero ( - id INTEGER, - name VARCHAR NOT NULL, - secret_name VARCHAR NOT NULL, - age INTEGER, + id INTEGER, + name VARCHAR NOT NULL, + secret_name VARCHAR NOT NULL, + age INTEGER, PRIMARY KEY (id) ) diff --git a/docs/tutorial/delete.md b/docs/tutorial/delete.md index 0c9238d..590b2ec 100644 --- a/docs/tutorial/delete.md +++ b/docs/tutorial/delete.md @@ -108,8 +108,8 @@ $ python app.py // The SELECT with WHERE INFO Engine BEGIN (implicit) -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.name = ? INFO Engine [no key 0.00011s] ('Spider-Youngster',) @@ -272,8 +272,8 @@ $ python app.py INFO Engine BEGIN (implicit) // SQL to search for the hero -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.name = ? INFO Engine [no key 0.00013s] ('Spider-Youngster',) ``` diff --git a/docs/tutorial/index.md b/docs/tutorial/index.md index e859414..7410777 100644 --- a/docs/tutorial/index.md +++ b/docs/tutorial/index.md @@ -132,7 +132,7 @@ Here are the commands you could use:
```console - // Remember that you might need to use python3.9 or similar πŸ’‘ + // Remember that you might need to use python3.9 or similar πŸ’‘ // Create the virtual environment using the module "venv" $ python3 -m venv env // ...here it creates the virtual environment in the directory "env" diff --git a/docs/tutorial/indexes.md b/docs/tutorial/indexes.md index 6513d7d..fef0081 100644 --- a/docs/tutorial/indexes.md +++ b/docs/tutorial/indexes.md @@ -342,10 +342,10 @@ $ python app.py // Create the table CREATE TABLE hero ( - id INTEGER, - name VARCHAR NOT NULL, - secret_name VARCHAR NOT NULL, - age INTEGER, + id INTEGER, + name VARCHAR NOT NULL, + secret_name VARCHAR NOT NULL, + age INTEGER, PRIMARY KEY (id) ) @@ -353,8 +353,8 @@ CREATE TABLE hero ( CREATE INDEX ix_hero_name ON hero (name) // The SELECT with WHERE looks the same -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.name = ? INFO Engine [no key 0.00014s] ('Deadpond',) diff --git a/docs/tutorial/limit-and-offset.md b/docs/tutorial/limit-and-offset.md index 3fb001c..dc4c280 100644 --- a/docs/tutorial/limit-and-offset.md +++ b/docs/tutorial/limit-and-offset.md @@ -93,7 +93,7 @@ $ python app.py // Previous output omitted πŸ™ˆ // Select with LIMIT -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age FROM hero LIMIT ? OFFSET ? INFO Engine [no key 0.00014s] (3, 0) @@ -165,7 +165,7 @@ $python app.py // Previous output omitted πŸ™ˆ // Select with LIMIT and OFFSET -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age FROM hero LIMIT ? OFFSET ? INFO Engine [no key 0.00020s] (3, 3) @@ -221,7 +221,7 @@ $ python app.py // Previous output omitted πŸ™ˆ // Select last batch with LIMIT and OFFSET -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age FROM hero LIMIT ? OFFSET ? INFO Engine [no key 0.00038s] (3, 6) @@ -241,7 +241,7 @@ You probably noticed the new SQL keywords `LIMIT` and `OFFSET`. You can use them in SQL, at the end of the other parts: ```SQL -SELECT id, name, secret_name, age +SELECT id, name, secret_name, age FROM hero LIMIT 3 OFFSET 6 ``` @@ -285,8 +285,8 @@ $ python app.py // Previous output omitted πŸ™ˆ // Select with WHERE and LIMIT -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.age > ? LIMIT ? OFFSET ? INFO Engine [no key 0.00022s] (32, 3, 0) diff --git a/docs/tutorial/many-to-many/create-data.md b/docs/tutorial/many-to-many/create-data.md index 2a51f5a..971659b 100644 --- a/docs/tutorial/many-to-many/create-data.md +++ b/docs/tutorial/many-to-many/create-data.md @@ -122,16 +122,16 @@ INFO Engine COMMIT // Automatically start a new transaction INFO Engine BEGIN (implicit) // Refresh the data -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.id = ? INFO Engine [generated in 0.00019s] (1,) -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.id = ? INFO Engine [cached since 0.001959s ago] (2,) -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.id = ? INFO Engine [cached since 0.003215s ago] (3,) @@ -139,8 +139,8 @@ INFO Engine [cached since 0.003215s ago] (3,) Deadpond: name='Deadpond' age=None id=1 secret_name='Dive Wilson' // Accessing the .team attribute triggers a refresh -INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters -FROM team, heroteamlink +INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters +FROM team, heroteamlink WHERE ? = heroteamlink.hero_id AND team.id = heroteamlink.team_id INFO Engine [generated in 0.00025s] (1,) @@ -151,8 +151,8 @@ Deadpond teams: [Team(id=1, name='Z-Force', headquarters='Sister Margaret’s Ba Rusty-Man: name='Rusty-Man' age=48 id=2 secret_name='Tommy Sharp' // Accessing the .team attribute triggers a refresh -INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters -FROM team, heroteamlink +INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters +FROM team, heroteamlink WHERE ? = heroteamlink.hero_id AND team.id = heroteamlink.team_id INFO Engine [cached since 0.001716s ago] (2,) @@ -163,8 +163,8 @@ Rusty-Man Teams: [Team(id=2, name='Preventers', headquarters='Sharp Tower')] Spider-Boy: name='Spider-Boy' age=None id=3 secret_name='Pedro Parqueador' // Accessing the .team attribute triggers a refresh -INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters -FROM team, heroteamlink +INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters +FROM team, heroteamlink WHERE ? = heroteamlink.hero_id AND team.id = heroteamlink.team_id INFO Engine [cached since 0.002739s ago] (3,) diff --git a/docs/tutorial/many-to-many/create-models-with-link.md b/docs/tutorial/many-to-many/create-models-with-link.md index bc4481f..63cbf3e 100644 --- a/docs/tutorial/many-to-many/create-models-with-link.md +++ b/docs/tutorial/many-to-many/create-models-with-link.md @@ -151,35 +151,35 @@ $ python app.py // Boilerplate omitted πŸ˜‰ -INFO Engine +INFO Engine CREATE TABLE team ( - id INTEGER, - name VARCHAR NOT NULL, - headquarters VARCHAR NOT NULL, + id INTEGER, + name VARCHAR NOT NULL, + headquarters VARCHAR NOT NULL, PRIMARY KEY (id) ) INFO Engine [no key 0.00033s] () -INFO Engine +INFO Engine CREATE TABLE hero ( - id INTEGER, - name VARCHAR NOT NULL, - secret_name VARCHAR NOT NULL, - age INTEGER, + id INTEGER, + name VARCHAR NOT NULL, + secret_name VARCHAR NOT NULL, + age INTEGER, PRIMARY KEY (id) ) INFO Engine [no key 0.00016s] () -INFO Engine +INFO Engine // Our shinny new link table ✨ CREATE TABLE heroteamlink ( - team_id INTEGER, - hero_id INTEGER, - PRIMARY KEY (team_id, hero_id), - FOREIGN KEY(team_id) REFERENCES team (id), + team_id INTEGER, + hero_id INTEGER, + PRIMARY KEY (team_id, hero_id), + FOREIGN KEY(team_id) REFERENCES team (id), FOREIGN KEY(hero_id) REFERENCES hero (id) ) diff --git a/docs/tutorial/many-to-many/link-with-extra-fields.md b/docs/tutorial/many-to-many/link-with-extra-fields.md index 9c3309d..c998175 100644 --- a/docs/tutorial/many-to-many/link-with-extra-fields.md +++ b/docs/tutorial/many-to-many/link-with-extra-fields.md @@ -165,16 +165,16 @@ INFO Engine COMMIT INFO Engine BEGIN (implicit) // Automatically fetch the data on attribute access -INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters -FROM team +INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters +FROM team WHERE team.id = ? INFO Engine [generated in 0.00028s] (1,) -INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training -FROM heroteamlink +INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training +FROM heroteamlink WHERE ? = heroteamlink.team_id INFO Engine [generated in 0.00026s] (1,) -INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age -FROM hero +INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age +FROM hero WHERE hero.id = ? INFO Engine [generated in 0.00024s] (1,) @@ -182,12 +182,12 @@ INFO Engine [generated in 0.00024s] (1,) Z-Force hero: name='Deadpond' age=None id=1 secret_name='Dive Wilson' is training: False // Automatically fetch the data on attribute access -INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters -FROM team +INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters +FROM team WHERE team.id = ? INFO Engine [cached since 0.008822s ago] (2,) -INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training -FROM heroteamlink +INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training +FROM heroteamlink WHERE ? = heroteamlink.team_id INFO Engine [cached since 0.005778s ago] (2,) @@ -195,8 +195,8 @@ INFO Engine [cached since 0.005778s ago] (2,) Preventers hero: name='Deadpond' age=None id=1 secret_name='Dive Wilson' is training: True // Automatically fetch the data on attribute access -INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age -FROM hero +INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age +FROM hero WHERE hero.id = ? INFO Engine [cached since 0.004196s ago] (2,) @@ -204,8 +204,8 @@ INFO Engine [cached since 0.004196s ago] (2,) Preventers hero: name='Spider-Boy' age=None id=2 secret_name='Pedro Parqueador' is training: True // Automatically fetch the data on attribute access -INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age -FROM hero +INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age +FROM hero WHERE hero.id = ? INFO Engine [cached since 0.006005s ago] (3,) @@ -253,14 +253,14 @@ $ python app.py INFO Engine BEGIN (implicit) // Select the hero -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.name = ? INFO Engine [no key 0.00014s] ('Spider-Boy',) // Select the team -INFO Engine SELECT team.id, team.name, team.headquarters -FROM team +INFO Engine SELECT team.id, team.name, team.headquarters +FROM team WHERE team.name = ? INFO Engine [no key 0.00012s] ('Z-Force',) @@ -269,18 +269,18 @@ INFO Engine INSERT INTO heroteamlink (team_id, hero_id, is_training) VALUES (?, INFO Engine [generated in 0.00023s] (1, 2, 1) // Automatically refresh the data on attribute access -INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training -FROM heroteamlink +INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training +FROM heroteamlink WHERE ? = heroteamlink.team_id INFO Engine [cached since 0.01514s ago] (1,) INFO Engine COMMIT INFO Engine BEGIN (implicit) -INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age -FROM hero +INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age +FROM hero WHERE hero.id = ? INFO Engine [cached since 0.08953s ago] (2,) -INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training -FROM heroteamlink +INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training +FROM heroteamlink WHERE ? = heroteamlink.hero_id INFO Engine [generated in 0.00018s] (2,) @@ -291,18 +291,18 @@ Updated Spider-Boy's Teams: [ ] // Automatically refresh team data on attribute access -INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters -FROM team +INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters +FROM team WHERE team.id = ? INFO Engine [cached since 0.1084s ago] (1,) -INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training -FROM heroteamlink +INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training +FROM heroteamlink WHERE ? = heroteamlink.team_id INFO Engine [cached since 0.1054s ago] (1,) // Print team hero links Z-Force heroes: [ - HeroTeamLink(team_id=1, is_training=False, hero_id=1), + HeroTeamLink(team_id=1, is_training=False, hero_id=1), HeroTeamLink(team_id=1, is_training=True, hero_id=2) ] ``` @@ -350,8 +350,8 @@ $ python app.py // Previous output omitted πŸ™ˆ // Automatically fetch team data on attribute access -INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters -FROM team +INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters +FROM team WHERE team.id = ? INFO Engine [generated in 0.00015s] (2,) @@ -366,16 +366,16 @@ INFO Engine COMMIT INFO Engine BEGIN (implicit) // Automatically fetch data on attribute access -INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age -FROM hero +INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age +FROM hero WHERE hero.id = ? INFO Engine [cached since 0.2004s ago] (2,) -INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training -FROM heroteamlink +INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training +FROM heroteamlink WHERE ? = heroteamlink.hero_id INFO Engine [cached since 0.1005s ago] (2,) -INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters -FROM team +INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters +FROM team WHERE team.id = ? INFO Engine [cached since 0.09707s ago] (2,) @@ -383,8 +383,8 @@ INFO Engine [cached since 0.09707s ago] (2,) Spider-Boy team: headquarters='Sharp Tower' id=2 name='Preventers' is training: False // Automatically fetch data on attribute access -INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters -FROM team +INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters +FROM team WHERE team.id = ? INFO Engine [cached since 0.2097s ago] (1,) diff --git a/docs/tutorial/many-to-many/update-remove-relationships.md b/docs/tutorial/many-to-many/update-remove-relationships.md index 5cc55e1..91f2f2c 100644 --- a/docs/tutorial/many-to-many/update-remove-relationships.md +++ b/docs/tutorial/many-to-many/update-remove-relationships.md @@ -115,12 +115,12 @@ INFO Engine COMMIT INFO Engine BEGIN (implicit) // Automatically refresh the data while accessing the attribute .teams -INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age -FROM hero +INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age +FROM hero WHERE hero.id = ? INFO Engine [generated in 0.00044s] (3,) -INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters -FROM team, heroteamlink +INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters +FROM team, heroteamlink WHERE ? = heroteamlink.hero_id AND team.id = heroteamlink.team_id INFO Engine [cached since 0.1648s ago] (3,) @@ -131,8 +131,8 @@ Updated Spider-Boy's Teams: [ ] // Automatically refresh the data while accessing the attribute .heores -INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age -FROM hero, heroteamlink +INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age +FROM hero, heroteamlink WHERE ? = heroteamlink.team_id AND hero.id = heroteamlink.hero_id INFO Engine [cached since 0.1499s ago] (1,) @@ -208,12 +208,12 @@ INFO Engine COMMIT INFO Engine BEGIN (implicit) // Automatically refresh the data while accessing the attribute .heroes -INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters -FROM team +INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters +FROM team WHERE team.id = ? INFO Engine [generated in 0.00029s] (1,) -INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age -FROM hero, heroteamlink +INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age +FROM hero, heroteamlink WHERE ? = heroteamlink.team_id AND hero.id = heroteamlink.hero_id INFO Engine [cached since 0.5625s ago] (1,) @@ -223,12 +223,12 @@ Reverted Z-Force's heroes: [ ] // Automatically refresh the data while accessing the attribute .teams -INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age -FROM hero +INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age +FROM hero WHERE hero.id = ? INFO Engine [cached since 0.4209s ago] (3,) -INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters -FROM team, heroteamlink +INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters +FROM team, heroteamlink WHERE ? = heroteamlink.hero_id AND team.id = heroteamlink.team_id INFO Engine [cached since 0.5842s ago] (3,) diff --git a/docs/tutorial/one.md b/docs/tutorial/one.md index f06343f..eadfc62 100644 --- a/docs/tutorial/one.md +++ b/docs/tutorial/one.md @@ -86,8 +86,8 @@ $ python app.py // Some boilerplate output omitted πŸ˜‰ // The SELECT with WHERE -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.age <= ? INFO Engine [no key 0.00021s] (35,) @@ -132,8 +132,8 @@ $ python app.py // Some boilerplate output omitted πŸ˜‰ // The SELECT with WHERE -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.age <= ? INFO Engine [no key 0.00021s] (35,) @@ -180,8 +180,8 @@ $ python app.py // Some boilerplate output omitted πŸ˜‰ // The SELECT with WHERE -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.name = ? INFO Engine [no key 0.00015s] ('Deadpond',) @@ -203,8 +203,8 @@ $ python app.py // Some boilerplate output omitted πŸ˜‰ // The SELECT with WHERE -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.name = ? INFO Engine [no key 0.00015s] ('Deadpond',) @@ -274,8 +274,8 @@ $ python app.py // Some boilerplate output omitted πŸ˜‰ // SELECT with WHERE -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.age < ? INFO Engine [no key 0.00014s] (25,) @@ -370,8 +370,8 @@ $ python app.py // Some boilerplate output omitted πŸ˜‰ // SELECT with WHERE -INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age -FROM hero +INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age +FROM hero WHERE hero.id = ? INFO Engine [generated in 0.00021s] (1,) @@ -413,8 +413,8 @@ $ python app.py // SELECT with WHERE INFO Engine BEGIN (implicit) -INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age -FROM hero +INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age +FROM hero WHERE hero.id = ? INFO Engine [generated in 0.00024s] (9001,) diff --git a/docs/tutorial/relationship-attributes/back-populates.md b/docs/tutorial/relationship-attributes/back-populates.md index 27129a0..dbd3e8c 100644 --- a/docs/tutorial/relationship-attributes/back-populates.md +++ b/docs/tutorial/relationship-attributes/back-populates.md @@ -144,10 +144,10 @@ But now, what happens when we print the `preventers_team.heroes`? ``` hl_lines="3" Preventers Team Heroes again: [ - Hero(name='Rusty-Man', age=48, id=2, secret_name='Tommy Sharp', team_id=2), - Hero(name='Spider-Boy', age=None, id=3, secret_name='Pedro Parqueador', team_id=2, team=None), - Hero(name='Tarantula', age=32, id=6, secret_name='Natalia Roman-on', team_id=2), - Hero(name='Dr. Weird', age=36, id=7, secret_name='Steve Weird', team_id=2), + Hero(name='Rusty-Man', age=48, id=2, secret_name='Tommy Sharp', team_id=2), + Hero(name='Spider-Boy', age=None, id=3, secret_name='Pedro Parqueador', team_id=2, team=None), + Hero(name='Tarantula', age=32, id=6, secret_name='Natalia Roman-on', team_id=2), + Hero(name='Dr. Weird', age=36, id=7, secret_name='Steve Weird', team_id=2), Hero(name='Captain North America', age=93, id=8, secret_name='Esteban Rogelios', team_id=2) ] ``` @@ -182,15 +182,15 @@ Now, if we commit it and print again: When we access `preventers_team.heroes` after the `commit`, that triggers a refresh, so we get the latest list, without **Spider-Boy**, so that's fine again: ``` -INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age, hero.team_id AS hero_team_id -FROM hero +INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age, hero.team_id AS hero_team_id +FROM hero WHERE ? = hero.team_id 2021-08-13 11:15:24,658 INFO sqlalchemy.engine.Engine [cached since 0.1924s ago] (2,) Preventers Team Heroes after commit: [ - Hero(name='Rusty-Man', age=48, id=2, secret_name='Tommy Sharp', team_id=2), - Hero(name='Tarantula', age=32, id=6, secret_name='Natalia Roman-on', team_id=2), - Hero(name='Dr. Weird', age=36, id=7, secret_name='Steve Weird', team_id=2), + Hero(name='Rusty-Man', age=48, id=2, secret_name='Tommy Sharp', team_id=2), + Hero(name='Tarantula', age=32, id=6, secret_name='Natalia Roman-on', team_id=2), + Hero(name='Dr. Weird', age=36, id=7, secret_name='Steve Weird', team_id=2), Hero(name='Captain North America', age=93, id=8, secret_name='Esteban Rogelios', team_id=2) ] ``` @@ -260,9 +260,9 @@ That second print would output: ``` Preventers Team Heroes again: [ - Hero(name='Rusty-Man', age=48, id=2, secret_name='Tommy Sharp', team_id=2), - Hero(name='Tarantula', age=32, id=6, secret_name='Natalia Roman-on', team_id=2), - Hero(name='Dr. Weird', age=36, id=7, secret_name='Steve Weird', team_id=2), + Hero(name='Rusty-Man', age=48, id=2, secret_name='Tommy Sharp', team_id=2), + Hero(name='Tarantula', age=32, id=6, secret_name='Natalia Roman-on', team_id=2), + Hero(name='Dr. Weird', age=36, id=7, secret_name='Steve Weird', team_id=2), Hero(name='Captain North America', age=93, id=8, secret_name='Esteban Rogelios', team_id=2) ] ``` diff --git a/docs/tutorial/relationship-attributes/read-relationships.md b/docs/tutorial/relationship-attributes/read-relationships.md index c970b5e..78e4207 100644 --- a/docs/tutorial/relationship-attributes/read-relationships.md +++ b/docs/tutorial/relationship-attributes/read-relationships.md @@ -111,8 +111,8 @@ That would print a list with all the heroes in the Preventers team: $ python app.py // Automatically fetch the heroes -INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age, hero.team_id AS hero_team_id -FROM hero +INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age, hero.team_id AS hero_team_id +FROM hero WHERE ? = hero.team_id INFO Engine [cached since 0.8774s ago] (2,) diff --git a/docs/tutorial/select.md b/docs/tutorial/select.md index 5de32db..e2f9af4 100644 --- a/docs/tutorial/select.md +++ b/docs/tutorial/select.md @@ -274,7 +274,7 @@ This `session.exec(statement)` will generate this output: ``` INFO Engine BEGIN (implicit) -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age FROM hero INFO Engine [no key 0.00032s] () ``` @@ -455,7 +455,7 @@ In this chapter we are touching some of them. ### SQLModel's `select` -When importing from `sqlmodel` the `select()` function, you are using **SQLModel**'s version of `select`. +When importing from `sqlmodel` the `select()` function, you are using **SQLModel**'s version of `select`. SQLAchemy also has it's own `select`, and SQLModel's `select` uses SQLAlchemy's `select` internally. diff --git a/docs/tutorial/update.md b/docs/tutorial/update.md index b3099f5..56cc7ac 100644 --- a/docs/tutorial/update.md +++ b/docs/tutorial/update.md @@ -132,8 +132,8 @@ $ python app.py // Some boilerplate and previous output omitted πŸ˜‰ // The SELECT with WHERE -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.name = ? INFO Engine [no key 0.00017s] ('Spider-Boy',) @@ -275,8 +275,8 @@ $ python app.py // Previous output omitted πŸ™ˆ // The SQL to SELECT the fresh hero data -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.id = ? INFO Engine [generated in 0.00018s] (2,) ``` diff --git a/docs/tutorial/where.md b/docs/tutorial/where.md index 47f1b9b..a3bf6b0 100644 --- a/docs/tutorial/where.md +++ b/docs/tutorial/where.md @@ -490,8 +490,8 @@ $ python app.py // Now the important part, the SELECT with WHERE πŸ’‘ -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.name = ? INFO Engine [no key 0.00014s] ('Deadpond',) @@ -726,8 +726,8 @@ This will select the rows `WHERE` the `age` is **greater than or equal** to `35` The equivalent SQL would be: ```SQL hl_lines="3" -SELECT id, name, secret_name, age -FROM hero +SELECT id, name, secret_name, age +FROM hero WHERE age >= 35 AND age < 40 ``` @@ -743,8 +743,8 @@ $ python app.py // Some boilerplate output omitted πŸ˜‰ // The SELECT statement with WHERE, also using AND -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.age >= ? AND hero.age < ? INFO Engine [no key 0.00014s] (35, 40) @@ -838,8 +838,8 @@ $ python app.py // Some boilerplate output omitted πŸ˜‰ // The SELECT statement with WHERE, also using OR πŸ” -INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age -FROM hero +INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age +FROM hero WHERE hero.age <= ? OR hero.age > ? INFO Engine [no key 0.00021s] (35, 90) diff --git a/docs_src/tutorial/automatic_id_none_refresh/annotations/en/tutorial002.md b/docs_src/tutorial/automatic_id_none_refresh/annotations/en/tutorial002.md index 8306d9b..725fcb6 100644 --- a/docs_src/tutorial/automatic_id_none_refresh/annotations/en/tutorial002.md +++ b/docs_src/tutorial/automatic_id_none_refresh/annotations/en/tutorial002.md @@ -181,8 +181,8 @@ ``` INFO Engine BEGIN (implicit) - INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age - FROM hero + INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age + FROM hero WHERE hero.id = ? INFO Engine [generated in 0.00017s] (1,) @@ -196,8 +196,8 @@ Generates the output: ``` - INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age - FROM hero + INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age + FROM hero WHERE hero.id = ? INFO Engine [cached since 0.001245s ago] (2,) @@ -211,8 +211,8 @@ Generates the output: ``` - INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age - FROM hero + INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age + FROM hero WHERE hero.id = ? INFO Engine [cached since 0.002215s ago] (3,) @@ -265,8 +265,8 @@ Generates the output: ``` - INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age - FROM hero + INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age + FROM hero WHERE hero.id = ? INFO Engine [generated in 0.00024s] (1,) ``` @@ -278,8 +278,8 @@ Generates the output: ``` - INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age - FROM hero + INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age + FROM hero WHERE hero.id = ? INFO Engine [cached since 0.001487s ago] (2,) ``` @@ -291,8 +291,8 @@ Generates the output: ``` - INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age - FROM hero + INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age + FROM hero WHERE hero.id = ? INFO Engine [cached since 0.002377s ago] (3,) ``` diff --git a/docs_src/tutorial/delete/annotations/en/tutorial002.md b/docs_src/tutorial/delete/annotations/en/tutorial002.md index 130016d..28dcc50 100644 --- a/docs_src/tutorial/delete/annotations/en/tutorial002.md +++ b/docs_src/tutorial/delete/annotations/en/tutorial002.md @@ -6,8 +6,8 @@ ``` INFO Engine BEGIN (implicit) - INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age - FROM hero + INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age + FROM hero WHERE hero.name = ? INFO Engine [no key 0.00011s] ('Spider-Youngster',) ``` @@ -65,8 +65,8 @@ ``` INFO Engine BEGIN (implicit) - INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age - FROM hero + INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age + FROM hero WHERE hero.name = ? INFO Engine [no key 0.00013s] ('Spider-Youngster',) ``` diff --git a/docs_src/tutorial/select/annotations/en/tutorial002.md b/docs_src/tutorial/select/annotations/en/tutorial002.md index 2570b54..312bd81 100644 --- a/docs_src/tutorial/select/annotations/en/tutorial002.md +++ b/docs_src/tutorial/select/annotations/en/tutorial002.md @@ -35,7 +35,7 @@ ``` INFO Engine BEGIN (implicit) - INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age + INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age FROM hero INFO Engine [no key 0.00032s] () ``` diff --git a/docs_src/tutorial/update/annotations/en/tutorial002.md b/docs_src/tutorial/update/annotations/en/tutorial002.md index 3a52bd9..eb1a820 100644 --- a/docs_src/tutorial/update/annotations/en/tutorial002.md +++ b/docs_src/tutorial/update/annotations/en/tutorial002.md @@ -5,8 +5,8 @@ This generates the output: ``` - INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age - FROM hero + INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age + FROM hero WHERE hero.name = ? INFO Engine [no key 0.00017s] ('Spider-Boy',) ``` @@ -53,8 +53,8 @@ This generates the output: ``` - INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age - FROM hero + INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age + FROM hero WHERE hero.id = ? INFO Engine [generated in 0.00018s] (2,) ``` diff --git a/docs_src/tutorial/update/annotations/en/tutorial004.md b/docs_src/tutorial/update/annotations/en/tutorial004.md index 3fcf104..8378d1b 100644 --- a/docs_src/tutorial/update/annotations/en/tutorial004.md +++ b/docs_src/tutorial/update/annotations/en/tutorial004.md @@ -5,8 +5,8 @@ This generates the output: ``` - INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age - FROM hero + INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age + FROM hero WHERE hero.name = ? INFO Engine [no key 0.00018s] ('Spider-Boy',) ``` @@ -29,8 +29,8 @@ ``` INFO Engine BEGIN (implicit) - INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age - FROM hero + INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age + FROM hero WHERE hero.name = ? INFO Engine [no key 0.00020s] ('Captain North America',) ``` @@ -109,8 +109,8 @@ ``` INFO Engine BEGIN (implicit) - INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age - FROM hero + INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age + FROM hero WHERE hero.id = ? INFO Engine [generated in 0.00023s] (2,) ``` @@ -123,8 +123,8 @@ This generates the output: ``` - INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age - FROM hero + INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age + FROM hero WHERE hero.id = ? INFO Engine [cached since 0.001709s ago] (7,) ``` diff --git a/sqlmodel/sql/sqltypes.py b/sqlmodel/sql/sqltypes.py index 09b8239..17d9b06 100644 --- a/sqlmodel/sql/sqltypes.py +++ b/sqlmodel/sql/sqltypes.py @@ -8,7 +8,6 @@ from sqlalchemy.sql.type_api import TypeEngine class AutoString(types.TypeDecorator): # type: ignore - impl = types.String cache_ok = True mysql_default_length = 255 diff --git a/tests/test_tutorial/test_fastapi/test_delete/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_delete/test_tutorial001.py index e560d04..3a44512 100644 --- a/tests/test_tutorial/test_fastapi/test_delete/test_tutorial001.py +++ b/tests/test_tutorial/test_fastapi/test_delete/test_tutorial001.py @@ -261,7 +261,6 @@ def test_tutorial(clear_sqlmodel): ) with TestClient(mod.app) as client: - hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"} hero2_data = { "name": "Spider-Boy", diff --git a/tests/test_tutorial/test_fastapi/test_limit_and_offset/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_limit_and_offset/test_tutorial001.py index b58afdf..1a38f7a 100644 --- a/tests/test_tutorial/test_fastapi/test_limit_and_offset/test_tutorial001.py +++ b/tests/test_tutorial/test_fastapi/test_limit_and_offset/test_tutorial001.py @@ -184,7 +184,6 @@ def test_tutorial(clear_sqlmodel): ) with TestClient(mod.app) as client: - hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"} hero2_data = { "name": "Spider-Boy", diff --git a/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial001.py index cf00856..8ad038f 100644 --- a/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial001.py +++ b/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial001.py @@ -123,7 +123,6 @@ def test_tutorial(clear_sqlmodel): ) with TestClient(mod.app) as client: - hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"} hero2_data = { "name": "Spider-Boy", diff --git a/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial002.py b/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial002.py index 57393a7..9fd3282 100644 --- a/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial002.py +++ b/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial002.py @@ -123,7 +123,6 @@ def test_tutorial(clear_sqlmodel): ) with TestClient(mod.app) as client: - hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"} hero2_data = { "name": "Spider-Boy", diff --git a/tests/test_tutorial/test_fastapi/test_read_one/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_read_one/test_tutorial001.py index 5b3c771..0609ae4 100644 --- a/tests/test_tutorial/test_fastapi/test_read_one/test_tutorial001.py +++ b/tests/test_tutorial/test_fastapi/test_read_one/test_tutorial001.py @@ -155,7 +155,6 @@ def test_tutorial(clear_sqlmodel): ) with TestClient(mod.app) as client: - hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"} hero2_data = { "name": "Spider-Boy", diff --git a/tests/test_tutorial/test_fastapi/test_response_model/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_response_model/test_tutorial001.py index 54fbbdc..ebb3046 100644 --- a/tests/test_tutorial/test_fastapi/test_response_model/test_tutorial001.py +++ b/tests/test_tutorial/test_fastapi/test_response_model/test_tutorial001.py @@ -111,7 +111,6 @@ def test_tutorial(clear_sqlmodel): ) with TestClient(mod.app) as client: - hero_data = {"name": "Deadpond", "secret_name": "Dive Wilson"} response = client.post("/heroes/", json=hero_data) data = response.json() diff --git a/tests/test_tutorial/test_fastapi/test_session_with_dependency/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_session_with_dependency/test_tutorial001.py index d8dbe3f..705146c 100644 --- a/tests/test_tutorial/test_fastapi/test_session_with_dependency/test_tutorial001.py +++ b/tests/test_tutorial/test_fastapi/test_session_with_dependency/test_tutorial001.py @@ -261,7 +261,6 @@ def test_tutorial(clear_sqlmodel): ) with TestClient(mod.app) as client: - hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"} hero2_data = { "name": "Spider-Boy", diff --git a/tests/test_tutorial/test_fastapi/test_simple_hero_api/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_simple_hero_api/test_tutorial001.py index 2f87faf..eb834ec 100644 --- a/tests/test_tutorial/test_fastapi/test_simple_hero_api/test_tutorial001.py +++ b/tests/test_tutorial/test_fastapi/test_simple_hero_api/test_tutorial001.py @@ -99,7 +99,6 @@ def test_tutorial(clear_sqlmodel): ) with TestClient(mod.app) as client: - hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"} hero2_data = { "name": "Spider-Boy", diff --git a/tests/test_tutorial/test_fastapi/test_teams/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_teams/test_tutorial001.py index 6ac1cff..04a4b0c 100644 --- a/tests/test_tutorial/test_fastapi/test_teams/test_tutorial001.py +++ b/tests/test_tutorial/test_fastapi/test_teams/test_tutorial001.py @@ -474,7 +474,6 @@ def test_tutorial(clear_sqlmodel): ) with TestClient(mod.app) as client: - hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"} hero2_data = { "name": "Spider-Boy", diff --git a/tests/test_tutorial/test_fastapi/test_update/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_update/test_tutorial001.py index e622fd3..ec75a2f 100644 --- a/tests/test_tutorial/test_fastapi/test_update/test_tutorial001.py +++ b/tests/test_tutorial/test_fastapi/test_update/test_tutorial001.py @@ -233,7 +233,6 @@ def test_tutorial(clear_sqlmodel): ) with TestClient(mod.app) as client: - hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"} hero2_data = { "name": "Spider-Boy", From 7c5894ee75b4d7d69dea9496a6a98f74a5d520e1 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Oct 2023 07:47:04 +0000 Subject: [PATCH 38/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 5e79cf0..969db48 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🎨 Run pre-commit on all files and autoformat. PR [#666](https://github.com/tiangolo/sqlmodel/pull/666) by [@tiangolo](https://github.com/tiangolo). * πŸ‘· Move to Ruff and add pre-commit. PR [#661](https://github.com/tiangolo/sqlmodel/pull/661) by [@tiangolo](https://github.com/tiangolo). * ✨ Raise a more clear error when a type is not valid. PR [#425](https://github.com/tiangolo/sqlmodel/pull/425) by [@ddanier](https://github.com/ddanier). * πŸ“ Update outdated link in `docs/db-to-code.md`. PR [#649](https://github.com/tiangolo/sqlmodel/pull/649) by [@MatveyF](https://github.com/MatveyF). From 56f43904c1ad8228523d96053541bb535ae6123c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 23 Oct 2023 12:11:36 +0400 Subject: [PATCH 39/85] =?UTF-8?q?=F0=9F=8E=A8=20Update=20docs=20format=20a?= =?UTF-8?q?nd=20references=20with=20pre-commit=20and=20Ruff=20(#667)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/tutorial/fastapi/relationships.md | 4 ++-- docs/tutorial/fastapi/session-with-dependency.md | 2 +- docs/tutorial/fastapi/teams.md | 2 +- docs_src/tutorial/fastapi/app_testing/tutorial001/main.py | 1 - docs_src/tutorial/fastapi/relationships/tutorial001.py | 1 - .../tutorial/fastapi/session_with_dependency/tutorial001.py | 1 - docs_src/tutorial/fastapi/teams/tutorial001.py | 1 - 7 files changed, 4 insertions(+), 8 deletions(-) diff --git a/docs/tutorial/fastapi/relationships.md b/docs/tutorial/fastapi/relationships.md index 6921b5a..f152b23 100644 --- a/docs/tutorial/fastapi/relationships.md +++ b/docs/tutorial/fastapi/relationships.md @@ -84,7 +84,7 @@ In this case, we used `response_model=TeamRead` and `response_model=HeroRead`, s # Code here omitted πŸ‘ˆ -{!./docs_src/tutorial/fastapi/teams/tutorial001.py[ln:159-164]!} +{!./docs_src/tutorial/fastapi/teams/tutorial001.py[ln:158-163]!} # Code below omitted πŸ‘‡ ``` @@ -234,7 +234,7 @@ In the case of the hero, this tells FastAPI to extract the `team` too. And in th # Code here omitted πŸ‘ˆ -{!./docs_src/tutorial/fastapi/relationships/tutorial001.py[ln:168-173]!} +{!./docs_src/tutorial/fastapi/relationships/tutorial001.py[ln:167-172]!} # Code below omitted πŸ‘‡ ``` diff --git a/docs/tutorial/fastapi/session-with-dependency.md b/docs/tutorial/fastapi/session-with-dependency.md index 52a800b..195c2e1 100644 --- a/docs/tutorial/fastapi/session-with-dependency.md +++ b/docs/tutorial/fastapi/session-with-dependency.md @@ -177,7 +177,7 @@ And then we remove the previous `with` block with the old **session**. # Code here omitted πŸ‘ˆ -{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py[ln:55-107]!} +{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py[ln:55-106]!} ```
diff --git a/docs/tutorial/fastapi/teams.md b/docs/tutorial/fastapi/teams.md index 0b19a95..52554cf 100644 --- a/docs/tutorial/fastapi/teams.md +++ b/docs/tutorial/fastapi/teams.md @@ -92,7 +92,7 @@ These are equivalent and very similar to the **path operations** for the **heroe ```Python hl_lines="3-9 12-20 23-28 31-47 50-57" # Code above omitted πŸ‘† -{!./docs_src/tutorial/fastapi/teams/tutorial001.py[ln:139-193]!} +{!./docs_src/tutorial/fastapi/teams/tutorial001.py[ln:138-192]!} # Code below omitted πŸ‘‡ ``` diff --git a/docs_src/tutorial/fastapi/app_testing/tutorial001/main.py b/docs_src/tutorial/fastapi/app_testing/tutorial001/main.py index 88b8fbb..d106c4e 100644 --- a/docs_src/tutorial/fastapi/app_testing/tutorial001/main.py +++ b/docs_src/tutorial/fastapi/app_testing/tutorial001/main.py @@ -98,7 +98,6 @@ def update_hero( @app.delete("/heroes/{hero_id}") def delete_hero(*, session: Session = Depends(get_session), hero_id: int): - hero = session.get(Hero, hero_id) if not hero: raise HTTPException(status_code=404, detail="Hero not found") diff --git a/docs_src/tutorial/fastapi/relationships/tutorial001.py b/docs_src/tutorial/fastapi/relationships/tutorial001.py index 97220b9..6a03846 100644 --- a/docs_src/tutorial/fastapi/relationships/tutorial001.py +++ b/docs_src/tutorial/fastapi/relationships/tutorial001.py @@ -136,7 +136,6 @@ def update_hero( @app.delete("/heroes/{hero_id}") def delete_hero(*, session: Session = Depends(get_session), hero_id: int): - hero = session.get(Hero, hero_id) if not hero: raise HTTPException(status_code=404, detail="Hero not found") diff --git a/docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py b/docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py index 88b8fbb..d106c4e 100644 --- a/docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py +++ b/docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py @@ -98,7 +98,6 @@ def update_hero( @app.delete("/heroes/{hero_id}") def delete_hero(*, session: Session = Depends(get_session), hero_id: int): - hero = session.get(Hero, hero_id) if not hero: raise HTTPException(status_code=404, detail="Hero not found") diff --git a/docs_src/tutorial/fastapi/teams/tutorial001.py b/docs_src/tutorial/fastapi/teams/tutorial001.py index 2a0bd60..6f84182 100644 --- a/docs_src/tutorial/fastapi/teams/tutorial001.py +++ b/docs_src/tutorial/fastapi/teams/tutorial001.py @@ -127,7 +127,6 @@ def update_hero( @app.delete("/heroes/{hero_id}") def delete_hero(*, session: Session = Depends(get_session), hero_id: int): - hero = session.get(Hero, hero_id) if not hero: raise HTTPException(status_code=404, detail="Hero not found") From 2676cf2b06d4ffaacb084b175b38cd2d609c5aa4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Oct 2023 08:12:08 +0000 Subject: [PATCH 40/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 969db48..06c9697 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🎨 Update docs format and references with pre-commit and Ruff. PR [#667](https://github.com/tiangolo/sqlmodel/pull/667) by [@tiangolo](https://github.com/tiangolo). * 🎨 Run pre-commit on all files and autoformat. PR [#666](https://github.com/tiangolo/sqlmodel/pull/666) by [@tiangolo](https://github.com/tiangolo). * πŸ‘· Move to Ruff and add pre-commit. PR [#661](https://github.com/tiangolo/sqlmodel/pull/661) by [@tiangolo](https://github.com/tiangolo). * ✨ Raise a more clear error when a type is not valid. PR [#425](https://github.com/tiangolo/sqlmodel/pull/425) by [@ddanier](https://github.com/ddanier). From b83e848699fc314d27e01e3db0b9caddd4601358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 23 Oct 2023 12:15:05 +0400 Subject: [PATCH 41/85] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Upgrade=20MkDocs=20M?= =?UTF-8?q?aterial=20(#668)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 3 +-- scripts/docs-live.sh | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 73d8b3a..7aa9f96 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,8 +39,7 @@ sqlalchemy2-stubs = {version = "*", allow-prereleases = true} pytest = "^7.0.1" mypy = "0.971" black = "^22.10.0" -mkdocs = "^1.2.1" -mkdocs-material = "^8.1.4" +mkdocs-material = "9.1.21" pillow = "^9.3.0" cairosvg = "^2.5.2" mdx-include = "^1.4.1" diff --git a/scripts/docs-live.sh b/scripts/docs-live.sh index 5342a9e..f9d31ba 100755 --- a/scripts/docs-live.sh +++ b/scripts/docs-live.sh @@ -2,4 +2,6 @@ set -e +export DYLD_FALLBACK_LIBRARY_PATH="/opt/homebrew/lib" + mkdocs serve --dev-addr 127.0.0.1:8008 From 40c1af92021ae02e771d43971b0f96a786c78875 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Oct 2023 08:15:40 +0000 Subject: [PATCH 42/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 06c9697..108942f 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆️ Upgrade MkDocs Material. PR [#668](https://github.com/tiangolo/sqlmodel/pull/668) by [@tiangolo](https://github.com/tiangolo). * 🎨 Update docs format and references with pre-commit and Ruff. PR [#667](https://github.com/tiangolo/sqlmodel/pull/667) by [@tiangolo](https://github.com/tiangolo). * 🎨 Run pre-commit on all files and autoformat. PR [#666](https://github.com/tiangolo/sqlmodel/pull/666) by [@tiangolo](https://github.com/tiangolo). * πŸ‘· Move to Ruff and add pre-commit. PR [#661](https://github.com/tiangolo/sqlmodel/pull/661) by [@tiangolo](https://github.com/tiangolo). From d3261cab591051759ad966eac8f61e6ee39ebaa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 23 Oct 2023 13:22:44 +0400 Subject: [PATCH 43/85] =?UTF-8?q?=F0=9F=90=9B=20Fix=20enum=20type=20checks?= =?UTF-8?q?=20ordering=20in=20`get=5Fsqlalchemy=5Ftype`=20(#669)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Pierre Cheynier --- sqlmodel/main.py | 5 +++-- tests/test_enums.py | 44 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/sqlmodel/main.py b/sqlmodel/main.py index d5a7302..a32be42 100644 --- a/sqlmodel/main.py +++ b/sqlmodel/main.py @@ -384,6 +384,9 @@ class SQLModelMetaclass(ModelMetaclass, DeclarativeMeta): def get_sqlalchemy_type(field: ModelField) -> Any: if isinstance(field.type_, type) and field.shape == SHAPE_SINGLETON: + # Check enums first as an enum can also be a str, needed by Pydantic/FastAPI + if issubclass(field.type_, Enum): + return sa_Enum(field.type_) if issubclass(field.type_, str): if field.field_info.max_length: return AutoString(length=field.field_info.max_length) @@ -402,8 +405,6 @@ def get_sqlalchemy_type(field: ModelField) -> Any: return Interval if issubclass(field.type_, time): return Time - if issubclass(field.type_, Enum): - return sa_Enum(field.type_) if issubclass(field.type_, bytes): return LargeBinary if issubclass(field.type_, Decimal): diff --git a/tests/test_enums.py b/tests/test_enums.py index aeec645..194bdef 100644 --- a/tests/test_enums.py +++ b/tests/test_enums.py @@ -14,12 +14,12 @@ Associated issues: """ -class MyEnum1(enum.Enum): +class MyEnum1(str, enum.Enum): A = "A" B = "B" -class MyEnum2(enum.Enum): +class MyEnum2(str, enum.Enum): C = "C" D = "D" @@ -70,3 +70,43 @@ def test_sqlite_ddl_sql(capsys): captured = capsys.readouterr() assert "enum_field VARCHAR(1) NOT NULL" in captured.out assert "CREATE TYPE" not in captured.out + + +def test_json_schema_flat_model(): + assert FlatModel.schema() == { + "title": "FlatModel", + "type": "object", + "properties": { + "id": {"title": "Id", "type": "string", "format": "uuid"}, + "enum_field": {"$ref": "#/definitions/MyEnum1"}, + }, + "required": ["id", "enum_field"], + "definitions": { + "MyEnum1": { + "title": "MyEnum1", + "description": "An enumeration.", + "enum": ["A", "B"], + "type": "string", + } + }, + } + + +def test_json_schema_inherit_model(): + assert InheritModel.schema() == { + "title": "InheritModel", + "type": "object", + "properties": { + "id": {"title": "Id", "type": "string", "format": "uuid"}, + "enum_field": {"$ref": "#/definitions/MyEnum2"}, + }, + "required": ["id", "enum_field"], + "definitions": { + "MyEnum2": { + "title": "MyEnum2", + "description": "An enumeration.", + "enum": ["C", "D"], + "type": "string", + } + }, + } From c25a8cb89b7b637dd0b74424f45357aae3141d22 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Oct 2023 09:23:24 +0000 Subject: [PATCH 44/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 108942f..6865188 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ› Fix enum type checks ordering in `get_sqlalchemy_type`. PR [#669](https://github.com/tiangolo/sqlmodel/pull/669) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Upgrade MkDocs Material. PR [#668](https://github.com/tiangolo/sqlmodel/pull/668) by [@tiangolo](https://github.com/tiangolo). * 🎨 Update docs format and references with pre-commit and Ruff. PR [#667](https://github.com/tiangolo/sqlmodel/pull/667) by [@tiangolo](https://github.com/tiangolo). * 🎨 Run pre-commit on all files and autoformat. PR [#666](https://github.com/tiangolo/sqlmodel/pull/666) by [@tiangolo](https://github.com/tiangolo). From 9511c4677db5370ccc2fb320e83eb1730f7e1d80 Mon Sep 17 00:00:00 2001 From: Daniil Fajnberg <60156134+daniil-berg@users.noreply.github.com> Date: Mon, 23 Oct 2023 09:39:55 +0000 Subject: [PATCH 45/85] =?UTF-8?q?=E2=AC=86=20Raise=20SQLAlchemy=20version?= =?UTF-8?q?=20requirement=20to=20at=20least=20`1.4.29`=20(related=20to=20#?= =?UTF-8?q?434)=20(#439)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SebastiΓ‘n RamΓ­rez --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7aa9f96..cd59bd4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,7 @@ classifiers = [ [tool.poetry.dependencies] python = "^3.7" -SQLAlchemy = ">=1.4.17,<=1.4.41" +SQLAlchemy = ">=1.4.29,<=1.4.41" pydantic = "^1.8.2" sqlalchemy2-stubs = {version = "*", allow-prereleases = true} From d281a0fa9f7a0c6384f6e4c30044e124fa26bb1c Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Oct 2023 09:40:31 +0000 Subject: [PATCH 46/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 6865188..4728d48 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ Raise SQLAlchemy version requirement to at least `1.4.29` (related to #434). PR [#439](https://github.com/tiangolo/sqlmodel/pull/439) by [@daniil-berg](https://github.com/daniil-berg). * πŸ› Fix enum type checks ordering in `get_sqlalchemy_type`. PR [#669](https://github.com/tiangolo/sqlmodel/pull/669) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Upgrade MkDocs Material. PR [#668](https://github.com/tiangolo/sqlmodel/pull/668) by [@tiangolo](https://github.com/tiangolo). * 🎨 Update docs format and references with pre-commit and Ruff. PR [#667](https://github.com/tiangolo/sqlmodel/pull/667) by [@tiangolo](https://github.com/tiangolo). From d1cf6134617cc374fa3aee2b374dc1387c9bc868 Mon Sep 17 00:00:00 2001 From: Sandro Tosi Date: Mon, 23 Oct 2023 07:22:10 -0400 Subject: [PATCH 47/85] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Upgrade=20support=20?= =?UTF-8?q?for=20SQLAlchemy=201.4.49,=20update=20tests=20(#519)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SebastiΓ‘n RamΓ­rez Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- pyproject.toml | 2 +- .../test_multiple_models/test_tutorial001.py | 14 ++++++++++++-- .../test_multiple_models/test_tutorial002.py | 14 ++++++++++++-- .../test_tutorial/test_indexes/test_tutorial001.py | 14 ++++++++++++-- .../test_tutorial/test_indexes/test_tutorial006.py | 14 ++++++++++++-- 5 files changed, 49 insertions(+), 9 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index cd59bd4..94fe55d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,7 @@ classifiers = [ [tool.poetry.dependencies] python = "^3.7" -SQLAlchemy = ">=1.4.29,<=1.4.41" +SQLAlchemy = ">=1.4.29,<2.0.0" pydantic = "^1.8.2" sqlalchemy2-stubs = {version = "*", allow-prereleases = true} diff --git a/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial001.py index 8ad038f..8d99cf9 100644 --- a/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial001.py +++ b/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial001.py @@ -172,8 +172,18 @@ def test_tutorial(clear_sqlmodel): insp: Inspector = inspect(mod.engine) indexes = insp.get_indexes(str(mod.Hero.__tablename__)) expected_indexes = [ - {"name": "ix_hero_name", "column_names": ["name"], "unique": 0}, - {"name": "ix_hero_age", "column_names": ["age"], "unique": 0}, + { + "name": "ix_hero_name", + "dialect_options": {}, + "column_names": ["name"], + "unique": 0, + }, + { + "name": "ix_hero_age", + "dialect_options": {}, + "column_names": ["age"], + "unique": 0, + }, ] for index in expected_indexes: assert index in indexes, "This expected index should be in the indexes in DB" diff --git a/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial002.py b/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial002.py index 9fd3282..94a41b3 100644 --- a/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial002.py +++ b/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial002.py @@ -172,8 +172,18 @@ def test_tutorial(clear_sqlmodel): insp: Inspector = inspect(mod.engine) indexes = insp.get_indexes(str(mod.Hero.__tablename__)) expected_indexes = [ - {"name": "ix_hero_age", "column_names": ["age"], "unique": 0}, - {"name": "ix_hero_name", "column_names": ["name"], "unique": 0}, + { + "name": "ix_hero_age", + "dialect_options": {}, + "column_names": ["age"], + "unique": 0, + }, + { + "name": "ix_hero_name", + "dialect_options": {}, + "column_names": ["name"], + "unique": 0, + }, ] for index in expected_indexes: assert index in indexes, "This expected index should be in the indexes in DB" diff --git a/tests/test_tutorial/test_indexes/test_tutorial001.py b/tests/test_tutorial/test_indexes/test_tutorial001.py index 5962077..f33db5b 100644 --- a/tests/test_tutorial/test_indexes/test_tutorial001.py +++ b/tests/test_tutorial/test_indexes/test_tutorial001.py @@ -25,8 +25,18 @@ def test_tutorial(clear_sqlmodel): insp: Inspector = inspect(mod.engine) indexes = insp.get_indexes(str(mod.Hero.__tablename__)) expected_indexes = [ - {"name": "ix_hero_name", "column_names": ["name"], "unique": 0}, - {"name": "ix_hero_age", "column_names": ["age"], "unique": 0}, + { + "name": "ix_hero_name", + "dialect_options": {}, + "column_names": ["name"], + "unique": 0, + }, + { + "name": "ix_hero_age", + "dialect_options": {}, + "column_names": ["age"], + "unique": 0, + }, ] for index in expected_indexes: assert index in indexes, "This expected index should be in the indexes in DB" diff --git a/tests/test_tutorial/test_indexes/test_tutorial006.py b/tests/test_tutorial/test_indexes/test_tutorial006.py index e26f8b2..893043d 100644 --- a/tests/test_tutorial/test_indexes/test_tutorial006.py +++ b/tests/test_tutorial/test_indexes/test_tutorial006.py @@ -26,8 +26,18 @@ def test_tutorial(clear_sqlmodel): insp: Inspector = inspect(mod.engine) indexes = insp.get_indexes(str(mod.Hero.__tablename__)) expected_indexes = [ - {"name": "ix_hero_name", "column_names": ["name"], "unique": 0}, - {"name": "ix_hero_age", "column_names": ["age"], "unique": 0}, + { + "name": "ix_hero_name", + "dialect_options": {}, + "column_names": ["name"], + "unique": 0, + }, + { + "name": "ix_hero_age", + "dialect_options": {}, + "column_names": ["age"], + "unique": 0, + }, ] for index in expected_indexes: assert index in indexes, "This expected index should be in the indexes in DB" From c213f5daf45091cb269fb8ee979efd0049b89927 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Oct 2023 11:22:53 +0000 Subject: [PATCH 48/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 4728d48..747d103 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆️ Upgrade support for SQLAlchemy 1.4.49, update tests. PR [#519](https://github.com/tiangolo/sqlmodel/pull/519) by [@sandrotosi](https://github.com/sandrotosi). * ⬆ Raise SQLAlchemy version requirement to at least `1.4.29` (related to #434). PR [#439](https://github.com/tiangolo/sqlmodel/pull/439) by [@daniil-berg](https://github.com/daniil-berg). * πŸ› Fix enum type checks ordering in `get_sqlalchemy_type`. PR [#669](https://github.com/tiangolo/sqlmodel/pull/669) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Upgrade MkDocs Material. PR [#668](https://github.com/tiangolo/sqlmodel/pull/668) by [@tiangolo](https://github.com/tiangolo). From 9809b5bc8323712fe41d1e7a92352da8a07ed69a Mon Sep 17 00:00:00 2001 From: Daniil Fajnberg <60156134+daniil-berg@users.noreply.github.com> Date: Mon, 23 Oct 2023 13:59:06 +0000 Subject: [PATCH 49/85] =?UTF-8?q?=F0=9F=90=9B=20Fix=20allowing=20using=20a?= =?UTF-8?q?=20`ForeignKey`=20directly,=20remove=20repeated=20column=20cons?= =?UTF-8?q?truction=20from=20`SQLModelMetaclass.=5F=5Finit=5F=5F`=20and=20?= =?UTF-8?q?upgrade=20minimum=20SQLAlchemy=20to=20`>=3D1.4.36`=20(#443)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SebastiΓ‘n RamΓ­rez --- pyproject.toml | 2 +- sqlmodel/main.py | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 94fe55d..57426b5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,7 @@ classifiers = [ [tool.poetry.dependencies] python = "^3.7" -SQLAlchemy = ">=1.4.29,<2.0.0" +SQLAlchemy = ">=1.4.36,<2.0.0" pydantic = "^1.8.2" sqlalchemy2-stubs = {version = "*", allow-prereleases = true} diff --git a/sqlmodel/main.py b/sqlmodel/main.py index a32be42..07e600e 100644 --- a/sqlmodel/main.py +++ b/sqlmodel/main.py @@ -334,14 +334,10 @@ class SQLModelMetaclass(ModelMetaclass, DeclarativeMeta): base_is_table = True break if getattr(cls.__config__, "table", False) and not base_is_table: - dict_used = dict_.copy() - for field_name, field_value in cls.__fields__.items(): - dict_used[field_name] = get_column_from_field(field_value) for rel_name, rel_info in cls.__sqlmodel_relationships__.items(): if rel_info.sa_relationship: # There's a SQLAlchemy relationship declared, that takes precedence # over anything else, use that and continue with the next attribute - dict_used[rel_name] = rel_info.sa_relationship setattr(cls, rel_name, rel_info.sa_relationship) # Fix #315 continue ann = cls.__annotations__[rel_name] @@ -375,9 +371,11 @@ class SQLModelMetaclass(ModelMetaclass, DeclarativeMeta): rel_value: RelationshipProperty = relationship( # type: ignore relationship_to, *rel_args, **rel_kwargs ) - dict_used[rel_name] = rel_value setattr(cls, rel_name, rel_value) # Fix #315 - DeclarativeMeta.__init__(cls, classname, bases, dict_used, **kw) + # SQLAlchemy no longer uses dict_ + # Ref: https://github.com/sqlalchemy/sqlalchemy/commit/428ea01f00a9cc7f85e435018565eb6da7af1b77 + # Tag: 1.4.36 + DeclarativeMeta.__init__(cls, classname, bases, dict_, **kw) else: ModelMetaclass.__init__(cls, classname, bases, dict_, **kw) From b8996f0e62bca6155e2d27200d15de8b54c40ac3 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Oct 2023 13:59:53 +0000 Subject: [PATCH 50/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 747d103..4ab34b5 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ› Fix allowing using a `ForeignKey` directly, remove repeated column construction from `SQLModelMetaclass.__init__` and upgrade minimum SQLAlchemy to `>=1.4.36`. PR [#443](https://github.com/tiangolo/sqlmodel/pull/443) by [@daniil-berg](https://github.com/daniil-berg). * ⬆️ Upgrade support for SQLAlchemy 1.4.49, update tests. PR [#519](https://github.com/tiangolo/sqlmodel/pull/519) by [@sandrotosi](https://github.com/sandrotosi). * ⬆ Raise SQLAlchemy version requirement to at least `1.4.29` (related to #434). PR [#439](https://github.com/tiangolo/sqlmodel/pull/439) by [@daniil-berg](https://github.com/daniil-berg). * πŸ› Fix enum type checks ordering in `get_sqlalchemy_type`. PR [#669](https://github.com/tiangolo/sqlmodel/pull/669) by [@tiangolo](https://github.com/tiangolo). From 9732c5ac60354b4a5c51e12ea35ca6fc4fb8d73b Mon Sep 17 00:00:00 2001 From: Arseny Boykov <36469655+Bobronium@users.noreply.github.com> Date: Mon, 23 Oct 2023 17:58:16 +0300 Subject: [PATCH 51/85] =?UTF-8?q?=F0=9F=90=9B=20Fix=20`AsyncSession`=20typ?= =?UTF-8?q?e=20annotations=20for=20`exec()`=20(#58)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SebastiΓ‘n RamΓ­rez --- sqlmodel/ext/asyncio/session.py | 46 ++++++++++++++++++++++++++++----- sqlmodel/orm/session.py | 2 +- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/sqlmodel/ext/asyncio/session.py b/sqlmodel/ext/asyncio/session.py index 80267b2..f500c44 100644 --- a/sqlmodel/ext/asyncio/session.py +++ b/sqlmodel/ext/asyncio/session.py @@ -1,17 +1,17 @@ -from typing import Any, Mapping, Optional, Sequence, TypeVar, Union +from typing import Any, Mapping, Optional, Sequence, TypeVar, Union, overload from sqlalchemy import util from sqlalchemy.ext.asyncio import AsyncSession as _AsyncSession from sqlalchemy.ext.asyncio import engine from sqlalchemy.ext.asyncio.engine import AsyncConnection, AsyncEngine from sqlalchemy.util.concurrency import greenlet_spawn -from sqlmodel.sql.base import Executable -from ...engine.result import ScalarResult +from ...engine.result import Result, ScalarResult from ...orm.session import Session -from ...sql.expression import Select +from ...sql.base import Executable +from ...sql.expression import Select, SelectOfScalar -_T = TypeVar("_T") +_TSelectParam = TypeVar("_TSelectParam") class AsyncSession(_AsyncSession): @@ -40,14 +40,46 @@ class AsyncSession(_AsyncSession): Session(bind=bind, binds=binds, **kw) # type: ignore ) + @overload async def exec( self, - statement: Union[Select[_T], Executable[_T]], + statement: Select[_TSelectParam], + *, + params: Optional[Union[Mapping[str, Any], Sequence[Mapping[str, Any]]]] = None, + execution_options: Mapping[str, Any] = util.EMPTY_DICT, + bind_arguments: Optional[Mapping[str, Any]] = None, + _parent_execute_state: Optional[Any] = None, + _add_event: Optional[Any] = None, + **kw: Any, + ) -> Result[_TSelectParam]: + ... + + @overload + async def exec( + self, + statement: SelectOfScalar[_TSelectParam], + *, + params: Optional[Union[Mapping[str, Any], Sequence[Mapping[str, Any]]]] = None, + execution_options: Mapping[str, Any] = util.EMPTY_DICT, + bind_arguments: Optional[Mapping[str, Any]] = None, + _parent_execute_state: Optional[Any] = None, + _add_event: Optional[Any] = None, + **kw: Any, + ) -> ScalarResult[_TSelectParam]: + ... + + async def exec( + self, + statement: Union[ + Select[_TSelectParam], + SelectOfScalar[_TSelectParam], + Executable[_TSelectParam], + ], params: Optional[Union[Mapping[str, Any], Sequence[Mapping[str, Any]]]] = None, execution_options: Mapping[Any, Any] = util.EMPTY_DICT, bind_arguments: Optional[Mapping[str, Any]] = None, **kw: Any, - ) -> ScalarResult[_T]: + ) -> Union[Result[_TSelectParam], ScalarResult[_TSelectParam]]: # TODO: the documentation says execution_options accepts a dict, but only # util.immutabledict has the union() method. Is this a bug in SQLAlchemy? execution_options = execution_options.union({"prebuffer_rows": True}) # type: ignore diff --git a/sqlmodel/orm/session.py b/sqlmodel/orm/session.py index 1692fdc..0c70c29 100644 --- a/sqlmodel/orm/session.py +++ b/sqlmodel/orm/session.py @@ -4,11 +4,11 @@ from sqlalchemy import util from sqlalchemy.orm import Query as _Query from sqlalchemy.orm import Session as _Session from sqlalchemy.sql.base import Executable as _Executable -from sqlmodel.sql.expression import Select, SelectOfScalar from typing_extensions import Literal from ..engine.result import Result, ScalarResult from ..sql.base import Executable +from ..sql.expression import Select, SelectOfScalar _TSelectParam = TypeVar("_TSelectParam") From 8e55ea51259ad19bf3f4769be137e77f3edb60fd Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Oct 2023 14:58:52 +0000 Subject: [PATCH 52/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 4ab34b5..c8cea2c 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ› Fix `AsyncSession` type annotations for `exec()`. PR [#58](https://github.com/tiangolo/sqlmodel/pull/58) by [@Bobronium](https://github.com/Bobronium). * πŸ› Fix allowing using a `ForeignKey` directly, remove repeated column construction from `SQLModelMetaclass.__init__` and upgrade minimum SQLAlchemy to `>=1.4.36`. PR [#443](https://github.com/tiangolo/sqlmodel/pull/443) by [@daniil-berg](https://github.com/daniil-berg). * ⬆️ Upgrade support for SQLAlchemy 1.4.49, update tests. PR [#519](https://github.com/tiangolo/sqlmodel/pull/519) by [@sandrotosi](https://github.com/sandrotosi). * ⬆ Raise SQLAlchemy version requirement to at least `1.4.29` (related to #434). PR [#439](https://github.com/tiangolo/sqlmodel/pull/439) by [@daniil-berg](https://github.com/daniil-berg). From 1062e1b4853484d1653115e3517fb1cfa482416b Mon Sep 17 00:00:00 2001 From: Michael Oliver Date: Mon, 23 Oct 2023 16:16:17 +0100 Subject: [PATCH 53/85] =?UTF-8?q?=F0=9F=94=A7=20Update=20mypy=20config,=20?= =?UTF-8?q?use=20`strict=20=3D=20true`=20instead=20of=20manual=20configs?= =?UTF-8?q?=20(#428)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SebastiΓ‘n RamΓ­rez --- pyproject.toml | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 57426b5..c7956da 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -73,21 +73,7 @@ exclude_lines = [ ] [tool.mypy] -# --strict -disallow_any_generics = true -disallow_subclassing_any = true -disallow_untyped_calls = true -disallow_untyped_defs = true -disallow_incomplete_defs = true -check_untyped_defs = true -disallow_untyped_decorators = true -no_implicit_optional = true -warn_redundant_casts = true -warn_unused_ignores = true -warn_return_any = true -implicit_reexport = false -strict_equality = true -# --strict end +strict = true [[tool.mypy.overrides]] module = "sqlmodel.sql.expression" From d6e4f9b9e3a6162b9ac7839d5bde19f27e7af3a2 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Oct 2023 15:16:53 +0000 Subject: [PATCH 54/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index c8cea2c..7cc9b97 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ”§ Update mypy config, use `strict = true` instead of manual configs. PR [#428](https://github.com/tiangolo/sqlmodel/pull/428) by [@michaeloliverx](https://github.com/michaeloliverx). * πŸ› Fix `AsyncSession` type annotations for `exec()`. PR [#58](https://github.com/tiangolo/sqlmodel/pull/58) by [@Bobronium](https://github.com/Bobronium). * πŸ› Fix allowing using a `ForeignKey` directly, remove repeated column construction from `SQLModelMetaclass.__init__` and upgrade minimum SQLAlchemy to `>=1.4.36`. PR [#443](https://github.com/tiangolo/sqlmodel/pull/443) by [@daniil-berg](https://github.com/daniil-berg). * ⬆️ Upgrade support for SQLAlchemy 1.4.49, update tests. PR [#519](https://github.com/tiangolo/sqlmodel/pull/519) by [@sandrotosi](https://github.com/sandrotosi). From 475b838c8b6ddb8c34aee5fa01c65519d7dbf351 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 19:32:09 +0400 Subject: [PATCH 55/85] =?UTF-8?q?=E2=AC=86=20Bump=20actions/checkout=20fro?= =?UTF-8?q?m=203=20to=204=20(#670)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-docs.yml | 4 ++-- .github/workflows/deploy-docs.yml | 2 +- .github/workflows/latest-changes.yml | 2 +- .github/workflows/publish.yml | 2 +- .github/workflows/test.yml | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index cf5295a..879cc7c 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -17,7 +17,7 @@ jobs: outputs: docs: ${{ steps.filter.outputs.docs }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # For pull requests it's not necessary to checkout the code but for the main branch it is - uses: dorny/paths-filter@v2 id: filter @@ -41,7 +41,7 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 25cd1ff..e7641a3 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -14,7 +14,7 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Clean site run: | rm -rf ./site diff --git a/.github/workflows/latest-changes.yml b/.github/workflows/latest-changes.yml index 357767b..7e84039 100644 --- a/.github/workflows/latest-changes.yml +++ b/.github/workflows/latest-changes.yml @@ -20,7 +20,7 @@ jobs: latest-changes: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: # To allow latest-changes to commit to the main branch token: ${{ secrets.SQLMODEL_LATEST_CHANGES }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 1c21cd4..42a0eec 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -15,7 +15,7 @@ jobs: publish: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 871557a..201abc7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,7 +28,7 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: @@ -74,7 +74,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: From 189059e07e194c097d0c4f9375294ae27897b46e Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Oct 2023 15:32:48 +0000 Subject: [PATCH 56/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 7cc9b97..14d5e9c 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ Bump actions/checkout from 3 to 4. PR [#670](https://github.com/tiangolo/sqlmodel/pull/670) by [@dependabot[bot]](https://github.com/apps/dependabot). * πŸ”§ Update mypy config, use `strict = true` instead of manual configs. PR [#428](https://github.com/tiangolo/sqlmodel/pull/428) by [@michaeloliverx](https://github.com/michaeloliverx). * πŸ› Fix `AsyncSession` type annotations for `exec()`. PR [#58](https://github.com/tiangolo/sqlmodel/pull/58) by [@Bobronium](https://github.com/Bobronium). * πŸ› Fix allowing using a `ForeignKey` directly, remove repeated column construction from `SQLModelMetaclass.__init__` and upgrade minimum SQLAlchemy to `>=1.4.36`. PR [#443](https://github.com/tiangolo/sqlmodel/pull/443) by [@daniil-berg](https://github.com/daniil-berg). From dee70033b81813674d2740e7556c9d4c3995dc62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 23 Oct 2023 19:33:08 +0400 Subject: [PATCH 57/85] =?UTF-8?q?=E2=9C=85=20Refactor=20OpenAPI=20FastAPI?= =?UTF-8?q?=20tests=20to=20simplify=20updating=20them=20later,=20this=20mo?= =?UTF-8?q?ves=20things=20around=20without=20changes=20(#671)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test_delete/test_tutorial001.py | 523 +++++---- .../test_limit_and_offset/test_tutorial001.py | 365 +++--- .../test_relationships/test_tutorial001.py | 1030 +++++++++-------- .../test_tutorial001.py | 523 +++++---- .../test_teams/test_tutorial001.py | 965 +++++++-------- .../test_update/test_tutorial001.py | 467 ++++---- 6 files changed, 1999 insertions(+), 1874 deletions(-) diff --git a/tests/test_tutorial/test_fastapi/test_delete/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_delete/test_tutorial001.py index 3a44512..8979245 100644 --- a/tests/test_tutorial/test_fastapi/test_delete/test_tutorial001.py +++ b/tests/test_tutorial/test_fastapi/test_delete/test_tutorial001.py @@ -2,255 +2,6 @@ from fastapi.testclient import TestClient from sqlmodel import create_engine from sqlmodel.pool import StaticPool -openapi_schema = { - "openapi": "3.0.2", - "info": {"title": "FastAPI", "version": "0.1.0"}, - "paths": { - "/heroes/": { - "get": { - "summary": "Read Heroes", - "operationId": "read_heroes_heroes__get", - "parameters": [ - { - "required": False, - "schema": {"title": "Offset", "type": "integer", "default": 0}, - "name": "offset", - "in": "query", - }, - { - "required": False, - "schema": { - "title": "Limit", - "type": "integer", - "default": 100, - "lte": 100, - }, - "name": "limit", - "in": "query", - }, - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "title": "Response Read Heroes Heroes Get", - "type": "array", - "items": {"$ref": "#/components/schemas/HeroRead"}, - } - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - "post": { - "summary": "Create Hero", - "operationId": "create_hero_heroes__post", - "requestBody": { - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroCreate"} - } - }, - "required": True, - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroRead"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - }, - "/heroes/{hero_id}": { - "get": { - "summary": "Read Hero", - "operationId": "read_hero_heroes__hero_id__get", - "parameters": [ - { - "required": True, - "schema": {"title": "Hero Id", "type": "integer"}, - "name": "hero_id", - "in": "path", - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroRead"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - "delete": { - "summary": "Delete Hero", - "operationId": "delete_hero_heroes__hero_id__delete", - "parameters": [ - { - "required": True, - "schema": {"title": "Hero Id", "type": "integer"}, - "name": "hero_id", - "in": "path", - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": {"application/json": {"schema": {}}}, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - "patch": { - "summary": "Update Hero", - "operationId": "update_hero_heroes__hero_id__patch", - "parameters": [ - { - "required": True, - "schema": {"title": "Hero Id", "type": "integer"}, - "name": "hero_id", - "in": "path", - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroUpdate"} - } - }, - "required": True, - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroRead"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - }, - }, - "components": { - "schemas": { - "HTTPValidationError": { - "title": "HTTPValidationError", - "type": "object", - "properties": { - "detail": { - "title": "Detail", - "type": "array", - "items": {"$ref": "#/components/schemas/ValidationError"}, - } - }, - }, - "HeroCreate": { - "title": "HeroCreate", - "required": ["name", "secret_name"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "secret_name": {"title": "Secret Name", "type": "string"}, - "age": {"title": "Age", "type": "integer"}, - }, - }, - "HeroRead": { - "title": "HeroRead", - "required": ["name", "secret_name", "id"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "secret_name": {"title": "Secret Name", "type": "string"}, - "age": {"title": "Age", "type": "integer"}, - "id": {"title": "Id", "type": "integer"}, - }, - }, - "HeroUpdate": { - "title": "HeroUpdate", - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "secret_name": {"title": "Secret Name", "type": "string"}, - "age": {"title": "Age", "type": "integer"}, - }, - }, - "ValidationError": { - "title": "ValidationError", - "required": ["loc", "msg", "type"], - "type": "object", - "properties": { - "loc": { - "title": "Location", - "type": "array", - "items": {"type": "string"}, - }, - "msg": {"title": "Message", "type": "string"}, - "type": {"title": "Error Type", "type": "string"}, - }, - }, - } - }, -} - def test_tutorial(clear_sqlmodel): from docs_src.tutorial.fastapi.delete import tutorial001 as mod @@ -284,10 +35,6 @@ def test_tutorial(clear_sqlmodel): assert response.status_code == 200, response.text response = client.get("/heroes/9000") assert response.status_code == 404, response.text - response = client.get("/openapi.json") - data = response.json() - assert response.status_code == 200, response.text - assert data == openapi_schema response = client.get("/heroes/") assert response.status_code == 200, response.text data = response.json() @@ -308,3 +55,273 @@ def test_tutorial(clear_sqlmodel): response = client.delete("/heroes/9000") assert response.status_code == 404, response.text + + response = client.get("/openapi.json") + data = response.json() + assert response.status_code == 200, response.text + assert data == { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/heroes/": { + "get": { + "summary": "Read Heroes", + "operationId": "read_heroes_heroes__get", + "parameters": [ + { + "required": False, + "schema": { + "title": "Offset", + "type": "integer", + "default": 0, + }, + "name": "offset", + "in": "query", + }, + { + "required": False, + "schema": { + "title": "Limit", + "type": "integer", + "default": 100, + "lte": 100, + }, + "name": "limit", + "in": "query", + }, + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Read Heroes Heroes Get", + "type": "array", + "items": { + "$ref": "#/components/schemas/HeroRead" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + "post": { + "summary": "Create Hero", + "operationId": "create_hero_heroes__post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroCreate" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroRead" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + }, + "/heroes/{hero_id}": { + "get": { + "summary": "Read Hero", + "operationId": "read_hero_heroes__hero_id__get", + "parameters": [ + { + "required": True, + "schema": {"title": "Hero Id", "type": "integer"}, + "name": "hero_id", + "in": "path", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroRead" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + "delete": { + "summary": "Delete Hero", + "operationId": "delete_hero_heroes__hero_id__delete", + "parameters": [ + { + "required": True, + "schema": {"title": "Hero Id", "type": "integer"}, + "name": "hero_id", + "in": "path", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + "patch": { + "summary": "Update Hero", + "operationId": "update_hero_heroes__hero_id__patch", + "parameters": [ + { + "required": True, + "schema": {"title": "Hero Id", "type": "integer"}, + "name": "hero_id", + "in": "path", + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroUpdate" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroRead" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + }, + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": { + "$ref": "#/components/schemas/ValidationError" + }, + } + }, + }, + "HeroCreate": { + "title": "HeroCreate", + "required": ["name", "secret_name"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "secret_name": {"title": "Secret Name", "type": "string"}, + "age": {"title": "Age", "type": "integer"}, + }, + }, + "HeroRead": { + "title": "HeroRead", + "required": ["name", "secret_name", "id"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "secret_name": {"title": "Secret Name", "type": "string"}, + "age": {"title": "Age", "type": "integer"}, + "id": {"title": "Id", "type": "integer"}, + }, + }, + "HeroUpdate": { + "title": "HeroUpdate", + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "secret_name": {"title": "Secret Name", "type": "string"}, + "age": {"title": "Age", "type": "integer"}, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } diff --git a/tests/test_tutorial/test_fastapi/test_limit_and_offset/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_limit_and_offset/test_tutorial001.py index 1a38f7a..d7f642a 100644 --- a/tests/test_tutorial/test_fastapi/test_limit_and_offset/test_tutorial001.py +++ b/tests/test_tutorial/test_fastapi/test_limit_and_offset/test_tutorial001.py @@ -2,178 +2,6 @@ from fastapi.testclient import TestClient from sqlmodel import create_engine from sqlmodel.pool import StaticPool -openapi_schema = { - "openapi": "3.0.2", - "info": {"title": "FastAPI", "version": "0.1.0"}, - "paths": { - "/heroes/": { - "get": { - "summary": "Read Heroes", - "operationId": "read_heroes_heroes__get", - "parameters": [ - { - "required": False, - "schema": {"title": "Offset", "type": "integer", "default": 0}, - "name": "offset", - "in": "query", - }, - { - "required": False, - "schema": { - "title": "Limit", - "type": "integer", - "default": 100, - "lte": 100, - }, - "name": "limit", - "in": "query", - }, - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "title": "Response Read Heroes Heroes Get", - "type": "array", - "items": {"$ref": "#/components/schemas/HeroRead"}, - } - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - "post": { - "summary": "Create Hero", - "operationId": "create_hero_heroes__post", - "requestBody": { - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroCreate"} - } - }, - "required": True, - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroRead"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - }, - "/heroes/{hero_id}": { - "get": { - "summary": "Read Hero", - "operationId": "read_hero_heroes__hero_id__get", - "parameters": [ - { - "required": True, - "schema": {"title": "Hero Id", "type": "integer"}, - "name": "hero_id", - "in": "path", - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroRead"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - } - }, - }, - "components": { - "schemas": { - "HTTPValidationError": { - "title": "HTTPValidationError", - "type": "object", - "properties": { - "detail": { - "title": "Detail", - "type": "array", - "items": {"$ref": "#/components/schemas/ValidationError"}, - } - }, - }, - "HeroCreate": { - "title": "HeroCreate", - "required": ["name", "secret_name"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "secret_name": {"title": "Secret Name", "type": "string"}, - "age": {"title": "Age", "type": "integer"}, - }, - }, - "HeroRead": { - "title": "HeroRead", - "required": ["name", "secret_name", "id"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "secret_name": {"title": "Secret Name", "type": "string"}, - "age": {"title": "Age", "type": "integer"}, - "id": {"title": "Id", "type": "integer"}, - }, - }, - "ValidationError": { - "title": "ValidationError", - "required": ["loc", "msg", "type"], - "type": "object", - "properties": { - "loc": { - "title": "Location", - "type": "array", - "items": {"type": "string"}, - }, - "msg": {"title": "Message", "type": "string"}, - "type": {"title": "Error Type", "type": "string"}, - }, - }, - } - }, -} - def test_tutorial(clear_sqlmodel): from docs_src.tutorial.fastapi.limit_and_offset import tutorial001 as mod @@ -207,10 +35,6 @@ def test_tutorial(clear_sqlmodel): assert response.status_code == 200, response.text response = client.get("/heroes/9000") assert response.status_code == 404, response.text - response = client.get("/openapi.json") - data = response.json() - assert response.status_code == 200, response.text - assert data == openapi_schema response = client.get("/heroes/") assert response.status_code == 200, response.text @@ -236,3 +60,192 @@ def test_tutorial(clear_sqlmodel): data = response.json() assert len(data) == 1 assert data[0]["name"] == hero2_data["name"] + + response = client.get("/openapi.json") + data = response.json() + assert response.status_code == 200, response.text + assert data == { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/heroes/": { + "get": { + "summary": "Read Heroes", + "operationId": "read_heroes_heroes__get", + "parameters": [ + { + "required": False, + "schema": { + "title": "Offset", + "type": "integer", + "default": 0, + }, + "name": "offset", + "in": "query", + }, + { + "required": False, + "schema": { + "title": "Limit", + "type": "integer", + "default": 100, + "lte": 100, + }, + "name": "limit", + "in": "query", + }, + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Read Heroes Heroes Get", + "type": "array", + "items": { + "$ref": "#/components/schemas/HeroRead" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + "post": { + "summary": "Create Hero", + "operationId": "create_hero_heroes__post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroCreate" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroRead" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + }, + "/heroes/{hero_id}": { + "get": { + "summary": "Read Hero", + "operationId": "read_hero_heroes__hero_id__get", + "parameters": [ + { + "required": True, + "schema": {"title": "Hero Id", "type": "integer"}, + "name": "hero_id", + "in": "path", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroRead" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": { + "$ref": "#/components/schemas/ValidationError" + }, + } + }, + }, + "HeroCreate": { + "title": "HeroCreate", + "required": ["name", "secret_name"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "secret_name": {"title": "Secret Name", "type": "string"}, + "age": {"title": "Age", "type": "integer"}, + }, + }, + "HeroRead": { + "title": "HeroRead", + "required": ["name", "secret_name", "id"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "secret_name": {"title": "Secret Name", "type": "string"}, + "age": {"title": "Age", "type": "integer"}, + "id": {"title": "Id", "type": "integer"}, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } diff --git a/tests/test_tutorial/test_fastapi/test_relationships/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_relationships/test_tutorial001.py index 125e001..2ea5e8d 100644 --- a/tests/test_tutorial/test_fastapi/test_relationships/test_tutorial001.py +++ b/tests/test_tutorial/test_fastapi/test_relationships/test_tutorial001.py @@ -2,502 +2,6 @@ from fastapi.testclient import TestClient from sqlmodel import create_engine from sqlmodel.pool import StaticPool -openapi_schema = { - "openapi": "3.0.2", - "info": {"title": "FastAPI", "version": "0.1.0"}, - "paths": { - "/heroes/": { - "get": { - "summary": "Read Heroes", - "operationId": "read_heroes_heroes__get", - "parameters": [ - { - "required": False, - "schema": {"title": "Offset", "type": "integer", "default": 0}, - "name": "offset", - "in": "query", - }, - { - "required": False, - "schema": { - "title": "Limit", - "type": "integer", - "default": 100, - "lte": 100, - }, - "name": "limit", - "in": "query", - }, - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "title": "Response Read Heroes Heroes Get", - "type": "array", - "items": {"$ref": "#/components/schemas/HeroRead"}, - } - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - "post": { - "summary": "Create Hero", - "operationId": "create_hero_heroes__post", - "requestBody": { - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroCreate"} - } - }, - "required": True, - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroRead"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - }, - "/heroes/{hero_id}": { - "get": { - "summary": "Read Hero", - "operationId": "read_hero_heroes__hero_id__get", - "parameters": [ - { - "required": True, - "schema": {"title": "Hero Id", "type": "integer"}, - "name": "hero_id", - "in": "path", - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HeroReadWithTeam" - } - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - "delete": { - "summary": "Delete Hero", - "operationId": "delete_hero_heroes__hero_id__delete", - "parameters": [ - { - "required": True, - "schema": {"title": "Hero Id", "type": "integer"}, - "name": "hero_id", - "in": "path", - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": {"application/json": {"schema": {}}}, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - "patch": { - "summary": "Update Hero", - "operationId": "update_hero_heroes__hero_id__patch", - "parameters": [ - { - "required": True, - "schema": {"title": "Hero Id", "type": "integer"}, - "name": "hero_id", - "in": "path", - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroUpdate"} - } - }, - "required": True, - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroRead"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - }, - "/teams/": { - "get": { - "summary": "Read Teams", - "operationId": "read_teams_teams__get", - "parameters": [ - { - "required": False, - "schema": {"title": "Offset", "type": "integer", "default": 0}, - "name": "offset", - "in": "query", - }, - { - "required": False, - "schema": { - "title": "Limit", - "type": "integer", - "default": 100, - "lte": 100, - }, - "name": "limit", - "in": "query", - }, - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "title": "Response Read Teams Teams Get", - "type": "array", - "items": {"$ref": "#/components/schemas/TeamRead"}, - } - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - "post": { - "summary": "Create Team", - "operationId": "create_team_teams__post", - "requestBody": { - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/TeamCreate"} - } - }, - "required": True, - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/TeamRead"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - }, - "/teams/{team_id}": { - "get": { - "summary": "Read Team", - "operationId": "read_team_teams__team_id__get", - "parameters": [ - { - "required": True, - "schema": {"title": "Team Id", "type": "integer"}, - "name": "team_id", - "in": "path", - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TeamReadWithHeroes" - } - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - "delete": { - "summary": "Delete Team", - "operationId": "delete_team_teams__team_id__delete", - "parameters": [ - { - "required": True, - "schema": {"title": "Team Id", "type": "integer"}, - "name": "team_id", - "in": "path", - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": {"application/json": {"schema": {}}}, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - "patch": { - "summary": "Update Team", - "operationId": "update_team_teams__team_id__patch", - "parameters": [ - { - "required": True, - "schema": {"title": "Team Id", "type": "integer"}, - "name": "team_id", - "in": "path", - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/TeamUpdate"} - } - }, - "required": True, - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/TeamRead"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - }, - }, - "components": { - "schemas": { - "HTTPValidationError": { - "title": "HTTPValidationError", - "type": "object", - "properties": { - "detail": { - "title": "Detail", - "type": "array", - "items": {"$ref": "#/components/schemas/ValidationError"}, - } - }, - }, - "HeroCreate": { - "title": "HeroCreate", - "required": ["name", "secret_name"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "secret_name": {"title": "Secret Name", "type": "string"}, - "age": {"title": "Age", "type": "integer"}, - "team_id": {"title": "Team Id", "type": "integer"}, - }, - }, - "HeroRead": { - "title": "HeroRead", - "required": ["name", "secret_name", "id"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "secret_name": {"title": "Secret Name", "type": "string"}, - "age": {"title": "Age", "type": "integer"}, - "team_id": {"title": "Team Id", "type": "integer"}, - "id": {"title": "Id", "type": "integer"}, - }, - }, - "HeroReadWithTeam": { - "title": "HeroReadWithTeam", - "required": ["name", "secret_name", "id"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "secret_name": {"title": "Secret Name", "type": "string"}, - "age": {"title": "Age", "type": "integer"}, - "team_id": {"title": "Team Id", "type": "integer"}, - "id": {"title": "Id", "type": "integer"}, - "team": {"$ref": "#/components/schemas/TeamRead"}, - }, - }, - "HeroUpdate": { - "title": "HeroUpdate", - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "secret_name": {"title": "Secret Name", "type": "string"}, - "age": {"title": "Age", "type": "integer"}, - "team_id": {"title": "Team Id", "type": "integer"}, - }, - }, - "TeamCreate": { - "title": "TeamCreate", - "required": ["name", "headquarters"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "headquarters": {"title": "Headquarters", "type": "string"}, - }, - }, - "TeamRead": { - "title": "TeamRead", - "required": ["name", "headquarters", "id"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "headquarters": {"title": "Headquarters", "type": "string"}, - "id": {"title": "Id", "type": "integer"}, - }, - }, - "TeamReadWithHeroes": { - "title": "TeamReadWithHeroes", - "required": ["name", "headquarters", "id"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "headquarters": {"title": "Headquarters", "type": "string"}, - "id": {"title": "Id", "type": "integer"}, - "heroes": { - "title": "Heroes", - "type": "array", - "items": {"$ref": "#/components/schemas/HeroRead"}, - "default": [], - }, - }, - }, - "TeamUpdate": { - "title": "TeamUpdate", - "type": "object", - "properties": { - "id": {"title": "Id", "type": "integer"}, - "name": {"title": "Name", "type": "string"}, - "headquarters": {"title": "Headquarters", "type": "string"}, - }, - }, - "ValidationError": { - "title": "ValidationError", - "required": ["loc", "msg", "type"], - "type": "object", - "properties": { - "loc": { - "title": "Location", - "type": "array", - "items": {"type": "string"}, - }, - "msg": {"title": "Message", "type": "string"}, - "type": {"title": "Error Type", "type": "string"}, - }, - }, - } - }, -} - def test_tutorial(clear_sqlmodel): from docs_src.tutorial.fastapi.relationships import tutorial001 as mod @@ -508,11 +12,6 @@ def test_tutorial(clear_sqlmodel): ) with TestClient(mod.app) as client: - response = client.get("/openapi.json") - data = response.json() - assert response.status_code == 200, response.text - assert data == openapi_schema - team_preventers = {"name": "Preventers", "headquarters": "Sharp Tower"} team_z_force = {"name": "Z-Force", "headquarters": "Sister Margaret’s Bar"} response = client.post("/teams/", json=team_preventers) @@ -604,3 +103,532 @@ def test_tutorial(clear_sqlmodel): assert response.status_code == 200, response.text data = response.json() assert len(data) == 1 + + response = client.get("/openapi.json") + data = response.json() + assert response.status_code == 200, response.text + assert data == { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/heroes/": { + "get": { + "summary": "Read Heroes", + "operationId": "read_heroes_heroes__get", + "parameters": [ + { + "required": False, + "schema": { + "title": "Offset", + "type": "integer", + "default": 0, + }, + "name": "offset", + "in": "query", + }, + { + "required": False, + "schema": { + "title": "Limit", + "type": "integer", + "default": 100, + "lte": 100, + }, + "name": "limit", + "in": "query", + }, + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Read Heroes Heroes Get", + "type": "array", + "items": { + "$ref": "#/components/schemas/HeroRead" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + "post": { + "summary": "Create Hero", + "operationId": "create_hero_heroes__post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroCreate" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroRead" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + }, + "/heroes/{hero_id}": { + "get": { + "summary": "Read Hero", + "operationId": "read_hero_heroes__hero_id__get", + "parameters": [ + { + "required": True, + "schema": {"title": "Hero Id", "type": "integer"}, + "name": "hero_id", + "in": "path", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroReadWithTeam" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + "delete": { + "summary": "Delete Hero", + "operationId": "delete_hero_heroes__hero_id__delete", + "parameters": [ + { + "required": True, + "schema": {"title": "Hero Id", "type": "integer"}, + "name": "hero_id", + "in": "path", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + "patch": { + "summary": "Update Hero", + "operationId": "update_hero_heroes__hero_id__patch", + "parameters": [ + { + "required": True, + "schema": {"title": "Hero Id", "type": "integer"}, + "name": "hero_id", + "in": "path", + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroUpdate" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroRead" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + }, + "/teams/": { + "get": { + "summary": "Read Teams", + "operationId": "read_teams_teams__get", + "parameters": [ + { + "required": False, + "schema": { + "title": "Offset", + "type": "integer", + "default": 0, + }, + "name": "offset", + "in": "query", + }, + { + "required": False, + "schema": { + "title": "Limit", + "type": "integer", + "default": 100, + "lte": 100, + }, + "name": "limit", + "in": "query", + }, + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Read Teams Teams Get", + "type": "array", + "items": { + "$ref": "#/components/schemas/TeamRead" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + "post": { + "summary": "Create Team", + "operationId": "create_team_teams__post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamCreate" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamRead" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + }, + "/teams/{team_id}": { + "get": { + "summary": "Read Team", + "operationId": "read_team_teams__team_id__get", + "parameters": [ + { + "required": True, + "schema": {"title": "Team Id", "type": "integer"}, + "name": "team_id", + "in": "path", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamReadWithHeroes" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + "delete": { + "summary": "Delete Team", + "operationId": "delete_team_teams__team_id__delete", + "parameters": [ + { + "required": True, + "schema": {"title": "Team Id", "type": "integer"}, + "name": "team_id", + "in": "path", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + "patch": { + "summary": "Update Team", + "operationId": "update_team_teams__team_id__patch", + "parameters": [ + { + "required": True, + "schema": {"title": "Team Id", "type": "integer"}, + "name": "team_id", + "in": "path", + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamUpdate" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamRead" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + }, + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": { + "$ref": "#/components/schemas/ValidationError" + }, + } + }, + }, + "HeroCreate": { + "title": "HeroCreate", + "required": ["name", "secret_name"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "secret_name": {"title": "Secret Name", "type": "string"}, + "age": {"title": "Age", "type": "integer"}, + "team_id": {"title": "Team Id", "type": "integer"}, + }, + }, + "HeroRead": { + "title": "HeroRead", + "required": ["name", "secret_name", "id"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "secret_name": {"title": "Secret Name", "type": "string"}, + "age": {"title": "Age", "type": "integer"}, + "team_id": {"title": "Team Id", "type": "integer"}, + "id": {"title": "Id", "type": "integer"}, + }, + }, + "HeroReadWithTeam": { + "title": "HeroReadWithTeam", + "required": ["name", "secret_name", "id"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "secret_name": {"title": "Secret Name", "type": "string"}, + "age": {"title": "Age", "type": "integer"}, + "team_id": {"title": "Team Id", "type": "integer"}, + "id": {"title": "Id", "type": "integer"}, + "team": {"$ref": "#/components/schemas/TeamRead"}, + }, + }, + "HeroUpdate": { + "title": "HeroUpdate", + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "secret_name": {"title": "Secret Name", "type": "string"}, + "age": {"title": "Age", "type": "integer"}, + "team_id": {"title": "Team Id", "type": "integer"}, + }, + }, + "TeamCreate": { + "title": "TeamCreate", + "required": ["name", "headquarters"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "headquarters": {"title": "Headquarters", "type": "string"}, + }, + }, + "TeamRead": { + "title": "TeamRead", + "required": ["name", "headquarters", "id"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "headquarters": {"title": "Headquarters", "type": "string"}, + "id": {"title": "Id", "type": "integer"}, + }, + }, + "TeamReadWithHeroes": { + "title": "TeamReadWithHeroes", + "required": ["name", "headquarters", "id"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "headquarters": {"title": "Headquarters", "type": "string"}, + "id": {"title": "Id", "type": "integer"}, + "heroes": { + "title": "Heroes", + "type": "array", + "items": {"$ref": "#/components/schemas/HeroRead"}, + "default": [], + }, + }, + }, + "TeamUpdate": { + "title": "TeamUpdate", + "type": "object", + "properties": { + "id": {"title": "Id", "type": "integer"}, + "name": {"title": "Name", "type": "string"}, + "headquarters": {"title": "Headquarters", "type": "string"}, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } diff --git a/tests/test_tutorial/test_fastapi/test_session_with_dependency/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_session_with_dependency/test_tutorial001.py index 705146c..da87b8e 100644 --- a/tests/test_tutorial/test_fastapi/test_session_with_dependency/test_tutorial001.py +++ b/tests/test_tutorial/test_fastapi/test_session_with_dependency/test_tutorial001.py @@ -2,255 +2,6 @@ from fastapi.testclient import TestClient from sqlmodel import create_engine from sqlmodel.pool import StaticPool -openapi_schema = { - "openapi": "3.0.2", - "info": {"title": "FastAPI", "version": "0.1.0"}, - "paths": { - "/heroes/": { - "get": { - "summary": "Read Heroes", - "operationId": "read_heroes_heroes__get", - "parameters": [ - { - "required": False, - "schema": {"title": "Offset", "type": "integer", "default": 0}, - "name": "offset", - "in": "query", - }, - { - "required": False, - "schema": { - "title": "Limit", - "type": "integer", - "default": 100, - "lte": 100, - }, - "name": "limit", - "in": "query", - }, - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "title": "Response Read Heroes Heroes Get", - "type": "array", - "items": {"$ref": "#/components/schemas/HeroRead"}, - } - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - "post": { - "summary": "Create Hero", - "operationId": "create_hero_heroes__post", - "requestBody": { - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroCreate"} - } - }, - "required": True, - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroRead"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - }, - "/heroes/{hero_id}": { - "get": { - "summary": "Read Hero", - "operationId": "read_hero_heroes__hero_id__get", - "parameters": [ - { - "required": True, - "schema": {"title": "Hero Id", "type": "integer"}, - "name": "hero_id", - "in": "path", - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroRead"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - "delete": { - "summary": "Delete Hero", - "operationId": "delete_hero_heroes__hero_id__delete", - "parameters": [ - { - "required": True, - "schema": {"title": "Hero Id", "type": "integer"}, - "name": "hero_id", - "in": "path", - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": {"application/json": {"schema": {}}}, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - "patch": { - "summary": "Update Hero", - "operationId": "update_hero_heroes__hero_id__patch", - "parameters": [ - { - "required": True, - "schema": {"title": "Hero Id", "type": "integer"}, - "name": "hero_id", - "in": "path", - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroUpdate"} - } - }, - "required": True, - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroRead"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - }, - }, - "components": { - "schemas": { - "HTTPValidationError": { - "title": "HTTPValidationError", - "type": "object", - "properties": { - "detail": { - "title": "Detail", - "type": "array", - "items": {"$ref": "#/components/schemas/ValidationError"}, - } - }, - }, - "HeroCreate": { - "title": "HeroCreate", - "required": ["name", "secret_name"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "secret_name": {"title": "Secret Name", "type": "string"}, - "age": {"title": "Age", "type": "integer"}, - }, - }, - "HeroRead": { - "title": "HeroRead", - "required": ["name", "secret_name", "id"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "secret_name": {"title": "Secret Name", "type": "string"}, - "age": {"title": "Age", "type": "integer"}, - "id": {"title": "Id", "type": "integer"}, - }, - }, - "HeroUpdate": { - "title": "HeroUpdate", - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "secret_name": {"title": "Secret Name", "type": "string"}, - "age": {"title": "Age", "type": "integer"}, - }, - }, - "ValidationError": { - "title": "ValidationError", - "required": ["loc", "msg", "type"], - "type": "object", - "properties": { - "loc": { - "title": "Location", - "type": "array", - "items": {"type": "string"}, - }, - "msg": {"title": "Message", "type": "string"}, - "type": {"title": "Error Type", "type": "string"}, - }, - }, - } - }, -} - def test_tutorial(clear_sqlmodel): from docs_src.tutorial.fastapi.session_with_dependency import tutorial001 as mod @@ -284,10 +35,6 @@ def test_tutorial(clear_sqlmodel): assert response.status_code == 200, response.text response = client.get("/heroes/9000") assert response.status_code == 404, response.text - response = client.get("/openapi.json") - data = response.json() - assert response.status_code == 200, response.text - assert data == openapi_schema response = client.get("/heroes/") assert response.status_code == 200, response.text data = response.json() @@ -308,3 +55,273 @@ def test_tutorial(clear_sqlmodel): response = client.delete("/heroes/9000") assert response.status_code == 404, response.text + + response = client.get("/openapi.json") + data = response.json() + assert response.status_code == 200, response.text + assert data == { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/heroes/": { + "get": { + "summary": "Read Heroes", + "operationId": "read_heroes_heroes__get", + "parameters": [ + { + "required": False, + "schema": { + "title": "Offset", + "type": "integer", + "default": 0, + }, + "name": "offset", + "in": "query", + }, + { + "required": False, + "schema": { + "title": "Limit", + "type": "integer", + "default": 100, + "lte": 100, + }, + "name": "limit", + "in": "query", + }, + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Read Heroes Heroes Get", + "type": "array", + "items": { + "$ref": "#/components/schemas/HeroRead" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + "post": { + "summary": "Create Hero", + "operationId": "create_hero_heroes__post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroCreate" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroRead" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + }, + "/heroes/{hero_id}": { + "get": { + "summary": "Read Hero", + "operationId": "read_hero_heroes__hero_id__get", + "parameters": [ + { + "required": True, + "schema": {"title": "Hero Id", "type": "integer"}, + "name": "hero_id", + "in": "path", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroRead" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + "delete": { + "summary": "Delete Hero", + "operationId": "delete_hero_heroes__hero_id__delete", + "parameters": [ + { + "required": True, + "schema": {"title": "Hero Id", "type": "integer"}, + "name": "hero_id", + "in": "path", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + "patch": { + "summary": "Update Hero", + "operationId": "update_hero_heroes__hero_id__patch", + "parameters": [ + { + "required": True, + "schema": {"title": "Hero Id", "type": "integer"}, + "name": "hero_id", + "in": "path", + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroUpdate" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroRead" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + }, + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": { + "$ref": "#/components/schemas/ValidationError" + }, + } + }, + }, + "HeroCreate": { + "title": "HeroCreate", + "required": ["name", "secret_name"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "secret_name": {"title": "Secret Name", "type": "string"}, + "age": {"title": "Age", "type": "integer"}, + }, + }, + "HeroRead": { + "title": "HeroRead", + "required": ["name", "secret_name", "id"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "secret_name": {"title": "Secret Name", "type": "string"}, + "age": {"title": "Age", "type": "integer"}, + "id": {"title": "Id", "type": "integer"}, + }, + }, + "HeroUpdate": { + "title": "HeroUpdate", + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "secret_name": {"title": "Secret Name", "type": "string"}, + "age": {"title": "Age", "type": "integer"}, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } diff --git a/tests/test_tutorial/test_fastapi/test_teams/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_teams/test_tutorial001.py index 04a4b0c..08be835 100644 --- a/tests/test_tutorial/test_fastapi/test_teams/test_tutorial001.py +++ b/tests/test_tutorial/test_fastapi/test_teams/test_tutorial001.py @@ -2,468 +2,6 @@ from fastapi.testclient import TestClient from sqlmodel import create_engine from sqlmodel.pool import StaticPool -openapi_schema = { - "openapi": "3.0.2", - "info": {"title": "FastAPI", "version": "0.1.0"}, - "paths": { - "/heroes/": { - "get": { - "summary": "Read Heroes", - "operationId": "read_heroes_heroes__get", - "parameters": [ - { - "required": False, - "schema": {"title": "Offset", "type": "integer", "default": 0}, - "name": "offset", - "in": "query", - }, - { - "required": False, - "schema": { - "title": "Limit", - "type": "integer", - "default": 100, - "lte": 100, - }, - "name": "limit", - "in": "query", - }, - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "title": "Response Read Heroes Heroes Get", - "type": "array", - "items": {"$ref": "#/components/schemas/HeroRead"}, - } - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - "post": { - "summary": "Create Hero", - "operationId": "create_hero_heroes__post", - "requestBody": { - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroCreate"} - } - }, - "required": True, - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroRead"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - }, - "/heroes/{hero_id}": { - "get": { - "summary": "Read Hero", - "operationId": "read_hero_heroes__hero_id__get", - "parameters": [ - { - "required": True, - "schema": {"title": "Hero Id", "type": "integer"}, - "name": "hero_id", - "in": "path", - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroRead"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - "delete": { - "summary": "Delete Hero", - "operationId": "delete_hero_heroes__hero_id__delete", - "parameters": [ - { - "required": True, - "schema": {"title": "Hero Id", "type": "integer"}, - "name": "hero_id", - "in": "path", - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": {"application/json": {"schema": {}}}, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - "patch": { - "summary": "Update Hero", - "operationId": "update_hero_heroes__hero_id__patch", - "parameters": [ - { - "required": True, - "schema": {"title": "Hero Id", "type": "integer"}, - "name": "hero_id", - "in": "path", - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroUpdate"} - } - }, - "required": True, - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroRead"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - }, - "/teams/": { - "get": { - "summary": "Read Teams", - "operationId": "read_teams_teams__get", - "parameters": [ - { - "required": False, - "schema": {"title": "Offset", "type": "integer", "default": 0}, - "name": "offset", - "in": "query", - }, - { - "required": False, - "schema": { - "title": "Limit", - "type": "integer", - "default": 100, - "lte": 100, - }, - "name": "limit", - "in": "query", - }, - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "title": "Response Read Teams Teams Get", - "type": "array", - "items": {"$ref": "#/components/schemas/TeamRead"}, - } - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - "post": { - "summary": "Create Team", - "operationId": "create_team_teams__post", - "requestBody": { - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/TeamCreate"} - } - }, - "required": True, - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/TeamRead"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - }, - "/teams/{team_id}": { - "get": { - "summary": "Read Team", - "operationId": "read_team_teams__team_id__get", - "parameters": [ - { - "required": True, - "schema": {"title": "Team Id", "type": "integer"}, - "name": "team_id", - "in": "path", - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/TeamRead"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - "delete": { - "summary": "Delete Team", - "operationId": "delete_team_teams__team_id__delete", - "parameters": [ - { - "required": True, - "schema": {"title": "Team Id", "type": "integer"}, - "name": "team_id", - "in": "path", - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": {"application/json": {"schema": {}}}, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - "patch": { - "summary": "Update Team", - "operationId": "update_team_teams__team_id__patch", - "parameters": [ - { - "required": True, - "schema": {"title": "Team Id", "type": "integer"}, - "name": "team_id", - "in": "path", - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/TeamUpdate"} - } - }, - "required": True, - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/TeamRead"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - }, - }, - "components": { - "schemas": { - "HTTPValidationError": { - "title": "HTTPValidationError", - "type": "object", - "properties": { - "detail": { - "title": "Detail", - "type": "array", - "items": {"$ref": "#/components/schemas/ValidationError"}, - } - }, - }, - "HeroCreate": { - "title": "HeroCreate", - "required": ["name", "secret_name"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "secret_name": {"title": "Secret Name", "type": "string"}, - "age": {"title": "Age", "type": "integer"}, - "team_id": {"title": "Team Id", "type": "integer"}, - }, - }, - "HeroRead": { - "title": "HeroRead", - "required": ["name", "secret_name", "id"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "secret_name": {"title": "Secret Name", "type": "string"}, - "age": {"title": "Age", "type": "integer"}, - "team_id": {"title": "Team Id", "type": "integer"}, - "id": {"title": "Id", "type": "integer"}, - }, - }, - "HeroUpdate": { - "title": "HeroUpdate", - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "secret_name": {"title": "Secret Name", "type": "string"}, - "age": {"title": "Age", "type": "integer"}, - "team_id": {"title": "Team Id", "type": "integer"}, - }, - }, - "TeamCreate": { - "title": "TeamCreate", - "required": ["name", "headquarters"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "headquarters": {"title": "Headquarters", "type": "string"}, - }, - }, - "TeamRead": { - "title": "TeamRead", - "required": ["name", "headquarters", "id"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "headquarters": {"title": "Headquarters", "type": "string"}, - "id": {"title": "Id", "type": "integer"}, - }, - }, - "TeamUpdate": { - "title": "TeamUpdate", - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "headquarters": {"title": "Headquarters", "type": "string"}, - }, - }, - "ValidationError": { - "title": "ValidationError", - "required": ["loc", "msg", "type"], - "type": "object", - "properties": { - "loc": { - "title": "Location", - "type": "array", - "items": {"type": "string"}, - }, - "msg": {"title": "Message", "type": "string"}, - "type": {"title": "Error Type", "type": "string"}, - }, - }, - } - }, -} - def test_tutorial(clear_sqlmodel): from docs_src.tutorial.fastapi.teams import tutorial001 as mod @@ -485,10 +23,6 @@ def test_tutorial(clear_sqlmodel): "secret_name": "Tommy Sharp", "age": 48, } - response = client.get("/openapi.json") - data = response.json() - assert response.status_code == 200, response.text - assert data == openapi_schema response = client.post("/heroes/", json=hero1_data) assert response.status_code == 200, response.text response = client.post("/heroes/", json=hero2_data) @@ -556,3 +90,502 @@ def test_tutorial(clear_sqlmodel): assert response.status_code == 200, response.text data = response.json() assert len(data) == 1 + + response = client.get("/openapi.json") + data = response.json() + assert response.status_code == 200, response.text + assert data == { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/heroes/": { + "get": { + "summary": "Read Heroes", + "operationId": "read_heroes_heroes__get", + "parameters": [ + { + "required": False, + "schema": { + "title": "Offset", + "type": "integer", + "default": 0, + }, + "name": "offset", + "in": "query", + }, + { + "required": False, + "schema": { + "title": "Limit", + "type": "integer", + "default": 100, + "lte": 100, + }, + "name": "limit", + "in": "query", + }, + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Read Heroes Heroes Get", + "type": "array", + "items": { + "$ref": "#/components/schemas/HeroRead" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + "post": { + "summary": "Create Hero", + "operationId": "create_hero_heroes__post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroCreate" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroRead" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + }, + "/heroes/{hero_id}": { + "get": { + "summary": "Read Hero", + "operationId": "read_hero_heroes__hero_id__get", + "parameters": [ + { + "required": True, + "schema": {"title": "Hero Id", "type": "integer"}, + "name": "hero_id", + "in": "path", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroRead" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + "delete": { + "summary": "Delete Hero", + "operationId": "delete_hero_heroes__hero_id__delete", + "parameters": [ + { + "required": True, + "schema": {"title": "Hero Id", "type": "integer"}, + "name": "hero_id", + "in": "path", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + "patch": { + "summary": "Update Hero", + "operationId": "update_hero_heroes__hero_id__patch", + "parameters": [ + { + "required": True, + "schema": {"title": "Hero Id", "type": "integer"}, + "name": "hero_id", + "in": "path", + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroUpdate" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroRead" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + }, + "/teams/": { + "get": { + "summary": "Read Teams", + "operationId": "read_teams_teams__get", + "parameters": [ + { + "required": False, + "schema": { + "title": "Offset", + "type": "integer", + "default": 0, + }, + "name": "offset", + "in": "query", + }, + { + "required": False, + "schema": { + "title": "Limit", + "type": "integer", + "default": 100, + "lte": 100, + }, + "name": "limit", + "in": "query", + }, + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Read Teams Teams Get", + "type": "array", + "items": { + "$ref": "#/components/schemas/TeamRead" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + "post": { + "summary": "Create Team", + "operationId": "create_team_teams__post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamCreate" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamRead" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + }, + "/teams/{team_id}": { + "get": { + "summary": "Read Team", + "operationId": "read_team_teams__team_id__get", + "parameters": [ + { + "required": True, + "schema": {"title": "Team Id", "type": "integer"}, + "name": "team_id", + "in": "path", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamRead" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + "delete": { + "summary": "Delete Team", + "operationId": "delete_team_teams__team_id__delete", + "parameters": [ + { + "required": True, + "schema": {"title": "Team Id", "type": "integer"}, + "name": "team_id", + "in": "path", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + "patch": { + "summary": "Update Team", + "operationId": "update_team_teams__team_id__patch", + "parameters": [ + { + "required": True, + "schema": {"title": "Team Id", "type": "integer"}, + "name": "team_id", + "in": "path", + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamUpdate" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamRead" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + }, + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": { + "$ref": "#/components/schemas/ValidationError" + }, + } + }, + }, + "HeroCreate": { + "title": "HeroCreate", + "required": ["name", "secret_name"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "secret_name": {"title": "Secret Name", "type": "string"}, + "age": {"title": "Age", "type": "integer"}, + "team_id": {"title": "Team Id", "type": "integer"}, + }, + }, + "HeroRead": { + "title": "HeroRead", + "required": ["name", "secret_name", "id"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "secret_name": {"title": "Secret Name", "type": "string"}, + "age": {"title": "Age", "type": "integer"}, + "team_id": {"title": "Team Id", "type": "integer"}, + "id": {"title": "Id", "type": "integer"}, + }, + }, + "HeroUpdate": { + "title": "HeroUpdate", + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "secret_name": {"title": "Secret Name", "type": "string"}, + "age": {"title": "Age", "type": "integer"}, + "team_id": {"title": "Team Id", "type": "integer"}, + }, + }, + "TeamCreate": { + "title": "TeamCreate", + "required": ["name", "headquarters"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "headquarters": {"title": "Headquarters", "type": "string"}, + }, + }, + "TeamRead": { + "title": "TeamRead", + "required": ["name", "headquarters", "id"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "headquarters": {"title": "Headquarters", "type": "string"}, + "id": {"title": "Id", "type": "integer"}, + }, + }, + "TeamUpdate": { + "title": "TeamUpdate", + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "headquarters": {"title": "Headquarters", "type": "string"}, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } diff --git a/tests/test_tutorial/test_fastapi/test_update/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_update/test_tutorial001.py index ec75a2f..7f48780 100644 --- a/tests/test_tutorial/test_fastapi/test_update/test_tutorial001.py +++ b/tests/test_tutorial/test_fastapi/test_update/test_tutorial001.py @@ -2,227 +2,6 @@ from fastapi.testclient import TestClient from sqlmodel import create_engine from sqlmodel.pool import StaticPool -openapi_schema = { - "openapi": "3.0.2", - "info": {"title": "FastAPI", "version": "0.1.0"}, - "paths": { - "/heroes/": { - "get": { - "summary": "Read Heroes", - "operationId": "read_heroes_heroes__get", - "parameters": [ - { - "required": False, - "schema": {"title": "Offset", "type": "integer", "default": 0}, - "name": "offset", - "in": "query", - }, - { - "required": False, - "schema": { - "title": "Limit", - "type": "integer", - "default": 100, - "lte": 100, - }, - "name": "limit", - "in": "query", - }, - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "title": "Response Read Heroes Heroes Get", - "type": "array", - "items": {"$ref": "#/components/schemas/HeroRead"}, - } - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - "post": { - "summary": "Create Hero", - "operationId": "create_hero_heroes__post", - "requestBody": { - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroCreate"} - } - }, - "required": True, - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroRead"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - }, - "/heroes/{hero_id}": { - "get": { - "summary": "Read Hero", - "operationId": "read_hero_heroes__hero_id__get", - "parameters": [ - { - "required": True, - "schema": {"title": "Hero Id", "type": "integer"}, - "name": "hero_id", - "in": "path", - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroRead"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - "patch": { - "summary": "Update Hero", - "operationId": "update_hero_heroes__hero_id__patch", - "parameters": [ - { - "required": True, - "schema": {"title": "Hero Id", "type": "integer"}, - "name": "hero_id", - "in": "path", - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroUpdate"} - } - }, - "required": True, - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/HeroRead"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - }, - }, - "components": { - "schemas": { - "HTTPValidationError": { - "title": "HTTPValidationError", - "type": "object", - "properties": { - "detail": { - "title": "Detail", - "type": "array", - "items": {"$ref": "#/components/schemas/ValidationError"}, - } - }, - }, - "HeroCreate": { - "title": "HeroCreate", - "required": ["name", "secret_name"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "secret_name": {"title": "Secret Name", "type": "string"}, - "age": {"title": "Age", "type": "integer"}, - }, - }, - "HeroRead": { - "title": "HeroRead", - "required": ["name", "secret_name", "id"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "secret_name": {"title": "Secret Name", "type": "string"}, - "age": {"title": "Age", "type": "integer"}, - "id": {"title": "Id", "type": "integer"}, - }, - }, - "HeroUpdate": { - "title": "HeroUpdate", - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "secret_name": {"title": "Secret Name", "type": "string"}, - "age": {"title": "Age", "type": "integer"}, - }, - }, - "ValidationError": { - "title": "ValidationError", - "required": ["loc", "msg", "type"], - "type": "object", - "properties": { - "loc": { - "title": "Location", - "type": "array", - "items": {"type": "string"}, - }, - "msg": {"title": "Message", "type": "string"}, - "type": {"title": "Error Type", "type": "string"}, - }, - }, - } - }, -} - def test_tutorial(clear_sqlmodel): from docs_src.tutorial.fastapi.update import tutorial001 as mod @@ -258,10 +37,6 @@ def test_tutorial(clear_sqlmodel): assert response.status_code == 200, response.text response = client.get("/heroes/9000") assert response.status_code == 404, response.text - response = client.get("/openapi.json") - data = response.json() - assert response.status_code == 200, response.text - assert data == openapi_schema response = client.get("/heroes/") assert response.status_code == 200, response.text data = response.json() @@ -287,3 +62,245 @@ def test_tutorial(clear_sqlmodel): response = client.patch("/heroes/9001", json={"name": "Dragon Cube X"}) assert response.status_code == 404, response.text + + response = client.get("/openapi.json") + data = response.json() + assert response.status_code == 200, response.text + assert data == { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/heroes/": { + "get": { + "summary": "Read Heroes", + "operationId": "read_heroes_heroes__get", + "parameters": [ + { + "required": False, + "schema": { + "title": "Offset", + "type": "integer", + "default": 0, + }, + "name": "offset", + "in": "query", + }, + { + "required": False, + "schema": { + "title": "Limit", + "type": "integer", + "default": 100, + "lte": 100, + }, + "name": "limit", + "in": "query", + }, + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Read Heroes Heroes Get", + "type": "array", + "items": { + "$ref": "#/components/schemas/HeroRead" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + "post": { + "summary": "Create Hero", + "operationId": "create_hero_heroes__post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroCreate" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroRead" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + }, + "/heroes/{hero_id}": { + "get": { + "summary": "Read Hero", + "operationId": "read_hero_heroes__hero_id__get", + "parameters": [ + { + "required": True, + "schema": {"title": "Hero Id", "type": "integer"}, + "name": "hero_id", + "in": "path", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroRead" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + "patch": { + "summary": "Update Hero", + "operationId": "update_hero_heroes__hero_id__patch", + "parameters": [ + { + "required": True, + "schema": {"title": "Hero Id", "type": "integer"}, + "name": "hero_id", + "in": "path", + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroUpdate" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeroRead" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + }, + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": { + "$ref": "#/components/schemas/ValidationError" + }, + } + }, + }, + "HeroCreate": { + "title": "HeroCreate", + "required": ["name", "secret_name"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "secret_name": {"title": "Secret Name", "type": "string"}, + "age": {"title": "Age", "type": "integer"}, + }, + }, + "HeroRead": { + "title": "HeroRead", + "required": ["name", "secret_name", "id"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "secret_name": {"title": "Secret Name", "type": "string"}, + "age": {"title": "Age", "type": "integer"}, + "id": {"title": "Id", "type": "integer"}, + }, + }, + "HeroUpdate": { + "title": "HeroUpdate", + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "secret_name": {"title": "Secret Name", "type": "string"}, + "age": {"title": "Age", "type": "integer"}, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } From beb7a242758257f2cd6605a52bdcdab1ce9e34e5 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Oct 2023 15:33:44 +0000 Subject: [PATCH 58/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 14d5e9c..979b3a6 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* βœ… Refactor OpenAPI FastAPI tests to simplify updating them later, this moves things around without changes. PR [#671](https://github.com/tiangolo/sqlmodel/pull/671) by [@tiangolo](https://github.com/tiangolo). * ⬆ Bump actions/checkout from 3 to 4. PR [#670](https://github.com/tiangolo/sqlmodel/pull/670) by [@dependabot[bot]](https://github.com/apps/dependabot). * πŸ”§ Update mypy config, use `strict = true` instead of manual configs. PR [#428](https://github.com/tiangolo/sqlmodel/pull/428) by [@michaeloliverx](https://github.com/michaeloliverx). * πŸ› Fix `AsyncSession` type annotations for `exec()`. PR [#58](https://github.com/tiangolo/sqlmodel/pull/58) by [@Bobronium](https://github.com/Bobronium). From d192142eb9e83d52c3cb5bd7d5bcba93d40cb41c Mon Sep 17 00:00:00 2001 From: Jerry Wu Date: Tue, 24 Oct 2023 00:28:51 +0800 Subject: [PATCH 59/85] =?UTF-8?q?=F0=9F=93=9D=20Fix=20docs=20for=20Pydanti?= =?UTF-8?q?c's=20fields=20using=20`le`=20(`lte`=20is=20invalid,=20use=20`l?= =?UTF-8?q?e`=20)=20(#207)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SebastiΓ‘n RamΓ­rez --- docs/tutorial/fastapi/limit-and-offset.md | 2 +- docs_src/tutorial/fastapi/app_testing/tutorial001/main.py | 2 +- docs_src/tutorial/fastapi/delete/tutorial001.py | 2 +- docs_src/tutorial/fastapi/limit_and_offset/tutorial001.py | 2 +- docs_src/tutorial/fastapi/relationships/tutorial001.py | 4 ++-- .../fastapi/session_with_dependency/tutorial001.py | 2 +- docs_src/tutorial/fastapi/teams/tutorial001.py | 4 ++-- docs_src/tutorial/fastapi/update/tutorial001.py | 2 +- .../test_fastapi/test_delete/test_tutorial001.py | 5 ++--- .../test_fastapi/test_limit_and_offset/test_tutorial001.py | 5 ++--- .../test_fastapi/test_relationships/test_tutorial001.py | 7 +++---- .../test_session_with_dependency/test_tutorial001.py | 5 ++--- .../test_fastapi/test_teams/test_tutorial001.py | 7 +++---- .../test_fastapi/test_update/test_tutorial001.py | 5 ++--- 14 files changed, 24 insertions(+), 30 deletions(-) diff --git a/docs/tutorial/fastapi/limit-and-offset.md b/docs/tutorial/fastapi/limit-and-offset.md index 92bbfc7..8802f4e 100644 --- a/docs/tutorial/fastapi/limit-and-offset.md +++ b/docs/tutorial/fastapi/limit-and-offset.md @@ -42,7 +42,7 @@ We want to allow clients to set different `offset` and `limit` values. But we don't want them to be able to set a `limit` of something like `9999`, that's over `9000`! 😱 -So, to prevent it, we add additional validation to the `limit` query parameter, declaring that it has to be **l**ess **t**han or **e**qual to `100` with `lte=100`. +So, to prevent it, we add additional validation to the `limit` query parameter, declaring that it has to be **l**ess than or **e**qual to `100` with `le=100`. This way, a client can decide to take fewer heroes if they want, but not more. diff --git a/docs_src/tutorial/fastapi/app_testing/tutorial001/main.py b/docs_src/tutorial/fastapi/app_testing/tutorial001/main.py index d106c4e..3f0602e 100644 --- a/docs_src/tutorial/fastapi/app_testing/tutorial001/main.py +++ b/docs_src/tutorial/fastapi/app_testing/tutorial001/main.py @@ -66,7 +66,7 @@ def read_heroes( *, session: Session = Depends(get_session), offset: int = 0, - limit: int = Query(default=100, lte=100), + limit: int = Query(default=100, le=100), ): heroes = session.exec(select(Hero).offset(offset).limit(limit)).all() return heroes diff --git a/docs_src/tutorial/fastapi/delete/tutorial001.py b/docs_src/tutorial/fastapi/delete/tutorial001.py index 3c15efb..3069fc5 100644 --- a/docs_src/tutorial/fastapi/delete/tutorial001.py +++ b/docs_src/tutorial/fastapi/delete/tutorial001.py @@ -58,7 +58,7 @@ def create_hero(hero: HeroCreate): @app.get("/heroes/", response_model=List[HeroRead]) -def read_heroes(offset: int = 0, limit: int = Query(default=100, lte=100)): +def read_heroes(offset: int = 0, limit: int = Query(default=100, le=100)): with Session(engine) as session: heroes = session.exec(select(Hero).offset(offset).limit(limit)).all() return heroes diff --git a/docs_src/tutorial/fastapi/limit_and_offset/tutorial001.py b/docs_src/tutorial/fastapi/limit_and_offset/tutorial001.py index aef2133..2b8739c 100644 --- a/docs_src/tutorial/fastapi/limit_and_offset/tutorial001.py +++ b/docs_src/tutorial/fastapi/limit_and_offset/tutorial001.py @@ -52,7 +52,7 @@ def create_hero(hero: HeroCreate): @app.get("/heroes/", response_model=List[HeroRead]) -def read_heroes(offset: int = 0, limit: int = Query(default=100, lte=100)): +def read_heroes(offset: int = 0, limit: int = Query(default=100, le=100)): with Session(engine) as session: heroes = session.exec(select(Hero).offset(offset).limit(limit)).all() return heroes diff --git a/docs_src/tutorial/fastapi/relationships/tutorial001.py b/docs_src/tutorial/fastapi/relationships/tutorial001.py index 6a03846..8477e4a 100644 --- a/docs_src/tutorial/fastapi/relationships/tutorial001.py +++ b/docs_src/tutorial/fastapi/relationships/tutorial001.py @@ -104,7 +104,7 @@ def read_heroes( *, session: Session = Depends(get_session), offset: int = 0, - limit: int = Query(default=100, lte=100), + limit: int = Query(default=100, le=100), ): heroes = session.exec(select(Hero).offset(offset).limit(limit)).all() return heroes @@ -158,7 +158,7 @@ def read_teams( *, session: Session = Depends(get_session), offset: int = 0, - limit: int = Query(default=100, lte=100), + limit: int = Query(default=100, le=100), ): teams = session.exec(select(Team).offset(offset).limit(limit)).all() return teams diff --git a/docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py b/docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py index d106c4e..3f0602e 100644 --- a/docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py +++ b/docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py @@ -66,7 +66,7 @@ def read_heroes( *, session: Session = Depends(get_session), offset: int = 0, - limit: int = Query(default=100, lte=100), + limit: int = Query(default=100, le=100), ): heroes = session.exec(select(Hero).offset(offset).limit(limit)).all() return heroes diff --git a/docs_src/tutorial/fastapi/teams/tutorial001.py b/docs_src/tutorial/fastapi/teams/tutorial001.py index 6f84182..1da0dad 100644 --- a/docs_src/tutorial/fastapi/teams/tutorial001.py +++ b/docs_src/tutorial/fastapi/teams/tutorial001.py @@ -95,7 +95,7 @@ def read_heroes( *, session: Session = Depends(get_session), offset: int = 0, - limit: int = Query(default=100, lte=100), + limit: int = Query(default=100, le=100), ): heroes = session.exec(select(Hero).offset(offset).limit(limit)).all() return heroes @@ -149,7 +149,7 @@ def read_teams( *, session: Session = Depends(get_session), offset: int = 0, - limit: int = Query(default=100, lte=100), + limit: int = Query(default=100, le=100), ): teams = session.exec(select(Team).offset(offset).limit(limit)).all() return teams diff --git a/docs_src/tutorial/fastapi/update/tutorial001.py b/docs_src/tutorial/fastapi/update/tutorial001.py index 3555487..bb98efd 100644 --- a/docs_src/tutorial/fastapi/update/tutorial001.py +++ b/docs_src/tutorial/fastapi/update/tutorial001.py @@ -58,7 +58,7 @@ def create_hero(hero: HeroCreate): @app.get("/heroes/", response_model=List[HeroRead]) -def read_heroes(offset: int = 0, limit: int = Query(default=100, lte=100)): +def read_heroes(offset: int = 0, limit: int = Query(default=100, le=100)): with Session(engine) as session: heroes = session.exec(select(Hero).offset(offset).limit(limit)).all() return heroes diff --git a/tests/test_tutorial/test_fastapi/test_delete/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_delete/test_tutorial001.py index 8979245..b08affb 100644 --- a/tests/test_tutorial/test_fastapi/test_delete/test_tutorial001.py +++ b/tests/test_tutorial/test_fastapi/test_delete/test_tutorial001.py @@ -57,9 +57,8 @@ def test_tutorial(clear_sqlmodel): assert response.status_code == 404, response.text response = client.get("/openapi.json") - data = response.json() assert response.status_code == 200, response.text - assert data == { + assert response.json() == { "openapi": "3.0.2", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { @@ -82,9 +81,9 @@ def test_tutorial(clear_sqlmodel): "required": False, "schema": { "title": "Limit", + "maximum": 100.0, "type": "integer", "default": 100, - "lte": 100, }, "name": "limit", "in": "query", diff --git a/tests/test_tutorial/test_fastapi/test_limit_and_offset/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_limit_and_offset/test_tutorial001.py index d7f642a..0aee3ca 100644 --- a/tests/test_tutorial/test_fastapi/test_limit_and_offset/test_tutorial001.py +++ b/tests/test_tutorial/test_fastapi/test_limit_and_offset/test_tutorial001.py @@ -62,9 +62,8 @@ def test_tutorial(clear_sqlmodel): assert data[0]["name"] == hero2_data["name"] response = client.get("/openapi.json") - data = response.json() assert response.status_code == 200, response.text - assert data == { + assert response.json() == { "openapi": "3.0.2", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { @@ -87,9 +86,9 @@ def test_tutorial(clear_sqlmodel): "required": False, "schema": { "title": "Limit", + "maximum": 100.0, "type": "integer", "default": 100, - "lte": 100, }, "name": "limit", "in": "query", diff --git a/tests/test_tutorial/test_fastapi/test_relationships/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_relationships/test_tutorial001.py index 2ea5e8d..8869862 100644 --- a/tests/test_tutorial/test_fastapi/test_relationships/test_tutorial001.py +++ b/tests/test_tutorial/test_fastapi/test_relationships/test_tutorial001.py @@ -105,9 +105,8 @@ def test_tutorial(clear_sqlmodel): assert len(data) == 1 response = client.get("/openapi.json") - data = response.json() assert response.status_code == 200, response.text - assert data == { + assert response.json() == { "openapi": "3.0.2", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { @@ -130,9 +129,9 @@ def test_tutorial(clear_sqlmodel): "required": False, "schema": { "title": "Limit", + "maximum": 100.0, "type": "integer", "default": 100, - "lte": 100, }, "name": "limit", "in": "query", @@ -329,9 +328,9 @@ def test_tutorial(clear_sqlmodel): "required": False, "schema": { "title": "Limit", + "maximum": 100.0, "type": "integer", "default": 100, - "lte": 100, }, "name": "limit", "in": "query", diff --git a/tests/test_tutorial/test_fastapi/test_session_with_dependency/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_session_with_dependency/test_tutorial001.py index da87b8e..cb0a6f9 100644 --- a/tests/test_tutorial/test_fastapi/test_session_with_dependency/test_tutorial001.py +++ b/tests/test_tutorial/test_fastapi/test_session_with_dependency/test_tutorial001.py @@ -57,9 +57,8 @@ def test_tutorial(clear_sqlmodel): assert response.status_code == 404, response.text response = client.get("/openapi.json") - data = response.json() assert response.status_code == 200, response.text - assert data == { + assert response.json() == { "openapi": "3.0.2", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { @@ -82,9 +81,9 @@ def test_tutorial(clear_sqlmodel): "required": False, "schema": { "title": "Limit", + "maximum": 100.0, "type": "integer", "default": 100, - "lte": 100, }, "name": "limit", "in": "query", diff --git a/tests/test_tutorial/test_fastapi/test_teams/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_teams/test_tutorial001.py index 08be835..e66c975 100644 --- a/tests/test_tutorial/test_fastapi/test_teams/test_tutorial001.py +++ b/tests/test_tutorial/test_fastapi/test_teams/test_tutorial001.py @@ -92,9 +92,8 @@ def test_tutorial(clear_sqlmodel): assert len(data) == 1 response = client.get("/openapi.json") - data = response.json() assert response.status_code == 200, response.text - assert data == { + assert response.json() == { "openapi": "3.0.2", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { @@ -117,9 +116,9 @@ def test_tutorial(clear_sqlmodel): "required": False, "schema": { "title": "Limit", + "maximum": 100.0, "type": "integer", "default": 100, - "lte": 100, }, "name": "limit", "in": "query", @@ -316,9 +315,9 @@ def test_tutorial(clear_sqlmodel): "required": False, "schema": { "title": "Limit", + "maximum": 100.0, "type": "integer", "default": 100, - "lte": 100, }, "name": "limit", "in": "query", diff --git a/tests/test_tutorial/test_fastapi/test_update/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_update/test_tutorial001.py index 7f48780..4990625 100644 --- a/tests/test_tutorial/test_fastapi/test_update/test_tutorial001.py +++ b/tests/test_tutorial/test_fastapi/test_update/test_tutorial001.py @@ -64,9 +64,8 @@ def test_tutorial(clear_sqlmodel): assert response.status_code == 404, response.text response = client.get("/openapi.json") - data = response.json() assert response.status_code == 200, response.text - assert data == { + assert response.json() == { "openapi": "3.0.2", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { @@ -89,9 +88,9 @@ def test_tutorial(clear_sqlmodel): "required": False, "schema": { "title": "Limit", + "maximum": 100.0, "type": "integer", "default": 100, - "lte": 100, }, "name": "limit", "in": "query", From a1caaa08d743700e0185996e6d203f72e61e949d Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Oct 2023 16:29:36 +0000 Subject: [PATCH 60/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 979b3a6..2283b21 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ“ Fix docs for Pydantic's fields using `le` (`lte` is invalid, use `le` ). PR [#207](https://github.com/tiangolo/sqlmodel/pull/207) by [@jrycw](https://github.com/jrycw). * βœ… Refactor OpenAPI FastAPI tests to simplify updating them later, this moves things around without changes. PR [#671](https://github.com/tiangolo/sqlmodel/pull/671) by [@tiangolo](https://github.com/tiangolo). * ⬆ Bump actions/checkout from 3 to 4. PR [#670](https://github.com/tiangolo/sqlmodel/pull/670) by [@dependabot[bot]](https://github.com/apps/dependabot). * πŸ”§ Update mypy config, use `strict = true` instead of manual configs. PR [#428](https://github.com/tiangolo/sqlmodel/pull/428) by [@michaeloliverx](https://github.com/michaeloliverx). From 403d44ea780cc59fadba2d485837685b4764c07a Mon Sep 17 00:00:00 2001 From: Jon Michaelchuck <5964742+jbmchuck@users.noreply.github.com> Date: Mon, 23 Oct 2023 09:55:53 -0700 Subject: [PATCH 61/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20docs,=20use=20`of?= =?UTF-8?q?fset`=20in=20example=20with=20`limit`=20and=20`where`=20(#273)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SebastiΓ‘n RamΓ­rez --- docs/tutorial/limit-and-offset.md | 15 +++++++-------- .../tutorial/offset_and_limit/tutorial004.py | 2 +- .../test_limit_and_offset/test_tutorial004.py | 19 ++++++++----------- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/docs/tutorial/limit-and-offset.md b/docs/tutorial/limit-and-offset.md index dc4c280..c8b0ddf 100644 --- a/docs/tutorial/limit-and-offset.md +++ b/docs/tutorial/limit-and-offset.md @@ -271,11 +271,11 @@ Of course, you can also combine `.limit()` and `.offset()` with `.where()` and o
-## Run the Program with Limit and Where on the Command Line +## Run the Program with Limit, Offset, and Where on the Command Line If we run it on the command line, it will find all the heroes in the database with an age above 32. That would normally be 4 heroes. -But we are limiting the results to only get the first 3: +But we are starting to include after an offset of 1 (so we don't count the first one), and we are limiting the results to only get the first 2 after that:
@@ -284,18 +284,17 @@ $ python app.py // Previous output omitted πŸ™ˆ -// Select with WHERE and LIMIT +// Select with WHERE and LIMIT and OFFSET INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age FROM hero WHERE hero.age > ? LIMIT ? OFFSET ? -INFO Engine [no key 0.00022s] (32, 3, 0) +INFO Engine [no key 0.00022s] (32, 2, 1) -// Print the heroes received, only 3 +// Print the heroes received, only 2 [ - Hero(age=35, secret_name='Trevor Challa', id=5, name='Black Lion'), - Hero(age=36, secret_name='Steve Weird', id=6, name='Dr. Weird'), - Hero(age=48, secret_name='Tommy Sharp', id=3, name='Rusty-Man') + Hero(age=36, id=6, name='Dr. Weird', secret_name='Steve Weird'), + Hero(age=48, id=3, name='Rusty-Man', secret_name='Tommy Sharp') ] ``` diff --git a/docs_src/tutorial/offset_and_limit/tutorial004.py b/docs_src/tutorial/offset_and_limit/tutorial004.py index a95715c..43828b8 100644 --- a/docs_src/tutorial/offset_and_limit/tutorial004.py +++ b/docs_src/tutorial/offset_and_limit/tutorial004.py @@ -43,7 +43,7 @@ def create_heroes(): def select_heroes(): with Session(engine) as session: - statement = select(Hero).where(Hero.age > 32).limit(3) + statement = select(Hero).where(Hero.age > 32).offset(1).limit(2) results = session.exec(statement) heroes = results.all() print(heroes) diff --git a/tests/test_tutorial/test_limit_and_offset/test_tutorial004.py b/tests/test_tutorial/test_limit_and_offset/test_tutorial004.py index 448b191..eb15a15 100644 --- a/tests/test_tutorial/test_limit_and_offset/test_tutorial004.py +++ b/tests/test_tutorial/test_limit_and_offset/test_tutorial004.py @@ -4,16 +4,6 @@ from sqlmodel import create_engine from ...conftest import get_testing_print_function -expected_calls = [ - [ - [ - {"id": 5, "name": "Black Lion", "secret_name": "Trevor Challa", "age": 35}, - {"id": 6, "name": "Dr. Weird", "secret_name": "Steve Weird", "age": 36}, - {"id": 3, "name": "Rusty-Man", "secret_name": "Tommy Sharp", "age": 48}, - ] - ] -] - def test_tutorial(clear_sqlmodel): from docs_src.tutorial.offset_and_limit import tutorial004 as mod @@ -26,4 +16,11 @@ def test_tutorial(clear_sqlmodel): with patch("builtins.print", new=new_print): mod.main() - assert calls == expected_calls + assert calls == [ + [ + [ + {"name": "Dr. Weird", "secret_name": "Steve Weird", "age": 36, "id": 6}, + {"name": "Rusty-Man", "secret_name": "Tommy Sharp", "age": 48, "id": 3}, + ] + ] + ] From 03f295b3976979922caba569a7ac21234d2b4a48 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Oct 2023 16:56:29 +0000 Subject: [PATCH 62/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 2283b21..7fcb59a 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ“ Update docs, use `offset` in example with `limit` and `where`. PR [#273](https://github.com/tiangolo/sqlmodel/pull/273) by [@jbmchuck](https://github.com/jbmchuck). * πŸ“ Fix docs for Pydantic's fields using `le` (`lte` is invalid, use `le` ). PR [#207](https://github.com/tiangolo/sqlmodel/pull/207) by [@jrycw](https://github.com/jrycw). * βœ… Refactor OpenAPI FastAPI tests to simplify updating them later, this moves things around without changes. PR [#671](https://github.com/tiangolo/sqlmodel/pull/671) by [@tiangolo](https://github.com/tiangolo). * ⬆ Bump actions/checkout from 3 to 4. PR [#670](https://github.com/tiangolo/sqlmodel/pull/670) by [@dependabot[bot]](https://github.com/apps/dependabot). From 6d361e3ffb542cdeef34127fd555494a300cc318 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 21:05:55 +0400 Subject: [PATCH 63/85] =?UTF-8?q?=E2=AC=86=20Bump=20dawidd6/action-downloa?= =?UTF-8?q?d-artifact=20from=202.24.2=20to=202.28.0=20(#660)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 2.24.2 to 2.28.0. - [Release notes](https://github.com/dawidd6/action-download-artifact/releases) - [Commits](https://github.com/dawidd6/action-download-artifact/compare/v2.24.2...v2.28.0) --- updated-dependencies: - dependency-name: dawidd6/action-download-artifact dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/deploy-docs.yml | 2 +- .github/workflows/smokeshow.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index e7641a3..f9035d8 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -21,7 +21,7 @@ jobs: mkdir ./site - name: Download Artifact Docs id: download - uses: dawidd6/action-download-artifact@v2.27.0 + uses: dawidd6/action-download-artifact@v2.28.0 with: if_no_artifact_found: ignore github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/smokeshow.yml b/.github/workflows/smokeshow.yml index 7ee17ca..d2c274f 100644 --- a/.github/workflows/smokeshow.yml +++ b/.github/workflows/smokeshow.yml @@ -20,7 +20,7 @@ jobs: - run: pip install smokeshow - - uses: dawidd6/action-download-artifact@v2.24.2 + - uses: dawidd6/action-download-artifact@v2.28.0 with: workflow: test.yml commit: ${{ github.event.workflow_run.head_sha }} From fc3120a877c81298658d6e549f6fc14c3fdada00 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Oct 2023 17:06:30 +0000 Subject: [PATCH 64/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 7fcb59a..161c6ca 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ Bump dawidd6/action-download-artifact from 2.24.2 to 2.28.0. PR [#660](https://github.com/tiangolo/sqlmodel/pull/660) by [@dependabot[bot]](https://github.com/apps/dependabot). * πŸ“ Update docs, use `offset` in example with `limit` and `where`. PR [#273](https://github.com/tiangolo/sqlmodel/pull/273) by [@jbmchuck](https://github.com/jbmchuck). * πŸ“ Fix docs for Pydantic's fields using `le` (`lte` is invalid, use `le` ). PR [#207](https://github.com/tiangolo/sqlmodel/pull/207) by [@jrycw](https://github.com/jrycw). * βœ… Refactor OpenAPI FastAPI tests to simplify updating them later, this moves things around without changes. PR [#671](https://github.com/tiangolo/sqlmodel/pull/671) by [@tiangolo](https://github.com/tiangolo). From 9b186c89a8a54812ba0c86c99b4e8768e5b79cd5 Mon Sep 17 00:00:00 2001 From: Abenezer Belachew <43050633+abenezerBelachew@users.noreply.github.com> Date: Mon, 23 Oct 2023 11:22:22 -0600 Subject: [PATCH 65/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20link=20to=20docs?= =?UTF-8?q?=20for=20intro=20to=20databases=20(#593)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SebastiΓ‘n RamΓ­rez --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index a9387c5..524ef99 100644 --- a/docs/index.md +++ b/docs/index.md @@ -68,7 +68,7 @@ Successfully installed sqlmodel ## Example -For an introduction to databases, SQL, and everything else, see the SQLModel documentation. +For an introduction to databases, SQL, and everything else, see the SQLModel documentation. Here's a quick example. ✨ From 30d2b30217289b7828af9124ea205cd366321416 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Oct 2023 17:22:58 +0000 Subject: [PATCH 66/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 161c6ca..adb290a 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ“ Update link to docs for intro to databases. PR [#593](https://github.com/tiangolo/sqlmodel/pull/593) by [@abenezerBelachew](https://github.com/abenezerBelachew). * ⬆ Bump dawidd6/action-download-artifact from 2.24.2 to 2.28.0. PR [#660](https://github.com/tiangolo/sqlmodel/pull/660) by [@dependabot[bot]](https://github.com/apps/dependabot). * πŸ“ Update docs, use `offset` in example with `limit` and `where`. PR [#273](https://github.com/tiangolo/sqlmodel/pull/273) by [@jbmchuck](https://github.com/jbmchuck). * πŸ“ Fix docs for Pydantic's fields using `le` (`lte` is invalid, use `le` ). PR [#207](https://github.com/tiangolo/sqlmodel/pull/207) by [@jrycw](https://github.com/jrycw). From 376603efb2799f5b0565a7a29660601ed629d1fd Mon Sep 17 00:00:00 2001 From: PookieBuns <83051474+PookieBuns@users.noreply.github.com> Date: Mon, 23 Oct 2023 12:21:38 -0700 Subject: [PATCH 67/85] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Fix=20contributing?= =?UTF-8?q?=20instructions=20to=20run=20tests,=20update=20script=20name=20?= =?UTF-8?q?(#634)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SebastiΓ‘n RamΓ­rez --- docs/contributing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing.md b/docs/contributing.md index 1cd62d4..217ed61 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -112,7 +112,7 @@ There is a script that you can run locally to test all the code and generate cov
```console -$ bash scripts/test-cov-html.sh +$ bash scripts/test.sh ```
From 6cd086f25fcf056b7f2a8263690115caeb05a8dc Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Oct 2023 19:22:23 +0000 Subject: [PATCH 68/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index adb290a..510dbd1 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏️ Fix contributing instructions to run tests, update script name. PR [#634](https://github.com/tiangolo/sqlmodel/pull/634) by [@PookieBuns](https://github.com/PookieBuns). * πŸ“ Update link to docs for intro to databases. PR [#593](https://github.com/tiangolo/sqlmodel/pull/593) by [@abenezerBelachew](https://github.com/abenezerBelachew). * ⬆ Bump dawidd6/action-download-artifact from 2.24.2 to 2.28.0. PR [#660](https://github.com/tiangolo/sqlmodel/pull/660) by [@dependabot[bot]](https://github.com/apps/dependabot). * πŸ“ Update docs, use `offset` in example with `limit` and `where`. PR [#273](https://github.com/tiangolo/sqlmodel/pull/273) by [@jbmchuck](https://github.com/jbmchuck). From 9d3ca01dd09d77f4bcff000621f683936d9fe3ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 24 Oct 2023 00:37:07 +0400 Subject: [PATCH 69/85] =?UTF-8?q?=F0=9F=93=9D=20Tweak=20wording=20in=20`do?= =?UTF-8?q?cs/tutorial/fastapi/multiple-models.md`=20(#674)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Luis Benitez --- docs/tutorial/fastapi/multiple-models.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/tutorial/fastapi/multiple-models.md b/docs/tutorial/fastapi/multiple-models.md index c37fad3..6845b98 100644 --- a/docs/tutorial/fastapi/multiple-models.md +++ b/docs/tutorial/fastapi/multiple-models.md @@ -53,11 +53,11 @@ Here's the weird thing, the `id` currently seems also "optional". πŸ€” This is because in our **SQLModel** class we declare the `id` with `Optional[int]`, because it could be `None` in memory until we save it in the database and we finally get the actual ID. -But in the responses, we would always send a model from the database, and it would **always have an ID**. So the `id` in the responses could be declared as required too. +But in the responses, we always send a model from the database, so it **always has an ID**. So the `id` in the responses can be declared as required. -This would mean that our application is making the compromise with the clients that if it sends a hero, it would for sure have an `id` with a value, it would not be `None`. +This means that our application is making the promise to the clients that if it sends a hero, it will for sure have an `id` with a value, it will not be `None`. -### Why Is it Important to Compromise with the Responses +### Why Is it Important to Have a Contract for Responses The ultimate goal of an API is for some **clients to use it**. From 9fd73066488d1ed158104e6a91f4f7181ec45898 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Oct 2023 20:37:48 +0000 Subject: [PATCH 70/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 510dbd1..6cd3a08 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ“ Tweak wording in `docs/tutorial/fastapi/multiple-models.md`. PR [#674](https://github.com/tiangolo/sqlmodel/pull/674) by [@tiangolo](https://github.com/tiangolo). * ✏️ Fix contributing instructions to run tests, update script name. PR [#634](https://github.com/tiangolo/sqlmodel/pull/634) by [@PookieBuns](https://github.com/PookieBuns). * πŸ“ Update link to docs for intro to databases. PR [#593](https://github.com/tiangolo/sqlmodel/pull/593) by [@abenezerBelachew](https://github.com/abenezerBelachew). * ⬆ Bump dawidd6/action-download-artifact from 2.24.2 to 2.28.0. PR [#660](https://github.com/tiangolo/sqlmodel/pull/660) by [@dependabot[bot]](https://github.com/apps/dependabot). From 1acb683f80fcf5eae1191b68f12dd398f34620a8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 24 Oct 2023 00:45:45 +0400 Subject: [PATCH 71/85] =?UTF-8?q?=E2=AC=86=20[pre-commit.ci]=20pre-commit?= =?UTF-8?q?=20autoupdate=20(#672)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.4.0 β†’ v4.5.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.4.0...v4.5.0) - [github.com/asottile/pyupgrade: v3.7.0 β†’ v3.15.0](https://github.com/asottile/pyupgrade/compare/v3.7.0...v3.15.0) - https://github.com/charliermarsh/ruff-pre-commit β†’ https://github.com/astral-sh/ruff-pre-commit - [github.com/astral-sh/ruff-pre-commit: v0.0.275 β†’ v0.1.1](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.275...v0.1.1) - [github.com/psf/black: 23.3.0 β†’ 23.10.0](https://github.com/psf/black/compare/23.3.0...23.10.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9f7085f..022ef24 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ default_language_version: python: python3.10 repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: check-added-large-files - id: check-toml @@ -14,20 +14,20 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/asottile/pyupgrade - rev: v3.7.0 + rev: v3.15.0 hooks: - id: pyupgrade args: - --py3-plus - --keep-runtime-typing -- repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.275 +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.1.1 hooks: - id: ruff args: - --fix - repo: https://github.com/psf/black - rev: 23.3.0 + rev: 23.10.0 hooks: - id: black ci: From 80fd7e03cf361e49b473057df815e953e4653e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Wei=C3=9F?= Date: Mon, 23 Oct 2023 22:46:05 +0200 Subject: [PATCH 72/85] =?UTF-8?q?=F0=9F=93=9D=20Clarify=20description=20of?= =?UTF-8?q?=20in-memory=20SQLite=20database=20in=20`docs/tutorial/create-d?= =?UTF-8?q?b-and-table.md`=20(#601)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SebastiΓ‘n RamΓ­rez --- docs/tutorial/create-db-and-table.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial/create-db-and-table.md b/docs/tutorial/create-db-and-table.md index 52a12fa..d0d2742 100644 --- a/docs/tutorial/create-db-and-table.md +++ b/docs/tutorial/create-db-and-table.md @@ -220,7 +220,7 @@ Each supported database has it's own URL type. For example, for **SQLite** it is * `sqlite:///databases/local/application.db` * `sqlite:///db.sqlite` -For SQLAlchemy, there's also a special one, which is a database all *in memory*, this means that it is deleted after the program terminates, and it's also very fast: +SQLite supports a special database that lives all *in memory*. Hence, it's very fast, but be careful, the database gets deleted after the program terminates. You can specify this in-memory database by using just two slash characters (`//`) and no file name: * `sqlite://` From dcc4e4c36ae76477edfa6411734953c566862a63 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Oct 2023 20:46:26 +0000 Subject: [PATCH 73/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 6cd3a08..6a2d45f 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#672](https://github.com/tiangolo/sqlmodel/pull/672) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). * πŸ“ Tweak wording in `docs/tutorial/fastapi/multiple-models.md`. PR [#674](https://github.com/tiangolo/sqlmodel/pull/674) by [@tiangolo](https://github.com/tiangolo). * ✏️ Fix contributing instructions to run tests, update script name. PR [#634](https://github.com/tiangolo/sqlmodel/pull/634) by [@PookieBuns](https://github.com/PookieBuns). * πŸ“ Update link to docs for intro to databases. PR [#593](https://github.com/tiangolo/sqlmodel/pull/593) by [@abenezerBelachew](https://github.com/abenezerBelachew). From a6ce817ca5e6b70c9427d89194dde07bb6c73cb8 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Oct 2023 20:46:39 +0000 Subject: [PATCH 74/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 6a2d45f..09427d8 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ“ Clarify description of in-memory SQLite database in `docs/tutorial/create-db-and-table.md`. PR [#601](https://github.com/tiangolo/sqlmodel/pull/601) by [@SimonCW](https://github.com/SimonCW). * ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#672](https://github.com/tiangolo/sqlmodel/pull/672) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). * πŸ“ Tweak wording in `docs/tutorial/fastapi/multiple-models.md`. PR [#674](https://github.com/tiangolo/sqlmodel/pull/674) by [@tiangolo](https://github.com/tiangolo). * ✏️ Fix contributing instructions to run tests, update script name. PR [#634](https://github.com/tiangolo/sqlmodel/pull/634) by [@PookieBuns](https://github.com/PookieBuns). From 596718d93b385c185693827145c4cf3ecb3004ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 24 Oct 2023 00:59:49 +0400 Subject: [PATCH 75/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 61 +++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/docs/release-notes.md b/docs/release-notes.md index 09427d8..9e95ad3 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,50 +2,67 @@ ## Latest Changes +### Breaking Changes + +* πŸ—‘οΈ Deprecate Python 3.6 and upgrade Poetry and Poetry Version Plugin. PR [#627](https://github.com/tiangolo/sqlmodel/pull/627) by [@tiangolo](https://github.com/tiangolo). + +### Features + +* ✨ Raise a more clear error when a type is not valid. PR [#425](https://github.com/tiangolo/sqlmodel/pull/425) by [@ddanier](https://github.com/ddanier). + +### Fixes + +* πŸ› Fix `AsyncSession` type annotations for `exec()`. PR [#58](https://github.com/tiangolo/sqlmodel/pull/58) by [@Bobronium](https://github.com/Bobronium). +* πŸ› Fix allowing using a `ForeignKey` directly, remove repeated column construction from `SQLModelMetaclass.__init__` and upgrade minimum SQLAlchemy to `>=1.4.36`. PR [#443](https://github.com/tiangolo/sqlmodel/pull/443) by [@daniil-berg](https://github.com/daniil-berg). +* πŸ› Fix enum type checks ordering in `get_sqlalchemy_type`. PR [#669](https://github.com/tiangolo/sqlmodel/pull/669) by [@tiangolo](https://github.com/tiangolo). +* πŸ› Fix SQLAlchemy version 1.4.36 breaks SQLModel relationships (#315). PR [#461](https://github.com/tiangolo/sqlmodel/pull/461) by [@byrman](https://github.com/byrman). + +### Upgrades + +* ⬆️ Upgrade support for SQLAlchemy 1.4.49, update tests. PR [#519](https://github.com/tiangolo/sqlmodel/pull/519) by [@sandrotosi](https://github.com/sandrotosi). +* ⬆ Raise SQLAlchemy version requirement to at least `1.4.29` (related to #434). PR [#439](https://github.com/tiangolo/sqlmodel/pull/439) by [@daniil-berg](https://github.com/daniil-berg). + +### Docs + * πŸ“ Clarify description of in-memory SQLite database in `docs/tutorial/create-db-and-table.md`. PR [#601](https://github.com/tiangolo/sqlmodel/pull/601) by [@SimonCW](https://github.com/SimonCW). -* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#672](https://github.com/tiangolo/sqlmodel/pull/672) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). * πŸ“ Tweak wording in `docs/tutorial/fastapi/multiple-models.md`. PR [#674](https://github.com/tiangolo/sqlmodel/pull/674) by [@tiangolo](https://github.com/tiangolo). * ✏️ Fix contributing instructions to run tests, update script name. PR [#634](https://github.com/tiangolo/sqlmodel/pull/634) by [@PookieBuns](https://github.com/PookieBuns). * πŸ“ Update link to docs for intro to databases. PR [#593](https://github.com/tiangolo/sqlmodel/pull/593) by [@abenezerBelachew](https://github.com/abenezerBelachew). -* ⬆ Bump dawidd6/action-download-artifact from 2.24.2 to 2.28.0. PR [#660](https://github.com/tiangolo/sqlmodel/pull/660) by [@dependabot[bot]](https://github.com/apps/dependabot). * πŸ“ Update docs, use `offset` in example with `limit` and `where`. PR [#273](https://github.com/tiangolo/sqlmodel/pull/273) by [@jbmchuck](https://github.com/jbmchuck). * πŸ“ Fix docs for Pydantic's fields using `le` (`lte` is invalid, use `le` ). PR [#207](https://github.com/tiangolo/sqlmodel/pull/207) by [@jrycw](https://github.com/jrycw). -* βœ… Refactor OpenAPI FastAPI tests to simplify updating them later, this moves things around without changes. PR [#671](https://github.com/tiangolo/sqlmodel/pull/671) by [@tiangolo](https://github.com/tiangolo). -* ⬆ Bump actions/checkout from 3 to 4. PR [#670](https://github.com/tiangolo/sqlmodel/pull/670) by [@dependabot[bot]](https://github.com/apps/dependabot). -* πŸ”§ Update mypy config, use `strict = true` instead of manual configs. PR [#428](https://github.com/tiangolo/sqlmodel/pull/428) by [@michaeloliverx](https://github.com/michaeloliverx). -* πŸ› Fix `AsyncSession` type annotations for `exec()`. PR [#58](https://github.com/tiangolo/sqlmodel/pull/58) by [@Bobronium](https://github.com/Bobronium). -* πŸ› Fix allowing using a `ForeignKey` directly, remove repeated column construction from `SQLModelMetaclass.__init__` and upgrade minimum SQLAlchemy to `>=1.4.36`. PR [#443](https://github.com/tiangolo/sqlmodel/pull/443) by [@daniil-berg](https://github.com/daniil-berg). -* ⬆️ Upgrade support for SQLAlchemy 1.4.49, update tests. PR [#519](https://github.com/tiangolo/sqlmodel/pull/519) by [@sandrotosi](https://github.com/sandrotosi). -* ⬆ Raise SQLAlchemy version requirement to at least `1.4.29` (related to #434). PR [#439](https://github.com/tiangolo/sqlmodel/pull/439) by [@daniil-berg](https://github.com/daniil-berg). -* πŸ› Fix enum type checks ordering in `get_sqlalchemy_type`. PR [#669](https://github.com/tiangolo/sqlmodel/pull/669) by [@tiangolo](https://github.com/tiangolo). -* ⬆️ Upgrade MkDocs Material. PR [#668](https://github.com/tiangolo/sqlmodel/pull/668) by [@tiangolo](https://github.com/tiangolo). -* 🎨 Update docs format and references with pre-commit and Ruff. PR [#667](https://github.com/tiangolo/sqlmodel/pull/667) by [@tiangolo](https://github.com/tiangolo). -* 🎨 Run pre-commit on all files and autoformat. PR [#666](https://github.com/tiangolo/sqlmodel/pull/666) by [@tiangolo](https://github.com/tiangolo). -* πŸ‘· Move to Ruff and add pre-commit. PR [#661](https://github.com/tiangolo/sqlmodel/pull/661) by [@tiangolo](https://github.com/tiangolo). -* ✨ Raise a more clear error when a type is not valid. PR [#425](https://github.com/tiangolo/sqlmodel/pull/425) by [@ddanier](https://github.com/ddanier). * πŸ“ Update outdated link in `docs/db-to-code.md`. PR [#649](https://github.com/tiangolo/sqlmodel/pull/649) by [@MatveyF](https://github.com/MatveyF). * ✏️ Fix typos found with codespell. PR [#520](https://github.com/tiangolo/sqlmodel/pull/520) by [@kianmeng](https://github.com/kianmeng). * πŸ“ Fix typos (duplication) in main page. PR [#631](https://github.com/tiangolo/sqlmodel/pull/631) by [@Mr-DRP](https://github.com/Mr-DRP). * πŸ“ Update release notes, add second author to PR. PR [#429](https://github.com/tiangolo/sqlmodel/pull/429) by [@br-follow](https://github.com/br-follow). * πŸ“ Update instructions about how to make a foreign key required in `docs/tutorial/relationship-attributes/define-relationships-attributes.md`. PR [#474](https://github.com/tiangolo/sqlmodel/pull/474) by [@jalvaradosegura](https://github.com/jalvaradosegura). -* πŸ› Fix SQLAlchemy version 1.4.36 breaks SQLModel relationships (#315). PR [#461](https://github.com/tiangolo/sqlmodel/pull/461) by [@byrman](https://github.com/byrman). +* πŸ“ Update help SQLModel docs. PR [#548](https://github.com/tiangolo/sqlmodel/pull/548) by [@tiangolo](https://github.com/tiangolo). +* ✏️ Fix typo in internal function name `get_sqlachemy_type()`. PR [#496](https://github.com/tiangolo/sqlmodel/pull/496) by [@cmarqu](https://github.com/cmarqu). +* ✏️ Fix typo in docs. PR [#446](https://github.com/tiangolo/sqlmodel/pull/446) by [@davidbrochart](https://github.com/davidbrochart). +* ✏️ Fix typo in `docs/tutorial/create-db-and-table.md`. PR [#477](https://github.com/tiangolo/sqlmodel/pull/477) by [@FluffyDietEngine](https://github.com/FluffyDietEngine). +* ✏️ Fix small typos in docs. PR [#481](https://github.com/tiangolo/sqlmodel/pull/481) by [@micuffaro](https://github.com/micuffaro). + +### Internal + +* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#672](https://github.com/tiangolo/sqlmodel/pull/672) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). +* ⬆ Bump dawidd6/action-download-artifact from 2.24.2 to 2.28.0. PR [#660](https://github.com/tiangolo/sqlmodel/pull/660) by [@dependabot[bot]](https://github.com/apps/dependabot). +* βœ… Refactor OpenAPI FastAPI tests to simplify updating them later, this moves things around without changes. PR [#671](https://github.com/tiangolo/sqlmodel/pull/671) by [@tiangolo](https://github.com/tiangolo). +* ⬆ Bump actions/checkout from 3 to 4. PR [#670](https://github.com/tiangolo/sqlmodel/pull/670) by [@dependabot[bot]](https://github.com/apps/dependabot). +* πŸ”§ Update mypy config, use `strict = true` instead of manual configs. PR [#428](https://github.com/tiangolo/sqlmodel/pull/428) by [@michaeloliverx](https://github.com/michaeloliverx). +* ⬆️ Upgrade MkDocs Material. PR [#668](https://github.com/tiangolo/sqlmodel/pull/668) by [@tiangolo](https://github.com/tiangolo). +* 🎨 Update docs format and references with pre-commit and Ruff. PR [#667](https://github.com/tiangolo/sqlmodel/pull/667) by [@tiangolo](https://github.com/tiangolo). +* 🎨 Run pre-commit on all files and autoformat. PR [#666](https://github.com/tiangolo/sqlmodel/pull/666) by [@tiangolo](https://github.com/tiangolo). +* πŸ‘· Move to Ruff and add pre-commit. PR [#661](https://github.com/tiangolo/sqlmodel/pull/661) by [@tiangolo](https://github.com/tiangolo). * πŸ› οΈ Add `CITATION.cff` file for academic citations. PR [#13](https://github.com/tiangolo/sqlmodel/pull/13) by [@sugatoray](https://github.com/sugatoray). * πŸ‘· Update docs deployments to Cloudflare. PR [#630](https://github.com/tiangolo/sqlmodel/pull/630) by [@tiangolo](https://github.com/tiangolo). * πŸ‘·β€β™‚οΈ Upgrade CI for docs. PR [#628](https://github.com/tiangolo/sqlmodel/pull/628) by [@tiangolo](https://github.com/tiangolo). -* πŸ—‘οΈ Deprecate Python 3.6 and upgrade Poetry and Poetry Version Plugin. PR [#627](https://github.com/tiangolo/sqlmodel/pull/627) by [@tiangolo](https://github.com/tiangolo). * πŸ‘· Update CI debug mode with Tmate. PR [#629](https://github.com/tiangolo/sqlmodel/pull/629) by [@tiangolo](https://github.com/tiangolo). * πŸ‘· Update latest changes token. PR [#616](https://github.com/tiangolo/sqlmodel/pull/616) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Upgrade analytics. PR [#558](https://github.com/tiangolo/sqlmodel/pull/558) by [@tiangolo](https://github.com/tiangolo). -* πŸ“ Update help SQLModel docs. PR [#548](https://github.com/tiangolo/sqlmodel/pull/548) by [@tiangolo](https://github.com/tiangolo). * πŸ”§ Update new issue chooser to point to GitHub Discussions. PR [#546](https://github.com/tiangolo/sqlmodel/pull/546) by [@tiangolo](https://github.com/tiangolo). * πŸ”§ Add template for GitHub Discussion questions and update issues template. PR [#544](https://github.com/tiangolo/sqlmodel/pull/544) by [@tiangolo](https://github.com/tiangolo). * πŸ‘· Refactor CI artifact upload/download for docs previews. PR [#514](https://github.com/tiangolo/sqlmodel/pull/514) by [@tiangolo](https://github.com/tiangolo). -* ✏️ Fix typo in internal function name `get_sqlachemy_type()`. PR [#496](https://github.com/tiangolo/sqlmodel/pull/496) by [@cmarqu](https://github.com/cmarqu). * ⬆ Bump actions/cache from 2 to 3. PR [#497](https://github.com/tiangolo/sqlmodel/pull/497) by [@dependabot[bot]](https://github.com/apps/dependabot). -* ✏️ Fix typo in docs. PR [#446](https://github.com/tiangolo/sqlmodel/pull/446) by [@davidbrochart](https://github.com/davidbrochart). * ⬆ Bump dawidd6/action-download-artifact from 2.24.0 to 2.24.2. PR [#493](https://github.com/tiangolo/sqlmodel/pull/493) by [@dependabot[bot]](https://github.com/apps/dependabot). -* ✏️ Fix typo in `docs/tutorial/create-db-and-table.md`. PR [#477](https://github.com/tiangolo/sqlmodel/pull/477) by [@FluffyDietEngine](https://github.com/FluffyDietEngine). -* ✏️ Fix small typos in docs. PR [#481](https://github.com/tiangolo/sqlmodel/pull/481) by [@micuffaro](https://github.com/micuffaro). * πŸ”§ Update Smokeshow coverage threshold. PR [#487](https://github.com/tiangolo/sqlmodel/pull/487) by [@tiangolo](https://github.com/tiangolo). * πŸ‘· Move from Codecov to Smokeshow. PR [#486](https://github.com/tiangolo/sqlmodel/pull/486) by [@tiangolo](https://github.com/tiangolo). * ⬆ Bump actions/setup-python from 2 to 4. PR [#411](https://github.com/tiangolo/sqlmodel/pull/411) by [@dependabot[bot]](https://github.com/apps/dependabot). From d05c3ee495bb81d2915b38052ac5f1909da60e37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 24 Oct 2023 01:01:18 +0400 Subject: [PATCH 76/85] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.0.9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 2 ++ sqlmodel/__init__.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/release-notes.md b/docs/release-notes.md index 9e95ad3..900804d 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,8 @@ ## Latest Changes +## 0.0.9 + ### Breaking Changes * πŸ—‘οΈ Deprecate Python 3.6 and upgrade Poetry and Poetry Version Plugin. PR [#627](https://github.com/tiangolo/sqlmodel/pull/627) by [@tiangolo](https://github.com/tiangolo). diff --git a/sqlmodel/__init__.py b/sqlmodel/__init__.py index 3aa6e0d..b51084b 100644 --- a/sqlmodel/__init__.py +++ b/sqlmodel/__init__.py @@ -1,4 +1,4 @@ -__version__ = "0.0.8" +__version__ = "0.0.9" # Re-export from SQLAlchemy from sqlalchemy.engine import create_mock_engine as create_mock_engine From 99f8ce3894564444f33770577a934749e479034e Mon Sep 17 00:00:00 2001 From: Daniil Fajnberg <60156134+daniil-berg@users.noreply.github.com> Date: Thu, 26 Oct 2023 12:18:05 +0200 Subject: [PATCH 77/85] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20all=20`?= =?UTF-8?q?Field`=20parameters=20from=20Pydantic=20`1.9.0`=20and=20above,?= =?UTF-8?q?=20make=20Pydantic=20`1.9.0`=20the=20minimum=20required=20versi?= =?UTF-8?q?on=20(#440)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SebastiΓ‘n RamΓ­rez --- pyproject.toml | 2 +- sqlmodel/main.py | 16 ++++++++- tests/test_pydantic/__init__.py | 0 tests/test_pydantic/test_field.py | 57 +++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 tests/test_pydantic/__init__.py create mode 100644 tests/test_pydantic/test_field.py diff --git a/pyproject.toml b/pyproject.toml index c7956da..181064e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ classifiers = [ [tool.poetry.dependencies] python = "^3.7" SQLAlchemy = ">=1.4.36,<2.0.0" -pydantic = "^1.8.2" +pydantic = "^1.9.0" sqlalchemy2-stubs = {version = "*", allow-prereleases = true} [tool.poetry.group.dev.dependencies] diff --git a/sqlmodel/main.py b/sqlmodel/main.py index 07e600e..3015aa9 100644 --- a/sqlmodel/main.py +++ b/sqlmodel/main.py @@ -145,12 +145,17 @@ def Field( lt: Optional[float] = None, le: Optional[float] = None, multiple_of: Optional[float] = None, + max_digits: Optional[int] = None, + decimal_places: Optional[int] = None, min_items: Optional[int] = None, max_items: Optional[int] = None, + unique_items: Optional[bool] = None, min_length: Optional[int] = None, max_length: Optional[int] = None, allow_mutation: bool = True, regex: Optional[str] = None, + discriminator: Optional[str] = None, + repr: bool = True, primary_key: bool = False, foreign_key: Optional[Any] = None, unique: bool = False, @@ -176,12 +181,17 @@ def Field( lt=lt, le=le, multiple_of=multiple_of, + max_digits=max_digits, + decimal_places=decimal_places, min_items=min_items, max_items=max_items, + unique_items=unique_items, min_length=min_length, max_length=max_length, allow_mutation=allow_mutation, regex=regex, + discriminator=discriminator, + repr=repr, primary_key=primary_key, foreign_key=foreign_key, unique=unique, @@ -587,7 +597,11 @@ class SQLModel(BaseModel, metaclass=SQLModelMetaclass, registry=default_registry def __repr_args__(self) -> Sequence[Tuple[Optional[str], Any]]: # Don't show SQLAlchemy private attributes - return [(k, v) for k, v in self.__dict__.items() if not k.startswith("_sa_")] + return [ + (k, v) + for k, v in super().__repr_args__() + if not (isinstance(k, str) and k.startswith("_sa_")) + ] # From Pydantic, override to enforce validation with dict @classmethod diff --git a/tests/test_pydantic/__init__.py b/tests/test_pydantic/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_pydantic/test_field.py b/tests/test_pydantic/test_field.py new file mode 100644 index 0000000..9d7bc77 --- /dev/null +++ b/tests/test_pydantic/test_field.py @@ -0,0 +1,57 @@ +from decimal import Decimal +from typing import Optional, Union + +import pytest +from pydantic import ValidationError +from sqlmodel import Field, SQLModel +from typing_extensions import Literal + + +def test_decimal(): + class Model(SQLModel): + dec: Decimal = Field(max_digits=4, decimal_places=2) + + Model(dec=Decimal("3.14")) + Model(dec=Decimal("69.42")) + + with pytest.raises(ValidationError): + Model(dec=Decimal("3.142")) + with pytest.raises(ValidationError): + Model(dec=Decimal("0.069")) + with pytest.raises(ValidationError): + Model(dec=Decimal("420")) + + +def test_discriminator(): + # Example adapted from + # [Pydantic docs](https://pydantic-docs.helpmanual.io/usage/types/#discriminated-unions-aka-tagged-unions): + + class Cat(SQLModel): + pet_type: Literal["cat"] + meows: int + + class Dog(SQLModel): + pet_type: Literal["dog"] + barks: float + + class Lizard(SQLModel): + pet_type: Literal["reptile", "lizard"] + scales: bool + + class Model(SQLModel): + pet: Union[Cat, Dog, Lizard] = Field(..., discriminator="pet_type") + n: int + + Model(pet={"pet_type": "dog", "barks": 3.14}, n=1) # type: ignore[arg-type] + + with pytest.raises(ValidationError): + Model(pet={"pet_type": "dog"}, n=1) # type: ignore[arg-type] + + +def test_repr(): + class Model(SQLModel): + id: Optional[int] = Field(primary_key=True) + foo: str = Field(repr=False) + + instance = Model(id=123, foo="bar") + assert "foo=" not in repr(instance) From 8d1423253812af999aed55ce56d2918211039b08 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 26 Oct 2023 10:18:41 +0000 Subject: [PATCH 78/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 900804d..4956a12 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add support for all `Field` parameters from Pydantic `1.9.0` and above, make Pydantic `1.9.0` the minimum required version. PR [#440](https://github.com/tiangolo/sqlmodel/pull/440) by [@daniil-berg](https://github.com/daniil-berg). ## 0.0.9 ### Breaking Changes From 7fdfee10a5275b6f076d18d70e584da6b632a313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 26 Oct 2023 18:32:26 +0400 Subject: [PATCH 79/85] =?UTF-8?q?=F0=9F=94=A7=20Adopt=20Ruff=20for=20forma?= =?UTF-8?q?tting=20(#679)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .pre-commit-config.yaml | 16 +++------------- pyproject.toml | 9 ++++++++- scripts/format.sh | 2 +- scripts/lint.sh | 2 +- tests/conftest.py | 3 +-- 5 files changed, 14 insertions(+), 18 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 022ef24..61aaf71 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,23 +13,13 @@ repos: - --unsafe - id: end-of-file-fixer - id: trailing-whitespace -- repo: https://github.com/asottile/pyupgrade - rev: v3.15.0 - hooks: - - id: pyupgrade - args: - - --py3-plus - - --keep-runtime-typing -- repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.1 +- repo: https://github.com/charliermarsh/ruff-pre-commit + rev: v0.1.2 hooks: - id: ruff args: - --fix -- repo: https://github.com/psf/black - rev: 23.10.0 - hooks: - - id: black + - id: ruff-format ci: autofix_commit_msg: 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks autoupdate_commit_msg: ⬆ [pre-commit.ci] pre-commit autoupdate diff --git a/pyproject.toml b/pyproject.toml index 181064e..2018851 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,6 +38,7 @@ sqlalchemy2-stubs = {version = "*", allow-prereleases = true} [tool.poetry.group.dev.dependencies] pytest = "^7.0.1" mypy = "0.971" +# Needed by the code generator using templates black = "^22.10.0" mkdocs-material = "9.1.21" pillow = "^9.3.0" @@ -46,7 +47,7 @@ mdx-include = "^1.4.1" coverage = {extras = ["toml"], version = "^6.2"} fastapi = "^0.68.1" requests = "^2.26.0" -ruff = "^0.1.1" +ruff = "^0.1.2" [build-system] requires = ["poetry-core"] @@ -87,11 +88,13 @@ select = [ "I", # isort "C", # flake8-comprehensions "B", # flake8-bugbear + "UP", # pyupgrade ] ignore = [ "E501", # line too long, handled by black "B008", # do not perform function calls in argument defaults "C901", # too complex + "W191", # indentation contains tabs ] [tool.ruff.per-file-ignores] @@ -99,3 +102,7 @@ ignore = [ [tool.ruff.isort] known-third-party = ["sqlmodel", "sqlalchemy", "pydantic", "fastapi"] + +[tool.ruff.pyupgrade] +# Preserve types, even if a file imports `from __future__ import annotations`. +keep-runtime-typing = true diff --git a/scripts/format.sh b/scripts/format.sh index b6aebd1..70c12e5 100755 --- a/scripts/format.sh +++ b/scripts/format.sh @@ -2,4 +2,4 @@ set -x ruff sqlmodel tests docs_src scripts --fix -black sqlmodel tests docs_src scripts +ruff format sqlmodel tests docs_src scripts diff --git a/scripts/lint.sh b/scripts/lint.sh index b328e3d..f668822 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -5,4 +5,4 @@ set -x mypy sqlmodel ruff sqlmodel tests docs_src scripts -black sqlmodel tests docs_src --check +ruff format sqlmodel tests docs_src --check diff --git a/tests/conftest.py b/tests/conftest.py index cd66420..2b8e5fc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -42,8 +42,7 @@ def coverage_run(*, module: str, cwd: Union[str, Path]) -> subprocess.CompletedP module, ], cwd=str(cwd), - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, + capture_output=True, encoding="utf-8", ) return result From 13cc722110b9d3b37cd00a9a0480fdd4bccb289a Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 26 Oct 2023 14:32:59 +0000 Subject: [PATCH 80/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 4956a12..11ad6fc 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* πŸ”§ Adopt Ruff for formatting. PR [#679](https://github.com/tiangolo/sqlmodel/pull/679) by [@tiangolo](https://github.com/tiangolo). * ✨ Add support for all `Field` parameters from Pydantic `1.9.0` and above, make Pydantic `1.9.0` the minimum required version. PR [#440](https://github.com/tiangolo/sqlmodel/pull/440) by [@daniil-berg](https://github.com/daniil-berg). ## 0.0.9 From e4e1385eedc700ad8c4e079841a85c32a29f1cff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 26 Oct 2023 18:34:49 +0400 Subject: [PATCH 81/85] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.0.10?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 10 +++++++++- sqlmodel/__init__.py | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/release-notes.md b/docs/release-notes.md index 11ad6fc..61cd9f6 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,8 +2,16 @@ ## Latest Changes -* πŸ”§ Adopt Ruff for formatting. PR [#679](https://github.com/tiangolo/sqlmodel/pull/679) by [@tiangolo](https://github.com/tiangolo). +## 0.0.10 + +### Features + * ✨ Add support for all `Field` parameters from Pydantic `1.9.0` and above, make Pydantic `1.9.0` the minimum required version. PR [#440](https://github.com/tiangolo/sqlmodel/pull/440) by [@daniil-berg](https://github.com/daniil-berg). + +### Internal + +* πŸ”§ Adopt Ruff for formatting. PR [#679](https://github.com/tiangolo/sqlmodel/pull/679) by [@tiangolo](https://github.com/tiangolo). + ## 0.0.9 ### Breaking Changes diff --git a/sqlmodel/__init__.py b/sqlmodel/__init__.py index b51084b..6b65860 100644 --- a/sqlmodel/__init__.py +++ b/sqlmodel/__init__.py @@ -1,4 +1,4 @@ -__version__ = "0.0.9" +__version__ = "0.0.10" # Re-export from SQLAlchemy from sqlalchemy.engine import create_mock_engine as create_mock_engine From 717594ef13b64d0d4fd1ce7c6305c945f68460d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 28 Oct 2023 17:55:23 +0400 Subject: [PATCH 82/85] =?UTF-8?q?=E2=9C=A8=20Do=20not=20allow=20invalid=20?= =?UTF-8?q?combinations=20of=20field=20parameters=20for=20columns=20and=20?= =?UTF-8?q?relationships,=20`sa=5Fcolumn`=20excludes=20`sa=5Fcolumn=5Fargs?= =?UTF-8?q?`,=20`primary=5Fkey`,=20`nullable`,=20etc.=20(#681)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ♻️ Make sa_column exclusive, do not allow incompatible arguments, sa_column_args, primary_key, etc * βœ… Add tests for new errors when incorrectly using sa_column * βœ… Add tests for sa_column_args and sa_column_kwargs * ♻️ Do not allow sa_relationship with sa_relationship_args or sa_relationship_kwargs * βœ… Add tests for relationship errors * βœ… Fix test for sa_column_args --- sqlmodel/main.py | 151 ++++++++++++++++++++++++++-- tests/test_field_sa_args_kwargs.py | 39 +++++++ tests/test_field_sa_column.py | 99 ++++++++++++++++++ tests/test_field_sa_relationship.py | 53 ++++++++++ 4 files changed, 332 insertions(+), 10 deletions(-) create mode 100644 tests/test_field_sa_args_kwargs.py create mode 100644 tests/test_field_sa_column.py create mode 100644 tests/test_field_sa_relationship.py diff --git a/sqlmodel/main.py b/sqlmodel/main.py index 3015aa9..f48e388 100644 --- a/sqlmodel/main.py +++ b/sqlmodel/main.py @@ -22,6 +22,7 @@ from typing import ( TypeVar, Union, cast, + overload, ) from pydantic import BaseConfig, BaseModel @@ -87,6 +88,28 @@ class FieldInfo(PydanticFieldInfo): "Passing sa_column_kwargs is not supported when " "also passing a sa_column" ) + if primary_key is not Undefined: + raise RuntimeError( + "Passing primary_key is not supported when " + "also passing a sa_column" + ) + if nullable is not Undefined: + raise RuntimeError( + "Passing nullable is not supported when " "also passing a sa_column" + ) + if foreign_key is not Undefined: + raise RuntimeError( + "Passing foreign_key is not supported when " + "also passing a sa_column" + ) + if unique is not Undefined: + raise RuntimeError( + "Passing unique is not supported when " "also passing a sa_column" + ) + if index is not Undefined: + raise RuntimeError( + "Passing index is not supported when " "also passing a sa_column" + ) super().__init__(default=default, **kwargs) self.primary_key = primary_key self.nullable = nullable @@ -126,6 +149,7 @@ class RelationshipInfo(Representation): self.sa_relationship_kwargs = sa_relationship_kwargs +@overload def Field( default: Any = Undefined, *, @@ -156,9 +180,88 @@ def Field( regex: Optional[str] = None, discriminator: Optional[str] = None, repr: bool = True, - primary_key: bool = False, - foreign_key: Optional[Any] = None, - unique: bool = False, + primary_key: Union[bool, UndefinedType] = Undefined, + foreign_key: Any = Undefined, + unique: Union[bool, UndefinedType] = Undefined, + nullable: Union[bool, UndefinedType] = Undefined, + index: Union[bool, UndefinedType] = Undefined, + sa_column_args: Union[Sequence[Any], UndefinedType] = Undefined, + sa_column_kwargs: Union[Mapping[str, Any], UndefinedType] = Undefined, + schema_extra: Optional[Dict[str, Any]] = None, +) -> Any: + ... + + +@overload +def Field( + default: Any = Undefined, + *, + default_factory: Optional[NoArgAnyCallable] = None, + alias: Optional[str] = None, + title: Optional[str] = None, + description: Optional[str] = None, + exclude: Union[ + AbstractSet[Union[int, str]], Mapping[Union[int, str], Any], Any + ] = None, + include: Union[ + AbstractSet[Union[int, str]], Mapping[Union[int, str], Any], Any + ] = None, + const: Optional[bool] = None, + gt: Optional[float] = None, + ge: Optional[float] = None, + lt: Optional[float] = None, + le: Optional[float] = None, + multiple_of: Optional[float] = None, + max_digits: Optional[int] = None, + decimal_places: Optional[int] = None, + min_items: Optional[int] = None, + max_items: Optional[int] = None, + unique_items: Optional[bool] = None, + min_length: Optional[int] = None, + max_length: Optional[int] = None, + allow_mutation: bool = True, + regex: Optional[str] = None, + discriminator: Optional[str] = None, + repr: bool = True, + sa_column: Union[Column, UndefinedType] = Undefined, # type: ignore + schema_extra: Optional[Dict[str, Any]] = None, +) -> Any: + ... + + +def Field( + default: Any = Undefined, + *, + default_factory: Optional[NoArgAnyCallable] = None, + alias: Optional[str] = None, + title: Optional[str] = None, + description: Optional[str] = None, + exclude: Union[ + AbstractSet[Union[int, str]], Mapping[Union[int, str], Any], Any + ] = None, + include: Union[ + AbstractSet[Union[int, str]], Mapping[Union[int, str], Any], Any + ] = None, + const: Optional[bool] = None, + gt: Optional[float] = None, + ge: Optional[float] = None, + lt: Optional[float] = None, + le: Optional[float] = None, + multiple_of: Optional[float] = None, + max_digits: Optional[int] = None, + decimal_places: Optional[int] = None, + min_items: Optional[int] = None, + max_items: Optional[int] = None, + unique_items: Optional[bool] = None, + min_length: Optional[int] = None, + max_length: Optional[int] = None, + allow_mutation: bool = True, + regex: Optional[str] = None, + discriminator: Optional[str] = None, + repr: bool = True, + primary_key: Union[bool, UndefinedType] = Undefined, + foreign_key: Any = Undefined, + unique: Union[bool, UndefinedType] = Undefined, nullable: Union[bool, UndefinedType] = Undefined, index: Union[bool, UndefinedType] = Undefined, sa_column: Union[Column, UndefinedType] = Undefined, # type: ignore @@ -206,6 +309,27 @@ def Field( return field_info +@overload +def Relationship( + *, + back_populates: Optional[str] = None, + link_model: Optional[Any] = None, + sa_relationship_args: Optional[Sequence[Any]] = None, + sa_relationship_kwargs: Optional[Mapping[str, Any]] = None, +) -> Any: + ... + + +@overload +def Relationship( + *, + back_populates: Optional[str] = None, + link_model: Optional[Any] = None, + sa_relationship: Optional[RelationshipProperty] = None, # type: ignore +) -> Any: + ... + + def Relationship( *, back_populates: Optional[str] = None, @@ -440,21 +564,28 @@ def get_column_from_field(field: ModelField) -> Column: # type: ignore if isinstance(sa_column, Column): return sa_column sa_type = get_sqlalchemy_type(field) - primary_key = getattr(field.field_info, "primary_key", False) + primary_key = getattr(field.field_info, "primary_key", Undefined) + if primary_key is Undefined: + primary_key = False index = getattr(field.field_info, "index", Undefined) if index is Undefined: index = False nullable = not primary_key and _is_field_noneable(field) # Override derived nullability if the nullable property is set explicitly # on the field - if hasattr(field.field_info, "nullable"): - field_nullable = getattr(field.field_info, "nullable") # noqa: B009 - if field_nullable != Undefined: - nullable = field_nullable + field_nullable = getattr(field.field_info, "nullable", Undefined) # noqa: B009 + if field_nullable != Undefined: + assert not isinstance(field_nullable, UndefinedType) + nullable = field_nullable args = [] - foreign_key = getattr(field.field_info, "foreign_key", None) - unique = getattr(field.field_info, "unique", False) + foreign_key = getattr(field.field_info, "foreign_key", Undefined) + if foreign_key is Undefined: + foreign_key = None + unique = getattr(field.field_info, "unique", Undefined) + if unique is Undefined: + unique = False if foreign_key: + assert isinstance(foreign_key, str) args.append(ForeignKey(foreign_key)) kwargs = { "primary_key": primary_key, diff --git a/tests/test_field_sa_args_kwargs.py b/tests/test_field_sa_args_kwargs.py new file mode 100644 index 0000000..94a1a13 --- /dev/null +++ b/tests/test_field_sa_args_kwargs.py @@ -0,0 +1,39 @@ +from typing import Optional + +from sqlalchemy import ForeignKey +from sqlmodel import Field, SQLModel, create_engine + + +def test_sa_column_args(clear_sqlmodel, caplog) -> None: + class Team(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str + + class Hero(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + team_id: Optional[int] = Field( + default=None, + sa_column_args=[ForeignKey("team.id")], + ) + + engine = create_engine("sqlite://", echo=True) + SQLModel.metadata.create_all(engine) + create_table_log = [ + message for message in caplog.messages if "CREATE TABLE hero" in message + ][0] + assert "FOREIGN KEY(team_id) REFERENCES team (id)" in create_table_log + + +def test_sa_column_kargs(clear_sqlmodel, caplog) -> None: + class Item(SQLModel, table=True): + id: Optional[int] = Field( + default=None, + sa_column_kwargs={"primary_key": True}, + ) + + engine = create_engine("sqlite://", echo=True) + SQLModel.metadata.create_all(engine) + create_table_log = [ + message for message in caplog.messages if "CREATE TABLE item" in message + ][0] + assert "PRIMARY KEY (id)" in create_table_log diff --git a/tests/test_field_sa_column.py b/tests/test_field_sa_column.py new file mode 100644 index 0000000..51cfdfa --- /dev/null +++ b/tests/test_field_sa_column.py @@ -0,0 +1,99 @@ +from typing import Optional + +import pytest +from sqlalchemy import Column, Integer, String +from sqlmodel import Field, SQLModel + + +def test_sa_column_takes_precedence() -> None: + class Item(SQLModel, table=True): + id: Optional[int] = Field( + default=None, + sa_column=Column(String, primary_key=True, nullable=False), + ) + + # It would have been nullable with no sa_column + assert Item.id.nullable is False # type: ignore + assert isinstance(Item.id.type, String) # type: ignore + + +def test_sa_column_no_sa_args() -> None: + with pytest.raises(RuntimeError): + + class Item(SQLModel, table=True): + id: Optional[int] = Field( + default=None, + sa_column_args=[Integer], + sa_column=Column(Integer, primary_key=True), + ) + + +def test_sa_column_no_sa_kargs() -> None: + with pytest.raises(RuntimeError): + + class Item(SQLModel, table=True): + id: Optional[int] = Field( + default=None, + sa_column_kwargs={"primary_key": True}, + sa_column=Column(Integer, primary_key=True), + ) + + +def test_sa_column_no_primary_key() -> None: + with pytest.raises(RuntimeError): + + class Item(SQLModel, table=True): + id: Optional[int] = Field( + default=None, + primary_key=True, + sa_column=Column(Integer, primary_key=True), + ) + + +def test_sa_column_no_nullable() -> None: + with pytest.raises(RuntimeError): + + class Item(SQLModel, table=True): + id: Optional[int] = Field( + default=None, + nullable=True, + sa_column=Column(Integer, primary_key=True), + ) + + +def test_sa_column_no_foreign_key() -> None: + with pytest.raises(RuntimeError): + + class Team(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str + + class Hero(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + team_id: Optional[int] = Field( + default=None, + foreign_key="team.id", + sa_column=Column(Integer, primary_key=True), + ) + + +def test_sa_column_no_unique() -> None: + with pytest.raises(RuntimeError): + + class Item(SQLModel, table=True): + id: Optional[int] = Field( + default=None, + unique=True, + sa_column=Column(Integer, primary_key=True), + ) + + +def test_sa_column_no_index() -> None: + with pytest.raises(RuntimeError): + + class Item(SQLModel, table=True): + id: Optional[int] = Field( + default=None, + index=True, + sa_column=Column(Integer, primary_key=True), + ) diff --git a/tests/test_field_sa_relationship.py b/tests/test_field_sa_relationship.py new file mode 100644 index 0000000..7606fd8 --- /dev/null +++ b/tests/test_field_sa_relationship.py @@ -0,0 +1,53 @@ +from typing import List, Optional + +import pytest +from sqlalchemy.orm import relationship +from sqlmodel import Field, Relationship, SQLModel + + +def test_sa_relationship_no_args() -> None: + with pytest.raises(RuntimeError): + + class Team(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(index=True) + headquarters: str + + heroes: List["Hero"] = Relationship( + back_populates="team", + sa_relationship_args=["Hero"], + sa_relationship=relationship("Hero", back_populates="team"), + ) + + class Hero(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(index=True) + secret_name: str + age: Optional[int] = Field(default=None, index=True) + + team_id: Optional[int] = Field(default=None, foreign_key="team.id") + team: Optional[Team] = Relationship(back_populates="heroes") + + +def test_sa_relationship_no_kwargs() -> None: + with pytest.raises(RuntimeError): + + class Team(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(index=True) + headquarters: str + + heroes: List["Hero"] = Relationship( + back_populates="team", + sa_relationship_kwargs={"lazy": "selectin"}, + sa_relationship=relationship("Hero", back_populates="team"), + ) + + class Hero(SQLModel, table=True): + id: Optional[int] = Field(default=None, primary_key=True) + name: str = Field(index=True) + secret_name: str + age: Optional[int] = Field(default=None, index=True) + + team_id: Optional[int] = Field(default=None, foreign_key="team.id") + team: Optional[Team] = Relationship(back_populates="heroes") From 6457775a0f6994cdaf48ecaf286bb16d4bd44840 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 28 Oct 2023 13:55:56 +0000 Subject: [PATCH 83/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 61cd9f6..9e5a876 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Do not allow invalid combinations of field parameters for columns and relationships, `sa_column` excludes `sa_column_args`, `primary_key`, `nullable`, etc.. PR [#681](https://github.com/tiangolo/sqlmodel/pull/681) by [@tiangolo](https://github.com/tiangolo). ## 0.0.10 ### Features From 963298066402813273a2982e450f4eaf2f86ab79 Mon Sep 17 00:00:00 2001 From: Matthieu LAURENT Date: Sun, 29 Oct 2023 08:24:32 +0100 Subject: [PATCH 84/85] =?UTF-8?q?=F0=9F=8E=A8=20Update=20inline=20source?= =?UTF-8?q?=20examples,=20hide=20`#`=20in=20annotations=20(from=20MkDocs?= =?UTF-8?q?=20Material)=20(#677)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SebastiΓ‘n RamΓ­rez --- .../automatic_id_none_refresh/tutorial002.py | 80 +++++++++---------- .../create_db_and_table/tutorial003.py | 28 +++---- docs_src/tutorial/delete/tutorial002.py | 26 +++--- .../app_testing/tutorial001/test_main_001.py | 18 ++--- .../app_testing/tutorial001/test_main_002.py | 10 +-- .../app_testing/tutorial001/test_main_003.py | 14 ++-- .../app_testing/tutorial001/test_main_004.py | 6 +- .../app_testing/tutorial001/test_main_005.py | 12 +-- .../app_testing/tutorial001/test_main_006.py | 16 ++-- docs_src/tutorial/insert/tutorial003.py | 22 ++--- docs_src/tutorial/select/tutorial002.py | 26 +++--- docs_src/tutorial/update/tutorial002.py | 18 ++--- docs_src/tutorial/update/tutorial004.py | 40 +++++----- 13 files changed, 158 insertions(+), 158 deletions(-) diff --git a/docs_src/tutorial/automatic_id_none_refresh/tutorial002.py b/docs_src/tutorial/automatic_id_none_refresh/tutorial002.py index 1c7cd53..c597506 100644 --- a/docs_src/tutorial/automatic_id_none_refresh/tutorial002.py +++ b/docs_src/tutorial/automatic_id_none_refresh/tutorial002.py @@ -21,56 +21,56 @@ def create_db_and_tables(): def create_heroes(): - hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") # (1) - hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") # (2) - hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48) # (3) + hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") # (1)! + hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") # (2)! + hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48) # (3)! - print("Before interacting with the database") # (4) - print("Hero 1:", hero_1) # (5) - print("Hero 2:", hero_2) # (6) - print("Hero 3:", hero_3) # (7) + print("Before interacting with the database") # (4)! + print("Hero 1:", hero_1) # (5)! + print("Hero 2:", hero_2) # (6)! + print("Hero 3:", hero_3) # (7)! - with Session(engine) as session: # (8) - session.add(hero_1) # (9) - session.add(hero_2) # (10) - session.add(hero_3) # (11) + with Session(engine) as session: # (8)! + session.add(hero_1) # (9)! + session.add(hero_2) # (10)! + session.add(hero_3) # (11)! - print("After adding to the session") # (12) - print("Hero 1:", hero_1) # (13) - print("Hero 2:", hero_2) # (14) - print("Hero 3:", hero_3) # (15) + print("After adding to the session") # (12)! + print("Hero 1:", hero_1) # (13)! + print("Hero 2:", hero_2) # (14)! + print("Hero 3:", hero_3) # (15)! - session.commit() # (16) + session.commit() # (16)! - print("After committing the session") # (17) - print("Hero 1:", hero_1) # (18) - print("Hero 2:", hero_2) # (19) - print("Hero 3:", hero_3) # (20) + print("After committing the session") # (17)! + print("Hero 1:", hero_1) # (18)! + print("Hero 2:", hero_2) # (19)! + print("Hero 3:", hero_3) # (20)! - print("After committing the session, show IDs") # (21) - print("Hero 1 ID:", hero_1.id) # (22) - print("Hero 2 ID:", hero_2.id) # (23) - print("Hero 3 ID:", hero_3.id) # (24) + print("After committing the session, show IDs") # (21)! + print("Hero 1 ID:", hero_1.id) # (22)! + print("Hero 2 ID:", hero_2.id) # (23)! + print("Hero 3 ID:", hero_3.id) # (24)! - print("After committing the session, show names") # (25) - print("Hero 1 name:", hero_1.name) # (26) - print("Hero 2 name:", hero_2.name) # (27) - print("Hero 3 name:", hero_3.name) # (28) + print("After committing the session, show names") # (25)! + print("Hero 1 name:", hero_1.name) # (26)! + print("Hero 2 name:", hero_2.name) # (27)! + print("Hero 3 name:", hero_3.name) # (28)! - session.refresh(hero_1) # (29) - session.refresh(hero_2) # (30) - session.refresh(hero_3) # (31) + session.refresh(hero_1) # (29)! + session.refresh(hero_2) # (30)! + session.refresh(hero_3) # (31)! - print("After refreshing the heroes") # (32) - print("Hero 1:", hero_1) # (33) - print("Hero 2:", hero_2) # (34) - print("Hero 3:", hero_3) # (35) - # (36) + print("After refreshing the heroes") # (32)! + print("Hero 1:", hero_1) # (33)! + print("Hero 2:", hero_2) # (34)! + print("Hero 3:", hero_3) # (35)! + # (36)! - print("After the session closes") # (37) - print("Hero 1:", hero_1) # (38) - print("Hero 2:", hero_2) # (39) - print("Hero 3:", hero_3) # (40) + print("After the session closes") # (37)! + print("Hero 1:", hero_1) # (38)! + print("Hero 2:", hero_2) # (39)! + print("Hero 3:", hero_3) # (40)! def main(): diff --git a/docs_src/tutorial/create_db_and_table/tutorial003.py b/docs_src/tutorial/create_db_and_table/tutorial003.py index 8650870..9406300 100644 --- a/docs_src/tutorial/create_db_and_table/tutorial003.py +++ b/docs_src/tutorial/create_db_and_table/tutorial003.py @@ -1,24 +1,24 @@ -from typing import Optional # (1) +from typing import Optional # (1)! -from sqlmodel import Field, SQLModel, create_engine # (2) +from sqlmodel import Field, SQLModel, create_engine # (2)! -class Hero(SQLModel, table=True): # (3) - id: Optional[int] = Field(default=None, primary_key=True) # (4) - name: str # (5) - secret_name: str # (6) - age: Optional[int] = None # (7) +class Hero(SQLModel, table=True): # (3)! + id: Optional[int] = Field(default=None, primary_key=True) # (4)! + name: str # (5)! + secret_name: str # (6)! + age: Optional[int] = None # (7)! -sqlite_file_name = "database.db" # (8) -sqlite_url = f"sqlite:///{sqlite_file_name}" # (9) +sqlite_file_name = "database.db" # (8)! +sqlite_url = f"sqlite:///{sqlite_file_name}" # (9)! -engine = create_engine(sqlite_url, echo=True) # (10) +engine = create_engine(sqlite_url, echo=True) # (10)! -def create_db_and_tables(): # (11) - SQLModel.metadata.create_all(engine) # (12) +def create_db_and_tables(): # (11)! + SQLModel.metadata.create_all(engine) # (12)! -if __name__ == "__main__": # (13) - create_db_and_tables() # (14) +if __name__ == "__main__": # (13)! + create_db_and_tables() # (14)! diff --git a/docs_src/tutorial/delete/tutorial002.py b/docs_src/tutorial/delete/tutorial002.py index 202d63b..4d8c368 100644 --- a/docs_src/tutorial/delete/tutorial002.py +++ b/docs_src/tutorial/delete/tutorial002.py @@ -71,23 +71,23 @@ def update_heroes(): def delete_heroes(): with Session(engine) as session: - statement = select(Hero).where(Hero.name == "Spider-Youngster") # (1) - results = session.exec(statement) # (2) - hero = results.one() # (3) - print("Hero: ", hero) # (4) + statement = select(Hero).where(Hero.name == "Spider-Youngster") # (1)! + results = session.exec(statement) # (2)! + hero = results.one() # (3)! + print("Hero: ", hero) # (4)! - session.delete(hero) # (5) - session.commit() # (6) + session.delete(hero) # (5)! + session.commit() # (6)! - print("Deleted hero:", hero) # (7) + print("Deleted hero:", hero) # (7)! - statement = select(Hero).where(Hero.name == "Spider-Youngster") # (8) - results = session.exec(statement) # (9) - hero = results.first() # (10) + statement = select(Hero).where(Hero.name == "Spider-Youngster") # (8)! + results = session.exec(statement) # (9)! + hero = results.first() # (10)! - if hero is None: # (11) - print("There's no hero named Spider-Youngster") # (12) - # (13) + if hero is None: # (11)! + print("There's no hero named Spider-Youngster") # (12)! + # (13)! def main(): diff --git a/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_001.py b/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_001.py index 38ab1f1..3ae4077 100644 --- a/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_001.py +++ b/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_001.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from sqlmodel import Session, SQLModel, create_engine -from .main import app, get_session # (1) +from .main import app, get_session # (1)! def test_create_hero(): @@ -17,16 +17,16 @@ def test_create_hero(): app.dependency_overrides[get_session] = get_session_override - client = TestClient(app) # (2) + client = TestClient(app) # (2)! - response = client.post( # (3) + response = client.post( # (3)! "/heroes/", json={"name": "Deadpond", "secret_name": "Dive Wilson"} ) app.dependency_overrides.clear() - data = response.json() # (4) + data = response.json() # (4)! - assert response.status_code == 200 # (5) - assert data["name"] == "Deadpond" # (6) - assert data["secret_name"] == "Dive Wilson" # (7) - assert data["age"] is None # (8) - assert data["id"] is not None # (9) + assert response.status_code == 200 # (5)! + assert data["name"] == "Deadpond" # (6)! + assert data["secret_name"] == "Dive Wilson" # (7)! + assert data["age"] is None # (8)! + assert data["id"] is not None # (9)! diff --git a/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_002.py b/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_002.py index 144360a..727580b 100644 --- a/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_002.py +++ b/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_002.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from sqlmodel import Session, SQLModel, create_engine -from .main import app, get_session # (1) +from .main import app, get_session # (1)! def test_create_hero(): @@ -12,17 +12,17 @@ def test_create_hero(): with Session(engine) as session: - def get_session_override(): # (2) - return session # (3) + def get_session_override(): # (2)! + return session # (3)! - app.dependency_overrides[get_session] = get_session_override # (4) + app.dependency_overrides[get_session] = get_session_override # (4)! client = TestClient(app) response = client.post( "/heroes/", json={"name": "Deadpond", "secret_name": "Dive Wilson"} ) - app.dependency_overrides.clear() # (5) + app.dependency_overrides.clear() # (5)! data = response.json() assert response.status_code == 200 diff --git a/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_003.py b/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_003.py index 5de06f8..465c525 100644 --- a/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_003.py +++ b/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_003.py @@ -1,21 +1,21 @@ from fastapi.testclient import TestClient from sqlmodel import Session, SQLModel, create_engine -from .main import app, get_session # (1) +from .main import app, get_session # (1)! def test_create_hero(): - engine = create_engine( # (2) + engine = create_engine( # (2)! "sqlite:///testing.db", connect_args={"check_same_thread": False} ) - SQLModel.metadata.create_all(engine) # (3) + SQLModel.metadata.create_all(engine) # (3)! - with Session(engine) as session: # (4) + with Session(engine) as session: # (4)! def get_session_override(): - return session # (5) + return session # (5)! - app.dependency_overrides[get_session] = get_session_override # (4) + app.dependency_overrides[get_session] = get_session_override # (4)! client = TestClient(app) @@ -30,4 +30,4 @@ def test_create_hero(): assert data["secret_name"] == "Dive Wilson" assert data["age"] is None assert data["id"] is not None - # (6) + # (6)! diff --git a/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_004.py b/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_004.py index f14fce8..b770a9a 100644 --- a/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_004.py +++ b/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_004.py @@ -1,15 +1,15 @@ from fastapi.testclient import TestClient from sqlmodel import Session, SQLModel, create_engine -from sqlmodel.pool import StaticPool # (1) +from sqlmodel.pool import StaticPool # (1)! from .main import app, get_session def test_create_hero(): engine = create_engine( - "sqlite://", # (2) + "sqlite://", # (2)! connect_args={"check_same_thread": False}, - poolclass=StaticPool, # (3) + poolclass=StaticPool, # (3)! ) SQLModel.metadata.create_all(engine) diff --git a/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_005.py b/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_005.py index b5200e6..f653eef 100644 --- a/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_005.py +++ b/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_005.py @@ -1,4 +1,4 @@ -import pytest # (1) +import pytest # (1)! from fastapi.testclient import TestClient from sqlmodel import Session, SQLModel, create_engine from sqlmodel.pool import StaticPool @@ -6,19 +6,19 @@ from sqlmodel.pool import StaticPool from .main import app, get_session -@pytest.fixture(name="session") # (2) -def session_fixture(): # (3) +@pytest.fixture(name="session") # (2)! +def session_fixture(): # (3)! engine = create_engine( "sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool ) SQLModel.metadata.create_all(engine) with Session(engine) as session: - yield session # (4) + yield session # (4)! -def test_create_hero(session: Session): # (5) +def test_create_hero(session: Session): # (5)! def get_session_override(): - return session # (6) + return session # (6)! app.dependency_overrides[get_session] = get_session_override diff --git a/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_006.py b/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_006.py index 577d56d..8dbfd45 100644 --- a/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_006.py +++ b/docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_006.py @@ -16,19 +16,19 @@ def session_fixture(): yield session -@pytest.fixture(name="client") # (1) -def client_fixture(session: Session): # (2) - def get_session_override(): # (3) +@pytest.fixture(name="client") # (1)! +def client_fixture(session: Session): # (2)! + def get_session_override(): # (3)! return session - app.dependency_overrides[get_session] = get_session_override # (4) + app.dependency_overrides[get_session] = get_session_override # (4)! - client = TestClient(app) # (5) - yield client # (6) - app.dependency_overrides.clear() # (7) + client = TestClient(app) # (5)! + yield client # (6)! + app.dependency_overrides.clear() # (7)! -def test_create_hero(client: TestClient): # (8) +def test_create_hero(client: TestClient): # (8)! response = client.post( "/heroes/", json={"name": "Deadpond", "secret_name": "Dive Wilson"} ) diff --git a/docs_src/tutorial/insert/tutorial003.py b/docs_src/tutorial/insert/tutorial003.py index 8133f29..03f51d2 100644 --- a/docs_src/tutorial/insert/tutorial003.py +++ b/docs_src/tutorial/insert/tutorial003.py @@ -20,24 +20,24 @@ def create_db_and_tables(): SQLModel.metadata.create_all(engine) -def create_heroes(): # (1) - hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") # (2) +def create_heroes(): # (1)! + hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") # (2)! hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48) - with Session(engine) as session: # (3) - session.add(hero_1) # (4) + with Session(engine) as session: # (3)! + session.add(hero_1) # (4)! session.add(hero_2) session.add(hero_3) - session.commit() # (5) - # (6) + session.commit() # (5)! + # (6)! -def main(): # (7) - create_db_and_tables() # (8) - create_heroes() # (9) +def main(): # (7)! + create_db_and_tables() # (8)! + create_heroes() # (9)! -if __name__ == "__main__": # (10) - main() # (11) +if __name__ == "__main__": # (10)! + main() # (11)! diff --git a/docs_src/tutorial/select/tutorial002.py b/docs_src/tutorial/select/tutorial002.py index 4f6d102..2229f3f 100644 --- a/docs_src/tutorial/select/tutorial002.py +++ b/docs_src/tutorial/select/tutorial002.py @@ -1,9 +1,9 @@ from typing import Optional -from sqlmodel import Field, Session, SQLModel, create_engine, select # (1) +from sqlmodel import Field, Session, SQLModel, create_engine, select # (1)! -class Hero(SQLModel, table=True): # (2) +class Hero(SQLModel, table=True): # (2)! id: Optional[int] = Field(default=None, primary_key=True) name: str secret_name: str @@ -13,19 +13,19 @@ class Hero(SQLModel, table=True): # (2) sqlite_file_name = "database.db" sqlite_url = f"sqlite:///{sqlite_file_name}" -engine = create_engine(sqlite_url, echo=True) # (3) +engine = create_engine(sqlite_url, echo=True) # (3)! def create_db_and_tables(): - SQLModel.metadata.create_all(engine) # (4) + SQLModel.metadata.create_all(engine) # (4)! def create_heroes(): - hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") # (5) + hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") # (5)! hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador") hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48) - with Session(engine) as session: # (6) + with Session(engine) as session: # (6)! session.add(hero_1) session.add(hero_2) session.add(hero_3) @@ -34,18 +34,18 @@ def create_heroes(): def select_heroes(): - with Session(engine) as session: # (7) - statement = select(Hero) # (8) - results = session.exec(statement) # (9) - for hero in results: # (10) - print(hero) # (11) - # (12) + with Session(engine) as session: # (7)! + statement = select(Hero) # (8)! + results = session.exec(statement) # (9)! + for hero in results: # (10)! + print(hero) # (11)! + # (12)! def main(): create_db_and_tables() create_heroes() - select_heroes() # (13) + select_heroes() # (13)! if __name__ == "__main__": diff --git a/docs_src/tutorial/update/tutorial002.py b/docs_src/tutorial/update/tutorial002.py index 4880f73..5721985 100644 --- a/docs_src/tutorial/update/tutorial002.py +++ b/docs_src/tutorial/update/tutorial002.py @@ -43,16 +43,16 @@ def create_heroes(): def update_heroes(): with Session(engine) as session: - statement = select(Hero).where(Hero.name == "Spider-Boy") # (1) - results = session.exec(statement) # (2) - hero = results.one() # (3) - print("Hero:", hero) # (4) + statement = select(Hero).where(Hero.name == "Spider-Boy") # (1)! + results = session.exec(statement) # (2)! + hero = results.one() # (3)! + print("Hero:", hero) # (4)! - hero.age = 16 # (5) - session.add(hero) # (6) - session.commit() # (7) - session.refresh(hero) # (8) - print("Updated hero:", hero) # (9) + hero.age = 16 # (5)! + session.add(hero) # (6)! + session.commit() # (7)! + session.refresh(hero) # (8)! + print("Updated hero:", hero) # (9)! def main(): diff --git a/docs_src/tutorial/update/tutorial004.py b/docs_src/tutorial/update/tutorial004.py index 868c66c..c74316e 100644 --- a/docs_src/tutorial/update/tutorial004.py +++ b/docs_src/tutorial/update/tutorial004.py @@ -43,31 +43,31 @@ def create_heroes(): def update_heroes(): with Session(engine) as session: - statement = select(Hero).where(Hero.name == "Spider-Boy") # (1) - results = session.exec(statement) # (2) - hero_1 = results.one() # (3) - print("Hero 1:", hero_1) # (4) + statement = select(Hero).where(Hero.name == "Spider-Boy") # (1)! + results = session.exec(statement) # (2)! + hero_1 = results.one() # (3)! + print("Hero 1:", hero_1) # (4)! - statement = select(Hero).where(Hero.name == "Captain North America") # (5) - results = session.exec(statement) # (6) - hero_2 = results.one() # (7) - print("Hero 2:", hero_2) # (8) + statement = select(Hero).where(Hero.name == "Captain North America") # (5)! + results = session.exec(statement) # (6)! + hero_2 = results.one() # (7)! + print("Hero 2:", hero_2) # (8)! - hero_1.age = 16 # (9) - hero_1.name = "Spider-Youngster" # (10) - session.add(hero_1) # (11) + hero_1.age = 16 # (9)! + hero_1.name = "Spider-Youngster" # (10)! + session.add(hero_1) # (11)! - hero_2.name = "Captain North America Except Canada" # (12) - hero_2.age = 110 # (13) - session.add(hero_2) # (14) + hero_2.name = "Captain North America Except Canada" # (12)! + hero_2.age = 110 # (13)! + session.add(hero_2) # (14)! - session.commit() # (15) - session.refresh(hero_1) # (16) - session.refresh(hero_2) # (17) + session.commit() # (15)! + session.refresh(hero_1) # (16)! + session.refresh(hero_2) # (17)! - print("Updated hero 1:", hero_1) # (18) - print("Updated hero 2:", hero_2) # (19) - # (20) + print("Updated hero 1:", hero_1) # (18)! + print("Updated hero 2:", hero_2) # (19)! + # (20)! def main(): From c557cf6d18a4a173cd922e34831989f8caab1c3e Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 29 Oct 2023 07:25:17 +0000 Subject: [PATCH 85/85] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index 9e5a876..f01af6c 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🎨 Update inline source examples, hide `#` in annotations (from MkDocs Material). PR [#677](https://github.com/tiangolo/sqlmodel/pull/677) by [@Matthieu-LAURENT39](https://github.com/Matthieu-LAURENT39). * ✨ Do not allow invalid combinations of field parameters for columns and relationships, `sa_column` excludes `sa_column_args`, `primary_key`, `nullable`, etc.. PR [#681](https://github.com/tiangolo/sqlmodel/pull/681) by [@tiangolo](https://github.com/tiangolo). ## 0.0.10