# Path: vasppy/summary.py
# def load_vasp_summary( filename ):
# def potcar_spec(filename, return_hashes=False):
# def find_vasp_calculations():
#     def __init__( self, directory='.' ):
#     def parse_vasprun( self ):
#     def stoich( self ):
#     def functional( self ):
#     def potcars_are_pbe( self ):
#     def output( self, to_print ):
#     def print_type( self ):
#     def print_title( self ):
#     def print_description( self ):
#     def print_notes( self ):
#     def print_status( self ):
#     def print_lreal( self ):
#     def print_stoichiometry( self ):
#     def print_potcar( self ):
#     def print_energy( self ):
#     def print_neb_energy( self ):
#     def print_version( self ):
#     def print_eatom( self ):
#     def print_kpoints( self ):
#     def print_functional( self ):
#     def print_ibrion( self ):
#     def print_ediffg( self ):
#     def print_encut( self ):
#     def print_converged( self ):
#     def print_vasprun_md5( self ):
#     def print_file_tracking( self ):
#     def print_directory( self ):
#     def print_plus_u( self ):
#     def print_cbm( self ):
#     def print_vbm( self ):
#     def print_nelect( self ):
# class Summary:
# 
# Path: vasppy/vaspmeta.py
# class VASPMeta:
#     """
#     VASPMeta class for storing additional VASP calculation metadata
#     """
# 
#     def __init__( self, title, description, status, notes=None, type=None, track=None ):
#         """
#         Initialise a VASPMeta object.
# 
#         Args:
#             title (Str): The title string for this calculation
#             description (Str): Long description
#             status (Str): Current status of the calculation. 
#                 Expected strings are (to-run, incomplete, finished, dropped)
#             notes (:obj:Str, optional): Any additional notes. Defaults to None.
#             type  (:obj:Str, optional): Can be used to describe the calculation type. 
#                 Defaults to None.
#             track (:obj:dict(str: str), optional): An optional dict of pairs of filenames
#                 for files to track. For each key: value pair, the key is the current filename
#                 in the directory. The value is the new filename that list of filenames to calculate md5 hashes
#                 files to calculate hashes for when summarising the calculation output.
#                 Defaults to None.
# 
#         Returns:
#             None
#         """
#         self.title = title
#         self.description = description
#         self.notes = notes
#         expected_status = [ 'to-run', 'incomplete', 'finished', 'dropped' ]
#         if status not in expected_status:
#             raise ValueError(f'Unexpected calculations status: "{status}"'
#                              f' for calculation {title}')
#         self.status = status
#         expected_types = [ 'single-point', 'neb' ]
#         if type:
#             if type not in expected_types:
#                 raise ValueError(f'Unexpected calculation type: "{type}"'
#                                  f' for calculation {title}')
#             self.type = type 
#         else:
#             self.type = None
#         self.track = track
# 
#     @classmethod
#     def from_file( cls, filename ):
#         """
#         Create a VASPMeta object by reading a `vaspmeta.yaml` file
# 
#         Args:
#             filename (Str): filename to read in.
# 
#         Returns:
#             (vasppy.VASPMeta): the VASPMeta object
#         """
#         with open( filename, 'r' ) as stream:
#             data = yaml.load( stream, Loader=yaml.SafeLoader )
#             notes = data.get( 'notes' )
#             v_type = data.get( 'type' )
#             track = data.get( 'track' )
#             xargs = {}
#             if track:
#                 if type( track ) is str:
#                     track = [ track ]
#                 xargs['track'] = track 
#             vaspmeta = VASPMeta( data['title'], 
#                                  data['description'], 
#                                  data['status'], 
#                                  notes=notes, 
#                                  type=v_type,
#                                  **xargs )
#         return vaspmeta


import unittest
import numpy as np
import io
import inspect
import os
from unittest.mock import Mock, patch, call
from io import StringIO
from vasppy.summary import (Summary, md5sum, potcar_spec, find_vasp_calculations,
                            load_vasp_summary)
from vasppy.vaspmeta import VASPMeta
from pymatgen.io.vasp.outputs import Vasprun
                     'LDA_52': { 'H': '101' },
                     'LDA_54': { 'I': '202' },
                     'GGA':    { 'J': '303' },
                     'USPP_GGA': { 'K': '404' },
                     'USPP_LDA': { 'L': '505' },
                     'PBE_54r': { 'M': '123' },
                     'LDA_54r': { 'N': '456' } }

class SummaryInitTestCase( unittest.TestCase ):

    @patch('vasppy.summary.VASPMeta')
    @patch('vasppy.summary.Summary.parse_vasprun')
    def test_summary_is_initialised( self, mock_parse_vasprun, MockVASPMeta ):
        MockVASPMeta.from_file = Mock( return_value='foo' )
        summary = Summary()
        self.assertEqual( mock_parse_vasprun.call_count, 1 )
        expected_print_methods = [ 'title', 'type', 'status', 'stoichiometry',
                                   'potcar', 'eatom', 'energy', 'k-points',
                                   'functional', 'encut', 'plus_u', 'ediffg',
                                   'ibrion', 'converged', 'version', 'md5',
                                   'directory', 'lreal', 'vbm', 'cbm' ]
        for key in expected_print_methods:
            self.assertTrue(key in summary.print_methods)
            self.assertTrue( inspect.ismethod( summary.print_methods[ key ] ) )

    @patch('vasppy.summary.VASPMeta')
    @patch('vasppy.summary.Summary.parse_vasprun')
    def test_summary_init_raises_filenotfounderror_if_file_is_not_found( self, mock_parse_vasprun, MockVASPMeta ):
        MockVASPMeta.from_file = Mock( side_effect=FileNotFoundError )
        with self.assertRaises( FileNotFoundError ):

# Path: vasppy/summary.py
# def load_vasp_summary( filename ):
# def potcar_spec(filename, return_hashes=False):
# def find_vasp_calculations():
#     def __init__( self, directory='.' ):
#     def parse_vasprun( self ):
#     def stoich( self ):
#     def functional( self ):
#     def potcars_are_pbe( self ):
#     def output( self, to_print ):
#     def print_type( self ):
#     def print_title( self ):
#     def print_description( self ):
#     def print_notes( self ):
#     def print_status( self ):
#     def print_lreal( self ):
#     def print_stoichiometry( self ):
#     def print_potcar( self ):
#     def print_energy( self ):
#     def print_neb_energy( self ):
#     def print_version( self ):
#     def print_eatom( self ):
#     def print_kpoints( self ):
#     def print_functional( self ):
#     def print_ibrion( self ):
#     def print_ediffg( self ):
#     def print_encut( self ):
#     def print_converged( self ):
#     def print_vasprun_md5( self ):
#     def print_file_tracking( self ):
#     def print_directory( self ):
#     def print_plus_u( self ):
#     def print_cbm( self ):
#     def print_vbm( self ):
#     def print_nelect( self ):
# class Summary:
# 
# Path: vasppy/vaspmeta.py
# class VASPMeta:
#     """
#     VASPMeta class for storing additional VASP calculation metadata
#     """
# 
#     def __init__( self, title, description, status, notes=None, type=None, track=None ):
#         """
#         Initialise a VASPMeta object.
# 
#         Args:
#             title (Str): The title string for this calculation
#             description (Str): Long description
#             status (Str): Current status of the calculation. 
#                 Expected strings are (to-run, incomplete, finished, dropped)
#             notes (:obj:Str, optional): Any additional notes. Defaults to None.
#             type  (:obj:Str, optional): Can be used to describe the calculation type. 
#                 Defaults to None.
#             track (:obj:dict(str: str), optional): An optional dict of pairs of filenames
#                 for files to track. For each key: value pair, the key is the current filename
#                 in the directory. The value is the new filename that list of filenames to calculate md5 hashes
#                 files to calculate hashes for when summarising the calculation output.
#                 Defaults to None.
# 
#         Returns:
#             None
#         """
#         self.title = title
#         self.description = description
#         self.notes = notes
#         expected_status = [ 'to-run', 'incomplete', 'finished', 'dropped' ]
#         if status not in expected_status:
#             raise ValueError(f'Unexpected calculations status: "{status}"'
#                              f' for calculation {title}')
#         self.status = status
#         expected_types = [ 'single-point', 'neb' ]
#         if type:
#             if type not in expected_types:
#                 raise ValueError(f'Unexpected calculation type: "{type}"'
#                                  f' for calculation {title}')
#             self.type = type 
#         else:
#             self.type = None
#         self.track = track
# 
#     @classmethod
#     def from_file( cls, filename ):
#         """
#         Create a VASPMeta object by reading a `vaspmeta.yaml` file
# 
#         Args:
#             filename (Str): filename to read in.
# 
#         Returns:
#             (vasppy.VASPMeta): the VASPMeta object
#         """
#         with open( filename, 'r' ) as stream:
#             data = yaml.load( stream, Loader=yaml.SafeLoader )
#             notes = data.get( 'notes' )
#             v_type = data.get( 'type' )
#             track = data.get( 'track' )
#             xargs = {}
#             if track:
#                 if type( track ) is str:
#                     track = [ track ]
#                 xargs['track'] = track 
#             vaspmeta = VASPMeta( data['title'], 
#                                  data['description'], 
#                                  data['status'], 
#                                  notes=notes, 
#                                  type=v_type,
#                                  **xargs )
#         return vaspmeta


# Path: tests/test_summary.py
import unittest
import numpy as np
import io
import inspect
import os
from unittest.mock import Mock, patch, call
from io import StringIO
from vasppy.summary import (Summary, md5sum, potcar_spec, find_vasp_calculations,
                            load_vasp_summary)
from vasppy.vaspmeta import VASPMeta
from pymatgen.io.vasp.outputs import Vasprun

                     'LDA_52': { 'H': '101' },
                     'LDA_54': { 'I': '202' },
                     'GGA':    { 'J': '303' },
                     'USPP_GGA': { 'K': '404' },
                     'USPP_LDA': { 'L': '505' },
                     'PBE_54r': { 'M': '123' },
                     'LDA_54r': { 'N': '456' } }

class SummaryInitTestCase( unittest.TestCase ):

    @patch('vasppy.summary.VASPMeta')
    @patch('vasppy.summary.Summary.parse_vasprun')
    def test_summary_is_initialised( self, mock_parse_vasprun, MockVASPMeta ):
        MockVASPMeta.from_file = Mock( return_value='foo' )
        summary = Summary()
        self.assertEqual( mock_parse_vasprun.call_count, 1 )
        expected_print_methods = [ 'title', 'type', 'status', 'stoichiometry',
                                   'potcar', 'eatom', 'energy', 'k-points',
                                   'functional', 'encut', 'plus_u', 'ediffg',
                                   'ibrion', 'converged', 'version', 'md5',
                                   'directory', 'lreal', 'vbm', 'cbm' ]
        for key in expected_print_methods:
            self.assertTrue(key in summary.print_methods)
            self.assertTrue( inspect.ismethod( summary.print_methods[ key ] ) )

    @patch('vasppy.summary.VASPMeta')
    @patch('vasppy.summary.Summary.parse_vasprun')
    def test_summary_init_raises_filenotfounderror_if_file_is_not_found( self, mock_parse_vasprun, MockVASPMeta ):
        MockVASPMeta.from_file = Mock( side_effect=FileNotFoundError )
        with self.assertRaises( FileNotFoundError ):

            summary = Summary()