content: """
  Arguments for the script are:
      -v or --version         Solidity version to be used to compile the contracts. If
                              blank, the script uses the latest hard-coded version
                              specified within the script.
  
      -f or --filename        If left blank, all .sol files will be compiled and the
                              respective contract data will be generated. Pass in a
                              specific ``.sol`` filename here to compile just one file.
  
  
  To run the script, you will need the ``py-solc-x`` library for compiling the files
  as well as ``black`` for linting. You can install those independently or install the
  full ``[dev]`` package extra as shown below.
  
  .. code:: sh
  
      $ pip install "web3[dev]"
  
  The following example compiles all the contracts and generates their respective
  contract data that is used across our test files for the test suites. This data gets
  generated within the ``contract_data`` subdirectory within the ``contract_sources``
  folder.
  
  .. code-block:: bash
  
      $ cd ../web3.py/web3/_utils/contract_sources
      $ python compile_contracts.py -v 0.8.17
      Compiling OffchainLookup
      ...
      ...
      reformatted ...
  
  To compile and generate contract data for only one ``.sol`` file, specify using the
  filename with the ``-f`` (or ``--filename``) argument flag.
  
  .. code-block:: bash
  
      $ cd ../web3.py/web3/_utils/contract_sources
      $ python compile_contracts.py -v 0.8.17 -f OffchainLookup.sol
      Compiling OffchainLookup.sol
      reformatted ...
  """
  
  import argparse
  import os
  import re
  from typing import (
      Any,
  )
  
  import solcx
  
  arg_parser = argparse.ArgumentParser()
  arg_parser.add_argument(
      "-v", "--version", help="Solidity version for compiling contracts."
  )
  arg_parser.add_argument(
      "-f",
      "--filename",
      help="(optional) The filename if only one file is to be compiled - "
      "otherwise all .sol files will be compiled at once.",
  )
  user_args = arg_parser.parse_args()
  
  LATEST_AVAILABLE_SOLIDITY_VERSION = sorted(solcx.get_compilable_solc_versions())[-1]
  # establish Solidity version from user-provided arg or use latest available version
  user_sol_version = user_args.version
  
  solidity_version = (
      user_sol_version if user_sol_version else LATEST_AVAILABLE_SOLIDITY_VERSION
  )
  solcx.install_solc(solidity_version)
  solcx.set_solc_version(solidity_version)
  
  
  # compile just the .sol file specified or all .sol files
  all_dot_sol_files = [f for f in os.listdir(os.getcwd()) if f.endswith(".sol")]
  user_filename = user_args.filename
  files_to_compile = [user_filename] if user_filename else all_dot_sol_files
  
  
  def _compile_dot_sol_files(dot_sol_filename: str) -> dict[str, Any]:
      compiled = solcx.compile_files(
          [f"./{dot_sol_filename}"],
          output_values=["abi", "bin", "bin-runtime"],
      )
      return compiled
  
  
  def _get_compiled_contract_data(
      sol_file_output: dict[str, dict[str, str]],
      dot_sol_filename: str,
      contract_name: str = None,
  ) -> dict[str, str]:
      if not contract_name:
          contract_name = dot_sol_filename.replace(".sol", "")
  
      contract_data = None
      for key in sol_file_output.keys():
          if f":{contract_name}" in key:
              contract_data = sol_file_output[key]
      if not contract_data:
          raise Exception(f"Could not find compiled data for contract: {contract_name}")
  
      contract_data["bin"] = f"0x{contract_data['bin']}"
      contract_data["bin-runtime"] = f"0x{contract_data['bin-runtime']}"
  
      return contract_data
  
  
  contracts_in_file = {}
  
  
  def compile_files(file_list: list[str]) -> None:
      for filename in file_list:
          with open(os.path.join(os.getcwd(), filename)) as f:
              dot_sol_file = f.readlines()
  
          contract_names = []
  
          for line in dot_sol_file:
              if all(_ in line for _ in ["contract", "{"]) and "abstract" not in line:
                  start_index = line.find("contract ") + len("contract ")
                  end_index = line[start_index:].find(" ") + start_index
                  contract_name = line[start_index:end_index]
                  contract_names.append(contract_name)
  
          contracts_in_file[filename] = contract_names
  
      for dot_sol_filename in contracts_in_file.keys():
          filename_no_extension = dot_sol_filename.replace(".sol", "")
          split_and_lowercase = [
              i.lower() for i in re.split(r"([A-Z][a-z]*)", filename_no_extension) if i
          ]
          python_filename = f"{'_'.join(split_and_lowercase)}.py"
          python_file_path = os.path.join(os.getcwd(), "contract_data", python_filename)
          try:
              # clean up existing files
              os.remove(python_file_path)
          except FileNotFoundError:
              pass
          print(f"compiling {dot_sol_filename}")
          compiled_dot_sol_data = _compile_dot_sol_files(dot_sol_filename)
          with open(python_file_path, "w") as f:
              f.write(f'"""\nGenerated by `{os.path.basename(__file__)}` script.\n')
              f.write(f'Compiled with Solidity v{solidity_version}.\n"""\n\n')
  
              for c in contracts_in_file[dot_sol_filename]:
                  c_name_split_and_uppercase = [
                      i.upper() for i in re.split(r"([A-Z0-9][a-z0-9]*)", c) if i
                  ]
                  contract_upper = "_".join(c_name_split_and_uppercase)
  
                  c_data = _get_compiled_contract_data(
                      compiled_dot_sol_data, dot_sol_filename, c
                  )
  
                  contract_source = (
                      f"# source: web3/_utils/contract_sources/{dot_sol_filename}:{c}"
                  )
                  if len(contract_source) > 88:
                      contract_source += "  # noqa: E501"
  
                  f.write(f"{contract_source}\n")
                  f.write(
                      f'{contract_upper}_BYTECODE = "{c_data["bin"]}"  # noqa: E501\n'
                  )
                  f.write(
                      f'{contract_upper}_RUNTIME = "{c_data["bin-runtime"]}"  # noqa: E501\n'
                  )
                  f.write(f"{contract_upper}_ABI = {c_data['abi']}\n")
                  f.write(contract_upper + "_DATA = {\n")
                  f.write(f'    "bytecode": {contract_upper}_BYTECODE,\n')
                  f.write(f'    "bytecode_runtime": {contract_upper}_RUNTIME,\n')
                  f.write(f'    "abi": {contract_upper}_ABI,\n')
                  f.write("}\n\n\n")
  
  
  compile_files(files_to_compile)
  os.system(f"black {os.getcwd()}")
  