class_docstr: Our constructor takes a definition of a Python package similar to that
  passed to `distutils.core.setup()` or `setuptools.setup()` (name, version,
  summary etc) plus callbacks for building, getting a list of sdist
  filenames, and cleaning.
  
  We provide methods that can be used to implement a Python package's
  `setup.py` supporting PEP-517.
  
  We also support basic command line handling for use
  with a legacy (pre-PEP-517) pip, as implemented
  by legacy distutils/setuptools and described in:
  https://pip.pypa.io/en/stable/reference/build-system/setup-py/
  
  Here is a `doctest` example of using pipcl to create a SWIG extension
  module. Requires `swig`.
  
  Create an empty test directory:
  
      >>> import os
      >>> import shutil
      >>> shutil.rmtree('pipcl_test', ignore_errors=1)
      >>> os.mkdir('pipcl_test')
  
  Create a `setup.py` which uses `pipcl` to define an extension module.
  
      >>> import textwrap
      >>> with open('pipcl_test/setup.py', 'w') as f:
      ...     _ = f.write(textwrap.dedent("""
      ...             import sys
      ...             import pipcl
      ...
      ...             def build():
      ...                 so_leaf = pipcl.build_extension(
      ...                         name = 'foo',
      ...                         path_i = 'foo.i',
      ...                         outdir = 'build',
      ...                         )
      ...                 return [
      ...                         ('build/foo.py', 'foo/__init__.py'),
      ...                         (f'build/{so_leaf}', f'foo/'),
      ...                         ('README', '$dist-info/'),
      ...                         ]
      ...
      ...             def sdist():
      ...                 return [
      ...                         'foo.i',
      ...                         'bar.i',
      ...                         'setup.py',
      ...                         'pipcl.py',
      ...                         'wdev.py',
      ...                         'README',
      ...                         ]
      ...
      ...             p = pipcl.Package(
      ...                     name = 'foo',
      ...                     version = '1.2.3',
      ...                     fn_build = build,
      ...                     fn_sdist = sdist,
      ...                     )
      ...
      ...             build_wheel = p.build_wheel
      ...             build_sdist = p.build_sdist
      ...
      ...             # Handle old-style setup.py command-line usage:
      ...             if __name__ == '__main__':
      ...                 p.handle_argv(sys.argv)
      ...             """))
  
  Create the files required by the above `setup.py` - the SWIG `.i` input
  file, the README file, and copies of `pipcl.py` and `wdev.py`.
  
      >>> with open('pipcl_test/foo.i', 'w') as f:
      ...     _ = f.write(textwrap.dedent("""
      ...             %include bar.i
      ...             %{
      ...             #include <stdio.h>
      ...             #include <string.h>
      ...             int bar(const char* text)
      ...             {
      ...                 printf("bar(): text: %s\\n", text);
      ...                 int len = (int) strlen(text);
      ...                 printf("bar(): len=%i\\n", len);
      ...                 fflush(stdout);
      ...                 return len;
      ...             }
      ...             %}
      ...             int bar(const char* text);
      ...             """))
  
      >>> with open('pipcl_test/bar.i', 'w') as f:
      ...     _ = f.write( '\n')
  
      >>> with open('pipcl_test/README', 'w') as f:
      ...     _ = f.write(textwrap.dedent("""
      ...             This is Foo.
      ...             """))
  
      >>> root = os.path.dirname(__file__)
      >>> _ = shutil.copy2(f'{root}/pipcl.py', 'pipcl_test/pipcl.py')
      >>> _ = shutil.copy2(f'{root}/wdev.py', 'pipcl_test/wdev.py')
  
  Use `setup.py`'s command-line interface to build and install the extension
  module into root `pipcl_test/install`.
  
      >>> _ = subprocess.run(
      ...         f'cd pipcl_test && {sys.executable} setup.py --root install install',
      ...         shell=1, check=1)
  
  The actual install directory depends on `sysconfig.get_path('platlib')`:
  
      >>> if windows():
      ...     install_dir = 'pipcl_test/install'
      ... else:
      ...     install_dir = f'pipcl_test/install/{sysconfig.get_path("platlib").lstrip(os.sep)}'
      >>> assert os.path.isfile( f'{install_dir}/foo/__init__.py')
  
  Create a test script which asserts that Python function call `foo.bar(s)`
  returns the length of `s`, and run it with `PYTHONPATH` set to the install
  directory:
  
      >>> with open('pipcl_test/test.py', 'w') as f:
      ...     _ = f.write(textwrap.dedent("""
      ...             import sys
      ...             import foo
      ...             text = 'hello'
      ...             print(f'test.py: calling foo.bar() with text={text!r}')
      ...             sys.stdout.flush()
      ...             l = foo.bar(text)
      ...             print(f'test.py: foo.bar() returned: {l}')
      ...             assert l == len(text)
      ...             """))
      >>> r = subprocess.run(
      ...         f'{sys.executable} pipcl_test/test.py',
      ...         shell=1, check=1, text=1,
      ...         stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
      ...         env=os.environ | dict(PYTHONPATH=install_dir),
      ...         )
      >>> print(r.stdout)
      test.py: calling foo.bar() with text='hello'
      bar(): text: hello
      bar(): len=5
      test.py: foo.bar() returned: 5
      <BLANKLINE>
  
  Check that building sdist and wheel succeeds. For now we don't attempt to
  check that the sdist and wheel actually work.
  
      >>> _ = subprocess.run(
      ...         f'cd pipcl_test && {sys.executable} setup.py sdist',
      ...         shell=1, check=1)
  
      >>> _ = subprocess.run(
      ...         f'cd pipcl_test && {sys.executable} setup.py bdist_wheel',
      ...         shell=1, check=1)
  
  Check that rebuild does nothing.
  
      >>> t0 = os.path.getmtime('pipcl_test/build/foo.py')
      >>> _ = subprocess.run(
      ...         f'cd pipcl_test && {sys.executable} setup.py bdist_wheel',
      ...         shell=1, check=1)
      >>> t = os.path.getmtime('pipcl_test/build/foo.py')
      >>> assert t == t0
  
  Check that touching bar.i forces rebuild.
  
      >>> os.utime('pipcl_test/bar.i')
      >>> _ = subprocess.run(
      ...         f'cd pipcl_test && {sys.executable} setup.py bdist_wheel',
      ...         shell=1, check=1)
      >>> t = os.path.getmtime('pipcl_test/build/foo.py')
      >>> assert t > t0
  
  Check that touching foo.i.cpp does not run swig, but does recompile/link.
  
      >>> t0 = time.time()
      >>> os.utime('pipcl_test/build/foo.i.cpp')
      >>> _ = subprocess.run(
      ...         f'cd pipcl_test && {sys.executable} setup.py bdist_wheel',
      ...         shell=1, check=1)
      >>> assert os.path.getmtime('pipcl_test/build/foo.py') <= t0
      >>> so = glob.glob('pipcl_test/build/*.so')
      >>> assert len(so) == 1
      >>> so = so[0]
      >>> assert os.path.getmtime(so) > t0
  
  Wheels and sdists
  
      Wheels:
          We generate wheels according to:
          https://packaging.python.org/specifications/binary-distribution-format/
  
          * `{name}-{version}.dist-info/RECORD` uses sha256 hashes.
          * We do not generate other `RECORD*` files such as
            `RECORD.jws` or `RECORD.p7s`.
          * `{name}-{version}.dist-info/WHEEL` has:
  
            * `Wheel-Version: 1.0`
            * `Root-Is-Purelib: false`
          * No support for signed wheels.
  
      Sdists:
          We generate sdist's according to:
          https://packaging.python.org/specifications/source-distribution-format/
class_docstr_tok: ["Our","constructor","takes","a","definition","of","a","Python","package","similar","to","that","passed","to","`","distutils.core.setup","(",")","`","or","`","setuptools.setup","(",")","`","(","name",",","version",",","summary","etc",")","plus","callbacks","for","building",",","getting","a","list","of","sdist","filenames",",","and","cleaning",".","We","provide","methods","that","can","be","used","to","implement","a","Python","package's","`","setup.py","`","supporting","PEP-517",".","We","also","support","basic","command","line","handling","for","use","with","a","legacy","(","pre-PEP-517",")","pip",",","as","implemented","by","legacy","distutils\/setuptools","and","described","in",":","https",":","\/\/pip.pypa.io\/en\/stable\/reference\/build-system\/setup-py\/","Here","is","a","`","doctest","`","example","of","using","pipcl","to","create","a","SWIG","extension","module",".","Requires","`","swig","`",".","Create","an","empty","test","directory",":",">",">",">","import","os",">",">",">","import","shutil",">",">",">","shutil.rmtree","(","'pipcl_test","'",",","ignore_errors=1",")",">",">",">","os.mkdir","(","'pipcl_test","'",")","Create","a","`","setup.py","`","which","uses","`","pipcl","`","to","define","an","extension","module",".",">",">",">","import","textwrap",">",">",">","with","open","(","'pipcl_test\/setup.py","'",",","'","w","'",")","as","f",":","...","_","=","f.write","(","textwrap.dedent","(","``","''","''","...","import","sys","...","import","pipcl","...","...","def","build","(",")",":","...","so_leaf","=","pipcl.build_extension","(","...","name","=","'foo","'",",","...","path_i","=","'foo.i","'",",","...","outdir","=","'build","'",",","...",")","...","return","[","...","(","'build\/foo.py","'",",","'foo\/__init__.py","'",")",",","...","(","f'build\/","{","so_leaf","}","'",",","f'foo\/","'",")",",","...","(","'README","'",",","'","$","dist-info\/","'",")",",","...","]","...","...","def","sdist","(",")",":","...","return","[","...","'foo.i","'",",","...","'bar.i","'",",","...","'setup.py","'",",","...","'pipcl.py","'",",","...","'wdev.py","'",",","...","'README","'",",","...","]","...","...","p","=","pipcl.Package","(","...","name","=","'foo","'",",","...","version","=","'","1.2.3","'",",","...","fn_build","=","build",",","...","fn_sdist","=","sdist",",","...",")","...","...","build_wheel","=","p.build_wheel","...","build_sdist","=","p.build_sdist","...","...","#","Handle","old-style","setup.py","command-line","usage",":","...","if","__name__","==","'__main__","'",":","...","p.handle_argv","(","sys.argv",")","...","``","''","''",")",")","Create","the","files","required","by","the","above","`","setup.py","`","-","the","SWIG","`",".i","`","input","file",",","the","README","file",",","and","copies","of","`","pipcl.py","`","and","`","wdev.py","`",".",">",">",">","with","open","(","'pipcl_test\/foo.i","'",",","'","w","'",")","as","f",":","...","_","=","f.write","(","textwrap.dedent","(","``","''","''","...","%","include","bar.i","...","%","{","...","#","include","<","stdio.h",">","...","#","include","<","string.h",">","...","int","bar","(","const","char","*","text",")","...","{","...","printf","(","``","bar","(",")",":","text",":","%","s\\\\n","''",",","text",")",";","...","int","len","=","(","int",")","strlen","(","text",")",";","...","printf","(","``","bar","(",")",":","len=","%","i\\\\n","''",",","len",")",";","...","fflush","(","stdout",")",";","...","return","len",";","...","}","...","%","}","...","int","bar","(","const","char","*","text",")",";","...","``","''","''",")",")",">",">",">","with","open","(","'pipcl_test\/bar.i","'",",","'","w","'",")","as","f",":","...","_","=","f.write","(","'\\n","'",")",">",">",">","with","open","(","'pipcl_test\/README","'",",","'","w","'",")","as","f",":","...","_","=","f.write","(","textwrap.dedent","(","``","''","''","...","This","is","Foo",".","...","``","''","''",")",")",">",">",">","root","=","os.path.dirname","(","__file__",")",">",">",">","_","=","shutil.copy2","(","f","'","{","root","}","\/pipcl.py","'",",","'pipcl_test\/pipcl.py","'",")",">",">",">","_","=","shutil.copy2","(","f","'","{","root","}","\/wdev.py","'",",","'pipcl_test\/wdev.py","'",")","Use","`","setup.py","`","'s","command-line","interface","to","build","and","install","the","extension","module","into","root","`","pipcl_test\/install","`",".",">",">",">","_","=","subprocess.run","(","...","f'cd","pipcl_test","&","&","{","sys.executable","}","setup.py","--","root","install","install","'",",","...","shell=1",",","check=1",")","The","actual","install","directory","depends","on","`","sysconfig.get_path","(","'platlib","'",")","`",":",">",">",">","if","windows","(",")",":","...","install_dir","=","'pipcl_test\/install'","...","else",":","...","install_dir","=","f'pipcl_test\/install\/","{","sysconfig.get_path","(","``","platlib","''",")",".lstrip","(","os.sep",")","}","'",">",">",">","assert","os.path.isfile","(","f","'","{","install_dir","}","\/foo\/__init__.py","'",")","Create","a","test","script","which","asserts","that","Python","function","call","`","foo.bar","(","s",")","`","returns","the","length","of","`","s","`",",","and","run","it","with","`","PYTHONPATH","`","set","to","the","install","directory",":",">",">",">","with","open","(","'pipcl_test\/test.py","'",",","'","w","'",")","as","f",":","...","_","=","f.write","(","textwrap.dedent","(","``","''","''","...","import","sys","...","import","foo","...","text","=","'hello'","...","print","(","f'test.py",":","calling","foo.bar","(",")","with","text=","{","text","!","r","}","'",")","...","sys.stdout.flush","(",")","...","l","=","foo.bar","(","text",")","...","print","(","f'test.py",":","foo.bar","(",")","returned",":","{","l","}","'",")","...","assert","l","==","len","(","text",")","...","``","''","''",")",")",">",">",">","r","=","subprocess.run","(","...","f","'","{","sys.executable","}","pipcl_test\/test.py","'",",","...","shell=1",",","check=1",",","text=1",",","...","stdout=subprocess.PIPE",",","stderr=subprocess.STDOUT",",","...","env=os.environ","|","dict","(","PYTHONPATH=install_dir",")",",","...",")",">",">",">","print","(","r.stdout",")","test.py",":","calling","foo.bar","(",")","with","text='hello'","bar","(",")",":","text",":","hello","bar","(",")",":","len=5","test.py",":","foo.bar","(",")","returned",":","5","<","BLANKLINE",">","Check","that","building","sdist","and","wheel","succeeds",".","For","now","we","do","n't","attempt","to","check","that","the","sdist","and","wheel","actually","work",".",">",">",">","_","=","subprocess.run","(","...","f'cd","pipcl_test","&","&","{","sys.executable","}","setup.py","sdist","'",",","...","shell=1",",","check=1",")",">",">",">","_","=","subprocess.run","(","...","f'cd","pipcl_test","&","&","{","sys.executable","}","setup.py","bdist_wheel","'",",","...","shell=1",",","check=1",")","Check","that","rebuild","does","nothing",".",">",">",">","t0","=","os.path.getmtime","(","'pipcl_test\/build\/foo.py","'",")",">",">",">","_","=","subprocess.run","(","...","f'cd","pipcl_test","&","&","{","sys.executable","}","setup.py","bdist_wheel","'",",","...","shell=1",",","check=1",")",">",">",">","t","=","os.path.getmtime","(","'pipcl_test\/build\/foo.py","'",")",">",">",">","assert","t","==","t0","Check","that","touching","bar.i","forces","rebuild",".",">",">",">","os.utime","(","'pipcl_test\/bar.i","'",")",">",">",">","_","=","subprocess.run","(","...","f'cd","pipcl_test","&","&","{","sys.executable","}","setup.py","bdist_wheel","'",",","...","shell=1",",","check=1",")",">",">",">","t","=","os.path.getmtime","(","'pipcl_test\/build\/foo.py","'",")",">",">",">","assert","t",">","t0","Check","that","touching","foo.i.cpp","does","not","run","swig",",","but","does","recompile\/link",".",">",">",">","t0","=","time.time","(",")",">",">",">","os.utime","(","'pipcl_test\/build\/foo.i.cpp","'",")",">",">",">","_","=","subprocess.run","(","...","f'cd","pipcl_test","&","&","{","sys.executable","}","setup.py","bdist_wheel","'",",","...","shell=1",",","check=1",")",">",">",">","assert","os.path.getmtime","(","'pipcl_test\/build\/foo.py","'",")","<","=","t0",">",">",">","so","=","glob.glob","(","'pipcl_test\/build\/","*",".so","'",")",">",">",">","assert","len","(","so",")","==","1",">",">",">","so","=","so","[","0","]",">",">",">","assert","os.path.getmtime","(","so",")",">","t0","Wheels","and","sdists","Wheels",":","We","generate","wheels","according","to",":","https",":","\/\/packaging.python.org\/specifications\/binary-distribution-format\/","*","`","{","name","}","-","{","version","}",".dist-info\/RECORD","`","uses","sha256","hashes",".","*","We","do","not","generate","other","`","RECORD","*","`","files","such","as","`","RECORD.jws","`","or","`","RECORD.p7s","`",".","*","`","{","name","}","-","{","version","}",".dist-info\/WHEEL","`","has",":","*","`","Wheel-Version",":","1.0","`","*","`","Root-Is-Purelib",":","false","`","*","No","support","for","signed","wheels",".","Sdists",":","We","generate","sdist","'s","according","to",":","https",":","\/\/packaging.python.org\/specifications\/source-distribution-format\/"]
docstr: Called by `handle_argv()`.
docstr_tok: ["Called","by","`","handle_argv","(",")","`","."]
code: def _argv_clean(self, all_):
      """
      Called by `handle_argv()`.
      """
      if not self.fn_clean:
          return
      paths = self.fn_clean(all_)
      if paths:
          if isinstance(paths, str):
              paths = (paths,)
          for path in paths:
              if not os.path.isabs(path):
                  path = ps.path.join(self.root, path)
              path = os.path.abspath(path)
              assert path.startswith(
                  self.root + os.sep
              ), f"path={path!r} does not start with root={self.root+os.sep!r}"
              log2(f"Removing: {path}")
              shutil.rmtree(path, ignore_errors=True)
  
imports: import base64
  import glob
  import hashlib
  import inspect
  import io
  import os
  import platform
  import re
  import shutil
  import site
  import setuptools
  import subprocess
  import sys
  import sysconfig
  import tarfile
  import textwrap
  import time
  import zipfile
  import wdev
label_desc: Use image node_id 5 for calling the Package obj's underlying member method code with example usage: obj._argv_clean(all_) without return types