import asyncio
import subprocess

from ..core.formatter import FormattedEntity
from .base import Worker


class Subprocess(FormattedEntity, Worker):
    """
    config:
        cmd: str - shell command with mask python format
        stdout: [none | PIPE | DEVNULL]
        stderr: [none | PIPE | DEVNULL]
        wait: bool - default True for wait shutdown process
        format: [json|str|bytes]
    """

    async def init(self):
        if self.config.get('stdout'):
            self._stdout = getattr(subprocess, self.config.get('stdout'))
        elif 'stdout' in self.config:
            self._stdout = None
        else:
            self._stdout = subprocess.PIPE

        if self.config.get('stderr'):
            self._stderr = getattr(subprocess, self.config.get('stderr'))
        else:
            self._stderr = None
        self._wait = self.config.get('wait', True)
        await super().init()

    @property
    def process(self):
        if hasattr(self, '_process') and self._process is not None:
            return self._process

    def make_command(self, value):
        if not self.config.get('cmd'):
            return value
        elif isinstance(value, str):
            return self.config.cmd + ' ' + value
        elif isinstance(value, dict):
            return self.config.cmd.format_map(value)
        elif isinstance(value, list):
            return self.config.cmd.format(*value)
        else:
            raise ValueError()

    async def run_cmd(self, *args, **kwargs):
        if args:
            value = args[0]
        elif kwargs:
            value = kwargs
        else:
            value = None
        cmd = self.make_command(value)
        self._process = await asyncio.create_subprocess_exec(
            cmd, stdout=self._stdout, stderr=self._stderr)
        if self._wait:
            await self._process.wait()
        if self._stdout:
            data = await self._process.stdout.read()
            return self.decode(data)

    run = run_cmd

@@ -25,16 +25,58 @@
 bprocess
+%0Afrom collections import Mapping, Sequence
 %0A%0Afrom .
@@ -261,16 +261,78 @@
  format%0A
+             list%5Bstr%5D - exec command with mask python format%0A
         
@@ -1196,14 +1196,13 @@
     
-if not
+cmd =
  sel
@@ -1224,47 +1224,573 @@
 md')
-:%0A            return value%0A        elif
+%0A        if not cmd and isinstance(value, Sequence):%0A            return value%0A        elif not cmd and isinstance(value, str):%0A            return value,%0A        elif isinstance(cmd, list) and isinstance(value, str):%0A            return cmd + %5Bvalue%5D%0A        elif isinstance(cmd, list) and isinstance(value, Sequence):%0A            result = list(cmd)%0A            result.extend(value)%0A            return result%0A        elif isinstance(cmd, list) and isinstance(value, Mapping):%0A            return %5Bi.format_map(value) for i in cmd%5D%0A        elif isinstance(cmd, str) and
  isi
@@ -1854,24 +1854,25 @@
  ' ' + value
+,
 %0A        eli
@@ -1888,19 +1888,47 @@
 nce(
-value, dict
+cmd, str) and isinstance(value, Mapping
 ):%0A 
@@ -1974,24 +1974,25 @@
 t_map(value)
+,
 %0A        eli
@@ -2008,19 +2008,48 @@
 nce(
-value, list
+cmd, str) and isinstance(value, Sequence
 ):%0A 
@@ -2092,24 +2092,25 @@
 rmat(*value)
+,
 %0A        els
@@ -2141,16 +2141,21 @@
 ueError(
+value
 )%0A%0A    a
@@ -2206,16 +2206,69 @@
      if 
+len(args) %3E 1:%0A            value = args%0A        elif 
 args:%0A  
@@ -2436,55 +2436,209 @@
 elf.
-_process = await asyncio.create_subprocess_exec
+logger.info(' '.join(cmd))%0A        if len(cmd) %3E 1:%0A            coro = asyncio.create_subprocess_exec%0A        else:%0A            coro = asyncio.create_subprocess_shell%0A        self._process = await coro
 (%0A  
@@ -2647,16 +2647,17 @@
         
+*
 cmd, std
@@ -2693,16 +2693,32 @@
 ._stderr
+, loop=self.loop
 )%0A      

support exec and shell in subprocess worker