Repository: PrefectHQ/prefect

Issue:
Block schema version changes don't register correctly
### First check

- [X] I added a descriptive title to this issue.
- [X] I used the GitHub search to find a similar issue and didn't find it.
- [X] I searched the Prefect documentation for this issue.
- [X] I checked that this issue is related to Prefect and not one of its dependencies.

### Bug summary

When the block schema version of a block subclass is updated, the expected behavior is that a new block schema is registered for the corresponding block type. It appears when a block schema with an existing checksum and new version is registered then the already registered block schema is found and returned instead of creating a new block schema and the block schema version is not being respected by the API.

### Reproduction

```python
from prefect import get_client
from prefect.blocks.core import block

class Test(Block):
    a: str
    b: str
    c: int

Test.register_type_and_schema(0

Test._block_schema_version = "new_version"

Test.register_type_and_schema()

async with get_client() as client:
    block_schema = await client.read_block_schema_by_checksum(                      
        checksum=NewBlock._calculate_schema_checksum(),
        version=NewBlock.get_block_schema_version(),
     )

assert block_schema.version == "new_version" # Fails because block_schema.version == "non-versioned"
```


### Error

```

# Copy complete stack trace and error message here, including log output if applicable.

```


### Versions

```
Version:             2.3.2
API version:         0.8.0
Python version:      3.9.13
Git commit:          6e931ee9
Built:               Tue, Sep 6, 2022 12:36 PM
OS/Arch:             darwin/x86_64
Profile:             prod
Server type:         cloud
```


### Additional context

_No response_


Discussion:

Resolving patch:
diff --git a/src/prefect/blocks/core.py b/src/prefect/blocks/core.py
--- a/src/prefect/blocks/core.py
+++ b/src/prefect/blocks/core.py
@@ -21,6 +21,7 @@
 from griffe.dataclasses import Docstring
 from griffe.docstrings.dataclasses import DocstringSection, DocstringSectionKind
 from griffe.docstrings.parsers import Parser, parse
+from packaging.version import InvalidVersion, Version
 from pydantic import BaseModel, HttpUrl, SecretBytes, SecretStr
 from slugify import slugify
 from typing_extensions import ParamSpec, Self, get_args, get_origin
@@ -247,9 +248,11 @@ def _get_current_package_version(cls):
                 current_module.__name__.split(".")[0] or "__main__"
             ]
             try:
-                return str(top_level_module.__version__)
-            except AttributeError:
-                # Module does not have a __version__ attribute
+                version = Version(top_level_module.__version__)
+                # Strips off any local version information
+                return version.base_version
+            except (AttributeError, InvalidVersion):
+                # Module does not have a __version__ attribute or is not a parsable format
                 pass
         return DEFAULT_BLOCK_SCHEMA_VERSION
 
@@ -707,7 +710,8 @@ async def register_type_and_schema(cls, client: Optional["OrionClient"] = None):
 
             try:
                 block_schema = await client.read_block_schema_by_checksum(
-                    checksum=cls._calculate_schema_checksum()
+                    checksum=cls._calculate_schema_checksum(),
+                    version=cls.get_block_schema_version(),
                 )
             except prefect.exceptions.ObjectNotFound:
                 block_schema = await client.create_block_schema(
diff --git a/src/prefect/client.py b/src/prefect/client.py
--- a/src/prefect/client.py
+++ b/src/prefect/client.py
@@ -1034,7 +1034,7 @@ async def create_block_schema(
                 json=block_schema.dict(
                     json_compatible=True,
                     exclude_unset=True,
-                    include={"type", "block_type_id", "fields"},
+                    exclude={"id", "block_type", "checksum"},
                 ),
             )
         except httpx.HTTPStatusError as e:
@@ -1126,13 +1126,16 @@ async def read_block_type_by_slug(self, slug: str) -> BlockType:
         return BlockType.parse_obj(response.json())
 
     async def read_block_schema_by_checksum(
-        self, checksum: str
+        self, checksum: str, version: Optional[str] = None
     ) -> schemas.core.BlockSchema:
         """
         Look up a block schema checksum
         """
         try:
-            response = await self._client.get(f"/block_schemas/checksum/{checksum}")
+            url = f"/block_schemas/checksum/{checksum}"
+            if version is not None:
+                url = f"{url}?version={version}"
+            response = await self._client.get(url)
         except httpx.HTTPStatusError as e:
             if e.response.status_code == status.HTTP_404_NOT_FOUND:
                 raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
diff --git a/src/prefect/orion/api/block_schemas.py b/src/prefect/orion/api/block_schemas.py
--- a/src/prefect/orion/api/block_schemas.py
+++ b/src/prefect/orion/api/block_schemas.py
@@ -44,7 +44,9 @@ async def create_block_schema(
         block_schema_checksum = Block._calculate_schema_checksum(block_schema.fields)
         existing_block_schema = (
             await models.block_schemas.read_block_schema_by_checksum(
-                session=session, checksum=block_schema_checksum
+                session=session,
+                checksum=block_schema_checksum,
+                version=block_schema.version,
             )
         )
         if existing_block_schema:


Test patch:
diff --git a/tests/blocks/test_core.py b/tests/blocks/test_core.py
--- a/tests/blocks/test_core.py
+++ b/tests/blocks/test_core.py
@@ -6,6 +6,7 @@
 from uuid import UUID, uuid4
 
 import pytest
+from packaging.version import Version
 from pydantic import BaseModel, Field, SecretBytes, SecretStr
 
 import prefect
@@ -514,7 +515,7 @@ def test_create_block_schema_with_version_specified(
     def test_create_block_schema_uses_prefect_version_for_built_in_blocks(self):
         Secret.register_type_and_schema()
         block_schema = Secret._to_block_schema()
-        assert block_schema.version == prefect.__version__
+        assert block_schema.version == Version(prefect.__version__).base_version
 
     def test_collecting_capabilities(self):
         class CanRun(Block):
@@ -808,6 +809,34 @@ class ImpostorBlock(Block):
         assert block_schema is not None
         assert block_schema.fields == self.NewBlock.schema()
 
+    async def test_register_new_block_schema_when_version_changes(
+        self, orion_client: OrionClient
+    ):
+        # Ignore warning caused by matching key in registry
+        warnings.filterwarnings("ignore", category=UserWarning)
+
+        await self.NewBlock.register_type_and_schema()
+
+        block_schema = await orion_client.read_block_schema_by_checksum(
+            checksum=self.NewBlock._calculate_schema_checksum()
+        )
+        assert block_schema is not None
+        assert block_schema.fields == self.NewBlock.schema()
+        assert block_schema.version == DEFAULT_BLOCK_SCHEMA_VERSION
+
+        self.NewBlock._block_schema_version = "new_version"
+
+        await self.NewBlock.register_type_and_schema()
+
+        block_schema = await orion_client.read_block_schema_by_checksum(
+            checksum=self.NewBlock._calculate_schema_checksum()
+        )
+        assert block_schema is not None
+        assert block_schema.fields == self.NewBlock.schema()
+        assert block_schema.version == "new_version"
+
+        self.NewBlock._block_schema_version = None
+
     async def test_register_nested_block(self, orion_client: OrionClient):
         class Big(Block):
             id: UUID = Field(default_factory=uuid4)