diff --git a/heudiconv/bids.py b/heudiconv/bids.py
index 40cd074..42283e6 100644
--- a/heudiconv/bids.py
+++ b/heudiconv/bids.py
@@ -11,7 +11,7 @@ import csv
 from random import sample
 from glob import glob
 
-from heudiconv.external.pydicom import dcm
+from .external.pydicom import dcm
 
 from .parser import find_files
 from .utils import (
diff --git a/heudiconv/cli/run.py b/heudiconv/cli/run.py
index 0d984fc..f51d167 100644
--- a/heudiconv/cli/run.py
+++ b/heudiconv/cli/run.py
@@ -142,7 +142,7 @@ def get_parser():
     group.add_argument('--files', nargs='*',
                        help='Files (tarballs, dicoms) or directories '
                        'containing files to process. Cannot be provided if '
-                       'using --dicom_dir_template or --subjects')
+                       'using --dicom_dir_template.')
     parser.add_argument('-s', '--subjects', dest='subjs', type=str, nargs='*',
                         help='list of subjects - required for dicom template. '
                         'If not provided, DICOMS would first be "sorted" and '
@@ -173,8 +173,6 @@ def get_parser():
                         'single argument and return a single anonymized ID. '
                         'Also see --conv-outdir')
     parser.add_argument('-f', '--heuristic', dest='heuristic',
-                        # some commands might not need heuristic
-                        # required=True,
                         help='Name of a known heuristic or path to the Python'
                              'script containing heuristic')
     parser.add_argument('-p', '--with-prov', action='store_true',
@@ -221,7 +219,9 @@ def get_parser():
                             default=None,
                             help='batch system to submit jobs in parallel')
     submission.add_argument('--queue-args', dest='queue_args', default=None,
-                            help='Additional queue arguments')
+                            help='Additional queue arguments passed as '
+                            'single string of Argument=Value pairs space '
+                            'separated.')
     return parser
 
 
@@ -246,6 +246,13 @@ def process_args(args):
     if not args.heuristic:
         raise RuntimeError("No heuristic specified - add to arguments and rerun")
 
+    if args.queue:
+        lgr.info("Queuing %s conversion", args.queue)
+        iterarg, iterables = ("files", len(args.files)) if args.files else \
+                             ("subjects", len(args.subjs))
+        queue_conversion(args.queue, iterarg, iterables, args.queue_args)
+        sys.exit(0)
+
     heuristic = load_heuristic(args.heuristic)
 
     study_sessions = get_study_sessions(args.dicom_dir_template, args.files,
@@ -281,31 +288,6 @@ def process_args(args):
             lgr.warning("Skipping unknown locator dataset")
             continue
 
-        if args.queue:
-            # if seqinfo and not dicoms:
-            #     # flatten them all and provide into batching, which again
-            #     # would group them... heh
-            #     dicoms = sum(seqinfo.values(), [])
-            #     raise NotImplementedError(
-            #         "we already grouped them so need to add a switch to avoid "
-            #         "any grouping, so no outdir prefix doubled etc")
-
-            pyscript = op.abspath(inspect.getfile(inspect.currentframe()))
-
-            studyid = sid
-            if session:
-                studyid += "-%s" % session
-            if locator:
-                studyid += "-%s" % locator
-            # remove any separators
-            studyid = studyid.replace(op.sep, '_')
-
-            queue_conversion(pyscript,
-                             args.queue,
-                             studyid,
-                             args.queue_args)
-            continue
-
         anon_sid = anonymize_sid(sid, args.anon_cmd) if args.anon_cmd else None
         if args.anon_cmd:
             lgr.info('Anonymized {} to {}'.format(sid, anon_sid))
diff --git a/heudiconv/dicoms.py b/heudiconv/dicoms.py
index 13a200b..9ef9b9c 100644
--- a/heudiconv/dicoms.py
+++ b/heudiconv/dicoms.py
@@ -4,8 +4,8 @@ import os.path as op
 import logging
 from collections import OrderedDict
 import tarfile
-from heudiconv.external.pydicom import dcm
 
+from .external.pydicom import dcm
 from .utils import SeqInfo, load_json, set_readonly
 
 lgr = logging.getLogger(__name__)
@@ -55,10 +55,10 @@ def group_dicoms_into_seqinfos(files, file_filter, dcmfilter, grouping):
         lgr.info('Filtering out {0} dicoms based on their filename'.format(
             nfl_before-nfl_after))
     for fidx, filename in enumerate(files):
-        from heudiconv.external.dcmstack import ds
+        import nibabel.nicom.dicomwrappers as dw
         # TODO after getting a regression test check if the same behavior
         #      with stop_before_pixels=True
-        mw = ds.wrapper_from_data(dcm.read_file(filename, force=True))
+        mw = dw.wrapper_from_data(dcm.read_file(filename, force=True))
 
         for sig in ('iop', 'ICE_Dims', 'SequenceName'):
             try:
@@ -385,7 +385,7 @@ def embed_nifti(dcmfiles, niftifile, infofile, bids_info, min_meta):
     import re
 
     if not min_meta:
-        import dcmstack as ds
+        from heudiconv.external.dcmstack import ds
         stack = ds.parse_and_stack(dcmfiles, force=True).values()
         if len(stack) > 1:
             raise ValueError('Found multiple series')
diff --git a/heudiconv/external/dcmstack.py b/heudiconv/external/dcmstack.py
index 80ebc33..4e00eb2 100644
--- a/heudiconv/external/dcmstack.py
+++ b/heudiconv/external/dcmstack.py
@@ -7,7 +7,7 @@ from .pydicom import dcm  # to assure that we have it one way or another
 try:
     import dcmstack as ds
 except ImportError as e:
-    from heudiconv import lgr
+    from .. import lgr
     # looks different between py2 and 3 so we go for very rudimentary matching
     e_str = str(e)
     # there were changes from how
diff --git a/heudiconv/queue.py b/heudiconv/queue.py
index ba8ad66..8e091ca 100644
--- a/heudiconv/queue.py
+++ b/heudiconv/queue.py
@@ -1,62 +1,112 @@
 import subprocess
 import sys
 import os
-
 import logging
 
+from .utils import which
+
 lgr = logging.getLogger(__name__)
 
-def queue_conversion(pyscript, queue, studyid, queue_args=None):
-        """
-        Write out conversion arguments to file and submit to a job scheduler.
-        Parses `sys.argv` for heudiconv arguments.
-
-        Parameters
-        ----------
-        pyscript: file
-            path to `heudiconv` script
-        queue: string
-            batch scheduler to use
-        studyid: string
-            identifier for conversion
-        queue_args: string (optional)
-            additional queue arguments for job submission
-
-        Returns
-        -------
-        proc: int
-            Queue submission exit code
-        """
-
-        SUPPORTED_QUEUES = {'SLURM': 'sbatch'}
-        if queue not in SUPPORTED_QUEUES:
-            raise NotImplementedError("Queuing with %s is not supported", queue)
-
-        args = sys.argv[1:]
-        # search args for queue flag
-        for i, arg in enumerate(args):
-            if arg in ["-q", "--queue"]:
-                break
-        if i == len(args) - 1:
-            raise RuntimeError(
-                "Queue flag not found (must be provided as a command-line arg)"
-            )
-        # remove queue flag and value
-        del args[i:i+2]
-
-        # make arguments executable again
-        args.insert(0, pyscript)
-        pypath = sys.executable or "python"
-        args.insert(0, pypath)
+def queue_conversion(queue, iterarg, iterables, queue_args=None):
+    """
+    Write out conversion arguments to file and submit to a job scheduler.
+    Parses `sys.argv` for heudiconv arguments.
+
+    Parameters
+    ----------
+    queue: string
+        Batch scheduler to use
+    iterarg: str
+        Multi-argument to index (`subjects` OR `files`)
+    iterables: int
+        Number of `iterarg` arguments
+    queue_args: string (optional)
+        Additional queue arguments for job submission
+
+    """
+
+    SUPPORTED_QUEUES = {'SLURM': 'sbatch'}
+    if queue not in SUPPORTED_QUEUES:
+        raise NotImplementedError("Queuing with %s is not supported", queue)
+
+    for i in range(iterables):
+        args = clean_args(sys.argv[1:], iterarg, i)
+        # make arguments executable
+        heudiconv_exec = which("heudiconv") or "heudiconv"
+        args.insert(0, heudiconv_exec)
         convertcmd = " ".join(args)
 
         # will overwrite across subjects
         queue_file = os.path.abspath('heudiconv-%s.sh' % queue)
         with open(queue_file, 'wt') as fp:
-            fp.writelines(['#!/bin/bash\n', convertcmd, '\n'])
+            fp.write("#!/bin/bash\n")
+            if queue_args:
+                for qarg in queue_args.split():
+                    fp.write("#SBATCH %s\n" % qarg)
+            fp.write(convertcmd + "\n")
 
         cmd = [SUPPORTED_QUEUES[queue], queue_file]
-        if queue_args:
-            cmd.insert(1, queue_args)
         proc = subprocess.call(cmd)
-        return proc
+    lgr.info("Submitted %d jobs", iterables)
+
+def clean_args(hargs, iterarg, iteridx):
+    """
+    Filters arguments for batch submission.
+
+    Parameters
+    ----------
+    hargs: list
+        Command-line arguments
+    iterarg: str
+        Multi-argument to index (`subjects` OR `files`)
+    iteridx: int
+        `iterarg` index to submit
+
+    Returns
+    -------
+    cmdargs : list
+        Filtered arguments for batch submission
+
+    Example
+    --------
+    >>> from heudiconv.queue import clean_args
+    >>> cmd = ['heudiconv', '-d', '/some/{subject}/path',
+    ...                     '-q', 'SLURM',
+    ...                     '-s', 'sub-1', 'sub-2', 'sub-3', 'sub-4']
+    >>> clean_args(cmd, 'subjects', 0)
+    ['heudiconv', '-d', '/some/{subject}/path', '-s', 'sub-1']
+    """
+
+    if iterarg == "subjects":
+        iterarg = ['-s', '--subjects']
+    elif iterarg == "files":
+        iterarg = ['--files']
+    else:
+        raise ValueError("Cannot index %s" % iterarg)
+
+    # remove these or cause an infinite loop
+    queue_args = ['-q', '--queue', '--queue-args']
+
+    # control variables for multi-argument parsing
+    is_iterarg = False
+    itercount = 0
+
+    indicies = []
+    cmdargs = hargs[:]
+
+    for i, arg in enumerate(hargs):
+        if arg.startswith('-') and is_iterarg:
+            # moving on to another argument
+            is_iterarg = False
+        if is_iterarg:
+            if iteridx != itercount:
+                indicies.append(i)
+            itercount += 1
+        if arg in iterarg:
+            is_iterarg = True
+        if arg in queue_args:
+            indicies.extend([i, i+1])
+
+    for j in sorted(indicies, reverse=True):
+        del cmdargs[j]
+    return cmdargs
diff --git a/heudiconv/utils.py b/heudiconv/utils.py
index a4cc1c9..847dfaf 100644
--- a/heudiconv/utils.py
+++ b/heudiconv/utils.py
@@ -12,6 +12,9 @@ import os.path as op
 from pathlib import Path
 from collections import namedtuple
 from glob import glob
+from subprocess import check_output
+
+from nipype.utils.filemanip import which
 
 import logging
 lgr = logging.getLogger(__name__)
@@ -103,18 +106,17 @@ def docstring_parameter(*sub):
 
 
 def anonymize_sid(sid, anon_sid_cmd):
-    import sys
-    from subprocess import check_output
-    
+
     cmd = [anon_sid_cmd, sid]
     shell_return = check_output(cmd)
 
-    ### Handle subprocess returning a bytes literal string to a python3 interpreter
-    if all([sys.version_info[0] > 2, isinstance(shell_return, bytes), isinstance(sid, str)]):
+    if all([sys.version_info[0] > 2,
+            isinstance(shell_return, bytes),
+            isinstance(sid, str)]):
         anon_sid = shell_return.decode()
     else:
         anon_sid = shell_return
-    
+
     return anon_sid.strip()
 
 

Issues w/ slurm
Greetings, 

heudiconv version 0.5.3. 

I am trying to run a basic heudiconv on one subject for testing w/ slurm (running on two nodes, partition name = heudiconv) to create my heuristic. 

1) Command as follows: 

heudiconv -d /srv/lab/fmri/mft/dicom4bids/data/{subject}*/* -f /srv/lab/fmri/mft/dicom4bids/data/convertall.py -s sub01 -q heudiconv -o /srv/lab/fmri/mft/dicom4bids/data/output/

This yields: 
INFO: Running heudiconv version 0.5.3
INFO: Need to process 1 study sessions
Traceback (most recent call last):
  File "/usr/local/anaconda3/envs/fmri/bin/heudiconv", line 11, in <module>
    sys.exit(main())
  File "/usr/local/anaconda3/envs/fmri/lib/python3.5/site-packages/heudiconv/cli/run.py", line 125, in main
    process_args(args)
  File "/usr/local/anaconda3/envs/fmri/lib/python3.5/site-packages/heudiconv/cli/run.py", line 296, in process_args
    study_outdir,
UnboundLocalError: local variable 'study_outdir' referenced before assignment

2) Now, adding "-l unknown" to the above command executes, but does not create a .heudiconv folder: 
INFO: Running heudiconv version 0.5.3
INFO: Need to process 1 study sessions
WARNING: Skipping unknown locator dataset

3) Curiously, removing the -q flag and the -l flag executes the command properly and creates .heudiconv under /output:
INFO: Running heudiconv version 0.5.3
INFO: Need to process 1 study sessions
INFO: PROCESSING STARTS: {'session': None, 'outdir': '/srv/lab/fmri/mft/dicom4bids/data/output/', 'subject': 'sub01'}
INFO: Processing 4976 dicoms
INFO: Analyzing 4976 dicoms
INFO: Generated sequence info with 10 entries
INFO: PROCESSING DONE: {'session': None, 'outdir': '/srv/lab/fmri/mft/dicom4bids/data/output/', 'subject': 'sub01'}

4) Anyone else experienced these issues? How come that adding -q breaks the locator inference? I still believe that a working scheduler integration for heudiconv will be extremely valuable w/ increasing data sets and I am happy to contribute. Perhaps a starting point would be to clarify what the -l flag actually requires. In the help menu for -l, it says: study path under outdir. If provided, it overloads the value provided by the heuristic. If --datalad is enabled, every directory within locator becomes a super-dataset thus establishing a hierarchy. Setting to "unknown" will skip that dataset. 

Thanks in advance!



diff --git a/heudiconv/tests/test_queue.py b/heudiconv/tests/test_queue.py
index a90dd9b..8d80448 100644
--- a/heudiconv/tests/test_queue.py
+++ b/heudiconv/tests/test_queue.py
@@ -3,9 +3,9 @@ import sys
 import subprocess
 
 from heudiconv.cli.run import main as runner
+from heudiconv.queue import clean_args, which
 from .utils import TESTS_DATA_PATH
 import pytest
-from nipype.utils.filemanip import which
 
 @pytest.mark.skipif(which("sbatch"), reason="skip a real slurm call")
 @pytest.mark.parametrize(
@@ -23,7 +23,7 @@ def test_queue_no_slurm(tmpdir, invocation):
     sys.argv = ['heudiconv'] + hargs
 
     try:
-        with pytest.raises(OSError):
+        with pytest.raises(OSError):  # SLURM should not be installed
             runner(hargs)
         # should have generated a slurm submission script
         slurm_cmd_file = (tmpdir / 'heudiconv-SLURM.sh').strpath
@@ -44,3 +44,50 @@ def test_queue_no_slurm(tmpdir, invocation):
     finally:
         # revert before breaking something
         sys.argv = _sys_args
+
+def test_argument_filtering(tmpdir):
+    cmd_files = [
+        'heudiconv',
+        '--files',
+        '/fake/path/to/files',
+        '/another/fake/path',
+        '-f',
+        'convertall',
+        '-q',
+        'SLURM',
+        '--queue-args',
+        '--cpus-per-task=4 --contiguous --time=10'
+    ]
+    filtered = [
+        'heudiconv',
+        '--files',
+        '/another/fake/path',
+        '-f',
+        'convertall',
+    ]
+    assert clean_args(cmd_files, 'files', 1) == filtered
+
+    cmd_subjects = [
+        'heudiconv',
+        '-d',
+        '/some/{subject}/path',
+        '--queue',
+        'SLURM',
+        '--subjects',
+        'sub1',
+        'sub2',
+        'sub3',
+        'sub4',
+        '-f',
+        'convertall'
+    ]
+    filtered = [
+        'heudiconv',
+        '-d',
+        '/some/{subject}/path',
+        '--subjects',
+        'sub3',
+        '-f',
+        'convertall'
+    ]
+    assert clean_args(cmd_subjects, 'subjects', 2) == filtered

pip install -e .[all]
parse_log_pytest
requirements.txt
apt-get update apt-get install -y gcc dcm2niix
3.6
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
annexremote==1.6.6
appdirs==1.4.4
attrs==22.2.0
boto==2.49.0
certifi==2021.5.30
cffi==1.15.1
chardet==5.0.0
charset-normalizer==2.0.12
ci-info==0.2.0
click==8.0.4
cryptography==40.0.2
datalad==0.15.6
dcmstack==0.9.0
decorator==4.4.2
Deprecated==1.2.18
etelemetry==0.2.2
fasteners==0.19
filelock==3.4.1
-e git+https://github.com/nipy/heudiconv.git@3467341dbf50bfa813f915b3e639d62105cb9ee0#egg=heudiconv
humanize==3.14.0
idna==3.10
importlib-metadata==4.8.3
importlib-resources==5.4.0
iniconfig==1.1.1
inotify==0.2.10
iso8601==1.1.0
isodate==0.6.1
jeepney==0.7.1
keyring==23.4.1
keyrings.alt==4.1.0
lxml==5.3.1
mock==5.2.0
msgpack==1.0.5
networkx==2.5.1
nibabel==3.2.2
nipype==1.7.1
nose==1.3.7
numpy==1.19.5
packaging==21.3
pathlib==1.0.1
patool==1.12
pluggy==1.0.0
prov==2.0.1
py==1.11.0
pycparser==2.21
pydicom==2.3.1
pydot==1.4.2
PyGithub==1.56
PyJWT==2.4.0
PyNaCl==1.5.0
pyparsing==3.1.4
pytest==7.0.1
python-dateutil==2.9.0.post0
python-gitlab==2.10.1
rdflib==5.0.0
requests==2.27.1
requests-toolbelt==1.0.0
scipy==1.5.4
SecretStorage==3.3.3
simplejson==3.20.1
six==1.17.0
swebench-matterhorn @ file:///swebench_matterhorn
tinydb==4.7.0
tomli==1.2.3
tqdm==4.64.1
traits==6.4.1
typing_extensions==4.1.1
urllib3==1.26.20
Whoosh==2.7.4
wrapt==1.16.0
zipp==3.6.0

name: heudiconv
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - annexremote==1.6.6
      - appdirs==1.4.4
      - attrs==22.2.0
      - boto==2.49.0
      - cffi==1.15.1
      - chardet==5.0.0
      - charset-normalizer==2.0.12
      - ci-info==0.2.0
      - click==8.0.4
      - cryptography==40.0.2
      - datalad==0.15.6
      - dcmstack==0.9.0
      - decorator==4.4.2
      - deprecated==1.2.18
      - etelemetry==0.2.2
      - fasteners==0.19
      - filelock==3.4.1
      - humanize==3.14.0
      - idna==3.10
      - importlib-metadata==4.8.3
      - importlib-resources==5.4.0
      - iniconfig==1.1.1
      - inotify==0.2.10
      - iso8601==1.1.0
      - isodate==0.6.1
      - jeepney==0.7.1
      - keyring==23.4.1
      - keyrings-alt==4.1.0
      - lxml==5.3.1
      - mock==5.2.0
      - msgpack==1.0.5
      - networkx==2.5.1
      - nibabel==3.2.2
      - nipype==1.7.1
      - nose==1.3.7
      - numpy==1.19.5
      - packaging==21.3
      - pathlib==1.0.1
      - patool==1.12
      - pluggy==1.0.0
      - prov==2.0.1
      - py==1.11.0
      - pycparser==2.21
      - pydicom==2.3.1
      - pydot==1.4.2
      - pygithub==1.56
      - pyjwt==2.4.0
      - pynacl==1.5.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - python-dateutil==2.9.0.post0
      - python-gitlab==2.10.1
      - rdflib==5.0.0
      - requests==2.27.1
      - requests-toolbelt==1.0.0
      - scipy==1.5.4
      - secretstorage==3.3.3
      - simplejson==3.20.1
      - six==1.17.0
      - swebench-matterhorn==0.0.0
      - tinydb==4.7.0
      - tomli==1.2.3
      - tqdm==4.64.1
      - traits==6.4.1
      - typing-extensions==4.1.1
      - urllib3==1.26.20
      - whoosh==2.7.4
      - wrapt==1.16.0
      - zipp==3.6.0
prefix: /opt/conda/envs/heudiconv

heudiconv/tests/test_queue.py::test_queue_no_slurm[--files heudiconv/tests/test_queue.py::test_queue_no_slurm[-d heudiconv/tests/test_queue.py::test_argument_filtering
heudiconv/cli/run.py heudiconv/utils.py heudiconv/queue.py heudiconv/external/dcmstack.py heudiconv/dicoms.py heudiconv/bids.py
heudiconv/cli/run.py heudiconv/utils.py heudiconv/queue.py heudiconv/external/dcmstack.py heudiconv/dicoms.py heudiconv/bids.py