<commit_before>from StringIO import StringIO
from ben10.foundation.hash import DumpDirHashToStringIO, GetRandomHash, IterHashes
import pytest

#===================================================================================================
# Test
#===================================================================================================
class Test:

    def testGetRandomHash(self):
        '''
        Tests that GetRandomHash gives a hexadecimal hash of the target length
        '''
        import re
        hash_ = GetRandomHash(length=10)
        assert re.match('[0-9a-f]{10}', hash_) is not None

    def testIterHashesGenerator(self):
        '''
        Tests that IterHashes returns a generator
        '''
        import types
        hashes = IterHashes(5)
        assert isinstance(hashes, types.GeneratorType) == True

    def testIterHashesLength(self):
        '''
        Tests that IterHashes has the given size
        '''
        assert len(list(IterHashes(5))) == 5

    def testIterHashesValues(self):
        '''
        Tests that IterHashes gives hexadecimal hashes of the target length
        '''
        import re
        for hash_ in IterHashes(5, hash_length=10):
            assert re.match('[0-9a-f]{10}', hash_) is not None

    def testIterHashesReceivesInteger(self):
        with pytest.raises(TypeError):
            list(IterHashes('50'))

    def testMd5Hash(self, embed_data):
        stringio = StringIO()
        DumpDirHashToStringIO(embed_data.GetDataDirectory(), stringio, 'bin')
        val = stringio.getvalue()
        assert (
            set(val.splitlines())
            == set([
                'bin/file1.txt=4124bc0a9335c27f086f24ba207a4912',
                'bin/file2.txt=633de4b0c14ca52ea2432a3c8a5c4c31'
            ])
        )

        stringio = StringIO()
        DumpDirHashToStringIO(embed_data.GetDataDirectory(), stringio, 'bin', exclude='*1.txt')
        val = stringio.getvalue()
        assert (
            set(val.splitlines())
            == set([
                'bin/file2.txt=633de4b0c14ca52ea2432a3c8a5c4c31'
            ])
        )

        stringio = StringIO()
        DumpDirHashToStringIO(embed_data.GetDataDirectory(), stringio, '', exclude='*1.txt')
        val = stringio.getvalue()
        assert (
            set(val.splitlines())
            == set([
                'file2.txt=633de4b0c14ca52ea2432a3c8a5c4c31'
            ])
        )

    def testMd5Hex(self):
        assert Md5Hex(contents='alpha, bravo') == '2c0d78abb6e32d1614a17c6d0e4391c0'
<commit_msg>Updated filesystem code from coilib50.<commit_after>from StringIO import StringIO
from ben10.foundation.hash import DumpDirHashToStringIO, GetRandomHash, IterHashes, Md5Hex
import pytest

#===================================================================================================
# Test
#===================================================================================================
class Test:

    def testGetRandomHash(self):
        '''
        Tests that GetRandomHash gives a hexadecimal hash of the target length
        '''
        import re
        hash_ = GetRandomHash(length=10)
        assert re.match('[0-9a-f]{10}', hash_) is not None

    def testIterHashesGenerator(self):
        '''
        Tests that IterHashes returns a generator
        '''
        import types
        hashes = IterHashes(5)
        assert isinstance(hashes, types.GeneratorType) == True

    def testIterHashesLength(self):
        '''
        Tests that IterHashes has the given size
        '''
        assert len(list(IterHashes(5))) == 5

    def testIterHashesValues(self):
        '''
        Tests that IterHashes gives hexadecimal hashes of the target length
        '''
        import re
        for hash_ in IterHashes(5, hash_length=10):
            assert re.match('[0-9a-f]{10}', hash_) is not None

    def testIterHashesReceivesInteger(self):
        with pytest.raises(TypeError):
            list(IterHashes('50'))

    def testMd5Hash(self, embed_data):
        stringio = StringIO()
        DumpDirHashToStringIO(embed_data.GetDataDirectory(), stringio, 'bin')
        val = stringio.getvalue()
        assert (
            set(val.splitlines())
            == {
                'bin/file1.txt=4124bc0a9335c27f086f24ba207a4912',
                'bin/file2.txt=633de4b0c14ca52ea2432a3c8a5c4c31',
            }
        )

        stringio = StringIO()
        DumpDirHashToStringIO(embed_data.GetDataDirectory(), stringio, 'bin', exclude='*1.txt')
        val = stringio.getvalue()
        assert (
            set(val.splitlines())
            == {
                'bin/file2.txt=633de4b0c14ca52ea2432a3c8a5c4c31',
            }
        )

        stringio = StringIO()
        DumpDirHashToStringIO(embed_data.GetDataDirectory(), stringio, '', exclude='*1.txt')
        val = stringio.getvalue()
        assert (
            set(val.splitlines())
            == {
                'file2.txt=633de4b0c14ca52ea2432a3c8a5c4c31',
            }
        )

    def testMd5Hex(self):
        assert Md5Hex(contents='alpha, bravo') == '2c0d78abb6e32d1614a17c6d0e4391c0'
<|endoftext|>


<commit_before># Copyright (c) 2007-2010 gocept gmbh & co. kg
# See also LICENSE.txt

from __future__ import with_statement
from zeit.cms.i18n import MessageFactory as _
import logging
import zeit.cms.checkout.interfaces
import zeit.cms.content.dav
import zeit.cms.content.interfaces
import zeit.cms.interfaces
import zeit.cms.relation.interfaces
import zeit.cms.syndication.interfaces
import zeit.cms.workflow.interfaces
import zeit.objectlog.interfaces
import zeit.workflow.interfaces
import zeit.workflow.timebased
import zope.component
import zope.event
import zope.interface
import zope.location.location

WORKFLOW_NS = zeit.workflow.interfaces.WORKFLOW_NS
logger = logging.getLogger(__name__)

class ContentWorkflow(zeit.workflow.timebased.TimeBasedWorkflow):
    """Adapt ICMSContent to IWorkflow using the "live" data from connector.

    We must read and write properties directly from the DAV to be sure we
    actually can do the transition.
    """

    zope.interface.implements(zeit.workflow.interfaces.IContentWorkflow)
    zope.component.adapts(zeit.cms.interfaces.IEditorialContent)

    zeit.cms.content.dav.mapProperties(
        zeit.workflow.interfaces.IContentWorkflow,
        WORKFLOW_NS,
        ('edited', 'corrected', 'refined', 'images_added', 'urgent'),
        live=True)

    def can_publish(self):
        if self.urgent:
            return True
        if all([self.edited, self.corrected, self.refined, self.images_added]):
            return True
        return False

@zope.component.adapter(
    zeit.workflow.interfaces.IContentWorkflow,
    zeit.cms.content.interfaces.IDAVPropertyChangedEvent)
def log_workflow_changes(workflow, event):
    if event.field.__name__ not in ('edited', 'corrected', 'refined',
                                    'images_added', 'urgent'):
        # Only act on certain fields.
        return

    content = workflow.context
    message = _('${name}: ${new_value}',
                mapping=dict(name=event.field.title,
                             old_value=event.old_value,
                             new_value=event.new_value))

    log = zope.component.getUtility(zeit.objectlog.interfaces.IObjectLog)
    log.log(content, message)

@zope.component.adapter(
    zeit.cms.interfaces.ICMSContent,
    zeit.cms.workflow.interfaces.IRetractedEvent)
def remove_from_channels_after_retract(context, event):
    """Removes objects from channels when they're retracted."""
    relations = zope.component.getUtility(
        zeit.cms.relation.interfaces.IRelations)
    syndicated_in = relations.get_relations(context)
    for feed in list(syndicated_in):
        # XXX we might want to store the kind of relation
        if not zeit.cms.syndication.interfaces.IFeed.providedBy(feed):
            continue
        with zeit.cms.checkout.helper.checked_out(feed) as checked_out:
            if checked_out is not None:
                try:
                    checked_out.remove(context)
                except ValueError:
                    # Was not in the feed, i.e. the index wasn't up to date.
                    # Ignore.
                    pass
<commit_msg>future import no longer required<commit_after># Copyright (c) 2007-2010 gocept gmbh & co. kg
# See also LICENSE.txt

from zeit.cms.i18n import MessageFactory as _
import logging
import zeit.cms.checkout.interfaces
import zeit.cms.content.dav
import zeit.cms.content.interfaces
import zeit.cms.interfaces
import zeit.cms.relation.interfaces
import zeit.cms.syndication.interfaces
import zeit.cms.workflow.interfaces
import zeit.objectlog.interfaces
import zeit.workflow.interfaces
import zeit.workflow.timebased
import zope.component
import zope.event
import zope.interface
import zope.location.location

WORKFLOW_NS = zeit.workflow.interfaces.WORKFLOW_NS
logger = logging.getLogger(__name__)

class ContentWorkflow(zeit.workflow.timebased.TimeBasedWorkflow):
    """Adapt ICMSContent to IWorkflow using the "live" data from connector.

    We must read and write properties directly from the DAV to be sure we
    actually can do the transition.
    """

    zope.interface.implements(zeit.workflow.interfaces.IContentWorkflow)
    zope.component.adapts(zeit.cms.interfaces.IEditorialContent)

    zeit.cms.content.dav.mapProperties(
        zeit.workflow.interfaces.IContentWorkflow,
        WORKFLOW_NS,
        ('edited', 'corrected', 'refined', 'images_added', 'urgent'),
        live=True)

    def can_publish(self):
        if self.urgent:
            return True
        if all([self.edited, self.corrected, self.refined, self.images_added]):
            return True
        return False

@zope.component.adapter(
    zeit.workflow.interfaces.IContentWorkflow,
    zeit.cms.content.interfaces.IDAVPropertyChangedEvent)
def log_workflow_changes(workflow, event):
    if event.field.__name__ not in ('edited', 'corrected', 'refined',
                                    'images_added', 'urgent'):
        # Only act on certain fields.
        return

    content = workflow.context
    message = _('${name}: ${new_value}',
                mapping=dict(name=event.field.title,
                             old_value=event.old_value,
                             new_value=event.new_value))

    log = zope.component.getUtility(zeit.objectlog.interfaces.IObjectLog)
    log.log(content, message)

@zope.component.adapter(
    zeit.cms.interfaces.ICMSContent,
    zeit.cms.workflow.interfaces.IRetractedEvent)
def remove_from_channels_after_retract(context, event):
    """Removes objects from channels when they're retracted."""
    relations = zope.component.getUtility(
        zeit.cms.relation.interfaces.IRelations)
    syndicated_in = relations.get_relations(context)
    for feed in list(syndicated_in):
        # XXX we might want to store the kind of relation
        if not zeit.cms.syndication.interfaces.IFeed.providedBy(feed):
            continue
        with zeit.cms.checkout.helper.checked_out(feed) as checked_out:
            if checked_out is not None:
                try:
                    checked_out.remove(context)
                except ValueError:
                    # Was not in the feed, i.e. the index wasn't up to date.
                    # Ignore.
                    pass
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

"""

ZUGBRUECKE
Calling routines in Windows DLLs from Python scripts running on unixlike systems
https://github.com/pleiszenburg/zugbruecke

	src/zugbruecke/core/config.py: Handles the modules configuration

	Required to run on platform / side: [UNIX]

	Copyright (C) 2017-2019 Sebastian M. Ernst <ernst@pleiszenburg.de>

<LICENSE_BLOCK>
The contents of this file are subject to the GNU Lesser General Public License
Version 2.1 ("LGPL" or "License"). You may not use this file except in
compliance with the License. You may obtain a copy of the License at
https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
https://github.com/pleiszenburg/zugbruecke/blob/master/LICENSE

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
specific language governing rights and limitations under the License.
</LICENSE_BLOCK>

"""

# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# IMPORT
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

import os
import json

from .const import CONFIG_FLD, CONFIG_FN
from .errors import config_parser_error
from .lib import generate_session_id

# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# CONFIGURATION CLASS
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

class config_class(dict):

	def __init__(self, **override_dict):

		# Call parent constructur, just in case
		super().__init__()

		# Create session id
		self['id'] = generate_session_id() # Generate unique session id

		# Get config from files as a prioritized list
		for config in self.__get_config_from_files__():
			self.update(config)

		# Add override parameters
		if len(override_dict) > 0:
			self.update(override_dict)

	def __getitem__(self, key):

		env_var = 'ZUGBRUECKE_{NAME:s}'.format(NAME = key.upper())
		if env_var in os.environ.keys():
			value = os.environ[env_var]
			if len(value) > 0:
				if value.isnumeric():
					return int(value)
				else:
					return value

		if key in self.keys():
			return super().__getitem__(key)

		if key == 'stdout':
			return True # Display messages from stdout
		elif key == 'stderr':
			return True # Display messages from stderr
		elif key == 'log_write':
			return False # Write log messages into file
		elif key == 'log_level':
			return 0 # Overall log level: No logs are generated by default
		elif key == 'arch':
			return 'win32' # Define Wine & Wine-Python architecture
		elif key == 'pythonversion':
			return '3.7.4' # Define Wine-Python version
		elif key == 'dir':
			return self.__get_default_config_directory__() # Default config directory
		elif key == 'timeout_start':
			return 30 # Timeout for waiting on Wine-Python start
		elif key == 'timeout_stop':
			return 30 # Timeout for waiting on Wine-Python stop
		elif key == 'winedebug':
			return '-all' # Wine debug output off
		elif key == 'wineprefix':
			return os.path.join(self['dir'], self['arch'] + '-wine')
		elif key == 'pythonprefix':
			return os.path.join(self['dir'], '%s-python%s' % (self['arch'], self['pythonversion']))
		elif key == '_issues_50_workaround':
			return False # Workaround for zugbruecke issue #50 (symlinks ...)
		else:
			raise KeyError('not a valid configuration key')

	def __get_default_config_directory__(self):

		return os.path.join(os.path.expanduser('~'), CONFIG_FLD)

	def __get_config_from_files__(self):

		# Look for config in the usual spots
		for fn in [
			'/etc/zugbruecke',
			os.path.join('/etc/zugbruecke', CONFIG_FN),
			os.path.join(self.__get_default_config_directory__(), CONFIG_FN),
			os.environ.get('ZUGBRUECKE'),
			os.path.join(os.environ.get('ZUGBRUECKE'), CONFIG_FN) if os.environ.get('ZUGBRUECKE') is not None else None,
			os.path.join(os.getcwd(), CONFIG_FN),
			]:

			cnt_dict = self.__load_config_from_file__(fn)

			if cnt_dict is not None:
				yield cnt_dict

	def __load_config_from_file__(self, try_path):

		# If there is a path ...
		if try_path is None:
			return

		# Is this a file?
		if not os.path.isfile(try_path):
			return

		# Read file
		try:
			with open(try_path, 'r', encoding = 'utf-8') as f:
				cnt = f.read()
		except:
			raise config_parser_error('Config file could not be read: "%s"' % try_path)

		# Try to parse it
		try:
			cnt_dict = json.loads(cnt)
		except:
			raise config_parser_error('Config file could not be parsed: "%s"' % try_path)

		# Ensure that config has the right format
		if not isinstance(cnt_dict, dict):
			raise config_parser_error('Config file is malformed: "%s"' % try_path)

		return cnt_dict
<commit_msg>config can fetch bools from environment<commit_after># -*- coding: utf-8 -*-

"""

ZUGBRUECKE
Calling routines in Windows DLLs from Python scripts running on unixlike systems
https://github.com/pleiszenburg/zugbruecke

	src/zugbruecke/core/config.py: Handles the modules configuration

	Required to run on platform / side: [UNIX]

	Copyright (C) 2017-2019 Sebastian M. Ernst <ernst@pleiszenburg.de>

<LICENSE_BLOCK>
The contents of this file are subject to the GNU Lesser General Public License
Version 2.1 ("LGPL" or "License"). You may not use this file except in
compliance with the License. You may obtain a copy of the License at
https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
https://github.com/pleiszenburg/zugbruecke/blob/master/LICENSE

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
specific language governing rights and limitations under the License.
</LICENSE_BLOCK>

"""

# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# IMPORT
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

import os
import json

from .const import CONFIG_FLD, CONFIG_FN
from .errors import config_parser_error
from .lib import generate_session_id

# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# CONFIGURATION CLASS
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

class config_class(dict):

	def __init__(self, **override_dict):

		# Call parent constructur, just in case
		super().__init__()

		# Create session id
		self['id'] = generate_session_id() # Generate unique session id

		# Get config from files as a prioritized list
		for config in self.__get_config_from_files__():
			self.update(config)

		# Add override parameters
		if len(override_dict) > 0:
			self.update(override_dict)

	def __getitem__(self, key):

		env_var = 'ZUGBRUECKE_{NAME:s}'.format(NAME = key.upper())
		if env_var in os.environ.keys():
			value = os.environ[env_var]
			if len(value) > 0:
				if value.isnumeric():
					return int(value)
				elif value.strip().lower() in ('true', 'false'):
					return {'true': True, 'false': False}[value.strip().lower()]
				else:
					return value

		if key in self.keys():
			return super().__getitem__(key)

		if key == 'stdout':
			return True # Display messages from stdout
		elif key == 'stderr':
			return True # Display messages from stderr
		elif key == 'log_write':
			return False # Write log messages into file
		elif key == 'log_level':
			return 0 # Overall log level: No logs are generated by default
		elif key == 'arch':
			return 'win32' # Define Wine & Wine-Python architecture
		elif key == 'pythonversion':
			return '3.7.4' # Define Wine-Python version
		elif key == 'dir':
			return self.__get_default_config_directory__() # Default config directory
		elif key == 'timeout_start':
			return 30 # Timeout for waiting on Wine-Python start
		elif key == 'timeout_stop':
			return 30 # Timeout for waiting on Wine-Python stop
		elif key == 'winedebug':
			return '-all' # Wine debug output off
		elif key == 'wineprefix':
			return os.path.join(self['dir'], self['arch'] + '-wine')
		elif key == 'pythonprefix':
			return os.path.join(self['dir'], '%s-python%s' % (self['arch'], self['pythonversion']))
		elif key == '_issues_50_workaround':
			return False # Workaround for zugbruecke issue #50 (symlinks ...)
		else:
			raise KeyError('not a valid configuration key')

	def __get_default_config_directory__(self):

		return os.path.join(os.path.expanduser('~'), CONFIG_FLD)

	def __get_config_from_files__(self):

		# Look for config in the usual spots
		for fn in [
			'/etc/zugbruecke',
			os.path.join('/etc/zugbruecke', CONFIG_FN),
			os.path.join(self.__get_default_config_directory__(), CONFIG_FN),
			os.environ.get('ZUGBRUECKE'),
			os.path.join(os.environ.get('ZUGBRUECKE'), CONFIG_FN) if os.environ.get('ZUGBRUECKE') is not None else None,
			os.path.join(os.getcwd(), CONFIG_FN),
			]:

			cnt_dict = self.__load_config_from_file__(fn)

			if cnt_dict is not None:
				yield cnt_dict

	def __load_config_from_file__(self, try_path):

		# If there is a path ...
		if try_path is None:
			return

		# Is this a file?
		if not os.path.isfile(try_path):
			return

		# Read file
		try:
			with open(try_path, 'r', encoding = 'utf-8') as f:
				cnt = f.read()
		except:
			raise config_parser_error('Config file could not be read: "%s"' % try_path)

		# Try to parse it
		try:
			cnt_dict = json.loads(cnt)
		except:
			raise config_parser_error('Config file could not be parsed: "%s"' % try_path)

		# Ensure that config has the right format
		if not isinstance(cnt_dict, dict):
			raise config_parser_error('Config file is malformed: "%s"' % try_path)

		return cnt_dict
<|endoftext|>


<commit_before># coding=utf-8

import io
import logging
import math
import re
import time

import rarfile

from bs4 import BeautifulSoup
from zipfile import ZipFile, is_zipfile
from rarfile import RarFile, is_rarfile
from babelfish import language_converters, Script
from requests import RequestException
from guessit import guessit
from subliminal_patch.http import RetryingCFSession
from subliminal_patch.providers import Provider
from subliminal_patch.providers.mixins import ProviderSubtitleArchiveMixin
from subliminal_patch.subtitle import Subtitle
from subliminal_patch.utils import sanitize, fix_inconsistent_naming as _fix_inconsistent_naming
from subliminal.exceptions import ProviderError
from subliminal.score import get_equivalent_release_groups
from subliminal.utils import sanitize_release_group
from subliminal.subtitle import guess_matches
from subliminal.video import Episode, Movie
from subliminal.subtitle import fix_line_ending
from subliminal_patch.pitcher import pitchers, load_verification, store_verification
from subzero.language import Language

from random import randint
from .utils import FIRST_THOUSAND_OR_SO_USER_AGENTS as AGENT_LIST

# parsing regex definitions
title_re = re.compile(r'(?P<title>(?:.+(?= [Aa][Kk][Aa] ))|.+)(?:(?:.+)(?P<altitle>(?<= [Aa][Kk][Aa] ).+))?')
lang_re = re.compile(r'(?<=flags/)(?P<lang>.{2})(?:.)(?P<script>c?)(?:.+)')
season_re = re.compile(r'Sezona (?P<season>\d+)')
episode_re = re.compile(r'Epizoda (?P<episode>\d+)')
year_re = re.compile(r'(?P<year>\d+)')
fps_re = re.compile(r'fps: (?P<fps>.+)')

def fix_inconsistent_naming(title):
    """Fix titles with inconsistent naming using dictionary and sanitize them.

    :param str title: original title.
    :return: new title.
    :rtype: str

    """
    return _fix_inconsistent_naming(title, {"DC's Legends of Tomorrow": "Legends of Tomorrow",
                                            "Marvel's Jessica Jones": "Jessica Jones"})

logger = logging.getLogger(__name__)

# Configure :mod:`rarfile` to use the same path separator as :mod:`zipfile`
rarfile.PATH_SEP = '/'

language_converters.register('titlovi = subliminal_patch.converters.titlovi:TitloviConverter')

class TitloviSubtitle(Subtitle):
    provider_name = 'titlovi'

    def __init__(self, language, page_link, download_link, sid, releases, title, alt_title=None, season=None,
                 episode=None, year=None, fps=None, asked_for_release_group=None, asked_for_episode=None):
        super(TitloviSubtitle, self).__init__(language, page_link=page_link)
        self.sid = sid
        self.releases = self.release_info = releases
        self.title = title
        self.alt_title = alt_title
        self.season = season
        self.episode = episode
        self.year = year
        self.download_link = download_link
        self.fps = fps
        self.matches = None
        self.asked_for_release_group = asked_for_release_group
        self.asked_for_episode = asked_for_episode

    @property
    def id(self):
        return self.sid

    def get_matches(self, video):
        matches = set()

        # handle movies and series separately
        if isinstance(video, Episode):
            # series
            if video.series and sanitize(self.title) == fix_inconsistent_naming(video.series) or sanitize(
                    self.alt_title) == fix_inconsistent_naming(video.series):
                matches.add('series')
            # year
            if video.original_series and self.year is None or video.year and video.year == self.year:
                matches.add('year')
            # season
            if video.season and self.season == video.season:
                matches.add('season')
            # episode
            if video.episode and self.episode == video.episode:
                matches.add('episode')
        # movie
        elif isinstance(video, Movie):
            # title
            if video.title and sanitize(self.title) == fix_inconsistent_naming(video.title) or sanitize(
                    self.alt_title) == fix_inconsistent_naming(video.title):
                matches.add('title')
            # year
            if video.year and self.year == video.year:
                matches.add('year')

        # rest is same for both groups

        # release_group
        if (video.release_group and self.releases and
                any(r in sanitize_release_group(self.releases)
                    for r in get_equivalent_release_groups(sanitize_release_group(video.release_group)))):
            matches.add('release_group')
        # resolution
        if video.resolution and self.releases and video.resolution in self.releases.lower():
            matches.add('resolution')
        # format
        if video.format and self.releases and video.format.lower() in self.releases.lower():
            matches.add('format')
        # other properties
        matches |= guess_matches(video, guessit(self.releases))

        self.matches = matches

        return matches

class TitloviProvider(Provider, ProviderSubtitleArchiveMixin):
    subtitle_class = TitloviSubtitle
    languages = {Language.fromtitlovi(l) for l in language_converters['titlovi'].codes} | {Language.fromietf('sr-Latn')}
    server_url = 'https://titlovi.com'
    search_url = server_url + '/titlovi/?'
    download_url = server_url + '/download/?type=1&mediaid='

    def initialize(self):
        self.session = RetryingCFSession()
        #load_verification("titlovi", self.session)

    def terminate(self):
        self.session.close()

    def query(self, languages, title, season=None, episode=None, year=None, video=None):
        items_per_page = 10
        current_page = 1

        used_languages = languages
        lang_strings = [str(lang) for lang in used_languages]

        # handle possible duplicate use of Serbian Latin
        if "sr" in lang_strings and "sr-Latn" in lang_strings:
            logger.info('Duplicate entries <Language [sr]> and <Language [sr-Latn]> found, filtering languages')
            used_languages = filter(lambda l: l != Language.fromietf('sr-Latn'), used_languages)
            logger.info('Filtered language list %r', used_languages)

        # convert list of languages into search string
        langs = '|'.join(map(str, [l.titlovi for l in used_languages]))

        # set query params
        params = {'prijevod': title, 'jezik': langs}
        is_episode = False
        if season and episode:
            is_episode = True
            params['s'] = season
            params['e'] = episode
        if year:
            params['g'] = year

        # loop through paginated results
        logger.info('Searching subtitles %r', params)
        subtitles = []

        while True:
            # query the server
            try:
                r = self.session.get(self.search_url, params=params, timeout=10)
                r.raise_for_status()
            except RequestException as e:
                logger.exception('RequestException %s', e)
                break
            else:
                try:
                    soup = BeautifulSoup(r.content, 'lxml')

                    # number of results
                    result_count = int(soup.select_one('.results_count b').string)
                except:
                    result_count = None

                # exit if no results
                if not result_count:
                    if not subtitles:
                        logger.debug('No subtitles found')
                    else:
                        logger.debug("No more subtitles found")
                    break

                # number of pages with results
                pages = int(math.ceil(result_count / float(items_per_page)))

                # get current page
                if 'pg' in params:
                    current_page = int(params['pg'])

                try:
                    sublist = soup.select('section.titlovi > ul.titlovi > li.subtitleContainer.canEdit')
                    for sub in sublist:
                        # subtitle id
                        sid = sub.find(attrs={'data-id': True}).attrs['data-id']
                        # get download link
                        download_link = self.download_url + sid
                        # title and alternate title
                        match = title_re.search(sub.a.string)
                        if match:
                            _title = match.group('title')
                            alt_title = match.group('altitle')
                        else:
                            continue

                        # page link
                        page_link = self.server_url + sub.a.attrs['href']
                        # subtitle language
                        _lang = sub.select_one('.lang')
                        match = lang_re.search(_lang.attrs.get('src', _lang.attrs.get('cfsrc', '')))
                        if match:
                            try:
                                # decode language
                                lang = Language.fromtitlovi(match.group('lang')+match.group('script'))
                            except ValueError:
                                continue

                        # relase year or series start year
                        match = year_re.search(sub.find(attrs={'data-id': True}).parent.i.string)
                        if match:
                            r_year = int(match.group('year'))
                        # fps
                        match = fps_re.search(sub.select_one('.fps').string)
                        if match:
                            fps = match.group('fps')
                        # releases
                        releases = str(sub.select_one('.fps').parent.contents[0].string)

                        # handle movies and series separately
                        if is_episode:
                            # season and episode info
                            sxe = sub.select_one('.s0xe0y').string
                            r_season = None
                            r_episode = None
                            if sxe:
                                match = season_re.search(sxe)
                                if match:
                                    r_season = int(match.group('season'))
                                match = episode_re.search(sxe)
                                if match:
                                    r_episode = int(match.group('episode'))

                            subtitle = self.subtitle_class(lang, page_link, download_link, sid, releases, _title,
                                                           alt_title=alt_title, season=r_season, episode=r_episode,
                                                           year=r_year, fps=fps,
                                                           asked_for_release_group=video.release_group,
                                                           asked_for_episode=episode)
                        else:
                            subtitle = self.subtitle_class(lang, page_link, download_link, sid, releases, _title,
                                                           alt_title=alt_title, year=r_year, fps=fps,
                                                           asked_for_release_group=video.release_group)
                        logger.debug('Found subtitle %r', subtitle)

                        # prime our matches so we can use the values later
                        subtitle.get_matches(video)

                        # add found subtitles
                        subtitles.append(subtitle)

                finally:
                    soup.decompose()

                # stop on last page
                if current_page >= pages:
                    break

                # increment current page
                params['pg'] = current_page + 1
                logger.debug('Getting page %d', params['pg'])

        return subtitles

    def list_subtitles(self, video, languages):
        season = episode = None
        if isinstance(video, Episode):
            title = video.series
            season = video.season
            episode = video.episode
        else:
            title = video.title

        return [s for s in
                self.query(languages, fix_inconsistent_naming(title), season=season, episode=episode, year=video.year,
                           video=video)]

    def download_subtitle(self, subtitle):
        r = self.session.get(subtitle.download_link, timeout=10)
        r.raise_for_status()

        # open the archive
        archive_stream = io.BytesIO(r.content)
        if is_rarfile(archive_stream):
            logger.debug('Archive identified as rar')
            archive = RarFile(archive_stream)
        elif is_zipfile(archive_stream):
            logger.debug('Archive identified as zip')
            archive = ZipFile(archive_stream)
        else:
            subtitle.content = r.content
            if subtitle.is_valid():
                return
            subtitle.content = None

            raise ProviderError('Unidentified archive type')

        subs_in_archive = archive.namelist()

        # if Serbian lat and cyr versions are packed together, try to find right version
        if len(subs_in_archive) > 1 and (subtitle.language == 'sr' or subtitle.language == 'sr-Cyrl'):
            self.get_subtitle_from_bundled_archive(subtitle, subs_in_archive, archive)
        else:
            # use default method for everything else
            subtitle.content = self.get_subtitle_from_archive(subtitle, archive)

    def get_subtitle_from_bundled_archive(self, subtitle, subs_in_archive, archive):
        sr_lat_subs = []
        sr_cyr_subs = []
        sub_to_extract = None

        for sub_name in subs_in_archive:
            if not ('.cyr' in sub_name or '.cir' in sub_name):
                sr_lat_subs.append(sub_name)

            if ('.cyr' in sub_name or '.cir' in sub_name) and not '.lat' in sub_name:
                sr_cyr_subs.append(sub_name)

        if subtitle.language == 'sr':
            if len(sr_lat_subs) > 0:
                sub_to_extract = sr_lat_subs[0]

        if subtitle.language == 'sr-Cyrl':
            if len(sr_cyr_subs) > 0:
                sub_to_extract = sr_cyr_subs[0]

        logger.info(u'Using %s from the archive', sub_to_extract)
        subtitle.content = fix_line_ending(archive.read(sub_to_extract))
<commit_msg>providers: titlovi: fix matching<commit_after># coding=utf-8

import io
import logging
import math
import re
import time

import rarfile

from bs4 import BeautifulSoup
from zipfile import ZipFile, is_zipfile
from rarfile import RarFile, is_rarfile
from babelfish import language_converters, Script
from requests import RequestException
from guessit import guessit
from subliminal_patch.http import RetryingCFSession
from subliminal_patch.providers import Provider
from subliminal_patch.providers.mixins import ProviderSubtitleArchiveMixin
from subliminal_patch.subtitle import Subtitle
from subliminal_patch.utils import sanitize, fix_inconsistent_naming as _fix_inconsistent_naming
from subliminal.exceptions import ProviderError
from subliminal.score import get_equivalent_release_groups
from subliminal.utils import sanitize_release_group
from subliminal.subtitle import guess_matches
from subliminal.video import Episode, Movie
from subliminal.subtitle import fix_line_ending
from subliminal_patch.pitcher import pitchers, load_verification, store_verification
from subzero.language import Language

from random import randint
from .utils import FIRST_THOUSAND_OR_SO_USER_AGENTS as AGENT_LIST

# parsing regex definitions
title_re = re.compile(r'(?P<title>(?:.+(?= [Aa][Kk][Aa] ))|.+)(?:(?:.+)(?P<altitle>(?<= [Aa][Kk][Aa] ).+))?')
lang_re = re.compile(r'(?<=flags/)(?P<lang>.{2})(?:.)(?P<script>c?)(?:.+)')
season_re = re.compile(r'Sezona (?P<season>\d+)')
episode_re = re.compile(r'Epizoda (?P<episode>\d+)')
year_re = re.compile(r'(?P<year>\d+)')
fps_re = re.compile(r'fps: (?P<fps>.+)')

def fix_inconsistent_naming(title):
    """Fix titles with inconsistent naming using dictionary and sanitize them.

    :param str title: original title.
    :return: new title.
    :rtype: str

    """
    return _fix_inconsistent_naming(title, {"DC's Legends of Tomorrow": "Legends of Tomorrow",
                                            "Marvel's Jessica Jones": "Jessica Jones"})

logger = logging.getLogger(__name__)

# Configure :mod:`rarfile` to use the same path separator as :mod:`zipfile`
rarfile.PATH_SEP = '/'

language_converters.register('titlovi = subliminal_patch.converters.titlovi:TitloviConverter')

class TitloviSubtitle(Subtitle):
    provider_name = 'titlovi'

    def __init__(self, language, page_link, download_link, sid, releases, title, alt_title=None, season=None,
                 episode=None, year=None, fps=None, asked_for_release_group=None, asked_for_episode=None):
        super(TitloviSubtitle, self).__init__(language, page_link=page_link)
        self.sid = sid
        self.releases = self.release_info = releases
        self.title = title
        self.alt_title = alt_title
        self.season = season
        self.episode = episode
        self.year = year
        self.download_link = download_link
        self.fps = fps
        self.matches = None
        self.asked_for_release_group = asked_for_release_group
        self.asked_for_episode = asked_for_episode

    @property
    def id(self):
        return self.sid

    def get_matches(self, video):
        matches = set()

        # handle movies and series separately
        if isinstance(video, Episode):
            # series
            if video.series and sanitize(self.title) == fix_inconsistent_naming(video.series) or sanitize(
                    self.alt_title) == fix_inconsistent_naming(video.series):
                matches.add('series')
            # year
            if video.original_series and self.year is None or video.year and video.year == self.year:
                matches.add('year')
            # season
            if video.season and self.season == video.season:
                matches.add('season')
            # episode
            if video.episode and self.episode == video.episode:
                matches.add('episode')
        # movie
        elif isinstance(video, Movie):
            # title
            if video.title and sanitize(self.title) == fix_inconsistent_naming(video.title) or sanitize(
                    self.alt_title) == fix_inconsistent_naming(video.title):
                matches.add('title')
            # year
            if video.year and self.year == video.year:
                matches.add('year')

        # rest is same for both groups

        # release_group
        if (video.release_group and self.releases and
                any(r in sanitize_release_group(self.releases)
                    for r in get_equivalent_release_groups(sanitize_release_group(video.release_group)))):
            matches.add('release_group')
        # resolution
        if video.resolution and self.releases and video.resolution in self.releases.lower():
            matches.add('resolution')
        # format
        if video.format and self.releases and video.format.lower() in self.releases.lower():
            matches.add('format')
        # other properties
        matches |= guess_matches(video, guessit(self.releases))

        self.matches = matches

        return matches

class TitloviProvider(Provider, ProviderSubtitleArchiveMixin):
    subtitle_class = TitloviSubtitle
    languages = {Language.fromtitlovi(l) for l in language_converters['titlovi'].codes} | {Language.fromietf('sr-Latn')}
    server_url = 'https://titlovi.com'
    search_url = server_url + '/titlovi/?'
    download_url = server_url + '/download/?type=1&mediaid='

    def initialize(self):
        self.session = RetryingCFSession()
        #load_verification("titlovi", self.session)

    def terminate(self):
        self.session.close()

    def query(self, languages, title, season=None, episode=None, year=None, video=None):
        items_per_page = 10
        current_page = 1

        used_languages = languages
        lang_strings = [str(lang) for lang in used_languages]

        # handle possible duplicate use of Serbian Latin
        if "sr" in lang_strings and "sr-Latn" in lang_strings:
            logger.info('Duplicate entries <Language [sr]> and <Language [sr-Latn]> found, filtering languages')
            used_languages = filter(lambda l: l != Language.fromietf('sr-Latn'), used_languages)
            logger.info('Filtered language list %r', used_languages)

        # convert list of languages into search string
        langs = '|'.join(map(str, [l.titlovi for l in used_languages]))

        # set query params
        params = {'prijevod': title, 'jezik': langs}
        is_episode = False
        if season and episode:
            is_episode = True
            params['s'] = season
            params['e'] = episode
        if year:
            params['g'] = year

        # loop through paginated results
        logger.info('Searching subtitles %r', params)
        subtitles = []

        while True:
            # query the server
            try:
                r = self.session.get(self.search_url, params=params, timeout=10)
                r.raise_for_status()
            except RequestException as e:
                logger.exception('RequestException %s', e)
                break
            else:
                try:
                    soup = BeautifulSoup(r.content, 'lxml')

                    # number of results
                    result_count = int(soup.select_one('.results_count b').string)
                except:
                    result_count = None

                # exit if no results
                if not result_count:
                    if not subtitles:
                        logger.debug('No subtitles found')
                    else:
                        logger.debug("No more subtitles found")
                    break

                # number of pages with results
                pages = int(math.ceil(result_count / float(items_per_page)))

                # get current page
                if 'pg' in params:
                    current_page = int(params['pg'])

                try:
                    sublist = soup.select('section.titlovi > ul.titlovi > li.subtitleContainer.canEdit')
                    for sub in sublist:
                        # subtitle id
                        sid = sub.find(attrs={'data-id': True}).attrs['data-id']
                        # get download link
                        download_link = self.download_url + sid
                        # title and alternate title
                        match = title_re.search(sub.a.string)
                        if match:
                            _title = match.group('title')
                            alt_title = match.group('altitle')
                        else:
                            continue

                        # page link
                        page_link = self.server_url + sub.a.attrs['href']
                        # subtitle language
                        _lang = sub.select_one('.lang')
                        match = lang_re.search(_lang.attrs.get('src', _lang.attrs.get('data-cfsrc', '')))
                        if match:
                            try:
                                # decode language
                                lang = Language.fromtitlovi(match.group('lang')+match.group('script'))
                            except ValueError:
                                continue

                        # relase year or series start year
                        match = year_re.search(sub.find(attrs={'data-id': True}).parent.i.string)
                        if match:
                            r_year = int(match.group('year'))
                        # fps
                        match = fps_re.search(sub.select_one('.fps').string)
                        if match:
                            fps = match.group('fps')
                        # releases
                        releases = str(sub.select_one('.fps').parent.contents[0].string)

                        # handle movies and series separately
                        if is_episode:
                            # season and episode info
                            sxe = sub.select_one('.s0xe0y').string
                            r_season = None
                            r_episode = None
                            if sxe:
                                match = season_re.search(sxe)
                                if match:
                                    r_season = int(match.group('season'))
                                match = episode_re.search(sxe)
                                if match:
                                    r_episode = int(match.group('episode'))

                            subtitle = self.subtitle_class(lang, page_link, download_link, sid, releases, _title,
                                                           alt_title=alt_title, season=r_season, episode=r_episode,
                                                           year=r_year, fps=fps,
                                                           asked_for_release_group=video.release_group,
                                                           asked_for_episode=episode)
                        else:
                            subtitle = self.subtitle_class(lang, page_link, download_link, sid, releases, _title,
                                                           alt_title=alt_title, year=r_year, fps=fps,
                                                           asked_for_release_group=video.release_group)
                        logger.debug('Found subtitle %r', subtitle)

                        # prime our matches so we can use the values later
                        subtitle.get_matches(video)

                        # add found subtitles
                        subtitles.append(subtitle)

                finally:
                    soup.decompose()

                # stop on last page
                if current_page >= pages:
                    break

                # increment current page
                params['pg'] = current_page + 1
                logger.debug('Getting page %d', params['pg'])

        return subtitles

    def list_subtitles(self, video, languages):
        season = episode = None
        if isinstance(video, Episode):
            title = video.series
            season = video.season
            episode = video.episode
        else:
            title = video.title

        return [s for s in
                self.query(languages, fix_inconsistent_naming(title), season=season, episode=episode, year=video.year,
                           video=video)]

    def download_subtitle(self, subtitle):
        r = self.session.get(subtitle.download_link, timeout=10)
        r.raise_for_status()

        # open the archive
        archive_stream = io.BytesIO(r.content)
        if is_rarfile(archive_stream):
            logger.debug('Archive identified as rar')
            archive = RarFile(archive_stream)
        elif is_zipfile(archive_stream):
            logger.debug('Archive identified as zip')
            archive = ZipFile(archive_stream)
        else:
            subtitle.content = r.content
            if subtitle.is_valid():
                return
            subtitle.content = None

            raise ProviderError('Unidentified archive type')

        subs_in_archive = archive.namelist()

        # if Serbian lat and cyr versions are packed together, try to find right version
        if len(subs_in_archive) > 1 and (subtitle.language == 'sr' or subtitle.language == 'sr-Cyrl'):
            self.get_subtitle_from_bundled_archive(subtitle, subs_in_archive, archive)
        else:
            # use default method for everything else
            subtitle.content = self.get_subtitle_from_archive(subtitle, archive)

    def get_subtitle_from_bundled_archive(self, subtitle, subs_in_archive, archive):
        sr_lat_subs = []
        sr_cyr_subs = []
        sub_to_extract = None

        for sub_name in subs_in_archive:
            if not ('.cyr' in sub_name or '.cir' in sub_name):
                sr_lat_subs.append(sub_name)

            if ('.cyr' in sub_name or '.cir' in sub_name) and not '.lat' in sub_name:
                sr_cyr_subs.append(sub_name)

        if subtitle.language == 'sr':
            if len(sr_lat_subs) > 0:
                sub_to_extract = sr_lat_subs[0]

        if subtitle.language == 'sr-Cyrl':
            if len(sr_cyr_subs) > 0:
                sub_to_extract = sr_cyr_subs[0]

        logger.info(u'Using %s from the archive', sub_to_extract)
        subtitle.content = fix_line_ending(archive.read(sub_to_extract))
<|endoftext|>


<commit_before>import sys
import struct
f = open("Foo.mspgangbin", 'rb')
data = f.read(1)
data_list = []
bin_list = []
while data:
    bin_val = int(ord(data))
    hex_val = "0x%0.2X" % bin_val
    bin_list.append(bin_val)
    data_list.append(hex_val)
    data = f.read(1)
bytes_ = []
count = -1
for i in range(len(bin_list)):
    if  i % 128 == 0:
        count = count + 1
        bytes_.append([])
        bytes_[count].append(hex(0x3E))
        bytes_[count].append(hex(0x43))
        bytes_[count].append(hex(128))
        bytes_[count].append(hex(128))
        if count % 2 == 0:
            bytes_[count].append(hex(0x00))
        else:
            bytes_[count].append(hex(0x80))
        bytes_[count].append(hex(count//2))
        bytes_[count].append(hex(0x00))
        bytes_[count].append(hex(0x00))
        bytes_[count].append(hex(122))
        bytes_[count].append(hex(0x00))

    bytes_[count].append(data_list[i])

for i in range(len(bytes_)):
    print str(i) + ": ("+str(len(bytes_[i]))+")" +  str(bytes_[i])
    print "\n\n"
<commit_msg>Removed bin.py.<commit_after><|endoftext|>


<commit_before>"""Implementing BST"""
# -*- coding: utf-8 -*-

class Node(object):
    """Creating class Node."""

    def __init__(self, data, right=None,left=None, parent=None):
        """Creating attributes upon initializion of class Node."""
        self.data = data
        self.right = right
        self.left = left
        self.parent = parent

class BST(object):
    """Creating class Binary Search Tree."""
    def __init__(self, data=None):
        if data is None:
            self.root = None
            return
        for item in data:
            self.insert(data)

    def insert(self, data=None, node=None):
        """Add nodes to the binary search tree in proper location."""
        new_node = Node(data)
        if self.root is None  #check node if none then empty
            self.root = new_node #if node then assign it
        if node is None:
            node = self.root
        if node.data > data:
            if node.left is None:
                node.left = new_node
            else:
                insert(data, node.left)
        if node.data < data:
            if node.right is None:
                node.right = new_node
            else:
                insert(data, node.right)

    def search(self, data=None, node=None):
        """Creating the search method."""
        search_found = Node(data)
        if self.root is None:
            return False
        else:
            if self.root == data
                return True
            elif self.root < data
                return search(data, node.right)
            else:
                return search(data, node.left)
<commit_msg>added contains.<commit_after>"""Implementing BST"""
# -*- coding: utf-8 -*-

from  collections import deque

class Node(object):
    """Creating class Node."""

    def __init__(self, data, right=None,left=None, parent=None):
        """Creating attributes upon initializion of class Node."""
        self.data = data
        self.right = right
        self.left = left
        self.parent = parent

class BST(object):
    """Creating class Binary Search Tree."""
    def __init__(self, data=None):
        if data is None:
            self.root = None
            return
        for item in data:
            self.insert(data)

    def insert(self, data=None, node=None):
        """Add nodes to the binary search tree in proper location."""
        new_node = Node(data)
        if self.root is None:  #check node if none then empty
            self.root = new_node #if node then assign it
        if node is None:
            node = self.root
        if node.data > data:
            if node.left is None:
                node.left = new_node
            else:
                self.insert(data, node.left)
        if node.data < data:
            if node.right is None:
                node.right = new_node
            else:
                self.insert(data, node.right)

    def search(self, data=None, node=None):
        """Creating the search method."""
        search_found = Node(data)
        if self.root is None:
            return None
        else:
            if self.root < data:
                return True
                self.root = search_found

     def contains(self, value):
        """Return True if value in tree."""
        if self.value == value:
            return True
        left.contains = False
        right.contains = False
        if self.left is not None:
            left.contains = self.left.contains(value)
        if self.right is not None:
            right.contains = self.right.contains(value)
        return left.contains or right.contains
<|endoftext|>


<commit_before>"""Python implementation of Binary Search Tree."""
from timeit import timeit

class BST():
    """Binary Search Tree."""

    def __init__(self, iterable=None):
        """Initialize Binary Search tree."""
        self._root = None
        self._length = 0
        self._rdepth = 0
        self._ldepth = 0
        self._depth = 0
        self._balance = 0
        if type(iterable) in [tuple, list]:
            for i in iterable:
                if type(i) in [int, float]:
                    self.insert(i)
                else:
                    raise TypeError('''
Try again with only numbers in your list or tuple.''')
        elif type(iterable) == int:
            self.insert(iterable)
        elif iterable is not None:
            raise TypeError('Try again with a list, tuple, int, or float.')

    def insert(self, val):
        """Insert new node into Binary Search Tree."""
        if type(val) not in [int, float]:
            raise TypeError('You can only add numbers to this tree.')
        curr = self._root
        depth = 0
        if curr is None:
            curr = Node(val)
            self._root = curr
            self._length += 1
            self._depth = 1
            return
        while True:
            if val == curr.val:
                return
            elif val < curr.val:
                if curr.left:
                    curr = curr.left
                    depth += 1
                else:
                    curr.left = Node(val)
                    curr.left.parent = curr
                    self._length += 1
                    if not curr.right:
                        depth += 1
                    elif curr == self._root:
                        depth += 1
                    if val < self._root.val:
                        if depth > self._ldepth:
                            self._ldepth = depth
                    else:
                        if depth > self._rdepth:
                            self._rdepth = depth
                    self._balance = self._rdepth - self._ldepth
                    self._depth = max([self._rdepth, self._ldepth]) + 1
                    return
            elif val > curr.val:
                if curr.right:
                    curr = curr.right
                    depth += 1
                else:
                    curr.right = Node(val)
                    curr.right.parent = curr
                    self._length += 1
                    if not curr.left:
                        depth += 1
                    elif curr == self._root:
                        depth += 1
                    if val < self._root.val:
                        if depth > self._ldepth:
                            self._ldepth = depth
                    else:
                        if depth > self._rdepth:
                            self._rdepth = depth
                    self._balance = self._rdepth - self._ldepth
                    self._depth = max([self._rdepth, self._ldepth]) + 1
                    return

    def delete(self, val):
        """Delete the node with value from the Binary Search Tree."""
        to_del = self.search(val)
        if to_del == self._root:
            self._root_shift(to_del, self._balance)
        elif to_del.left and to_del.right:
            sub_balance = self._sub_tree_bal(to_del)
            self._root_shift(to_del, sub_balance)
        elif to_del.left:
            if to_del.parent.left == to_del:
                to_del.parent.left = to_del.left
                to_del.left.parent = to_del.parent
            else:
                to_del.parent.right = to_del.left
                to_del.left.parent = to_del.parent
        elif to_del.right:
            if to_del.parent.left == to_del:
                to_del.parent.left = to_del.right
                to_del.right.parent = to_del.parent
            else:
                to_del.parent.right = to_del.right
                to_del.right.parent = to_del.parent
        else:
            self._del_leaf(to_del)
        self._length -= 1
        self._depth_and_bal(to_del)
        return

    def _sub_tree_bal(self, node):
        """Get the balance of a sub tree for deletion."""
        l_depth = 1
        r_depth = 1
        visited = []
        curr = node.left
        right_side = False
        while curr != node and not right_side:
            if curr.left and curr.right:
                if curr not in visited:
                    visited.append(curr)
                if curr.left not in visited:
                    curr = curr.left
                elif curr.right not in visited:
                    curr = curr.right
                    if curr == node:
                        curr = node.right
                        right_side = True
            elif curr.left:
                if curr not in visited:
                    visited.append(curr)
                if curr.left not in visited:
                    curr = curr.left
            elif curr.right:
                if curr not in visited:
                    visited.append(curr)
                if curr.right not in visited:
                    curr = curr.right
                else:
                    if right_side:
                        r_depth += 1
                    else:
                        l_depth += 1
                    curr = curr.parent
            else:
                if curr.parent.left and curr == curr.parent.left:
                    if right_side:
                        r_depth += 1
                    else:
                        l_depth += 1
                elif not curr.parent.left:
                    if right_side:
                        r_depth += 1
                    else:
                        l_depth += 1
                else:
                    if right_side:
                        r_depth += 1
                    else:
                        l_depth += 1
                visited.append(curr)
                curr = curr.parent
        bal = r_depth - l_depth
        return bal

    def _root_shift(self, node, balance):
        """Delete the root of the tree or sub trees."""
        if balance < 0:
            curr = node.left
            while curr.right:
                curr = curr.right
            if curr.left:
                curr.parent.right = curr.left
            if node == self._root:
                self._root = curr
            elif node == node.parent.left:
                node.parent.left = curr
            elif node == node.parent.right:
                node.parent.right = curr
            if node.right != curr:
                curr.right = node.right
                curr.right.parent = curr
            curr.left = node.left
            curr.left.parent = curr
        else:
            curr = node.right
            while curr.left:
                curr = curr.left
            if curr.right:
                curr.parent.left = curr.right
            if node == self._root:
                self._root = curr
            elif node == node.parent.left:
                node.parent.left = curr
            elif node == node.parent.right:
                node.parent.right = curr
            if node.left != curr:
                curr.left = node.left
                curr.left.parent = curr
            curr.right = node.right
            curr.right.parent = curr

    def _del_leaf(self, node):
        """If the node being deleted is a leaf."""
        par = node.parent
        if node == par.left:
            par.left = None
            node.parent = None
            return
        par.right = None
        node.parent = None
        return

    def _depth_and_bal(self, node):
        """."""
        nodes = []
        curr_index = 0
        r_depth = 0
        l_depth = 0
        nodes.append(self._root)
        if node.val < self._root.val:
            while len(nodes) != self._length:
                if nodes[curr_index].left:
                    nodes.append(nodes[curr_index].left)
                    l_depth += 1
                if nodes[curr_index].right:
                    nodes.append(nodes[curr_index].right)
                    if not nodes[curr_index].left:
                        l_depth += 1
                curr_index += 1
        else:
            while len(nodes) != self._length:
                if nodes[curr_index].left:
                    nodes.append(nodes[curr_index].left)
                    r_depth += 1
                if nodes[curr_index].right:
                    nodes.append(nodes[curr_index].right)
                    if not nodes[curr_index].left:
                            r_depth += 1
                curr_index += 1
        if r_depth:
            self._rdepth = r_depth
        else:
            self._ldepth = l_depth
        self._depth = max([self._rdepth, self._ldepth]) + 1
        self._balance = self._rdepth - self._ldepth

    def search(self, val):
        """Find the node at val in Binary Search Tree."""
        curr = self._root
        if type(val) not in [int, float]:
            raise TypeError('This tree only contains numbers.')
        while True:
            if curr is None:
                return None
            elif val == curr.val:
                return curr
            elif val < curr.val:
                curr = curr.left
            elif val > curr.val:
                curr = curr.right

    def size(self):
        """Return the amount of nodes in Binary Search Tree."""
        return self._length

    def depth(self):
        """Return the levels of the Binary Search Tree."""
        return self._depth

    def contains(self, val):
        """Return true if specified val is in tree, false if it is not."""
        if type(val) not in [int, float]:
            raise TypeError('This tree only contains numbers.')
        if self.search(val):
            return True
        return False

    def balance(self):
        """Return the difference of left and right depth from root."""
        return self._balance

    def in_order(self):
        """Return generator that returns values from BST 'in order'."""
        nodes = []
        curr = self._root
        while len(nodes) != self._length:
            if not curr.right and not curr.left and not curr.parent:
                nodes.append(curr)
            elif curr.left and curr not in nodes and curr.left not in nodes:
                curr = curr.left
            elif not curr.left and curr not in nodes:
                nodes.append(curr)
                if not curr.right:
                    curr = curr.parent
                if curr not in nodes:
                    nodes.append(curr)
            elif curr.right and curr.right not in nodes:
                curr = curr.right
            elif not curr.right and curr not in nodes:
                nodes.append(curr)
                curr = curr.parent
            elif not curr.right:
                curr = curr.parent
            else:
                curr = curr.parent
                nodes.append(curr)
        for node in nodes:
            yield node.val

    def pre_order(self):
        """Return generator that returns values from BST 'pre ordered'."""
        nodes = []
        curr = self._root
        while len(nodes) != self._length:
            if curr not in nodes:
                nodes.append(curr)
            if curr.left and curr.left not in nodes:
                curr = curr.left
            elif curr.right and curr.right not in nodes:
                curr = curr.right
            else:
                curr = curr.parent
        for node in nodes:
            yield node.val

    def post_order(self):
        """Return generator that returns values from BST 'post ordered'."""
        nodes = []
        curr = self._root
        while len(nodes) != self._length:
            if not curr.right and not curr.left and not curr.parent:
                nodes.append(curr)
            elif curr.left and curr not in nodes and curr.left not in nodes:
                curr = curr.left
            elif not curr.left and not curr.right and curr not in nodes:
                nodes.append(curr)
                if not curr.right:
                    curr = curr.parent
                    while curr != self._root:
                        if curr.left and curr.left not in nodes:
                            curr = curr.left
                            break
                        elif curr.right and curr.right not in nodes:
                            curr = curr.right
                        elif curr.right:
                            nodes.append(curr)
                            curr = curr.parent
                            if curr == self._root and (len(nodes) ==
                                                       self._length - 1):
                                nodes.append(curr)
                        else:
                            nodes.append(curr)
                            curr = curr.parent
                            if curr == self._root and (len(nodes) ==
                                                       self._length - 1):
                                nodes.append(curr)
            elif curr.right:
                curr = curr.right
        for node in nodes:
            yield node.val

    def breadth_first(self):
        """Return generator that returns values from BST 'breadth first'."""
        nodes = []
        curr_index = 0
        nodes.append(self._root)
        while len(nodes) != self._length:
            if nodes[curr_index].left:
                nodes.append(nodes[curr_index].left)
            if nodes[curr_index].right:
                nodes.append(nodes[curr_index].right)
            curr_index += 1
        for node in nodes:
            yield node.val

class Node():
    """Create a node to add to the Binary Search Tree."""

    def __init__(self, val, parent=None, left=None, right=None):
        """Initialize a new node."""
        self.val = val
        self.parent = parent
        self.left = left
        self.right = right

def wrapper(func, *args, **kwargs):  # pragma: no cover
    """Create a value for a function with a specific arguement called to it."""
    def wrapped():
        return func(*args, **kwargs)
    return wrapped
    #  code found through Erik Enderlein
    #  he found it at http://pythoncentral.io/time-a-python-function/

if __name__ == '__main__':  # pragma: no cover
    best_stuff_tree = BST()
    find5 = wrapper(best_stuff_tree.search, 5)
    find24 = wrapper(best_stuff_tree.search, 24)
    nodes = [5, 3, 8, 2.2, 4, 9.5, 1, 2.6,
             3.3, 4.5, 9, 11, 8.5, 10, 14,
             16, 15, 21, 23, 24]
    for node in nodes:
        best_stuff_tree.insert(node)
    print(timeit(find5))
    print(timeit(find24))
<commit_msg>fixing left right balancing selection.<commit_after>"""Python implementation of Binary Search Tree."""
from timeit import timeit

class BST():
    """Binary Search Tree."""

    def __init__(self, iterable=None):
        """Initialize Binary Search tree."""
        self._root = None
        self._length = 0
        self._rdepth = 0
        self._ldepth = 0
        self._depth = 0
        self._balance = 0
        if type(iterable) in [tuple, list]:
            for i in iterable:
                if type(i) in [int, float]:
                    self.insert(i)
                else:
                    raise TypeError('''
Try again with only numbers in your list or tuple.''')
        elif type(iterable) == int:
            self.insert(iterable)
        elif iterable is not None:
            raise TypeError('Try again with a list, tuple, int, or float.')

    def insert(self, val):
        """Insert new node into Binary Search Tree."""
        if type(val) not in [int, float]:
            raise TypeError('You can only add numbers to this tree.')
        curr = self._root
        depth = 0
        if curr is None:
            curr = Node(val)
            self._root = curr
            self._length += 1
            self._depth = 1
            return
        while True:
            if val == curr.val:
                return
            elif val < curr.val:
                if curr.left:
                    curr = curr.left
                    depth += 1
                else:
                    curr.left = Node(val)
                    curr.left.parent = curr
                    self._length += 1
                    if not curr.right:
                        depth += 1
                    elif curr == self._root:
                        depth += 1
                    if val < self._root.val:
                        if depth > self._ldepth:
                            self._ldepth = depth
                    else:
                        if depth > self._rdepth:
                            self._rdepth = depth
                    self._balance = self._rdepth - self._ldepth
                    self._depth = max([self._rdepth, self._ldepth]) + 1
                    return
            elif val > curr.val:
                if curr.right:
                    curr = curr.right
                    depth += 1
                else:
                    curr.right = Node(val)
                    curr.right.parent = curr
                    self._length += 1
                    if not curr.left:
                        depth += 1
                    elif curr == self._root:
                        depth += 1
                    if val < self._root.val:
                        if depth > self._ldepth:
                            self._ldepth = depth
                    else:
                        if depth > self._rdepth:
                            self._rdepth = depth
                    self._balance = self._rdepth - self._ldepth
                    self._depth = max([self._rdepth, self._ldepth]) + 1
                    return

    def delete(self, val):
        """Delete the node with value from the Binary Search Tree."""
        to_del = self.search(val)
        if to_del == self._root:
            self._root_shift(to_del, self._balance)
        elif to_del.left and to_del.right:
            sub_balance = self._sub_tree_bal(to_del)
            self._root_shift(to_del, sub_balance)
        elif to_del.left:
            if to_del.parent.left == to_del:
                to_del.parent.left = to_del.left
                to_del.left.parent = to_del.parent
            else:
                to_del.parent.right = to_del.left
                to_del.left.parent = to_del.parent
        elif to_del.right:
            if to_del.parent.left == to_del:
                to_del.parent.left = to_del.right
                to_del.right.parent = to_del.parent
            else:
                to_del.parent.right = to_del.right
                to_del.right.parent = to_del.parent
        else:
            self._del_leaf(to_del)
        self._length -= 1
        self._depth_and_bal(to_del)
        return

    def _sub_tree_bal(self, node):
        """Get the balance of a sub tree for deletion."""
        l_depth = 1
        r_depth = 1
        visited = []
        curr = node.left
        right_side = False
        while curr != node and not right_side:
            if curr.left and curr.right:
                if curr not in visited:
                    visited.append(curr)
                if curr.left not in visited:
                    curr = curr.left
                elif curr.right not in visited:
                    curr = curr.right
                    if curr == node:
                        curr = node.right
                        right_side = True
            elif curr.left:
                if curr not in visited:
                    visited.append(curr)
                if curr.left not in visited:
                    curr = curr.left
            elif curr.right:
                if curr not in visited:
                    visited.append(curr)
                if curr.right not in visited:
                    curr = curr.right
                else:
                    if right_side:
                        r_depth += 1
                    else:
                        l_depth += 1
                    curr = curr.parent
            else:
                if curr.parent.left and curr == curr.parent.left:
                    if right_side:
                        r_depth += 1
                    else:
                        l_depth += 1
                elif not curr.parent.left:
                    if right_side:
                        r_depth += 1
                    else:
                        l_depth += 1
                else:
                    if right_side:
                        r_depth += 1
                    else:
                        l_depth += 1
                visited.append(curr)
                curr = curr.parent
        bal = r_depth - l_depth
        return bal

    def _root_shift(self, node, balance):
        """Delete the root of the tree or sub trees."""
        if balance <= 0:
            curr = node.left
            while curr.right:
                curr = curr.right
            if curr.left:
                curr.parent.right = curr.left
            if node == self._root:
                self._root = curr
            elif node == node.parent.left:
                node.parent.left = curr
            elif node == node.parent.right:
                node.parent.right = curr
            if node.right != curr:
                curr.right = node.right
                curr.right.parent = curr
            curr.left = node.left
            curr.left.parent = curr
        else:
            curr = node.right
            while curr.left:
                curr = curr.left
            if curr.right:
                curr.parent.left = curr.right
            if node == self._root:
                self._root = curr
            elif node == node.parent.left:
                node.parent.left = curr
            elif node == node.parent.right:
                node.parent.right = curr
            if node.left != curr:
                curr.left = node.left
                curr.left.parent = curr
            curr.right = node.right
            curr.right.parent = curr

    def _del_leaf(self, node):
        """If the node being deleted is a leaf."""
        par = node.parent
        if node == par.left:
            par.left = None
            node.parent = None
            return
        par.right = None
        node.parent = None
        return

    def _depth_and_bal(self, node):
        """."""
        nodes = []
        curr_index = 0
        r_depth = 0
        l_depth = 0
        nodes.append(self._root)
        if node.val < self._root.val:
            while len(nodes) != self._length:
                if nodes[curr_index].left:
                    nodes.append(nodes[curr_index].left)
                    l_depth += 1
                if nodes[curr_index].right:
                    nodes.append(nodes[curr_index].right)
                    if not nodes[curr_index].left:
                        l_depth += 1
                curr_index += 1
        else:
            while len(nodes) != self._length:
                if nodes[curr_index].left:
                    nodes.append(nodes[curr_index].left)
                    r_depth += 1
                if nodes[curr_index].right:
                    nodes.append(nodes[curr_index].right)
                    if not nodes[curr_index].left:
                            r_depth += 1
                curr_index += 1
        if r_depth:
            self._rdepth = r_depth
        else:
            self._ldepth = l_depth
        self._depth = max([self._rdepth, self._ldepth]) + 1
        self._balance = self._rdepth - self._ldepth

    def search(self, val):
        """Find the node at val in Binary Search Tree."""
        curr = self._root
        if type(val) not in [int, float]:
            raise TypeError('This tree only contains numbers.')
        while True:
            if curr is None:
                return None
            elif val == curr.val:
                return curr
            elif val < curr.val:
                curr = curr.left
            elif val > curr.val:
                curr = curr.right

    def size(self):
        """Return the amount of nodes in Binary Search Tree."""
        return self._length

    def depth(self):
        """Return the levels of the Binary Search Tree."""
        return self._depth

    def contains(self, val):
        """Return true if specified val is in tree, false if it is not."""
        if type(val) not in [int, float]:
            raise TypeError('This tree only contains numbers.')
        if self.search(val):
            return True
        return False

    def balance(self):
        """Return the difference of left and right depth from root."""
        return self._balance

    def in_order(self):
        """Return generator that returns values from BST 'in order'."""
        nodes = []
        curr = self._root
        while len(nodes) != self._length:
            if not curr.right and not curr.left and not curr.parent:
                nodes.append(curr)
            elif curr.left and curr not in nodes and curr.left not in nodes:
                curr = curr.left
            elif not curr.left and curr not in nodes:
                nodes.append(curr)
                if not curr.right:
                    curr = curr.parent
                if curr not in nodes:
                    nodes.append(curr)
            elif curr.right and curr.right not in nodes:
                curr = curr.right
            elif not curr.right and curr not in nodes:
                nodes.append(curr)
                curr = curr.parent
            elif not curr.right:
                curr = curr.parent
            else:
                curr = curr.parent
                nodes.append(curr)
        for node in nodes:
            yield node.val

    def pre_order(self):
        """Return generator that returns values from BST 'pre ordered'."""
        nodes = []
        curr = self._root
        while len(nodes) != self._length:
            if curr not in nodes:
                nodes.append(curr)
            if curr.left and curr.left not in nodes:
                curr = curr.left
            elif curr.right and curr.right not in nodes:
                curr = curr.right
            else:
                curr = curr.parent
        for node in nodes:
            yield node.val

    def post_order(self):
        """Return generator that returns values from BST 'post ordered'."""
        nodes = []
        curr = self._root
        while len(nodes) != self._length:
            if not curr.right and not curr.left and not curr.parent:
                nodes.append(curr)
            elif curr.left and curr not in nodes and curr.left not in nodes:
                curr = curr.left
            elif not curr.left and not curr.right and curr not in nodes:
                nodes.append(curr)
                if not curr.right:
                    curr = curr.parent
                    while curr != self._root:
                        if curr.left and curr.left not in nodes:
                            curr = curr.left
                            break
                        elif curr.right and curr.right not in nodes:
                            curr = curr.right
                        elif curr.right:
                            nodes.append(curr)
                            curr = curr.parent
                            if curr == self._root and (len(nodes) ==
                                                       self._length - 1):
                                nodes.append(curr)
                        else:
                            nodes.append(curr)
                            curr = curr.parent
                            if curr == self._root and (len(nodes) ==
                                                       self._length - 1):
                                nodes.append(curr)
            elif curr.right:
                curr = curr.right
        for node in nodes:
            yield node.val

    def breadth_first(self):
        """Return generator that returns values from BST 'breadth first'."""
        nodes = []
        curr_index = 0
        nodes.append(self._root)
        while len(nodes) != self._length:
            if nodes[curr_index].left:
                nodes.append(nodes[curr_index].left)
            if nodes[curr_index].right:
                nodes.append(nodes[curr_index].right)
            curr_index += 1
        for node in nodes:
            yield node.val

class Node():
    """Create a node to add to the Binary Search Tree."""

    def __init__(self, val, parent=None, left=None, right=None):
        """Initialize a new node."""
        self.val = val
        self.parent = parent
        self.left = left
        self.right = right

def wrapper(func, *args, **kwargs):  # pragma: no cover
    """Create a value for a function with a specific arguement called to it."""
    def wrapped():
        return func(*args, **kwargs)
    return wrapped
    #  code found through Erik Enderlein
    #  he found it at http://pythoncentral.io/time-a-python-function/

if __name__ == '__main__':  # pragma: no cover
    best_stuff_tree = BST()
    find5 = wrapper(best_stuff_tree.search, 5)
    find24 = wrapper(best_stuff_tree.search, 24)
    nodes = [5, 3, 8, 2.2, 4, 9.5, 1, 2.6,
             3.3, 4.5, 9, 11, 8.5, 10, 14,
             16, 15, 21, 23, 24]
    for node in nodes:
        best_stuff_tree.insert(node)
    print(timeit(find5))
    print(timeit(find24))
<|endoftext|>


<commit_before>"""Python implementation of Binary Search Tree."""
from timeit import timeit

class BST():
    """Binary Search Tree."""

    def __init__(self, iterable=None):
        """Initialize Binary Search tree."""
        self._root = None
        self._length = 0
        self._depth = 0
        self._balance = 0
        if type(iterable) in [tuple, list]:
            for i in iterable:
                if type(i) in [int, float]:
                    self.insert(i)
                else:
                    raise TypeError('''
Try again with only numbers in your list or tuple.''')
        elif type(iterable) == int:
            self.insert(iterable)
        elif iterable is not None:
            raise TypeError('Try again with a list, tuple, int, or float.')

    def insert(self, val):
        """Insert new node into Binary Search Tree."""
        if type(val) not in [int, float]:
            raise TypeError('You can only add numbers to this tree.')
        curr = self._root
        path = []
        iteration = 0
        left = False
        right = False
        bal_chg = False
        if curr is None:
            curr = Node(val)
            self._root = curr
            self._length += 1
            path.append(curr)
            if len(path) > self._depth:
                self._depth = len(path)
            return
        path.append(curr)
        while True:
            if val == curr.val:
                return
            elif val < curr.val:
                if curr.left:
                    path.append(curr)
                    curr = curr.left
                    if iteration == 0:
                        left = True
                        iteration += 1
                else:
                    curr.left = Node(val)
                    self._length += 1
                    path.append(curr.left)
                    if len(path) > self._depth:
                        self._depth = len(path)
                        bal_chg = True
                    if iteration == 0:
                        left = True
                        iteration += 1
                    if left and bal_chg:
                        self._balance -= 1
                    if right and bal_chg:
                        self._balance += 1
                    return
            elif val > curr.val:
                if curr.right:
                    path.append(curr)
                    curr = curr.right
                    if iteration == 0:
                        right = True
                        iteration += 1
                else:
                    curr.right = Node(val)
                    self._length += 1
                    path.append(curr.right)
                    if len(path) > self._depth:
                        self._depth = len(path)
                        bal_chg = True
                    if iteration == 0:
                        right = True
                        iteration += 1
                    if left and bal_chg:
                        self._balance -= 1
                    if right and bal_chg:
                        self._balance += 1
                    return

    def search(self, val):
        """Find the node at val in Binary Search Tree."""
        curr = self._root
        if type(val) not in [int, float]:
            raise TypeError('This tree only contains numbers.')
        while True:
            if curr is None:
                return None
            elif val == curr.val:
                return curr
            elif val < curr.val:
                curr = curr.left
            elif val > curr.val:
                curr = curr.right

    def size(self):
        """Return the amount of nodes in Binary Search Tree."""
        return self._length

    def depth(self):
        """Return the levels of the Binary Search Tree."""
        return self._depth

    def contains(self, val):
        """Return true if specified val is in tree, false if it is not."""
        if type(val) not in [int, float]:
            raise TypeError('This tree only contains numbers.')
        if self.search(val):
            return True
        return False

    def balance(self):
        """Return the difference of left and right depth from root."""
        return self._balance

class Node():
    """Create a node to add to the Binary Search Tree."""

    def __init__(self, val, left=None, right=None):
        """Initialize a new node."""
        self.val = val
        self.left = left
        self.right = right

def wrapper(func, *args, **kwargs):  # pragma: no cover
    """Create a value for a function with a specific arguement called to it."""
    def wrapped():
        return func(*args, **kwargs)
    return wrapped
    #  code found through Erik Enderlein
    #  he found it at http://pythoncentral.io/time-a-python-function/

if __name__ == '__main__':  # pragma: no cover
    best_stuff_tree = BST()
    find5 = wrapper(best_stuff_tree.search, 5)
    find24 = wrapper(best_stuff_tree.search, 24)
    nodes = [5, 3, 8, 2.2, 4, 9.5, 1, 2.6,
             3.3, 4.5, 9, 11, 8.5, 10, 14,
             16, 15, 21, 23, 24]
    for node in nodes:
        best_stuff_tree.insert(node)
    print(timeit(find5))
    print(timeit(find24))
<commit_msg>missed object inheritance.<commit_after>"""Python implementation of Binary Search Tree."""
from timeit import timeit

class BST(object):
    """Binary Search Tree."""

    def __init__(self, iterable=None):
        """Initialize Binary Search tree."""
        self._root = None
        self._length = 0
        self._depth = 0
        self._balance = 0
        if type(iterable) in [tuple, list]:
            for i in iterable:
                if type(i) in [int, float]:
                    self.insert(i)
                else:
                    raise TypeError('''
Try again with only numbers in your list or tuple.''')
        elif type(iterable) == int:
            self.insert(iterable)
        elif iterable is not None:
            raise TypeError('Try again with a list, tuple, int, or float.')

    def insert(self, val):
        """Insert new node into Binary Search Tree."""
        if type(val) not in [int, float]:
            raise TypeError('You can only add numbers to this tree.')
        curr = self._root
        path = []
        iteration = 0
        left = False
        right = False
        bal_chg = False
        if curr is None:
            curr = Node(val)
            self._root = curr
            self._length += 1
            path.append(curr)
            if len(path) > self._depth:
                self._depth = len(path)
            return
        path.append(curr)
        while True:
            if val == curr.val:
                return
            elif val < curr.val:
                if curr.left:
                    path.append(curr)
                    curr = curr.left
                    if iteration == 0:
                        left = True
                        iteration += 1
                else:
                    curr.left = Node(val)
                    self._length += 1
                    path.append(curr.left)
                    if len(path) > self._depth:
                        self._depth = len(path)
                        bal_chg = True
                    if iteration == 0:
                        left = True
                        iteration += 1
                    if left and bal_chg:
                        self._balance -= 1
                    if right and bal_chg:
                        self._balance += 1
                    return
            elif val > curr.val:
                if curr.right:
                    path.append(curr)
                    curr = curr.right
                    if iteration == 0:
                        right = True
                        iteration += 1
                else:
                    curr.right = Node(val)
                    self._length += 1
                    path.append(curr.right)
                    if len(path) > self._depth:
                        self._depth = len(path)
                        bal_chg = True
                    if iteration == 0:
                        right = True
                        iteration += 1
                    if left and bal_chg:
                        self._balance -= 1
                    if right and bal_chg:
                        self._balance += 1
                    return

    def search(self, val):
        """Find the node at val in Binary Search Tree."""
        curr = self._root
        if type(val) not in [int, float]:
            raise TypeError('This tree only contains numbers.')
        while True:
            if curr is None:
                return None
            elif val == curr.val:
                return curr
            elif val < curr.val:
                curr = curr.left
            elif val > curr.val:
                curr = curr.right

    def size(self):
        """Return the amount of nodes in Binary Search Tree."""
        return self._length

    def depth(self):
        """Return the levels of the Binary Search Tree."""
        return self._depth

    def contains(self, val):
        """Return true if specified val is in tree, false if it is not."""
        if type(val) not in [int, float]:
            raise TypeError('This tree only contains numbers.')
        if self.search(val):
            return True
        return False

    def balance(self):
        """Return the difference of left and right depth from root."""
        return self._balance

class Node(object):
    """Create a node to add to the Binary Search Tree."""

    def __init__(self, val, left=None, right=None):
        """Initialize a new node."""
        self.val = val
        self.left = left
        self.right = right

def wrapper(func, *args, **kwargs):  # pragma: no cover
    """Create a value for a function with a specific arguement called to it."""
    def wrapped():
        return func(*args, **kwargs)
    return wrapped
    #  code found through Erik Enderlein
    #  he found it at http://pythoncentral.io/time-a-python-function/

if __name__ == '__main__':  # pragma: no cover
    best_stuff_tree = BST()
    find5 = wrapper(best_stuff_tree.search, 5)
    find24 = wrapper(best_stuff_tree.search, 24)
    nodes = [5, 3, 8, 2.2, 4, 9.5, 1, 2.6,
             3.3, 4.5, 9, 11, 8.5, 10, 14,
             16, 15, 21, 23, 24]
    for node in nodes:
        best_stuff_tree.insert(node)
    print(timeit(find5))
    print(timeit(find24))
<|endoftext|>