<commit_before># Copyright (c) 2009 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

{
  'target_defaults': {
    'conditions': [
      ['OS!="linux" and OS!="freebsd"', {'sources/': [['exclude', '/linux/']]}],
      ['OS!="mac"', {'sources/': [['exclude', '/mac/']]}],
      ['OS!="win"', {'sources/': [['exclude', '/win/']]}],
    ],
  },
  'variables': {
    # Allow overridding the selection of which ffmpeg binaries to copy via an
    # environment variable.  Affects the ffmpeg_binaries target.
    'ffmpeg_branding%': '<(branding)',

    'use_system_ffmpeg%': 0,
  },
  'targets': [
    {
      'variables': {
        'generate_stubs_script': 'generate_stubs.py',
        'sig_files': [
          # Note that these must be listed in dependency order.
          # (i.e. if A depends on B, then B must be listed before A.)
          'avutil-50.sigs',
          'avcodec-52.sigs',
          'avformat-52.sigs',
        ],
        'extra_header': 'ffmpeg_stub_headers.fragment',
      },
      'target_name': 'ffmpeg',
      'msvs_guid': 'D7A94F58-576A-45D9-A45F-EB87C63ABBB0',
      'dependencies': [
        'ffmpeg_binaries',
      ],
      'sources': [
        'include/libavcodec/avcodec.h',
        'include/libavcodec/opt.h',
        'include/libavcodec/vdpau.h',
        'include/libavcodec/xvmc.h',
        'include/libavformat/avformat.h',
        'include/libavformat/avio.h',
        'include/libavutil/adler32.h',
        'include/libavutil/avstring.h',
        'include/libavutil/avutil.h',
        'include/libavutil/base64.h',
        'include/libavutil/common.h',
        'include/libavutil/crc.h',
        'include/libavutil/fifo.h',
        'include/libavutil/intfloat_readwrite.h',
        'include/libavutil/log.h',
        'include/libavutil/lzo.h',
        'include/libavutil/mathematics.h',
        'include/libavutil/md5.h',
        'include/libavutil/mem.h',
        'include/libavutil/pixfmt.h',
        'include/libavutil/rational.h',
        'include/libavutil/sha1.h',
        'include/win/inttypes.h',
        'include/win/stdint.h',
        '<@(sig_files)',
        '<(extra_header)'
      ],
      'hard_dependency': 1,
      'direct_dependent_settings': {
        'include_dirs': [
          'include',
        ],
      },
      'conditions': [
        ['OS=="win"',
          {
            'variables': {
              'outfile_type': 'windows_lib',
              'output_dir': '<(PRODUCT_DIR)/lib',
              'intermediate_dir': '<(INTERMEDIATE_DIR)',
            },
            'type': 'none',
            'sources!': [
              '<(extra_header)',
            ],
            'direct_dependent_settings': {
              'include_dirs': [
                'include/win',
              ],
              'link_settings': {
                'libraries': [
                  '<(output_dir)/avcodec-52.lib',
                  '<(output_dir)/avformat-52.lib',
                  '<(output_dir)/avutil-50.lib',
                ],
                'msvs_settings': {
                  'VCLinkerTool': {
                    'DelayLoadDLLs': [
                      'avcodec-52.dll',
                      'avformat-52.dll',
                      'avutil-50.dll',
                    ],
                  },
                },
              },
            },
            'rules': [
              {
                'rule_name': 'generate_libs',
                'extension': 'sigs',
                'inputs': [
                  '<(generate_stubs_script)',
                  '<@(sig_files)',
                ],
                'outputs': [
                  '<(output_dir)/<(RULE_INPUT_ROOT).lib',
                ],
                'action': ['python', '<(generate_stubs_script)',
                           '-i', '<(intermediate_dir)',
                           '-o', '<(output_dir)',
                           '-t', '<(outfile_type)',
                           '<@(RULE_INPUT_PATH)',
                ],
                'message': 'Generating FFmpeg import libraries.',
              },
            ],
          }, {  # else OS!="win"
            'variables': {
              'outfile_type': 'posix_stubs',
              'stubs_filename_root': 'ffmpeg_stubs',
              'project_path': 'third_party/ffmpeg',
              'intermediate_dir': '<(INTERMEDIATE_DIR)',
              'output_root': '<(SHARED_INTERMEDIATE_DIR)/ffmpeg',
            },
            'type': '<(library)',
            'include_dirs': [
              'include',
              '<(output_root)',
              '../..',  # The chromium 'src' directory.
            ],
            'direct_dependent_settings': {
              'defines': [
                '__STDC_CONSTANT_MACROS',  # FFmpeg uses INT64_C.
              ],
              'include_dirs': [
                '<(output_root)',
                '../..',  # The chromium 'src' directory.
              ],
            },
            'link_settings': {
              'libraries': [
                # We need dl for dlopen() and friends.
                '-ldl',
              ],
            },
            'actions': [
              {
                'action_name': 'generate_stubs',
                'inputs': [
                  '<(generate_stubs_script)',
                  '<(extra_header)',
                  '<@(sig_files)',
                ],
                'outputs': [
                  '<(intermediate_dir)/<(stubs_filename_root).cc',
                  '<(output_root)/<(project_path)/<(stubs_filename_root).h',
                ],
                'action': ['python',
                           '<(generate_stubs_script)',
                           '-i', '<(intermediate_dir)',
                           '-o', '<(output_root)/<(project_path)',
                           '-t', '<(outfile_type)',
                           '-e', '<(extra_header)',
                           '-s', '<(stubs_filename_root)',
                           '-p', '<(project_path)',
                           '<@(_inputs)',
                ],
                'message': 'Generating FFmpeg stubs for dynamic loading.',
                'process_outputs_as_sources': 1,
              },
            ],
          }
        ],
      ],
    },
    {
      'target_name': 'ffmpeg_binaries',
      'type': 'none',
      'msvs_guid': '4E4070E1-EFD9-4EF1-8634-3960956F6F10',
      'variables': {
        'conditions': [
          [ 'ffmpeg_branding=="Chrome"', {
               'branding_dir': 'chrome',
          }, { # else ffmpeg_branding!="Chrome"
               'branding_dir': 'chromium',
          }],
        ],
      },
      'conditions': [
        ['OS=="win"', {
          'variables': {
            'source_files': [
              'binaries/<(branding_dir)/avcodec-52.dll',
              'binaries/<(branding_dir)/avformat-52.dll',
              'binaries/<(branding_dir)/avutil-50.dll',
            ],
          },
          'dependencies': ['../../build/win/system.gyp:cygwin'],
        }], ['OS=="linux" or OS=="freebsd"', {
          'conditions': [
            ['use_system_ffmpeg==0', {
              'variables': {
                'source_files': [
                  'binaries/<(branding_dir)/libavcodec.so.52',
                  'binaries/<(branding_dir)/libavformat.so.52',
                  'binaries/<(branding_dir)/libavutil.so.50',
                ],
              },
            }, {
              'variables': {
                'source_files': []
              },
            }],
          ]},
        ], ['OS=="mac"', {
              'variables': {
                'source_files': [
                  'binaries/<(branding_dir)/libavcodec.52.dylib',
                  'binaries/<(branding_dir)/libavformat.52.dylib',
                  'binaries/<(branding_dir)/libavutil.50.dylib',
                ],
              },
        }],
      ],
      'copies': [
        {
          'destination': '<(PRODUCT_DIR)/',
          'files': [
            '<@(source_files)',
          ]
        },
      ],
    },
  ],
}
<commit_msg>Properly only add linker flag for linux/freebsd.<commit_after># Copyright (c) 2009 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

{
  'target_defaults': {
    'conditions': [
      ['OS!="linux" and OS!="freebsd"', {'sources/': [['exclude', '/linux/']]}],
      ['OS!="mac"', {'sources/': [['exclude', '/mac/']]}],
      ['OS!="win"', {'sources/': [['exclude', '/win/']]}],
    ],
  },
  'variables': {
    # Allow overridding the selection of which ffmpeg binaries to copy via an
    # environment variable.  Affects the ffmpeg_binaries target.
    'ffmpeg_branding%': '<(branding)',

    'use_system_ffmpeg%': 0,
  },
  'targets': [
    {
      'variables': {
        'generate_stubs_script': 'generate_stubs.py',
        'sig_files': [
          # Note that these must be listed in dependency order.
          # (i.e. if A depends on B, then B must be listed before A.)
          'avutil-50.sigs',
          'avcodec-52.sigs',
          'avformat-52.sigs',
        ],
        'extra_header': 'ffmpeg_stub_headers.fragment',
      },
      'target_name': 'ffmpeg',
      'msvs_guid': 'D7A94F58-576A-45D9-A45F-EB87C63ABBB0',
      'dependencies': [
        'ffmpeg_binaries',
      ],
      'sources': [
        'include/libavcodec/avcodec.h',
        'include/libavcodec/opt.h',
        'include/libavcodec/vdpau.h',
        'include/libavcodec/xvmc.h',
        'include/libavformat/avformat.h',
        'include/libavformat/avio.h',
        'include/libavutil/adler32.h',
        'include/libavutil/avstring.h',
        'include/libavutil/avutil.h',
        'include/libavutil/base64.h',
        'include/libavutil/common.h',
        'include/libavutil/crc.h',
        'include/libavutil/fifo.h',
        'include/libavutil/intfloat_readwrite.h',
        'include/libavutil/log.h',
        'include/libavutil/lzo.h',
        'include/libavutil/mathematics.h',
        'include/libavutil/md5.h',
        'include/libavutil/mem.h',
        'include/libavutil/pixfmt.h',
        'include/libavutil/rational.h',
        'include/libavutil/sha1.h',
        'include/win/inttypes.h',
        'include/win/stdint.h',
        '<@(sig_files)',
        '<(extra_header)'
      ],
      'hard_dependency': 1,
      'direct_dependent_settings': {
        'include_dirs': [
          'include',
        ],
      },
      'conditions': [
        ['OS=="win"',
          {
            'variables': {
              'outfile_type': 'windows_lib',
              'output_dir': '<(PRODUCT_DIR)/lib',
              'intermediate_dir': '<(INTERMEDIATE_DIR)',
            },
            'type': 'none',
            'sources!': [
              '<(extra_header)',
            ],
            'direct_dependent_settings': {
              'include_dirs': [
                'include/win',
              ],
              'link_settings': {
                'libraries': [
                  '<(output_dir)/avcodec-52.lib',
                  '<(output_dir)/avformat-52.lib',
                  '<(output_dir)/avutil-50.lib',
                ],
                'msvs_settings': {
                  'VCLinkerTool': {
                    'DelayLoadDLLs': [
                      'avcodec-52.dll',
                      'avformat-52.dll',
                      'avutil-50.dll',
                    ],
                  },
                },
              },
            },
            'rules': [
              {
                'rule_name': 'generate_libs',
                'extension': 'sigs',
                'inputs': [
                  '<(generate_stubs_script)',
                  '<@(sig_files)',
                ],
                'outputs': [
                  '<(output_dir)/<(RULE_INPUT_ROOT).lib',
                ],
                'action': ['python', '<(generate_stubs_script)',
                           '-i', '<(intermediate_dir)',
                           '-o', '<(output_dir)',
                           '-t', '<(outfile_type)',
                           '<@(RULE_INPUT_PATH)',
                ],
                'message': 'Generating FFmpeg import libraries.',
              },
            ],
          }, {  # else OS!="win"
            'variables': {
              'outfile_type': 'posix_stubs',
              'stubs_filename_root': 'ffmpeg_stubs',
              'project_path': 'third_party/ffmpeg',
              'intermediate_dir': '<(INTERMEDIATE_DIR)',
              'output_root': '<(SHARED_INTERMEDIATE_DIR)/ffmpeg',
            },
            'type': '<(library)',
            'include_dirs': [
              'include',
              '<(output_root)',
              '../..',  # The chromium 'src' directory.
            ],
            'direct_dependent_settings': {
              'defines': [
                '__STDC_CONSTANT_MACROS',  # FFmpeg uses INT64_C.
              ],
              'include_dirs': [
                '<(output_root)',
                '../..',  # The chromium 'src' directory.
              ],
            },
            'actions': [
              {
                'action_name': 'generate_stubs',
                'inputs': [
                  '<(generate_stubs_script)',
                  '<(extra_header)',
                  '<@(sig_files)',
                ],
                'outputs': [
                  '<(intermediate_dir)/<(stubs_filename_root).cc',
                  '<(output_root)/<(project_path)/<(stubs_filename_root).h',
                ],
                'action': ['python',
                           '<(generate_stubs_script)',
                           '-i', '<(intermediate_dir)',
                           '-o', '<(output_root)/<(project_path)',
                           '-t', '<(outfile_type)',
                           '-e', '<(extra_header)',
                           '-s', '<(stubs_filename_root)',
                           '-p', '<(project_path)',
                           '<@(_inputs)',
                ],
                'message': 'Generating FFmpeg stubs for dynamic loading.',
                'process_outputs_as_sources': 1,
              },
            ],
          },
        ],
        ['OS=="linux" or OS=="freebsd"', {
          'link_settings': {
            'libraries': [
              # We need dl for dlopen() and friends.
              '-ldl',
            ],
          },
        }],
      ],  # conditions
    },
    {
      'target_name': 'ffmpeg_binaries',
      'type': 'none',
      'msvs_guid': '4E4070E1-EFD9-4EF1-8634-3960956F6F10',
      'variables': {
        'conditions': [
          [ 'ffmpeg_branding=="Chrome"', {
               'branding_dir': 'chrome',
          }, { # else ffmpeg_branding!="Chrome"
               'branding_dir': 'chromium',
          }],
        ],
      },
      'conditions': [
        ['OS=="win"', {
          'variables': {
            'source_files': [
              'binaries/<(branding_dir)/avcodec-52.dll',
              'binaries/<(branding_dir)/avformat-52.dll',
              'binaries/<(branding_dir)/avutil-50.dll',
            ],
          },
          'dependencies': ['../../build/win/system.gyp:cygwin'],
        }], ['OS=="linux" or OS=="freebsd"', {
          'conditions': [
            ['use_system_ffmpeg==0', {
              'variables': {
                'source_files': [
                  'binaries/<(branding_dir)/libavcodec.so.52',
                  'binaries/<(branding_dir)/libavformat.so.52',
                  'binaries/<(branding_dir)/libavutil.so.50',
                ],
              },
            }, {
              'variables': {
                'source_files': []
              },
            }],
          ]},
        ], ['OS=="mac"', {
              'variables': {
                'source_files': [
                  'binaries/<(branding_dir)/libavcodec.52.dylib',
                  'binaries/<(branding_dir)/libavformat.52.dylib',
                  'binaries/<(branding_dir)/libavutil.50.dylib',
                ],
              },
        }],
      ],
      'copies': [
        {
          'destination': '<(PRODUCT_DIR)/',
          'files': [
            '<@(source_files)',
          ]
        },
      ],
    },
  ],
}
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
# File              : pymdb.py
# Author            : Kaushik S Kalmady
# Date              : 07.11.2015
# Last Modified Date: 07.11.2017
# Last Modified By  : Kaushik S Kalmady

from __future__ import print_function
import json
import string
try:
    from urllib.request import urlopen
    from urllib.parse import urlencode
except:
    from urllib import urlopen
    from urllib import urlencode
import re

def top_250():
    """
    Pulls out IMDb Top 250 movies names.
    :return: dictionary
    """

    url = 'http://www.imdb.com/chart/top'
    try:
        raw_file = urlopen(url).read()
        titles = re.findall('title=".*?dir.*?>(.*?)', raw_file)
        return {i: title for i, title in enumerate(titles, 1)}
    except EnvironmentError:
        print("NetWorkError: [Please make sure you are connected to internet]")
        return {}

def top250_year_count():
    """
    Pulls out number of movies of a particular year in the IMDb Top 250
    :return: dictionary
    """

    year_count = {}

    url = 'http://www.imdb.com/chart/top'
    try:
        raw_file = urlopen(url).read()
        years = re.findall('secondaryInfo">\((.*?)\)', raw_file)
        for year in years:
            year_count[year] = year_count.get(year, 0) + 1
        return year_count
    except EnvironmentError:
        print("NetWorkError: [Please make sure you are connected to internet]")
        return year_count

def years_top250():
    """
    Pulls out IMDb Top 250 movies years
    :return: dictionary
    """

    url = 'http://www.imdb.com/chart/top'
    try:
        raw_file = urlopen(url).read()
        years = re.findall('secondaryInfo">\((.*?)\)', raw_file)
        return {i: year for i, year in enumerate(years, 1)}
    except EnvironmentError:
        print("NetWorkError: [Please make sure you are connected to internet]")
        return {}

def top250_id():
    """Pulls out ImDb Title ID's from the Imdb Top 250 webpage and adds them to a list.
    Returns List"""
    movielist = []
    url2 = 'http://www.imdb.com/chart/top'
    file = urlopen(url2).read()
    links = re.findall('

', file)

    for link in links:
        movielist.append(link)
    return movielist

class Movie:
    """Movie
    Enter movie title as parameter. Year is an optional argument"""

    def __init__(self, title, year=None, mytype=''):
        """Fetches JSON for given Movie from omdbapi.com

        Args:
            title (str): title of the movie
            year (None, optional): year of release
            mytype (str, optional): one of "movie", "series", "episode"

        """
        assert mytype in ('', "movie", "series", "episode")
        service_url = 'http://www.omdbapi.com/?apikey=eed67065&'
        url = service_url + urlencode({'t': title, 'type': mytype, 'y': year, 'plot': 'short',
                                       'r': 'json'})
        try:
            self.stuff = json.loads(urlopen(url).read())
        except EnvironmentError:
            print("NetWorkError: [Please make sure you are connected to internet]")
            #exit()

    @classmethod
    def search(self, title, mytype='', year=None):
        """search for a movie or series by title

        Args:
            title (str): title of the movie
            year (None, optional): year of release
            mytype (str, optional): one of "movie", "series", "episode"
        """
        assert mytype in ('', "movie", "series", "episode")
        service_url = 'http://www.omdbapi.com/?apikey=eed67065&'
        url = service_url + urlencode({'s': title, 'type': mytype, 'y': year,'r': 'json'})
        try:
            results = json.loads(urlopen(url).read())["Search"]
            for item in results:
                print("\t" + item["Title"] + " (" + item["Year"] + ")" + " [" + item["imdbID"] + "]" + " {" + item["Type"] + "}")
            print("Found total {} matching results".format(len(results)))
        except KeyError:
            print("Not found")

    def info(self):
        """Prints basic Info from IMDb"""
        print(self.stuff["Title"])
        print("Year: ", self.stuff["Year"])
        print("Rating: {rating} ({votes} votes)".format(rating=self.stuff["imdbRating"], votes=self.stuff["imdbVotes"]))
        print("Metascore: ", self.stuff["Metascore"])
        print("Language: ", self.stuff["Language"])
        print("Genre: ", self.stuff["Genre"])
        print("Director: ", self.stuff["Director"])
        print("Awards: ", self.stuff["Awards"])

    def getposter(self):
        """Saves poster of movie in current directory or raise exception if anything goes wrong
        To check current directort type 'os.getcwd()'
        To change current directory type 'os.chdir('path you wish')'
        """
        try:
            link = self.stuff["Poster"]
            image = urlopen(link).read()
            filename = self.stuff["Title"].translate(string.punctuation) + ".jpg"
            outfile = open(filename , 'wb')
            outfile.write(image)
            outfile.close()
            print("Poster saved to " + filename)
        except AttributeError:
            print("Error: [ Something went wrong while downloading image, make sure you entered correct name or ID ]")
        except IOError:
            print("IOError: [ No such Image Exist ]")

    def year(self):
        """
        :return: Year of Movie
        """
        return int(self.stuff["Year"])

    def ratings(self):
        """
        :return: IMDb, RT, Metacritic ratings
        """
        data = self.stuff["Ratings"]
        rating = {}
        for entry in data:
            rating[entry["Source"]] = entry["Value"]
        return rating

    def director(self):
        """
        :return: list of Name of Directors of movie
        """
        return list(map(str, self.stuff["Director"].split(",")))

    def actors(self):
        """
        :return: list of Name of Cast in movie
        """
        return list(map(str, self.stuff["Actors"].split(",")))

    def plot(self):
        """Prints Short Plot"""
        print(self.stuff["Plot"])
        print("For more visit:\n ", self.stuff["tomatoURL"])
        print("http://www.imdb.com/title/%s" % self.stuff["imdbID"])

    def awards(self):
        """
        :return: rewards earned by the movie
        """
        return self.stuff["Awards"]

    def reviews(self):
        """Prints Rotten Tomatoes Critics Consensus"""
        print(self.stuff["tomatoConsensus"])
        print("For more visit: ", self.stuff["tomatoeURL"])
        print("http://www.imdb.com/title/%s/reviews?ref_=tt_ov_rt" % self.stuff["imdbID"])

class MovieId(Movie):
    """Takes IMDb ID as parameter instead of title"""

    def __init__(self, movie_id, mytype=''):
        try:
            assert mytype in ('', "movie", "series", "episode")
            service_url = 'http://www.omdbapi.com/?apikey=eed67065&'
            url = service_url + urlencode({'i': movie_id, 'type': mytype, 'plot': 'short',
                                           'r': 'json'})
            self.stuff = json.loads(urlopen(url).read())

        except EnvironmentError:
            print("NetWorkError: [Please make sure you are connected to internet]")
            #exit()

    def title(self):
        """
        :return: Title of movie which has this particular id on IMDb
        """
        return self.stuff["Title"]
<commit_msg>Changed varuable name mytype to category<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
# File              : pymdb.py
# Author            : Kaushik S Kalmady
# Date              : 07.11.2015
# Last Modified Date: 07.11.2017
# Last Modified By  : Kaushik S Kalmady

from __future__ import print_function
import json
import string
try:
    from urllib.request import urlopen
    from urllib.parse import urlencode
except:
    from urllib import urlopen
    from urllib import urlencode
import re

def top_250():
    """
    Pulls out IMDb Top 250 movies names.
    :return: dictionary
    """

    url = 'http://www.imdb.com/chart/top'
    try:
        raw_file = urlopen(url).read()
        titles = re.findall('title=".*?dir.*?>(.*?)', raw_file)
        return {i: title for i, title in enumerate(titles, 1)}
    except EnvironmentError:
        print("NetWorkError: [Please make sure you are connected to internet]")
        return {}

def top250_year_count():
    """
    Pulls out number of movies of a particular year in the IMDb Top 250
    :return: dictionary
    """

    year_count = {}

    url = 'http://www.imdb.com/chart/top'
    try:
        raw_file = urlopen(url).read()
        years = re.findall('secondaryInfo">\((.*?)\)', raw_file)
        for year in years:
            year_count[year] = year_count.get(year, 0) + 1
        return year_count
    except EnvironmentError:
        print("NetWorkError: [Please make sure you are connected to internet]")
        return year_count

def years_top250():
    """
    Pulls out IMDb Top 250 movies years
    :return: dictionary
    """

    url = 'http://www.imdb.com/chart/top'
    try:
        raw_file = urlopen(url).read()
        years = re.findall('secondaryInfo">\((.*?)\)', raw_file)
        return {i: year for i, year in enumerate(years, 1)}
    except EnvironmentError:
        print("NetWorkError: [Please make sure you are connected to internet]")
        return {}

def top250_id():
    """Pulls out ImDb Title ID's from the Imdb Top 250 webpage and adds them to a list.
    Returns List"""
    movielist = []
    url2 = 'http://www.imdb.com/chart/top'
    file = urlopen(url2).read()
    links = re.findall('

', file)

    for link in links:
        movielist.append(link)
    return movielist

class Movie:
    """Movie
    Enter movie title as parameter. Year is an optional argument"""

    def __init__(self, title, year=None, category=''):
        """Fetches JSON for given Movie from omdbapi.com

        Args:
            title (str): title of the movie
            year (None, optional): year of release
            category (str, optional): one of "movie", "series", "episode"

        """
        assert category in ('', "movie", "series", "episode")
        service_url = 'http://www.omdbapi.com/?apikey=eed67065&'
        url = service_url + urlencode({'t': title, 'type': category, 'y': year, 'plot': 'short',
                                       'r': 'json'})
        try:
            self.stuff = json.loads(urlopen(url).read())
        except EnvironmentError:
            print("NetWorkError: [Please make sure you are connected to internet]")
            #exit()

    @classmethod
    def search(self, title, category='', year=None):
        """search for a movie or series by title

        Args:
            title (str): title of the movie
            year (None, optional): year of release
            category (str, optional): one of "movie", "series", "episode"
        """
        assert category in ('', "movie", "series", "episode")
        service_url = 'http://www.omdbapi.com/?apikey=eed67065&'
        url = service_url + urlencode({'s': title, 'type': category, 'y': year,'r': 'json'})
        try:
            results = json.loads(urlopen(url).read())["Search"]
            for item in results:
                print("\t" + item["Title"] + " (" + item["Year"] + ")" + " [" + item["imdbID"] + "]" + " {" + item["Type"] + "}")
            print("Found total {} matching results".format(len(results)))
        except KeyError:
            print("Not found")

    def info(self):
        """Prints basic Info from IMDb"""
        print(self.stuff["Title"])
        print("Year: ", self.stuff["Year"])
        print("Rating: {rating} ({votes} votes)".format(rating=self.stuff["imdbRating"], votes=self.stuff["imdbVotes"]))
        print("Metascore: ", self.stuff["Metascore"])
        print("Language: ", self.stuff["Language"])
        print("Genre: ", self.stuff["Genre"])
        print("Director: ", self.stuff["Director"])
        print("Awards: ", self.stuff["Awards"])

    def getposter(self):
        """Saves poster of movie in current directory or raise exception if anything goes wrong
        To check current directort type 'os.getcwd()'
        To change current directory type 'os.chdir('path you wish')'
        """
        try:
            link = self.stuff["Poster"]
            image = urlopen(link).read()
            filename = self.stuff["Title"].translate(string.punctuation) + ".jpg"
            outfile = open(filename , 'wb')
            outfile.write(image)
            outfile.close()
            print("Poster saved to " + filename)
        except AttributeError:
            print("Error: [ Something went wrong while downloading image, make sure you entered correct name or ID ]")
        except IOError:
            print("IOError: [ No such Image Exist ]")

    def year(self):
        """
        :return: Year of Movie
        """
        return int(self.stuff["Year"])

    def ratings(self):
        """
        :return: IMDb, RT, Metacritic ratings
        """
        data = self.stuff["Ratings"]
        rating = {}
        for entry in data:
            rating[entry["Source"]] = entry["Value"]
        return rating

    def director(self):
        """
        :return: list of Name of Directors of movie
        """
        return list(map(str, self.stuff["Director"].split(",")))

    def actors(self):
        """
        :return: list of Name of Cast in movie
        """
        return list(map(str, self.stuff["Actors"].split(",")))

    def plot(self):
        """Prints Short Plot"""
        print(self.stuff["Plot"])
        print("For more visit:\n ", self.stuff["tomatoURL"])
        print("http://www.imdb.com/title/%s" % self.stuff["imdbID"])

    def awards(self):
        """
        :return: rewards earned by the movie
        """
        return self.stuff["Awards"]

    def reviews(self):
        """Prints Rotten Tomatoes Critics Consensus"""
        print(self.stuff["tomatoConsensus"])
        print("For more visit: ", self.stuff["tomatoeURL"])
        print("http://www.imdb.com/title/%s/reviews?ref_=tt_ov_rt" % self.stuff["imdbID"])

class MovieId(Movie):
    """Takes IMDb ID as parameter instead of title"""

    def __init__(self, movie_id, category=''):
        try:
            assert category in ('', "movie", "series", "episode")
            service_url = 'http://www.omdbapi.com/?apikey=eed67065&'
            url = service_url + urlencode({'i': movie_id, 'type': category, 'plot': 'short',
                                           'r': 'json'})
            self.stuff = json.loads(urlopen(url).read())

        except EnvironmentError:
            print("NetWorkError: [Please make sure you are connected to internet]")
            #exit()

    def title(self):
        """
        :return: Title of movie which has this particular id on IMDb
        """
        return self.stuff["Title"]
<|endoftext|>


<commit_before>#!/usr/bin/env python
"""
Tools for tree walking and visiting etc.
"""

from __future__ import print_function, absolute_import, division, unicode_literals
import logging
import copy

from . import ast

logger = logging.getLogger("pymola")

# TODO class name spaces
# TODO dot notation
# TODO find_symbol, find_class

class TreeWalker(object):

    def walk(self, listener, tree):
        name = tree.__class__.__name__
        if hasattr(listener, 'enterEvery'):
            getattr(listener, 'enterEvery')(tree)
        if hasattr(listener, 'enter' + name):
            getattr(listener, 'enter' + name)(tree)
        for child_name in tree.ast_spec.keys():
            self.handle_walk(self, listener, tree.__dict__[child_name])
        if hasattr(listener, 'exitEvery'):
            getattr(listener, 'exitEvery')(tree)
        if hasattr(listener, 'exit' + name):
            getattr(listener, 'exit' + name)(tree)

    @classmethod
    def handle_walk(cls, walker, listener, tree):
        if isinstance(tree, ast.Node):
            walker.walk(listener, tree)
        elif isinstance(tree, dict):
            for k in tree.keys():
                cls.handle_walk(walker, listener, tree[k])
        elif isinstance(tree, list):
            for i in range(len(tree)):
                cls.handle_walk(walker, listener, tree[i])
        else:
            pass

class TreeListener(object):

    def __init__(self):
        self.context = {}

    def enterEvery(self, tree):
        self.context[type(tree).__name__] = tree

    def exitEvery(self, tree):
        self.context[type(tree).__name__] = None

    def enterFile(self, tree):
        pass

    def exitFile(self, tree):
        pass

    def enterClass(self, tree):
        pass

    def exitClass(self, tree):
        pass

    def enterImportAsClause(self, tree):
        pass

    def exitImportAsClause(self, tree):
        pass

    def enterImportFromClause(self, tree):
        pass

    def exitImportFromClause(self, tree):
        pass

    def enterElementModification(self, tree):
        pass

    def exitElementModification(self, tree):
        pass

    def enterClassModification(self, tree):
        pass

    def exitClassModification(self, tree):
        pass

    def enterExtendsClause(self, tree):
        pass

    def exitExtendsClause(self, tree):
        pass

    def enterIfExpression(self, tree):
        pass

    def exitIfExpression(self, tree):
        pass

    def enterExpression(self, tree):
        pass

    def exitExpression(self, tree):
        pass

    def enterIfEquation(self, tree):
        pass

    def exitIfEquation(self, tree):
        pass

    def enterForIndex(self, tree):
        pass

    def exitForIndex(self, tree):
        pass

    def enterForEquation(self, tree):
        pass

    def exitForEquation(self, tree):
        pass

    def enterEquation(self, tree):
        pass

    def exitEquation(self, tree):
        pass

    def enterConnectClause(self, tree):
        pass

    def exitConnectClause(self, tree):
        pass

    def enterSymbol(self, tree):
        pass

    def exitSymbol(self, tree):
        pass

    def enterComponentClause(self, tree):
        pass

    def exitComponentClause(self, tree):
        pass

    def enterArray(self, tree):
        pass

    def exitArray(self, tree):
        pass

    def enterSlice(self, tree):
        pass

    def exitSlice(self, tree):
        pass

    def enterPrimary(self, tree):
        pass

    def exitPrimary(self, tree):
        pass

    def enterComponentRef(self, tree):
        pass

    def exitComponentRef(self, tree):
        pass

def flatten(root, class_name, instance_name=''):
    """
    This function takes and flattens it so that all subclasses instances
    are replaced by the their equations and symbols with name mangling
    of the instance name passed.
    :param root: The root of the tree that contains all class definitions
    :param class_name: The class we want to flatten
    :param instance_name:
    :return: flat_class, the flattened class of type Class
    """

    # extract the original class of interest
    orig_class = root.classes[class_name]

    # create the returned class
    flat_class = ast.Class(
        name=class_name,
    )

    # flat file
    flat_file = ast.File()
    flat_file.classes[class_name] = flat_class

    # append period to non empty instance_name
    if instance_name != '':
        instance_prefix = instance_name + '.'
    else:
        instance_prefix = instance_name

    def modify_class(c, modification):
        for argument in modification.arguments:
            if argument.name in ast.Symbol.ATTRIBUTES:
                setattr(c, argument.name, argument.modifications[0])
            else:
                sym = flat_class.symbols[argument.name]

                for modification in argument.modifications:
                    if isinstance(modification, ast.ClassModification):
                        modify_class(sym, modification)
                    else:
                        sym.value = modification

    def flatten_symbol(sym, instance_prefix):
        sym_copy = copy.deepcopy(sym)
        sym_copy.name = instance_prefix + sym.name
        return sym_copy

    def flatten_equation(equation, instance_prefix):
        equation_copy = copy.deepcopy(equation)

        class EquationFlattener(TreeListener):
            def __init__(self, instance_prefix):
                self.instance_prefix = instance_prefix
                self.d = 0

                super(EquationFlattener, self).__init__()

            def enterComponentRef(self, tree):
                self.d += 1

                if self.d == 1:
                    tree.name = self.instance_prefix + tree.name
                    c = tree
                    while len(c.child) > 0:
                        c = tree.child[0]
                        tree.name += '.' + c.name
                    tree.child = []

            def exitComponentRef(self, tree):
                self.d -= 1

        w = TreeWalker()
        w.walk(EquationFlattener(instance_prefix), equation_copy)

        return equation_copy

    # pull in parent classes
    for extends in orig_class.extends:
        c = root.find_class(extends.component)

        # recursively call flatten on the parent class
        flat_parent_file = flatten(root, c.name, instance_name=instance_name)
        flat_parent_class = flat_parent_file.classes[c.name]

        # add parent class members symbols and equations
        for parent_sym_name, parent_sym in flat_parent_class.symbols.items():
            flat_sym = flatten_symbol(parent_sym, instance_prefix)
            flat_class.symbols[flat_sym.name] = flat_sym
        flat_class.equations += [flatten_equation(e, instance_prefix) for e in flat_parent_class.equations]

        # carry out modifications
        modify_class(c, extends.class_modification)

    # for all symbols in the original class
    for sym_name, sym in orig_class.symbols.items():
        # if the symbol type is a class
        try:
            class_data = root.find_class(sym.type)
            if class_data.type == 'connector':
                flat_class.symbols[instance_prefix + sym_name] = copy.deepcopy(sym)
                for sym_name2, sym2 in class_data.symbols.items():
                    flat_class.symbols[instance_prefix + sym_name + "." + sym_name2] = copy.deepcopy(sym2)

            # recursively call flatten on the sub class
            flat_sub_file = flatten(root, sym.type.name, instance_name=sym_name)
            flat_sub_class = flat_sub_file.find_class(sym.type) # TODO

            # add sub_class members symbols and equations
            for sub_sym_name, sub_sym in flat_sub_class.symbols.items():
                flat_sym = flatten_symbol(sub_sym, instance_prefix)
                flat_class.symbols[flat_sym.name] = flat_sym
            flat_class.equations += [flatten_equation(e, instance_prefix) for e in flat_sub_class.equations]

        except KeyError:
            # append original symbol to flat class
            flat_sym = flatten_symbol(sym, instance_prefix)
            flat_class.symbols[flat_sym.name] = flat_sym

    # for all equations in original class
    for equation in orig_class.equations:
        flat_equation = flatten_equation(equation, instance_prefix)
        if isinstance(equation, ast.ConnectClause):
            # expand connector
            connect_equations = []
            sym_left = root.find_symbol(orig_class, equation.left)
            sym_right = root.find_symbol(orig_class, equation.right)

            try:
                class_left = root.find_class(sym_left.type)
                class_right = root.find_class(sym_right.type)

                assert(class_left == class_right)

                for connector_variable in class_left.symbols.keys():
                    left_name = flat_equation.left.name + '.' + connector_variable
                    left = ast.ComponentRef(name=left_name)
                    right_name = flat_equation.right.name + '.' + connector_variable
                    right = ast.ComponentRef(name=right_name)
                    connect_equation = ast.Equation(left=left, right=right)
                    connect_equations.append(connect_equation)
            except KeyError:
                logger.debug("Connector class not defined.  Assuming it to be an elementary type.")

                connect_equation = ast.Equation(left=flat_equation.left, right=flat_equation.right)
                connect_equations.append(connect_equation)

            # TODO if flow in prefixes:  flow_equalities[port_a] = flow_equalities[port_b] = flow_variables,

            flat_class.equations += connect_equations
        else:
            # flatten equation
            flat_class.equations += [flat_equation]

    return flat_file
<commit_msg>Basic support for flow connectors<commit_after>#!/usr/bin/env python
"""
Tools for tree walking and visiting etc.
"""

from __future__ import print_function, absolute_import, division, unicode_literals
import logging
import copy

from . import ast

logger = logging.getLogger("pymola")

# TODO class name spaces
# TODO dot notation
# TODO find_symbol, find_class
# TODO Flatten function vs. conversion classes

class TreeWalker(object):

    def walk(self, listener, tree):
        name = tree.__class__.__name__
        if hasattr(listener, 'enterEvery'):
            getattr(listener, 'enterEvery')(tree)
        if hasattr(listener, 'enter' + name):
            getattr(listener, 'enter' + name)(tree)
        for child_name in tree.ast_spec.keys():
            self.handle_walk(self, listener, tree.__dict__[child_name])
        if hasattr(listener, 'exitEvery'):
            getattr(listener, 'exitEvery')(tree)
        if hasattr(listener, 'exit' + name):
            getattr(listener, 'exit' + name)(tree)

    @classmethod
    def handle_walk(cls, walker, listener, tree):
        if isinstance(tree, ast.Node):
            walker.walk(listener, tree)
        elif isinstance(tree, dict):
            for k in tree.keys():
                cls.handle_walk(walker, listener, tree[k])
        elif isinstance(tree, list):
            for i in range(len(tree)):
                cls.handle_walk(walker, listener, tree[i])
        else:
            pass

class TreeListener(object):

    def __init__(self):
        self.context = {}

    def enterEvery(self, tree):
        self.context[type(tree).__name__] = tree

    def exitEvery(self, tree):
        self.context[type(tree).__name__] = None

    def enterFile(self, tree):
        pass

    def exitFile(self, tree):
        pass

    def enterClass(self, tree):
        pass

    def exitClass(self, tree):
        pass

    def enterImportAsClause(self, tree):
        pass

    def exitImportAsClause(self, tree):
        pass

    def enterImportFromClause(self, tree):
        pass

    def exitImportFromClause(self, tree):
        pass

    def enterElementModification(self, tree):
        pass

    def exitElementModification(self, tree):
        pass

    def enterClassModification(self, tree):
        pass

    def exitClassModification(self, tree):
        pass

    def enterExtendsClause(self, tree):
        pass

    def exitExtendsClause(self, tree):
        pass

    def enterIfExpression(self, tree):
        pass

    def exitIfExpression(self, tree):
        pass

    def enterExpression(self, tree):
        pass

    def exitExpression(self, tree):
        pass

    def enterIfEquation(self, tree):
        pass

    def exitIfEquation(self, tree):
        pass

    def enterForIndex(self, tree):
        pass

    def exitForIndex(self, tree):
        pass

    def enterForEquation(self, tree):
        pass

    def exitForEquation(self, tree):
        pass

    def enterEquation(self, tree):
        pass

    def exitEquation(self, tree):
        pass

    def enterConnectClause(self, tree):
        pass

    def exitConnectClause(self, tree):
        pass

    def enterSymbol(self, tree):
        pass

    def exitSymbol(self, tree):
        pass

    def enterComponentClause(self, tree):
        pass

    def exitComponentClause(self, tree):
        pass

    def enterArray(self, tree):
        pass

    def exitArray(self, tree):
        pass

    def enterSlice(self, tree):
        pass

    def exitSlice(self, tree):
        pass

    def enterPrimary(self, tree):
        pass

    def exitPrimary(self, tree):
        pass

    def enterComponentRef(self, tree):
        pass

    def exitComponentRef(self, tree):
        pass

def flatten(root, class_name, instance_name=''):
    """
    This function takes and flattens it so that all subclasses instances
    are replaced by the their equations and symbols with name mangling
    of the instance name passed.
    :param root: The root of the tree that contains all class definitions
    :param class_name: The class we want to flatten
    :param instance_name:
    :return: flat_class, the flattened class of type Class
    """

    # extract the original class of interest
    orig_class = root.classes[class_name]

    # create the returned class
    flat_class = ast.Class(
        name=class_name,
    )

    # flat file
    flat_file = ast.File()
    flat_file.classes[class_name] = flat_class

    # append period to non empty instance_name
    if instance_name != '':
        instance_prefix = instance_name + '.'
    else:
        instance_prefix = instance_name

    def modify_class(c, modification):
        for argument in modification.arguments:
            if argument.name in ast.Symbol.ATTRIBUTES:
                setattr(c, argument.name, argument.modifications[0])
            else:
                sym = flat_class.symbols[argument.name]

                for modification in argument.modifications:
                    if isinstance(modification, ast.ClassModification):
                        modify_class(sym, modification)
                    else:
                        sym.value = modification

    def flatten_symbol(sym, instance_prefix):
        sym_copy = copy.deepcopy(sym)
        sym_copy.name = instance_prefix + sym.name
        return sym_copy

    def flatten_equation(equation, instance_prefix):
        equation_copy = copy.deepcopy(equation)

        class EquationFlattener(TreeListener):
            def __init__(self, instance_prefix):
                self.instance_prefix = instance_prefix
                self.d = 0

                super(EquationFlattener, self).__init__()

            def enterComponentRef(self, tree):
                self.d += 1

                if self.d == 1:
                    tree.name = self.instance_prefix + tree.name
                    c = tree
                    while len(c.child) > 0:
                        c = tree.child[0]
                        tree.name += '.' + c.name
                    tree.child = []

            def exitComponentRef(self, tree):
                self.d -= 1

        w = TreeWalker()
        w.walk(EquationFlattener(instance_prefix), equation_copy)

        return equation_copy

    # pull in parent classes
    for extends in orig_class.extends:
        c = root.find_class(extends.component)

        # recursively call flatten on the parent class
        flat_parent_file = flatten(root, c.name, instance_name=instance_name)
        flat_parent_class = flat_parent_file.classes[c.name]

        # add parent class members symbols and equations
        for parent_sym_name, parent_sym in flat_parent_class.symbols.items():
            flat_sym = flatten_symbol(parent_sym, instance_prefix)
            flat_class.symbols[flat_sym.name] = flat_sym
        flat_class.equations += [flatten_equation(e, instance_prefix) for e in flat_parent_class.equations]

        # carry out modifications
        modify_class(c, extends.class_modification)

    # for all symbols in the original class
    for sym_name, sym in orig_class.symbols.items():
        # if the symbol type is a class
        try:
            class_data = root.find_class(sym.type)
            if class_data.type == 'connector':
                flat_class.symbols[instance_prefix + sym_name] = copy.deepcopy(sym)
                for sym_name2, sym2 in class_data.symbols.items():
                    flat_class.symbols[instance_prefix + sym_name + "." + sym_name2] = copy.deepcopy(sym2)

            # recursively call flatten on the sub class
            flat_sub_file = flatten(root, sym.type.name, instance_name=sym_name)
            flat_sub_class = flat_sub_file.find_class(sym.type) # TODO

            # add sub_class members symbols and equations
            for sub_sym_name, sub_sym in flat_sub_class.symbols.items():
                flat_sym = flatten_symbol(sub_sym, instance_prefix)
                flat_class.symbols[flat_sym.name] = flat_sym
            flat_class.equations += [flatten_equation(e, instance_prefix) for e in flat_sub_class.equations]

        except KeyError:
            # append original symbol to flat class
            flat_sym = flatten_symbol(sym, instance_prefix)
            flat_class.symbols[flat_sym.name] = flat_sym

    # for all equations in original class
    flow_connections = {}
    for equation in orig_class.equations:
        flat_equation = flatten_equation(equation, instance_prefix)
        if isinstance(equation, ast.ConnectClause):
            # expand connector
            connect_equations = []
            sym_left = root.find_symbol(orig_class, equation.left)
            sym_right = root.find_symbol(orig_class, equation.right)

            try:
                class_left = root.find_class(sym_left.type)
                class_right = root.find_class(sym_right.type)

                assert(class_left == class_right)

                for connector_variable in class_left.symbols.values():
                    left_name = flat_equation.left.name + '.' + connector_variable.name
                    right_name = flat_equation.right.name + '.' + connector_variable.name
                    if len(connector_variable.prefixes) == 0:
                        left = ast.ComponentRef(name=left_name)
                        right = ast.ComponentRef(name=right_name)
                        connect_equation = ast.Equation(left=left, right=right)
                        connect_equations.append(connect_equation)
                    elif connector_variable.prefixes == ['flow']:
                        left_connected_variables = flow_connections.get(left_name, set())
                        right_connected_variables = flow_connections.get(right_name, set())

                        connected_variables = left_connected_variables.union(right_connected_variables)
                        if left_name not in connected_variables:
                            connected_variables.add(left_name)
                        if right_name not in connected_variables:
                            connected_variables.add(right_name)

                        connected_variables = frozenset(connected_variables)
                        for connected_variable in connected_variables:
                            flow_connections[connected_variable] = connected_variables
                    else:
                        raise Exception("Unsupported connector variable prefixes {}".format(connector_variable.prefixes))
            except KeyError:
                logger.debug("Connector class not defined.  Assuming it to be an elementary type.")

                connect_equation = ast.Equation(left=flat_equation.left, right=flat_equation.right)
                connect_equations.append(connect_equation)

            # TODO if flow in prefixes:  flow_equalities[port_a] = flow_equalities[port_b] = flow_variables,

            flat_class.equations += connect_equations
        else:
            # flatten equation
            flat_class.equations += [flat_equation]

    # add flow equations
    if len(flow_connections) > 0:
        # TODO Flatten first
        logger.warning("Note: Connections between connectors with flow variables are not supported across levels of the class hierarchy")
    for connected_variables in set(flow_connections.values()):
        operands = [ast.ComponentRef(name=variable) for variable in connected_variables]
        connect_equation = ast.Equation(left=ast.Expression(operator='+', operands=operands), right=ast.Primary(value=0))
        flat_class.equations += [connect_equation]

    return flat_file
<|endoftext|>


<commit_before>#!/usr/bin/env python
"""
Tools for tree walking and visiting etc.
"""

from __future__ import print_function, absolute_import, division, unicode_literals
import copy

from . import ast

class TreeWalker(object):

    def walk(self, listener, tree):
        name = tree.__class__.__name__
        if hasattr(listener, 'enterEvery'):
            getattr(listener, 'enterEvery')(tree)
        if hasattr(listener, 'enter' + name):
            getattr(listener, 'enter' + name)(tree)
        for child_name in tree.ast_spec.keys():
            self.handle_walk(self, listener, tree.__dict__[child_name])
        if hasattr(listener, 'exitEvery'):
            getattr(listener, 'exitEvery')(tree)
        if hasattr(listener, 'exit' + name):
            getattr(listener, 'exit' + name)(tree)

    @classmethod
    def handle_walk(cls, walker, listener, tree):
        if isinstance(tree, ast.Node):
            walker.walk(listener, tree)
        elif isinstance(tree, dict):
            for k in tree.keys():
                cls.handle_walk(walker, listener, tree[k])
        elif isinstance(tree, list):
            for i in range(len(tree)):
                cls.handle_walk(walker, listener, tree[i])
        else:
            pass

class TreeVisitor(object):
    """
    TODO this class hasn't been tested
    """

    def visit(self, visitor, tree):
        name = self.__class__.__name__
        if hasattr(visitor, 'visit' + name):
            return visitor.__getattribute__('visit' + name)(tree)
        else:
            res = []
            for k in tree.ast_spec.keys():
                res += [self.handle_visit(visitor, tree[k])]
            if len(res) == 1:
                res = res[0]
            return res

    @classmethod
    def handle_visit(cls, visitor, tree):
        res = []
        if isinstance(tree, ast.Node):
            res += visitor.visit(visitor, tree)
        elif isinstance(tree, dict):
            for k in tree.keys():
                res += [cls.handle_visit(tree[k], visitor)]
        elif isinstance(tree, list):
            for c in tree:
                res += [cls.handle_visit(c, visitor)]
        if len(res) == 1:
            res = res[0]
        return res

class TreeListener(object):

    def __init__(self):
        self.context = {}

    def enterEvery(self, tree):
        self.context[type(tree).__name__] = tree

    def exitEvery(self, tree):
        self.context[type(tree).__name__] = None

    def enterFile(self, tree):
        pass

    def exitFile(self, tree):
        pass

    def enterClass(self, tree):
        pass

    def exitClass(self, tree):
        pass

    def enterImportAsClause(self, tree):
        pass

    def exitImportAsClause(self, tree):
        pass

    def enterImportFromClause(self, tree):
        pass

    def exitImportFromClause(self, tree):
        pass

    def enterElementModification(self, tree):
        pass

    def exitElementModification(self, tree):
        pass

    def enterClassModification(self, tree):
        pass

    def exitClassModification(self, tree):
        pass

    def enterExtendsClause(self, tree):
        pass

    def exitExtendsClause(self, tree):
        pass

    def enterIfExpression(self, tree):
        pass

    def exitIfExpression(self, tree):
        pass

    def enterExpression(self, tree):
        pass

    def exitExpression(self, tree):
        pass

    def enterIfEquation(self, tree):
        pass

    def exitIfEquation(self, tree):
        pass

    def enterForIndex(self, tree):
        pass

    def exitForIndex(self, tree):
        pass

    def enterForEquation(self, tree):
        pass

    def exitForEquation(self, tree):
        pass

    def enterEquation(self, tree):
        pass

    def exitEquation(self, tree):
        pass

    def enterConnectClause(self, tree):
        pass

    def exitConnectClause(self, tree):
        pass

    def enterSymbol(self, tree):
        pass

    def exitSymbol(self, tree):
        pass

    def enterComponentClause(self, tree):
        pass

    def exitComponentClause(self, tree):
        pass

    def enterArray(self, tree):
        pass

    def exitArray(self, tree):
        pass

    def enterSlice(self, tree):
        pass

    def exitSlice(self, tree):
        pass

    def enterPrimary(self, tree):
        pass

    def exitPrimary(self, tree):
        pass

    def enterComponentRef(self, tree):
        pass

    def exitComponentRef(self, tree):
        pass

def flatten(root, class_name, instance_name=''):
    """
    This function takes and flattens it so that all subclasses instances
    are replaced by the their equations and symbols with name mangling
    of the instance name passed.
    :param root: The root of the tree that contains all class definitions
    :param class_name: The class we want to flatten
    :param instance_name:
    :return: flat_class, the flattened class of type Class
    """

    # extract the original class of interest
    orig_class = root.classes[class_name]

    # create the returned class
    flat_class = ast.Class(
        name=class_name,
    )

    # flat file
    flat_file = ast.File()
    flat_file.classes[class_name] = flat_class

    # append period to non empty instance_name
    if instance_name != '':
        instance_prefix = instance_name + '.'
    else:
        instance_prefix = instance_name

    def modify_class(c, modification):
        for argument in modification.arguments:
            if argument.name in ast.Symbol.ATTRIBUTES:
                setattr(c, argument.name, argument.modifications[0])
            else:
                sym = flat_class.symbols[argument.name]

                for modification in argument.modifications:
                    if isinstance(modification, ast.ClassModification):
                        modify_class(sym, modification)
                    else:
                        sym.value = modification

    def flatten_symbol(sym, instance_prefix):
        sym_copy = copy.deepcopy(sym)
        sym_copy.name = instance_prefix + sym.name
        return sym_copy

    def flatten_equation(equation, instance_prefix):
        equation_copy = copy.deepcopy(equation)

        class EquationFlattener(TreeListener):
            def __init__(self, instance_prefix):
                self.instance_prefix = instance_prefix
                self.d = 0

                super(EquationFlattener, self).__init__()

            def enterComponentRef(self, tree):
                self.d += 1

                if self.d == 1:
                    tree.name = self.instance_prefix + tree.name

            def exitComponentRef(self, tree):
                self.d -= 1

        w = TreeWalker()
        w.walk(EquationFlattener(instance_prefix), equation_copy)

        return equation_copy

    # pull in parent classes
    for extends in orig_class.extends:
        c = root.find_class(extends.component)

        # recursively call flatten on the parent class
        flat_parent_file = flatten(root, c.name, instance_name=instance_name)
        flat_parent_class = flat_parent_file.classes[c.name]

        # add parent class members symbols and equations
        for parent_sym_name, parent_sym in flat_parent_class.symbols.items():
            flat_sym = flatten_symbol(parent_sym, instance_prefix)
            flat_class.symbols[flat_sym.name] = flat_sym
        flat_class.equations += [flatten_equation(e, instance_prefix) for e in flat_parent_class.equations]

        # carry out modifications
        modify_class(c, extends.class_modification)

    # create a walker
    ast_walker = TreeWalker()

    # for all symbols in the original class
    for sym_name, sym in orig_class.symbols.items():
        # if the symbol type is a class
        try:
            class_data = root.find_class(sym.type)
            if class_data.type == 'connector':
                continue

            # recursively call flatten on the sub class
            flat_sub_file = flatten(root, sym.type.name, instance_name=sym_name)
            flat_sub_class = flat_sub_file.find_class(sym.type)

            # add sub_class members symbols and equations
            for sub_sym_name, sub_sym in flat_sub_class.symbols.items():
                flat_sym = flatten_symbol(sub_sym, instance_prefix)
                flat_class.symbols[flat_sym.name] = flat_sym
            flat_class.equations += [flatten_equation(e, instance_prefix) for e in flat_sub_class.equations]

        except KeyError:
            # append original symbol to flat class
            flat_sym = flatten_symbol(sym, instance_prefix)
            flat_class.symbols[flat_sym.name] = flat_sym

    # for all equations in the original class
    flat_class.equations += [flatten_equation(e, instance_prefix) for e in orig_class.equations]

    # walker for expanding connect equations
    # ast_walker.walk(ConnectExpanderListener(), flat_class)

    return flat_file

class Instatiator(TreeListener):
    """
    Instantiates all classes that are not connectors.
    """

    def __init__(self, classes, scope=[]):
        super(Instatiator, self).__init__()
        self.classes = classes
        self.res = {}
        self.scope = scope

    @staticmethod
    def get_scoped_name(scope, name):
        scope = copy.deepcopy(scope)
        scope += [str(name)]
        return '.'.join(scope)

    def enterComponentRef(self, tree):
        name = self.get_scoped_name(self.scope, tree.name)
        tree.name = name

    def exitSymbol(self, tree):
        """
        Set the result of classes to their definitions if it is
        not a connector, otherwise set the result to the symbol
        """
        if tree.type in self.classes:
            class_def = self.classes[tree.type]
            if class_def.type == 'connector':
                self.res[tree] = tree
            else:
                self.res[tree] = class_def
        else:
            self.res[tree] = tree

    def exitEquation(self, tree):
        self.res[tree] = tree

    def exitClass(self, tree):
        """
        For each nested class definition, expand its attributes,
        fore each equation and symbol, copy them to the result
        """
        c = ast.Class()
        for key, val in tree.symbols.items():
            name = self.get_scoped_name(self.scope, key)
            root = self.res[val]
            if type(root) == ast.Class:
                walker = TreeWalker()
                instantiator = Instatiator(
                    classes=self.classes,
                    scope=self.scope + [key]
                )
                walker.walk(instantiator, root)
                c.symbols.update(instantiator.res[root].symbols)
                c.equations.extend(instantiator.res[root].equations)
            elif type(root) == ast.Symbol:
                root.name = name
                c.symbols[name] = root
            else:
                raise RuntimeError('unhandled type', type(root))
        c.equations.extend(tree.equations)
        self.res[tree] = c

class ConnectExpander(TreeListener):

    def __init__(self, classes):
        super(ConnectExpander, self).__init__()
        self.scope = []
        self.classes = classes

    def enterConnectClause(self, tree):
        left_class = self.context['Class'].symbols[tree.left.name]
        right_class =self.context['Class'].symbols[tree.right.name]
        assert left_class.type == 'connector'
        assert right_class.type == 'connector'
        assert left_class == right_class<commit_msg>Quick-and-dirty implementation of full symbol name flattening.  To be improved.<commit_after>#!/usr/bin/env python
"""
Tools for tree walking and visiting etc.
"""

from __future__ import print_function, absolute_import, division, unicode_literals
import copy

from . import ast

class TreeWalker(object):

    def walk(self, listener, tree):
        name = tree.__class__.__name__
        if hasattr(listener, 'enterEvery'):
            getattr(listener, 'enterEvery')(tree)
        if hasattr(listener, 'enter' + name):
            getattr(listener, 'enter' + name)(tree)
        for child_name in tree.ast_spec.keys():
            self.handle_walk(self, listener, tree.__dict__[child_name])
        if hasattr(listener, 'exitEvery'):
            getattr(listener, 'exitEvery')(tree)
        if hasattr(listener, 'exit' + name):
            getattr(listener, 'exit' + name)(tree)

    @classmethod
    def handle_walk(cls, walker, listener, tree):
        if isinstance(tree, ast.Node):
            walker.walk(listener, tree)
        elif isinstance(tree, dict):
            for k in tree.keys():
                cls.handle_walk(walker, listener, tree[k])
        elif isinstance(tree, list):
            for i in range(len(tree)):
                cls.handle_walk(walker, listener, tree[i])
        else:
            pass

class TreeVisitor(object):
    """
    TODO this class hasn't been tested
    """

    def visit(self, visitor, tree):
        name = self.__class__.__name__
        if hasattr(visitor, 'visit' + name):
            return visitor.__getattribute__('visit' + name)(tree)
        else:
            res = []
            for k in tree.ast_spec.keys():
                res += [self.handle_visit(visitor, tree[k])]
            if len(res) == 1:
                res = res[0]
            return res

    @classmethod
    def handle_visit(cls, visitor, tree):
        res = []
        if isinstance(tree, ast.Node):
            res += visitor.visit(visitor, tree)
        elif isinstance(tree, dict):
            for k in tree.keys():
                res += [cls.handle_visit(tree[k], visitor)]
        elif isinstance(tree, list):
            for c in tree:
                res += [cls.handle_visit(c, visitor)]
        if len(res) == 1:
            res = res[0]
        return res

class TreeListener(object):

    def __init__(self):
        self.context = {}

    def enterEvery(self, tree):
        self.context[type(tree).__name__] = tree

    def exitEvery(self, tree):
        self.context[type(tree).__name__] = None

    def enterFile(self, tree):
        pass

    def exitFile(self, tree):
        pass

    def enterClass(self, tree):
        pass

    def exitClass(self, tree):
        pass

    def enterImportAsClause(self, tree):
        pass

    def exitImportAsClause(self, tree):
        pass

    def enterImportFromClause(self, tree):
        pass

    def exitImportFromClause(self, tree):
        pass

    def enterElementModification(self, tree):
        pass

    def exitElementModification(self, tree):
        pass

    def enterClassModification(self, tree):
        pass

    def exitClassModification(self, tree):
        pass

    def enterExtendsClause(self, tree):
        pass

    def exitExtendsClause(self, tree):
        pass

    def enterIfExpression(self, tree):
        pass

    def exitIfExpression(self, tree):
        pass

    def enterExpression(self, tree):
        pass

    def exitExpression(self, tree):
        pass

    def enterIfEquation(self, tree):
        pass

    def exitIfEquation(self, tree):
        pass

    def enterForIndex(self, tree):
        pass

    def exitForIndex(self, tree):
        pass

    def enterForEquation(self, tree):
        pass

    def exitForEquation(self, tree):
        pass

    def enterEquation(self, tree):
        pass

    def exitEquation(self, tree):
        pass

    def enterConnectClause(self, tree):
        pass

    def exitConnectClause(self, tree):
        pass

    def enterSymbol(self, tree):
        pass

    def exitSymbol(self, tree):
        pass

    def enterComponentClause(self, tree):
        pass

    def exitComponentClause(self, tree):
        pass

    def enterArray(self, tree):
        pass

    def exitArray(self, tree):
        pass

    def enterSlice(self, tree):
        pass

    def exitSlice(self, tree):
        pass

    def enterPrimary(self, tree):
        pass

    def exitPrimary(self, tree):
        pass

    def enterComponentRef(self, tree):
        pass

    def exitComponentRef(self, tree):
        pass

def flatten(root, class_name, instance_name=''):
    """
    This function takes and flattens it so that all subclasses instances
    are replaced by the their equations and symbols with name mangling
    of the instance name passed.
    :param root: The root of the tree that contains all class definitions
    :param class_name: The class we want to flatten
    :param instance_name:
    :return: flat_class, the flattened class of type Class
    """

    # extract the original class of interest
    orig_class = root.classes[class_name]

    # create the returned class
    flat_class = ast.Class(
        name=class_name,
    )

    # flat file
    flat_file = ast.File()
    flat_file.classes[class_name] = flat_class

    # append period to non empty instance_name
    if instance_name != '':
        instance_prefix = instance_name + '.'
    else:
        instance_prefix = instance_name

    def modify_class(c, modification):
        for argument in modification.arguments:
            if argument.name in ast.Symbol.ATTRIBUTES:
                setattr(c, argument.name, argument.modifications[0])
            else:
                sym = flat_class.symbols[argument.name]

                for modification in argument.modifications:
                    if isinstance(modification, ast.ClassModification):
                        modify_class(sym, modification)
                    else:
                        sym.value = modification

    def flatten_symbol(sym, instance_prefix):
        sym_copy = copy.deepcopy(sym)
        sym_copy.name = instance_prefix + sym.name
        return sym_copy

    def flatten_equation(equation, instance_prefix):
        equation_copy = copy.deepcopy(equation)

        class EquationFlattener(TreeListener):
            def __init__(self, instance_prefix):
                self.instance_prefix = instance_prefix
                self.d = 0

                super(EquationFlattener, self).__init__()

            def enterComponentRef(self, tree):
                self.d += 1

                if self.d == 1:
                    tree.name = self.instance_prefix + tree.name
                    c = tree
                    while len(c.child) > 0:
                        c = tree.child[0]
                        tree.name += '.' + c.name
                    tree.child = []

            def exitComponentRef(self, tree):
                self.d -= 1

        w = TreeWalker()
        w.walk(EquationFlattener(instance_prefix), equation_copy)

        return equation_copy

    # pull in parent classes
    for extends in orig_class.extends:
        c = root.find_class(extends.component)

        # recursively call flatten on the parent class
        flat_parent_file = flatten(root, c.name, instance_name=instance_name)
        flat_parent_class = flat_parent_file.classes[c.name]

        # add parent class members symbols and equations
        for parent_sym_name, parent_sym in flat_parent_class.symbols.items():
            flat_sym = flatten_symbol(parent_sym, instance_prefix)
            flat_class.symbols[flat_sym.name] = flat_sym
        flat_class.equations += [flatten_equation(e, instance_prefix) for e in flat_parent_class.equations]

        # carry out modifications
        modify_class(c, extends.class_modification)

    # create a walker
    ast_walker = TreeWalker()

    # for all symbols in the original class
    for sym_name, sym in orig_class.symbols.items():
        # if the symbol type is a class
        try:
            class_data = root.find_class(sym.type)
            if class_data.type == 'connector':
                continue

            # recursively call flatten on the sub class
            flat_sub_file = flatten(root, sym.type.name, instance_name=sym_name)
            flat_sub_class = flat_sub_file.find_class(sym.type)

            # add sub_class members symbols and equations
            for sub_sym_name, sub_sym in flat_sub_class.symbols.items():
                flat_sym = flatten_symbol(sub_sym, instance_prefix)
                flat_class.symbols[flat_sym.name] = flat_sym
            flat_class.equations += [flatten_equation(e, instance_prefix) for e in flat_sub_class.equations]

        except KeyError:
            # append original symbol to flat class
            flat_sym = flatten_symbol(sym, instance_prefix)
            flat_class.symbols[flat_sym.name] = flat_sym

    # for all equations in the original class
    flat_class.equations += [flatten_equation(e, instance_prefix) for e in orig_class.equations]

    # walker for expanding connect equations
    # ast_walker.walk(ConnectExpanderListener(), flat_class)

    return flat_file

class Instatiator(TreeListener):
    """
    Instantiates all classes that are not connectors.
    """

    def __init__(self, classes, scope=[]):
        super(Instatiator, self).__init__()
        self.classes = classes
        self.res = {}
        self.scope = scope

    @staticmethod
    def get_scoped_name(scope, name):
        scope = copy.deepcopy(scope)
        scope += [str(name)]
        return '.'.join(scope)

    def enterComponentRef(self, tree):
        name = self.get_scoped_name(self.scope, tree.name)
        tree.name = name

    def exitSymbol(self, tree):
        """
        Set the result of classes to their definitions if it is
        not a connector, otherwise set the result to the symbol
        """
        if tree.type in self.classes:
            class_def = self.classes[tree.type]
            if class_def.type == 'connector':
                self.res[tree] = tree
            else:
                self.res[tree] = class_def
        else:
            self.res[tree] = tree

    def exitEquation(self, tree):
        self.res[tree] = tree

    def exitClass(self, tree):
        """
        For each nested class definition, expand its attributes,
        fore each equation and symbol, copy them to the result
        """
        c = ast.Class()
        for key, val in tree.symbols.items():
            name = self.get_scoped_name(self.scope, key)
            root = self.res[val]
            if type(root) == ast.Class:
                walker = TreeWalker()
                instantiator = Instatiator(
                    classes=self.classes,
                    scope=self.scope + [key]
                )
                walker.walk(instantiator, root)
                c.symbols.update(instantiator.res[root].symbols)
                c.equations.extend(instantiator.res[root].equations)
            elif type(root) == ast.Symbol:
                root.name = name
                c.symbols[name] = root
            else:
                raise RuntimeError('unhandled type', type(root))
        c.equations.extend(tree.equations)
        self.res[tree] = c

class ConnectExpander(TreeListener):

    def __init__(self, classes):
        super(ConnectExpander, self).__init__()
        self.scope = []
        self.classes = classes

    def enterConnectClause(self, tree):
        left_class = self.context['Class'].symbols[tree.left.name]
        right_class =self.context['Class'].symbols[tree.right.name]
        assert left_class.type == 'connector'
        assert right_class.type == 'connector'
        assert left_class == right_class<|endoftext|>


<commit_before>
import logging

""" Logging utilities """

class Message(object):
    def __init__(self, fmt, args):
        self.fmt = fmt
        self.args = args

    def __str__(self):
        return self.fmt.format(*self.args)

class BracesAdapter(logging.LoggerAdapter):
    def __init__(self, logger, extra=None):
        super().__init__(logger, extra or {})

    def log(self, level, msg, *args, **kwargs):
        if self.isEnabledFor(level):
            msg, kwargs = self.process(msg, kwargs)
            self.logger._log(level, Message(msg, args), (), **kwargs)

def get_logger(name):
    return BracesAdapter(logging.getLogger(name))

<commit_msg>utils: move run utility to utils<commit_after>
import logging
import subprocess

""" Logging utilities """

class Message(object):
    def __init__(self, fmt, args):
        self.fmt = fmt
        self.args = args

    def __str__(self):
        return self.fmt.format(*self.args)

class BracesAdapter(logging.LoggerAdapter):
    def __init__(self, logger, extra=None):
        super().__init__(logger, extra or {})

    def log(self, level, msg, *args, **kwargs):
        if self.isEnabledFor(level):
            msg, kwargs = self.process(msg, kwargs)
            self.logger._log(level, Message(msg, args), (), **kwargs)

def get_logger(name):
    return BracesAdapter(logging.getLogger(name))

""" Binary utilities """

def run(args, stdin=None):
    """Executes a command and waits for the result.

    Parameters
    ----------
    args : list
        The list of arguments for the program to execute. Arguments should be
        formatted as for the ``subprocess.Popen`` constructor.
    stdin : str or bytes
        String or bytes containing the input stream for the process.

    Returns
    -------
    CompletedProcess
        An instance of CompletedProcess containing the information about
        the executed process, including stdout, stderr and running time.

    Raises
    ------
    CalledProcessError
        When the process returns an error.
    """
    log = get_logger(__name__)
    log.debug('Executing command with args: {}', args)
    start = time.time()
    with subprocess.Popen(args, bufsize=1, universal_newlines=True,
                          stdin=subprocess.PIPE,
                          stdout=subprocess.PIPE,
                          stderr=subprocess.PIPE) as process:
        out, err = process.communicate(stdin)
        ret = process.poll()
    elapsed = time.time() - start
    log.debug('Done. Running time: {0:.2f} seconds'.format(elapsed))
    process = subprocess.CompletedProcess(args, ret, out, err)
    process.check_returncode()
    return process

<|endoftext|>


<commit_before>#
#

# Copyright (C) 2011, 2012 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.

"""IP address pool management functions.

"""

import ipaddr

from bitarray import bitarray

from ganeti import errors

class AddressPool(object):
  """Address pool class, wrapping an C{objects.Network} object.

  This class provides methods to manipulate address pools, backed by
  L{objects.Network} objects.

  """
  FREE = bitarray("0")
  RESERVED = bitarray("1")

  def __init__(self, network):
    """Initialize a new IPv4 address pool from an L{objects.Network} object.

    @type network: L{objects.Network}
    @param network: the network object from which the pool will be generated

    """
    self.network = None
    self.gateway = None
    self.network6 = None
    self.gateway6 = None

    self.net = network

    self.network = ipaddr.IPNetwork(self.net.network)
    if self.net.gateway:
      self.gateway = ipaddr.IPAddress(self.net.gateway)

    if self.net.network6:
      self.network6 = ipaddr.IPv6Network(self.net.network6)
    if self.net.gateway6:
      self.gateway6 = ipaddr.IPv6Address(self.net.gateway6)

    if self.net.reservations:
      self.reservations = bitarray(self.net.reservations)
    else:
      self.reservations = bitarray(self.network.numhosts)
      # pylint: disable=E1103
      self.reservations.setall(False)

    if self.net.ext_reservations:
      self.ext_reservations = bitarray(self.net.ext_reservations)
    else:
      self.ext_reservations = bitarray(self.network.numhosts)
      # pylint: disable=E1103
      self.ext_reservations.setall(False)

    assert len(self.reservations) == self.network.numhosts
    assert len(self.ext_reservations) == self.network.numhosts

  def Contains(self, address):
    if address is None:
      return False
    addr = ipaddr.IPAddress(address)

    return addr in self.network

  def _GetAddrIndex(self, address):
    addr = ipaddr.IPAddress(address)

    if not addr in self.network:
      raise errors.AddressPoolError("%s does not contain %s" %
                                    (self.network, addr))

    return int(addr) - int(self.network.network)

  def Update(self):
    """Write address pools back to the network object.

    """
    # pylint: disable=E1103
    self.net.ext_reservations = self.ext_reservations.to01()
    self.net.reservations = self.reservations.to01()

  def _Mark(self, address, value=True, external=False):
    idx = self._GetAddrIndex(address)
    if external:
      self.ext_reservations[idx] = value
    else:
      self.reservations[idx] = value
    self.Update()

  def _GetSize(self):
    return 2 ** (32 - self.network.prefixlen)

  @property
  def all_reservations(self):
    """Return a combined map of internal and external reservations.

    """
    return (self.reservations | self.ext_reservations)

  def Validate(self):
    assert len(self.reservations) == self._GetSize()
    assert len(self.ext_reservations) == self._GetSize()
    all_res = self.reservations & self.ext_reservations
    assert not all_res.any()

    if self.gateway is not None:
      assert self.gateway in self.network

    if self.network6 and self.gateway6:
      assert self.gateway6 in self.network6

    return True

  def IsFull(self):
    """Check whether the network is full.

    """
    return self.all_reservations.all()

  def GetReservedCount(self):
    """Get the count of reserved addresses.

    """
    return self.all_reservations.count(True)

  def GetFreeCount(self):
    """Get the count of unused addresses.

    """
    return self.all_reservations.count(False)

  def GetMap(self):
    """Return a textual representation of the network's occupation status.

    """
    return self.all_reservations.to01().replace("1", "X").replace("0", ".")

  def IsReserved(self, address):
    """Checks if the given IP is reserved.

    """
    idx = self._GetAddrIndex(address)
    return self.all_reservations[idx]

  def Reserve(self, address, external=False):
    """Mark an address as used.

    """
    if self.IsReserved(address):
      raise errors.AddressPoolError("%s is already reserved" % address)
    self._Mark(address, external=external)

  def Release(self, address, external=False):
    """Release a given address reservation.

    """
    self._Mark(address, value=False, external=external)

  def GetFreeAddress(self):
    """Returns the first available address.

    """
    if self.IsFull():
      raise errors.AddressPoolError("%s is full" % self.network)

    idx = self.all_reservations.index(False)
    address = str(self.network[idx])
    self.Reserve(address)
    return address

  def GenerateFree(self):
    """Returns the first free address of the network.

    @raise errors.AddressPoolError: Pool is full

    """
    idx = self.all_reservations.search(self.FREE, 1)
    if idx:
      return str(self.network[idx[0]])
    else:
      raise errors.AddressPoolError("%s is full" % self.network)

  def GetExternalReservations(self):
    """Returns a list of all externally reserved addresses.

    """
    # pylint: disable=E1103
    idxs = self.ext_reservations.search(self.RESERVED)
    return [str(self.network[idx]) for idx in idxs]

  @classmethod
  def InitializeNetwork(cls, net):
    """Initialize an L{objects.Network} object.

    Reserve the network, broadcast and gateway IP addresses.

    """
    obj = cls(net)
    obj.Update()
    for ip in [obj.network[0], obj.network[-1]]:
      obj.Reserve(ip, external=True)
    if obj.net.gateway is not None:
      obj.Reserve(obj.net.gateway, external=True)
    obj.Validate()
    return obj
<commit_msg>Check minimum size of networks on creation<commit_after>#
#

# Copyright (C) 2011, 2012 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.

"""IP address pool management functions.

"""

import ipaddr

from bitarray import bitarray

from ganeti import errors

IPV4_NETWORK_MIN_SIZE = 30
IPV4_NETWORK_MIN_NUM_HOSTS = 2 ** (32 - IPV4_NETWORK_MIN_SIZE)

class AddressPool(object):
  """Address pool class, wrapping an C{objects.Network} object.

  This class provides methods to manipulate address pools, backed by
  L{objects.Network} objects.

  """
  FREE = bitarray("0")
  RESERVED = bitarray("1")

  def __init__(self, network):
    """Initialize a new IPv4 address pool from an L{objects.Network} object.

    @type network: L{objects.Network}
    @param network: the network object from which the pool will be generated

    """
    self.network = None
    self.gateway = None
    self.network6 = None
    self.gateway6 = None

    self.net = network

    self.network = ipaddr.IPNetwork(self.net.network)
    if self.network.numhosts < IPV4_NETWORK_MIN_NUM_HOSTS:
      raise errors.AddressPoolError("A network with only %s host(s) is too"
                                    " small, please specify at least a /%s"
                                    " network" %
                                    (str(self.network.numhosts),
                                     IPV4_NETWORK_MIN_SIZE))
    if self.net.gateway:
      self.gateway = ipaddr.IPAddress(self.net.gateway)

    if self.net.network6:
      self.network6 = ipaddr.IPv6Network(self.net.network6)
    if self.net.gateway6:
      self.gateway6 = ipaddr.IPv6Address(self.net.gateway6)

    if self.net.reservations:
      self.reservations = bitarray(self.net.reservations)
    else:
      self.reservations = bitarray(self.network.numhosts)
      # pylint: disable=E1103
      self.reservations.setall(False)

    if self.net.ext_reservations:
      self.ext_reservations = bitarray(self.net.ext_reservations)
    else:
      self.ext_reservations = bitarray(self.network.numhosts)
      # pylint: disable=E1103
      self.ext_reservations.setall(False)

    assert len(self.reservations) == self.network.numhosts
    assert len(self.ext_reservations) == self.network.numhosts

  def Contains(self, address):
    if address is None:
      return False
    addr = ipaddr.IPAddress(address)

    return addr in self.network

  def _GetAddrIndex(self, address):
    addr = ipaddr.IPAddress(address)

    if not addr in self.network:
      raise errors.AddressPoolError("%s does not contain %s" %
                                    (self.network, addr))

    return int(addr) - int(self.network.network)

  def Update(self):
    """Write address pools back to the network object.

    """
    # pylint: disable=E1103
    self.net.ext_reservations = self.ext_reservations.to01()
    self.net.reservations = self.reservations.to01()

  def _Mark(self, address, value=True, external=False):
    idx = self._GetAddrIndex(address)
    if external:
      self.ext_reservations[idx] = value
    else:
      self.reservations[idx] = value
    self.Update()

  def _GetSize(self):
    return 2 ** (32 - self.network.prefixlen)

  @property
  def all_reservations(self):
    """Return a combined map of internal and external reservations.

    """
    return (self.reservations | self.ext_reservations)

  def Validate(self):
    assert len(self.reservations) == self._GetSize()
    assert len(self.ext_reservations) == self._GetSize()
    all_res = self.reservations & self.ext_reservations
    assert not all_res.any()

    if self.gateway is not None:
      assert self.gateway in self.network

    if self.network6 and self.gateway6:
      assert self.gateway6 in self.network6

    return True

  def IsFull(self):
    """Check whether the network is full.

    """
    return self.all_reservations.all()

  def GetReservedCount(self):
    """Get the count of reserved addresses.

    """
    return self.all_reservations.count(True)

  def GetFreeCount(self):
    """Get the count of unused addresses.

    """
    return self.all_reservations.count(False)

  def GetMap(self):
    """Return a textual representation of the network's occupation status.

    """
    return self.all_reservations.to01().replace("1", "X").replace("0", ".")

  def IsReserved(self, address):
    """Checks if the given IP is reserved.

    """
    idx = self._GetAddrIndex(address)
    return self.all_reservations[idx]

  def Reserve(self, address, external=False):
    """Mark an address as used.

    """
    if self.IsReserved(address):
      raise errors.AddressPoolError("%s is already reserved" % address)
    self._Mark(address, external=external)

  def Release(self, address, external=False):
    """Release a given address reservation.

    """
    self._Mark(address, value=False, external=external)

  def GetFreeAddress(self):
    """Returns the first available address.

    """
    if self.IsFull():
      raise errors.AddressPoolError("%s is full" % self.network)

    idx = self.all_reservations.index(False)
    address = str(self.network[idx])
    self.Reserve(address)
    return address

  def GenerateFree(self):
    """Returns the first free address of the network.

    @raise errors.AddressPoolError: Pool is full

    """
    idx = self.all_reservations.search(self.FREE, 1)
    if idx:
      return str(self.network[idx[0]])
    else:
      raise errors.AddressPoolError("%s is full" % self.network)

  def GetExternalReservations(self):
    """Returns a list of all externally reserved addresses.

    """
    # pylint: disable=E1103
    idxs = self.ext_reservations.search(self.RESERVED)
    return [str(self.network[idx]) for idx in idxs]

  @classmethod
  def InitializeNetwork(cls, net):
    """Initialize an L{objects.Network} object.

    Reserve the network, broadcast and gateway IP addresses.

    """
    obj = cls(net)
    obj.Update()
    for ip in [obj.network[0], obj.network[-1]]:
      obj.Reserve(ip, external=True)
    if obj.net.gateway is not None:
      obj.Reserve(obj.net.gateway, external=True)
    obj.Validate()
    return obj
<|endoftext|>