I’m in the process of migrating from a Prefect 1.0 cloud deployment to a 2.0 cloud deploying and I’m receiving the error “AttributeError: ‘coroutine’ object has no attribute ‘apply’” when trying to run the hi_deploy.py deployment code example.
hi_deploy.py:
from prefect import flow
from prefect.deployments import Deployment
@flow(log_prints=True)
def hi():
print("Hi from Prefect!")
def deploy():
deployment = Deployment.build_from_flow(
flow=hi,
name="prefect-example-deployment"
deployment.apply()
if __name__ == "__main__":
deploy()
full error context:
File ~\Anaconda3\envs\prefect\lib\site-packages\spyder_kernels\py3compat.py:356 in compat_exec
exec(code, globals, locals)
File ~\untitled0.py:16
deploy()
File ~\untitled0.py:13 in deploy
deployment.apply()
AttributeError: 'coroutine' object has no attribute 'apply'
I’m running the example in new conda environment on a windows 10 machine with the following packages installed:
aiosqlite==0.18.0
alabaster==0.7.12
alembic==1.10.2
anyio==3.6.2
apprise==1.3.0
arrow==1.2.3
asgi-lifespan==2.0.0
asn1crypto==1.5.1
astroid==2.11.7
asttokens==2.0.5
asyncpg==0.27.0
atomicwrites==1.4.0
attrs==22.2.0
autopep8==1.6.0
Babel==2.11.0
backcall==0.2.0
bcrypt==3.2.0
beautifulsoup4==4.12.0
binaryornot==0.4.4
black==22.6.0
bleach==4.1.0
boto3==1.24.28
botocore==1.27.59
Bottleneck==1.3.5
brotlipy==0.7.0
cachetools==5.3.0
certifi==2022.12.7
cffi==1.15.1
chardet==4.0.0
charset-normalizer==3.1.0
click==8.1.3
cloudpickle==2.2.1
colorama==0.4.6
comm==0.1.2
cookiecutter==1.7.3
coolname==2.2.0
croniter==1.3.8
cryptography==39.0.2
dateparser==1.1.7
debugpy==1.5.1
decorator==5.1.1
defusedxml==0.7.1
diff-match-patch==20200713
dill==0.3.6
docker==6.0.1
docstring-to-markdown==0.11
docutils==0.18.1
ecdsa==0.17.0
entrypoints==0.4
et-xmlfile==1.1.0
executing==0.8.3
fastapi==0.95.0
fastjsonschema==2.16.2
flake8==6.0.0
flit_core==3.6.0
fsspec==2023.1.0
google-auth==2.16.2
greenlet==2.0.2
griffe==0.25.5
h11==0.14.0
h2==4.1.0
hpack==4.0.0
httpcore==0.16.3
httpx==0.23.3
hyperframe==6.0.1
idna==3.4
imagesize==1.4.1
importlib-metadata==4.11.3
inflection==0.5.1
intervaltree==3.1.0
ipykernel==6.19.2
ipython==8.8.0
ipython-genutils==0.2.0
isort==5.9.3
jedi==0.18.1
jellyfish==0.9.0
Jinja2==3.1.2
jinja2-time==0.2.0
jmespath==0.10.0
jsonpatch==1.32
jsonpointer==2.3
jsonschema==4.17.3
jupyter_client==7.4.9
jupyter_core==5.1.1
jupyterlab-pygments==0.1.2
keyring==23.4.0
kubernetes==26.1.0
lazy-object-proxy==1.6.0
lxml==4.9.1
Mako==1.2.4
Markdown==3.4.1
markdown-it-py==2.2.0
MarkupSafe==2.1.2
matplotlib-inline==0.1.6
mccabe==0.7.0
mdurl==0.1.2
mistune==0.8.4
mkl-fft==1.3.1
mkl-random==1.2.2
mkl-service==2.4.0
mypy-extensions==0.4.3
nbclient==0.5.13
nbconvert==6.5.4
nbformat==5.7.0
nest-asyncio==1.5.6
numexpr==2.8.4
numpy==1.23.5
numpydoc==1.5.0
oauthlib==3.2.2
openpyxl==3.0.10
orjson==3.8.8
packaging==23.0
pandas==1.5.3
pandocfilters==1.5.0
paramiko==2.8.1
parso==0.8.3
pathspec==0.11.1
pendulum==2.1.2
pexpect==4.8.0
pickleshare==0.7.5
pip==23.0.1
platformdirs==2.5.2
plotly==5.9.0
pluggy==1.0.0
ply==3.11
poyo==0.5.0
prefect==2.8.6
prompt-toolkit==3.0.36
psutil==5.9.0
psycopg2==2.9.3
ptyprocess==0.7.0
pure-eval==0.2.2
pyarrow==8.0.0
pyasn1==0.4.8
pyasn1-modules==0.2.8
pycodestyle==2.10.0
pycparser==2.21
pydantic==1.10.6
pydocstyle==6.3.0
pyflakes==3.0.1
Pygments==2.14.0
pylint==2.14.5
pylint-venv==2.3.0
pyls-spyder==0.4.0
PyNaCl==1.5.0
pyodbc==4.0.34
pyOpenSSL==23.0.0
PyQt5==5.15.7
PyQt5-sip==12.11.0
PyQtWebEngine==5.15.4
pyrsistent==0.19.3
PySocks==1.7.1
python-dateutil==2.8.2
python-dotenv==1.0.0
python-http-client==3.3.2
python-lsp-black==1.2.1
python-lsp-jsonrpc==1.0.0
python-lsp-server==1.7.1
python-slugify==8.0.1
pytoolconfig==0.0.0
pytz==2022.7.1
pytz-deprecation-shim==0.1.0.post0
pytzdata==2020.1
pywin32==305.1
pywin32-ctypes==0.2.0
PyYAML==6.0
pyzmq==23.2.0
QDarkStyle==3.0.2
qstylizer==0.2.2
QtAwesome==1.2.2
qtconsole==5.4.0
QtPy==2.2.0
readchar==4.0.5
redshift-connector==2.0.910
regex==2022.10.31
requests==2.28.2
requests-oauthlib==1.3.1
rfc3986==1.5.0
rich==13.3.2
rope==1.7.0
rsa==4.9
Rtree==1.0.1
s3transfer==0.6.0
scramp==1.4.4
sendgrid==6.7.1
setuptools==65.6.3
sip==6.6.2
six==1.16.0
sniffio==1.3.0
snowballstemmer==2.2.0
sortedcontainers==2.4.0
soupsieve==2.3.2.post1
Sphinx==5.0.2
sphinxcontrib-applehelp==1.0.2
sphinxcontrib-devhelp==1.0.2
sphinxcontrib-htmlhelp==2.0.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.3
sphinxcontrib-serializinghtml==1.1.5
spyder==5.4.2
spyder-kernels==2.4.2
SQLAlchemy==1.4.47
stack-data==0.2.0
starkbank-ecdsa==1.1.1
starlette==0.26.1
tenacity==8.0.1
text-unidecode==1.3
textdistance==4.2.1
three-merge==0.1.1
tinycss2==1.2.1
toml==0.10.2
tomli==2.0.1
tomlkit==0.11.1
tornado==6.2
traitlets==5.7.1
typer==0.7.0
typing_extensions==4.5.0
tzdata==2022.7
tzlocal==4.3
ujson==5.4.0
Unidecode==1.2.0
urllib3==1.26.15
uvicorn==0.21.1
watchdog==2.1.6
wcwidth==0.2.5
webencodings==0.5.1
websocket-client==1.5.1
websockets==10.4
Werkzeug==2.2.2
whatthepatch==1.0.2
wheel==0.38.4
win-inet-pton==1.1.0
wincertstore==0.2
wrapt==1.14.1
XlsxWriter==3.0.3
yapf==0.31.0
zipp==3.15.0
When inspecting the contents of the ~\Lib\site-packages\prefect\deployments.py file I can see that the apply attribute is definitely present in the Deployment Class
@experimental_field(
"work_pool_name",
group="work_pools",
when=lambda x: x is not None and x != DEFAULT_AGENT_WORK_POOL_NAME,
class Deployment(BaseModel):
# ........................ truncated ..........................
@sync_compatible
async def apply(
self, upload: bool = False, work_queue_concurrency: int = None
) -> UUID:
Registers this deployment with the API and returns the deployment's ID.
Args:
upload: if True, deployment files are automatically uploaded to remote storage
work_queue_concurrency: If provided, sets the concurrency limit on the deployment's work queue
if not self.name or not self.flow_name:
raise ValueError("Both a deployment name and flow name must be set.")
async with get_client() as client:
# prep IDs
flow_id = await client.create_flow_from_name(self.flow_name)
infrastructure_document_id = self.infrastructure._block_document_id
if not infrastructure_document_id:
# if not building off a block, will create an anonymous block
self.infrastructure = self.infrastructure.copy()
infrastructure_document_id = await self.infrastructure._save(
is_anonymous=True,
if upload:
await self.upload_to_storage()
if self.work_queue_name and work_queue_concurrency is not None:
res = await client.create_work_queue(
name=self.work_queue_name, work_pool_name=self.work_pool_name
except ObjectAlreadyExists:
res = await client.read_work_queue_by_name(
name=self.work_queue_name, work_pool_name=self.work_pool_name
await client.update_work_queue(
res.id, concurrency_limit=work_queue_concurrency
# we assume storage was already saved
storage_document_id = getattr(self.storage, "_block_document_id", None)
deployment_id = await client.create_deployment(
flow_id=flow_id,
name=self.name,
work_queue_name=self.work_queue_name,
work_pool_name=self.work_pool_name,
version=self.version,
schedule=self.schedule,
is_schedule_active=self.is_schedule_active,
parameters=self.parameters,
description=self.description,
tags=self.tags,
manifest_path=self.manifest_path, # allows for backwards YAML compat
path=self.path,
entrypoint=self.entrypoint,
infra_overrides=self.infra_overrides,
storage_document_id=storage_document_id,
infrastructure_document_id=infrastructure_document_id,
parameter_openapi_schema=self.parameter_openapi_schema.dict(),
return deployment_id
# ........................ truncated ..........................
if apply:
await deployment.apply()
return deployment
I think I found my issue, or at least a work around… It looks like the Prefect 2.0 deployment script will not run properly when trying to execute it in the Spyder IDE (version 5.4.2), as was possible when trying to register a flow with flow.register(project_name = “gather_shells”) in Prefect 1.0
I was able to run the deployment script and register the project from the CLI. It would be nice to be able to register the project directly from an IDE.