This reverts commit 895ae970ac
.
This commit is contained in:
parent
e629bc32d5
commit
d243efae19
|
@ -37,8 +37,3 @@
|
|||
- [codegen/python] - Fixes issue with `$fn_output` functions failing in
|
||||
preview when called with unknown arguments
|
||||
[#8320](https://github.com/pulumi/pulumi/pull/8320)
|
||||
|
||||
### Miscellaneous
|
||||
|
||||
- [sdk/python] - Drop support for python 3.6
|
||||
[#8161](https://github.com/pulumi/pulumi/pull/8161)
|
||||
|
|
|
@ -173,8 +173,8 @@ details of the core Pulumi CLI and [programming model concepts](https://www.pulu
|
|||
|
||||
| Architecture | Build Status |
|
||||
| ------------ | ------------ |
|
||||
| Linux/macOS x64 | ![Linux x64 Build Status](https://github.com/pulumi/pulumi/actions/workflows/master.yml/badge.svg) |
|
||||
| Windows x64 | ![Windows x64 Build Status](https://github.com/pulumi/pulumi/actions/workflows/master.yml/badge.svg) |
|
||||
| Linux/macOS x64 | [![Linux x64 Build Status](https://travis-ci.com/pulumi/pulumi.svg?token=cTUUEgrxaTEGyecqJpDn&branch=master)](https://travis-ci.com/pulumi/pulumi) |
|
||||
| Windows x64 | [![Windows x64 Build Status](https://ci.appveyor.com/api/projects/status/uqrduw6qnoss7g4i?svg=true&branch=master)](https://ci.appveyor.com/project/pulumi/pulumi) |
|
||||
|
||||
### Languages
|
||||
|
||||
|
@ -182,7 +182,7 @@ details of the core Pulumi CLI and [programming model concepts](https://www.pulu
|
|||
| -- | -------- | ------ | ------- |
|
||||
| <img src="https://www.pulumi.com/logos/tech/logo-js.png" height=38 /> | [JavaScript](./sdk/nodejs) | Stable | Node.js 12+ |
|
||||
| <img src="https://www.pulumi.com/logos/tech/logo-ts.png" height=38 /> | [TypeScript](./sdk/nodejs) | Stable | Node.js 12+ |
|
||||
| <img src="https://www.pulumi.com/logos/tech/logo-python.png" height=38 /> | [Python](./sdk/python) | Stable | Python 3.7+ |
|
||||
| <img src="https://www.pulumi.com/logos/tech/logo-python.png" height=38 /> | [Python](./sdk/python) | Stable | Python 3.6+ |
|
||||
| <img src="https://www.pulumi.com/logos/tech/logo-golang.png" height=38 /> | [Go](./sdk/go) | Stable | Go 1.14+ |
|
||||
| <img src="https://www.pulumi.com/logos/tech/dotnet.png" height=38 /> | [.NET (C#/F#/VB.NET)](./sdk/dotnet) | Stable | .NET Core 3.1+ |
|
||||
|
||||
|
@ -193,5 +193,5 @@ full list of supported cloud and infrastructure providers.
|
|||
|
||||
## Contributing
|
||||
|
||||
Please see [CONTRIBUTING.md](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
|
||||
Please See [CONTRIBUTING.md](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
|
||||
for information on building Pulumi from source or contributing improvements.
|
||||
|
|
|
@ -69,15 +69,21 @@ if __name__ == "__main__":
|
|||
|
||||
successful = False
|
||||
|
||||
try:
|
||||
# The docs for get_running_loop are somewhat misleading because they state:
|
||||
# This function can only be called from a coroutine or a callback. However, if the function is
|
||||
# called from outside a coroutine or callback (the standard case when running `pulumi up`), the function
|
||||
# raises a RuntimeError as expected and falls through to the exception clause below.
|
||||
loop = asyncio.get_running_loop()
|
||||
except RuntimeError:
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
# asyncio.get_running_loop was only added in python 3.7 but we still support python 3.6
|
||||
# In python 3.10, asyncio.get_event_loop prints a deprecation warning if no loop is present
|
||||
# This code will be cleaned up as part of https://github.com/pulumi/pulumi/issues/8131
|
||||
if sys.version_info[0] == 3 and sys.version_info[1] < 7:
|
||||
loop = asyncio.get_event_loop()
|
||||
else:
|
||||
try:
|
||||
# The docs for get_running_loop are somewhat misleading because they state:
|
||||
# This function can only be called from a coroutine or a callback. However, if the function is
|
||||
# called from outside a coroutine or callback (the standard case when running `pulumi up`), the function
|
||||
# raises a RuntimeError as expected and falls through to the exception clause below.
|
||||
loop = asyncio.get_running_loop()
|
||||
except RuntimeError:
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
|
||||
# We are (unfortunately) suppressing the log output of asyncio to avoid showing to users some of the bad things we
|
||||
# do in our programming model.
|
||||
|
|
|
@ -276,6 +276,7 @@ from . import _utils
|
|||
|
||||
T = TypeVar('T')
|
||||
|
||||
|
||||
_PULUMI_NAME = "_pulumi_name"
|
||||
_PULUMI_INPUT_TYPE = "_pulumi_input_type"
|
||||
_PULUMI_OUTPUT_TYPE = "_pulumi_output_type"
|
||||
|
@ -286,27 +287,22 @@ _TRANSLATE_PROPERTY = "_translate_property"
|
|||
def is_input_type(cls: type) -> bool:
|
||||
return hasattr(cls, _PULUMI_INPUT_TYPE)
|
||||
|
||||
|
||||
def is_output_type(cls: type) -> bool:
|
||||
return hasattr(cls, _PULUMI_OUTPUT_TYPE)
|
||||
|
||||
|
||||
class _MISSING_TYPE:
|
||||
pass
|
||||
|
||||
|
||||
MISSING = _MISSING_TYPE()
|
||||
"""
|
||||
MISSING is a singleton sentinel object to detect if a parameter is supplied or not.
|
||||
"""
|
||||
|
||||
|
||||
class _Property:
|
||||
"""
|
||||
Represents a Pulumi property. It is not meant to be created outside this module,
|
||||
rather, the property() function should be used.
|
||||
"""
|
||||
|
||||
def __init__(self, name: str, default: Any = MISSING) -> None:
|
||||
if not name:
|
||||
raise TypeError("Missing name argument")
|
||||
|
@ -394,10 +390,8 @@ def _create_py_property(a_name: str, pulumi_name: str, typ: Any, setter: bool =
|
|||
"""
|
||||
Returns a Python property getter that looks up the value using get.
|
||||
"""
|
||||
|
||||
def getter_fn(self):
|
||||
return get(self, a_name)
|
||||
|
||||
getter_fn.__name__ = a_name
|
||||
getter_fn.__annotations__ = {"return": typ}
|
||||
setattr(getter_fn, _PULUMI_NAME, pulumi_name)
|
||||
|
@ -405,7 +399,6 @@ def _create_py_property(a_name: str, pulumi_name: str, typ: Any, setter: bool =
|
|||
if setter:
|
||||
def setter_fn(self, value):
|
||||
return set(self, a_name, value)
|
||||
|
||||
setter_fn.__name__ = a_name
|
||||
setter_fn.__annotations__ = {"value": typ}
|
||||
return builtins.property(fget=getter_fn, fset=setter_fn)
|
||||
|
@ -422,7 +415,6 @@ def _py_properties(cls: type) -> Iterator[Tuple[str, str, builtins.property]]:
|
|||
if pulumi_name is not MISSING:
|
||||
yield (python_name, pulumi_name, prop)
|
||||
|
||||
|
||||
def input_type(cls: Type[T]) -> Type[T]:
|
||||
"""
|
||||
Returns the same class as was passed in, but marked as an input type.
|
||||
|
@ -438,7 +430,6 @@ def input_type(cls: Type[T]) -> Type[T]:
|
|||
def create_setter(name: str) -> Callable:
|
||||
def setter_fn(self, value):
|
||||
set(self, name, value)
|
||||
|
||||
return setter_fn
|
||||
|
||||
# Now, process the class's properties, replacing properties with empty setters with
|
||||
|
@ -549,7 +540,6 @@ def getter(_fn=None, *, name: Optional[str] = None):
|
|||
|
||||
name is the Pulumi property name. If not set, the name of the function is used.
|
||||
"""
|
||||
|
||||
def decorator(fn: Callable) -> Callable:
|
||||
if not callable(fn):
|
||||
raise TypeError("Expected fn to be callable")
|
||||
|
@ -561,7 +551,6 @@ def getter(_fn=None, *, name: Optional[str] = None):
|
|||
def get_fn(self):
|
||||
# Get the value using the Python name, which is the name of the function.
|
||||
return get(self, fn.__name__)
|
||||
|
||||
fn = get_fn
|
||||
setattr(fn, _PULUMI_NAME, pulumi_name)
|
||||
return fn
|
||||
|
@ -651,22 +640,41 @@ if sys.version_info[:2] >= (3, 8):
|
|||
get_origin = typing.get_origin # type: ignore
|
||||
# pylint: disable=no-member
|
||||
get_args = typing.get_args # type: ignore
|
||||
else:
|
||||
elif sys.version_info[:2] >= (3, 7):
|
||||
def get_origin(tp):
|
||||
if isinstance(tp, typing._GenericAlias): # type: ignore
|
||||
return tp.__origin__
|
||||
return None
|
||||
|
||||
|
||||
def get_args(tp):
|
||||
if isinstance(tp, typing._GenericAlias): # type: ignore
|
||||
return tp.__args__
|
||||
return ()
|
||||
else:
|
||||
def get_origin(tp):
|
||||
if hasattr(tp, "__origin__"):
|
||||
return tp.__origin__
|
||||
return None
|
||||
|
||||
def get_args(tp):
|
||||
# Emulate the behavior of get_args for Union on Python 3.6.
|
||||
if _is_union_type(tp) and hasattr(tp, "_subs_tree"):
|
||||
tree = tp._subs_tree()
|
||||
if isinstance(tree, tuple) and len(tree) > 1:
|
||||
def _eval(args):
|
||||
return tuple(arg if not isinstance(arg, tuple) else arg[0][_eval(arg[1:])] for arg in args)
|
||||
return _eval(tree[1:])
|
||||
if hasattr(tp, "__args__"):
|
||||
return tp.__args__
|
||||
return ()
|
||||
|
||||
|
||||
def _is_union_type(tp):
|
||||
return (tp is Union or
|
||||
isinstance(tp, typing._GenericAlias) and tp.__origin__ is Union) # type: ignore
|
||||
if sys.version_info[:2] >= (3, 7):
|
||||
return (tp is Union or
|
||||
isinstance(tp, typing._GenericAlias) and tp.__origin__ is Union) # type: ignore
|
||||
# pylint: disable=unidiomatic-typecheck, no-member
|
||||
return type(tp) is typing._Union # type: ignore
|
||||
|
||||
|
||||
def _is_optional_type(tp):
|
||||
|
@ -911,29 +919,29 @@ def unwrap_type(val: type) -> type:
|
|||
def isInputType(args):
|
||||
assert len(args) > 1
|
||||
return (is_input_type(args[0]) and
|
||||
args[1] is dict or get_origin(args[1]) in {dict, Dict, Mapping, collections.abc.Mapping})
|
||||
args[1] is dict or get_origin(args[1]) in {dict, Dict, Mapping, collections.abc.Mapping})
|
||||
|
||||
def isInput(args, i=1):
|
||||
def isInput(args, i = 1):
|
||||
assert len(args) > i + 1
|
||||
return (get_origin(args[i]) in {typing.Awaitable, collections.abc.Awaitable} and
|
||||
get_origin(args[i + 1]) is Output)
|
||||
get_origin(args[i + 1]) is Output)
|
||||
|
||||
args = get_args(val)
|
||||
if len(args) == 2:
|
||||
if isInputType(args): # InputType[T]
|
||||
if isInputType(args): # InputType[T]
|
||||
return args[0]
|
||||
elif len(args) == 3:
|
||||
if isInput(args): # Input[T]
|
||||
if isInput(args): # Input[T]
|
||||
return args[0]
|
||||
if isInputType(args) and args[2] is type(None): # Optional[InputType[T]]
|
||||
if isInputType(args) and args[2] is type(None): # Optiona[InputType[T]]
|
||||
return args[0]
|
||||
elif len(args) == 4:
|
||||
if isInput(args) and args[3] is type(None): # Optional[Input[T]]
|
||||
if isInput(args) and args[3] is type(None): # Optional[Input[T]]
|
||||
return args[0]
|
||||
if isInputType(args) and isInput(args, 2): # Input[InputType[T]]
|
||||
if isInputType(args) and isInput(args, 2): # Input[InputType[T]]
|
||||
return args[0]
|
||||
elif len(args) == 5:
|
||||
if isInputType(args) and isInput(args, 2) and args[4] is type(None): # Optional[Input[InputType[T]]]
|
||||
if isInputType(args) and isInput(args, 2) and args[4] is type(None): # Optional[Input[InputType[T]]]
|
||||
return args[0]
|
||||
|
||||
return unwrap_optional_type(val)
|
||||
|
|
|
@ -24,6 +24,8 @@ from ..runtime.proto import language_pb2, plugin_pb2, LanguageRuntimeServicer
|
|||
from ..runtime import run_in_stack, reset_options, set_all_config
|
||||
from ..errors import RunError
|
||||
|
||||
_py_version_less_than_3_7 = sys.version_info[0] == 3 and sys.version_info[1] < 7
|
||||
|
||||
|
||||
class LanguageServer(LanguageRuntimeServicer):
|
||||
program: PulumiFn
|
||||
|
@ -87,7 +89,7 @@ class LanguageServer(LanguageRuntimeServicer):
|
|||
# at the time the loop is closed, which results in a `Task was destroyed but it is pending!` error being
|
||||
# logged to stdout. To avoid this, we collect all the unresolved tasks in the loop and cancel them before
|
||||
# closing the loop.
|
||||
pending = asyncio.all_tasks(loop)
|
||||
pending = asyncio.Task.all_tasks(loop) if _py_version_less_than_3_7 else asyncio.all_tasks(loop) # pylint: disable=no-member
|
||||
log.debug(f"Cancelling {len(pending)} tasks.")
|
||||
for task in pending:
|
||||
task.cancel()
|
||||
|
|
|
@ -25,7 +25,7 @@ from . import rpc, rpc_manager
|
|||
from .settings import Settings, configure, get_stack, get_project, get_root_resource
|
||||
from .sync_await import _ensure_event_loop, _sync_await
|
||||
from ..runtime.proto import engine_pb2, provider_pb2, resource_pb2
|
||||
from ..runtime.stack import Stack, run_pulumi_func
|
||||
from ..runtime.stack import Stack, run_pulumi_func, wait_for_rpcs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..resource import Resource
|
||||
|
@ -68,8 +68,7 @@ class MockResourceArgs:
|
|||
resource_id: Optional[str] = None,
|
||||
custom: Optional[bool] = None) -> None:
|
||||
"""
|
||||
:param str typ: The token that indicates which resource type is being constructed.
|
||||
This token is of the form "package:module:type".
|
||||
:param str typ: The token that indicates which resource type is being constructed. This token is of the form "package:module:type".
|
||||
:param str name: The logical name of the resource instance.
|
||||
:param dict inputs: The inputs for the resource.
|
||||
:param str provider: The identifier of the provider instance being used to manage this resource.
|
||||
|
@ -94,8 +93,7 @@ class MockCallArgs:
|
|||
|
||||
def __init__(self, token: str, args: dict, provider: str) -> None:
|
||||
"""
|
||||
:param str token: The token that indicates which function is being called.
|
||||
This token is of the form "package:module:function".
|
||||
:param str token: The token that indicates which function is being called. This token is of the form "package:module:function".
|
||||
:param dict args: The arguments provided to the function call.
|
||||
:param str provider: The identifier of the provider instance being used to make the call
|
||||
"""
|
||||
|
@ -106,26 +104,26 @@ class MockCallArgs:
|
|||
|
||||
class Mocks(ABC):
|
||||
"""
|
||||
Mocks is an abstract class that allows subclasses to replace operations normally implemented by the Pulumi
|
||||
engine with their own implementations. This can be used during testing to ensure that calls to provider
|
||||
functions and resource constructors return predictable values.
|
||||
Mocks is an abstract class that allows subclasses to replace operations normally implemented by the Pulumi engine with
|
||||
their own implementations. This can be used during testing to ensure that calls to provider functions and resource constructors
|
||||
return predictable values.
|
||||
"""
|
||||
@abstractmethod
|
||||
def call(self, args: MockCallArgs) -> Tuple[dict, Optional[List[Tuple[str, str]]]]:
|
||||
def call(self, args: MockCallArgs) -> Tuple[dict, Optional[List[Tuple[str,str]]]]:
|
||||
"""
|
||||
call mocks provider-implemented function calls (e.g. aws.get_availability_zones).
|
||||
|
||||
:param args MockCallArgs
|
||||
:param MockCallArgs args.
|
||||
"""
|
||||
return {}, None
|
||||
|
||||
@abstractmethod
|
||||
def new_resource(self, args: MockResourceArgs) -> Tuple[Optional[str], dict]:
|
||||
"""
|
||||
new_resource mocks resource construction calls. This function should return the physical identifier and
|
||||
the output properties for the resource being constructed.
|
||||
new_resource mocks resource construction calls. This function should return the physical identifier and the output properties
|
||||
for the resource being constructed.
|
||||
|
||||
:param args MockResourceArgs
|
||||
:param MockResourceArgs args.
|
||||
"""
|
||||
return "", {}
|
||||
|
||||
|
@ -145,9 +143,9 @@ class MockMonitor:
|
|||
|
||||
def make_urn(self, parent: str, type_: str, name: str) -> str:
|
||||
if parent != "":
|
||||
qualified_type = parent.split("::")[2]
|
||||
parent_type = qualified_type.split("$").pop()
|
||||
type_ = parent_type + "$" + type_
|
||||
qualifiedType = parent.split("::")[2]
|
||||
parentType = qualifiedType.split("$").pop()
|
||||
type_ = parentType + "$" + type_
|
||||
|
||||
return "urn:pulumi:" + "::".join([get_stack(), get_project(), type_, name])
|
||||
|
||||
|
@ -170,9 +168,7 @@ class MockMonitor:
|
|||
if isinstance(tup, dict):
|
||||
(ret, failures) = (tup, None)
|
||||
else:
|
||||
(ret, failures) = tup[0], [
|
||||
provider_pb2.CheckFailure(property=failure[0], reason=failure[1]) for failure in tup[1]
|
||||
]
|
||||
(ret, failures) = tup[0], [provider_pb2.CheckFailure(property=failure[0], reason=failure[1]) for failure in tup[1]]
|
||||
|
||||
ret_proto = _sync_await(rpc.serialize_properties(ret, {}))
|
||||
|
||||
|
@ -233,7 +229,7 @@ class MockMonitor:
|
|||
# Support for "outputValues" is deliberately disabled for the mock monitor so
|
||||
# instances of `Output` don't show up in `MockResourceArgs` inputs.
|
||||
has_support = request.id in {"secrets", "resourceReferences"}
|
||||
return type('SupportsFeatureResponse', (object,), {'hasSupport': has_support})
|
||||
return type('SupportsFeatureResponse', (object,), {'hasSupport' : has_support})
|
||||
|
||||
|
||||
class MockEngine:
|
||||
|
|
|
@ -44,10 +44,7 @@ class RPCManager:
|
|||
def __init__(self):
|
||||
self.clear()
|
||||
|
||||
def do_rpc(self,
|
||||
name: str,
|
||||
rpc_function: Callable[..., Awaitable[Tuple[Any, Exception]]]
|
||||
) -> Callable[..., Awaitable[Tuple[Any, Exception]]]:
|
||||
def do_rpc(self, name: str, rpc_function: Callable[..., Awaitable[Tuple[Any, Exception]]]) -> Callable[..., Awaitable[Tuple[Any, Exception]]]:
|
||||
"""
|
||||
Wraps a given RPC function by producing an awaitable function suitable to be run in the asyncio
|
||||
event loop. The wrapped function catches all unhandled exceptions and reports them to the exception
|
||||
|
|
|
@ -22,6 +22,7 @@ from typing import Callable, Any, Dict, List, TYPE_CHECKING
|
|||
from ..resource import ComponentResource, Resource, ResourceTransformation
|
||||
from .settings import get_project, get_stack, get_root_resource, is_dry_run, set_root_resource
|
||||
from .rpc_manager import RPC_MANAGER
|
||||
from .sync_await import _all_tasks, _get_current_task
|
||||
from .. import log
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
@ -30,9 +31,9 @@ if TYPE_CHECKING:
|
|||
|
||||
def _get_running_tasks() -> List[asyncio.Task]:
|
||||
pending = []
|
||||
for task in asyncio.all_tasks():
|
||||
for task in _all_tasks():
|
||||
# Don't kill ourselves, that would be silly.
|
||||
if not task == asyncio.current_task():
|
||||
if not task == _get_current_task():
|
||||
pending.append(task)
|
||||
return pending
|
||||
|
||||
|
|
|
@ -12,8 +12,31 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import asyncio
|
||||
import sys
|
||||
from typing import Any, Awaitable
|
||||
|
||||
# If we are not running on Python 3.7 or later, we need to swap the Python implementation of Task in for the C
|
||||
# implementation in order to support synchronous invokes.
|
||||
if sys.version_info[0] == 3 and sys.version_info[1] < 7:
|
||||
asyncio.Task = asyncio.tasks._PyTask
|
||||
asyncio.tasks.Task = asyncio.tasks._PyTask
|
||||
|
||||
def enter_task(loop, task):
|
||||
task.__class__._current_tasks[loop] = task
|
||||
|
||||
def leave_task(loop, task):
|
||||
task.__class__._current_tasks.pop(loop)
|
||||
|
||||
_enter_task = enter_task
|
||||
_leave_task = leave_task
|
||||
_all_tasks = asyncio.Task.all_tasks
|
||||
_get_current_task = asyncio.Task.current_task
|
||||
else:
|
||||
_enter_task = asyncio.tasks._enter_task # type: ignore
|
||||
_leave_task = asyncio.tasks._leave_task # type: ignore
|
||||
_all_tasks = asyncio.all_tasks # type: ignore
|
||||
_get_current_task = asyncio.current_task # type: ignore
|
||||
|
||||
|
||||
def _sync_await(awaitable: Awaitable[Any]) -> Any:
|
||||
"""
|
||||
|
@ -32,9 +55,9 @@ def _sync_await(awaitable: Awaitable[Any]) -> Any:
|
|||
|
||||
# If we are executing inside a task, pretend we've returned from its current callback--effectively yielding to
|
||||
# the event loop--by calling _leave_task.
|
||||
task = asyncio.current_task(loop)
|
||||
task = _get_current_task(loop)
|
||||
if task is not None:
|
||||
asyncio.tasks._leave_task(loop, task) # type: ignore
|
||||
_leave_task(loop, task)
|
||||
|
||||
# Pump the event loop until the future is complete. This is the kernel of BaseEventLoop.run_forever, and may not
|
||||
# work with alternative event loop implementations.
|
||||
|
@ -44,21 +67,21 @@ def _sync_await(awaitable: Awaitable[Any]) -> Any:
|
|||
#
|
||||
# See https://github.com/python/cpython/blob/3.6/Lib/asyncio/base_events.py#L1428-L1452 for the details of the
|
||||
# _run_once kernel with which we need to cooperate.
|
||||
ntodo = len(loop._ready) # type: ignore
|
||||
ntodo = len(loop._ready) # type: ignore
|
||||
while not fut.done() and not fut.cancelled():
|
||||
loop._run_once() # type: ignore
|
||||
if loop._stopping: # type: ignore
|
||||
loop._run_once() # type: ignore
|
||||
if loop._stopping: # type: ignore
|
||||
break
|
||||
# If we drained the ready list past what a calling _run_once would have expected, fix things up by pushing
|
||||
# cancelled handles onto the list.
|
||||
while len(loop._ready) < ntodo: # type: ignore
|
||||
while len(loop._ready) < ntodo: # type: ignore
|
||||
handle = asyncio.Handle(lambda: None, [], loop)
|
||||
handle._cancelled = True
|
||||
loop._ready.append(handle) # type: ignore
|
||||
loop._ready.append(handle) # type: ignore
|
||||
|
||||
# If we were executing inside a task, restore its context and continue on.
|
||||
if task is not None:
|
||||
asyncio.tasks._enter_task(loop, task) # type: ignore
|
||||
_enter_task(loop, task)
|
||||
|
||||
# Return the result of the future.
|
||||
return fut.result()
|
||||
|
|
|
@ -35,7 +35,6 @@ setup(name='pulumi',
|
|||
'py.typed'
|
||||
]
|
||||
},
|
||||
python_requires='>=3.7',
|
||||
# Keep this list in sync with Pipfile
|
||||
install_requires=[
|
||||
'protobuf>=3.6.0',
|
||||
|
|
Loading…
Reference in a new issue