<commit_before># -*- coding: utf-8 -*-
#
# ViennaGrid for Python documentation build configuration file, created by
# sphinx-quickstart on Wed Jun 12 19:54:14 2013.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys, os

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))

# -- General configuration -----------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'

# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.pngmath', 'sphinx.ext.mathjax', 'sphinx.ext.viewcode']

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

# The suffix of source filenames.
source_suffix = '.rst'

# The encoding of source files.
#source_encoding = 'utf-8-sig'

# The master toctree document.
master_doc = 'index'

# General information about the project.
project = u'ViennaGrid for Python'
copyright = u'2013, Jonan Cruz-Martin'

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.1'
# The full version, including alpha/beta/rc tags.
release = '0.1.0'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None

# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = []

# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None

# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True

# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True

# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'

# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []

# -- Options for HTML output ---------------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
html_theme = 'default'

# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}

# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []

# The name for this set of Sphinx documents.  If None, it defaults to
# "<project> v<release> documentation".
#html_title = None

# A shorter title for the navigation bar.  Default is the same as html_title.
#html_short_title = None

# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None

# The name of an image file (within the static path) to use as favicon of the
# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'

# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True

# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}

# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}

# If false, no module index is generated.
#html_domain_indices = True

# If false, no index is generated.
#html_use_index = True

# If true, the index is split into individual pages for each letter.
#html_split_index = False

# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True

# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True

# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True

# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it.  The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''

# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None

# Output file base name for HTML help builder.
htmlhelp_basename = 'ViennaGridforPythondoc'

# -- Options for LaTeX output --------------------------------------------------

latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',

# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',

# Additional stuff for the LaTeX preamble.
#'preamble': '',
}

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
  ('index', 'ViennaGridforPython.tex', u'ViennaGrid for Python Documentation',
   u'Jonan Cruz-Martin', 'manual'),
]

# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None

# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False

# If true, show page references after internal links.
#latex_show_pagerefs = False

# If true, show URL addresses after external links.
#latex_show_urls = False

# Documents to append as an appendix to all manuals.
#latex_appendices = []

# If false, no module index is generated.
#latex_domain_indices = True

# -- Options for manual page output --------------------------------------------

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
    ('index', 'viennagridforpython', u'ViennaGrid for Python Documentation',
     [u'Jonan Cruz-Martin'], 1)
]

# If true, show URL addresses after external links.
#man_show_urls = False

# -- Options for Texinfo output ------------------------------------------------

# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
#  dir menu entry, description, category)
texinfo_documents = [
  ('index', 'ViennaGridforPython', u'ViennaGrid for Python Documentation',
   u'Jonan Cruz-Martin', 'ViennaGridforPython', 'One line description of project.',
   'Miscellaneous'),
]

# Documents to append as an appendix to all manuals.
#texinfo_appendices = []

# If false, no module index is generated.
#texinfo_domain_indices = True

# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'

# -- Options for Epub output ---------------------------------------------------

# Bibliographic Dublin Core info.
epub_title = u'ViennaGrid for Python'
epub_author = u'Jonan Cruz-Martin'
epub_publisher = u'Jonan Cruz-Martin'
epub_copyright = u'2013, Jonan Cruz-Martin'

# The language of the text. It defaults to the language option
# or en if the language is not set.
#epub_language = ''

# The scheme of the identifier. Typical schemes are ISBN or URL.
#epub_scheme = ''

# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#epub_identifier = ''

# A unique identification for the text.
#epub_uid = ''

# A tuple containing the cover image and cover page html template filenames.
#epub_cover = ()

# HTML files that should be inserted before the pages created by sphinx.
# The format is a list of tuples containing the path and title.
#epub_pre_files = []

# HTML files shat should be inserted after the pages created by sphinx.
# The format is a list of tuples containing the path and title.
#epub_post_files = []

# A list of files that should not be packed into the epub file.
#epub_exclude_files = []

# The depth of the table of contents in toc.ncx.
#epub_tocdepth = 3

# Allow duplicate toc entries.
#epub_tocdup = True
<commit_msg>Modify Sphinx configuration to extract version number from the wrapper instead of manually writing it to the configuration.<commit_after># -*- coding: utf-8 -*-
#
# ViennaGrid for Python documentation build configuration file, created by
# sphinx-quickstart on Wed Jun 12 19:54:14 2013.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys, os

sys.path.append('../..')
import viennagrid_wrapper

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))

# -- General configuration -----------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'

# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.pngmath', 'sphinx.ext.mathjax', 'sphinx.ext.viewcode']

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

# The suffix of source filenames.
source_suffix = '.rst'

# The encoding of source files.
#source_encoding = 'utf-8-sig'

# The master toctree document.
master_doc = 'index'

# General information about the project.
project = u'ViennaGrid for Python'
copyright = u'2013, Jonan Cruz-Martin'

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = viennagrid_wrapper.version()[:3]
# The full version, including alpha/beta/rc tags.
release = viennagrid_wrapper.version()

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None

# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = []

# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None

# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True

# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True

# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'

# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []

# -- Options for HTML output ---------------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
html_theme = 'default'

# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}

# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []

# The name for this set of Sphinx documents.  If None, it defaults to
# "<project> v<release> documentation".
#html_title = None

# A shorter title for the navigation bar.  Default is the same as html_title.
#html_short_title = None

# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None

# The name of an image file (within the static path) to use as favicon of the
# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'

# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True

# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}

# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}

# If false, no module index is generated.
#html_domain_indices = True

# If false, no index is generated.
#html_use_index = True

# If true, the index is split into individual pages for each letter.
#html_split_index = False

# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True

# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True

# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True

# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it.  The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''

# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None

# Output file base name for HTML help builder.
htmlhelp_basename = 'ViennaGridforPythondoc'

# -- Options for LaTeX output --------------------------------------------------

latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',

# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',

# Additional stuff for the LaTeX preamble.
#'preamble': '',
}

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
  ('index', 'ViennaGridforPython.tex', u'ViennaGrid for Python Documentation',
   u'Jonan Cruz-Martin', 'manual'),
]

# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None

# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False

# If true, show page references after internal links.
#latex_show_pagerefs = False

# If true, show URL addresses after external links.
#latex_show_urls = False

# Documents to append as an appendix to all manuals.
#latex_appendices = []

# If false, no module index is generated.
#latex_domain_indices = True

# -- Options for manual page output --------------------------------------------

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
    ('index', 'viennagridforpython', u'ViennaGrid for Python Documentation',
     [u'Jonan Cruz-Martin'], 1)
]

# If true, show URL addresses after external links.
#man_show_urls = False

# -- Options for Texinfo output ------------------------------------------------

# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
#  dir menu entry, description, category)
texinfo_documents = [
  ('index', 'ViennaGridforPython', u'ViennaGrid for Python Documentation',
   u'Jonan Cruz-Martin', 'ViennaGridforPython', 'One line description of project.',
   'Miscellaneous'),
]

# Documents to append as an appendix to all manuals.
#texinfo_appendices = []

# If false, no module index is generated.
#texinfo_domain_indices = True

# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'

# -- Options for Epub output ---------------------------------------------------

# Bibliographic Dublin Core info.
epub_title = u'ViennaGrid for Python'
epub_author = u'Jonan Cruz-Martin'
epub_publisher = u'Jonan Cruz-Martin'
epub_copyright = u'2013, Jonan Cruz-Martin'

# The language of the text. It defaults to the language option
# or en if the language is not set.
#epub_language = ''

# The scheme of the identifier. Typical schemes are ISBN or URL.
#epub_scheme = ''

# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#epub_identifier = ''

# A unique identification for the text.
#epub_uid = ''

# A tuple containing the cover image and cover page html template filenames.
#epub_cover = ()

# HTML files that should be inserted before the pages created by sphinx.
# The format is a list of tuples containing the path and title.
#epub_pre_files = []

# HTML files shat should be inserted after the pages created by sphinx.
# The format is a list of tuples containing the path and title.
#epub_post_files = []

# A list of files that should not be packed into the epub file.
#epub_exclude_files = []

# The depth of the table of contents in toc.ncx.
#epub_tocdepth = 3

# Allow duplicate toc entries.
#epub_tocdup = True
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
'''
Manage Windows users with the net user command

NOTE: This currently only works with local user accounts, not domain accounts
'''

# Import salt libs
import salt.utils
from salt._compat import string_types
import logging

log = logging.getLogger(__name__)

try:
    import win32net
    import win32netcon
    HAS_WIN32NET_MODS = True
except ImportError:
    HAS_WIN32NET_MODS = False

# Define the module's virtual name
__virtualname__ = 'user'

def __virtual__():
    '''
    Set the user module if the kernel is Windows
    '''
    if HAS_WIN32NET_MODS is True and salt.utils.is_windows():
        return __virtualname__
    return False

def add(name,
        # Disable pylint checking on the next options. They exist to match the
        # user modules of other distributions.
        # pylint: disable=W0613
        uid=None,
        gid=None,
        groups=None,
        home=False,
        shell=None,
        unique=False,
        system=False,
        fullname=False,
        roomnumber=False,
        workphone=False,
        homephone=False,
        createhome=False
        # pylint: enable=W0613
        ):
    '''
    Add a user to the minion

    CLI Example:

    .. code-block:: bash

        salt '*' user.add name password
    '''
    ret = __salt__['cmd.run_all']('net user {0} /add'.format(name))
    if groups:
        chgroups(name, groups)
    if fullname:
        chfullname(name, fullname)
    return ret['retcode'] == 0

def delete(name,
           # Disable pylint checking on the next options. They exist to match
           # the user modules of other distributions.
           # pylint: disable=W0613
           purge=False,
           force=False
           # pylint: enable=W0613
           ):
    '''
    Remove a user from the minion
    NOTE: purge and force have not been implemented on Windows yet

    CLI Example:

    .. code-block:: bash

        salt '*' user.delete name
    '''
    ret = __salt__['cmd.run_all']('net user {0} /delete'.format(name))
    return ret['retcode'] == 0

def setpassword(name, password):
    '''
    Set a user's password

    CLI Example:

    .. code-block:: bash

        salt '*' user.setpassword name password
    '''
    ret = __salt__['cmd.run_all'](
        'net user {0} {1}'.format(name, password), output_loglevel='quiet'
    )
    return ret['retcode'] == 0

def addgroup(name, group):
    '''
    Add user to a group

    CLI Example:

    .. code-block:: bash

        salt '*' user.addgroup username groupname
    '''
    user = info(name)
    if not user:
        return False
    if group in user['groups']:
        return True
    ret = __salt__['cmd.run_all'](
        'net localgroup {0} {1} /add'.format(group, name)
    )
    return ret['retcode'] == 0

def removegroup(name, group):
    '''
    Remove user from a group

    CLI Example:

    .. code-block:: bash

        salt '*' user.removegroup username groupname
    '''
    user = info(name)

    if not user:
        return False

    if group not in user['groups']:
        return True

    ret = __salt__['cmd.run_all'](
        'net localgroup {0} {1} /delete'.format(group, name)
    )
    return ret['retcode'] == 0

def chhome(name, home):
    '''
    Change the home directory of the user

    CLI Example:

    .. code-block:: bash

        salt '*' user.chhome foo \\\\fileserver\\home\\foo
    '''
    pre_info = info(name)

    if not pre_info:
        return False

    if home == pre_info['home']:
        return True

    if __salt__['cmd.retcode']('net user {0} /homedir:{1}'.format(
            name, home)) != 0:
        return False

    post_info = info(name)
    if post_info['home'] != pre_info['home']:
        return post_info['home'] == home

    return False

def chprofile(name, profile):
    '''
    Change the profile directory of the user

    CLI Example:

    .. code-block:: bash

        salt '*' user.chprofile foo \\\\fileserver\\profiles\\foo
    '''
    pre_info = info(name)

    if not pre_info:
        return False

    if profile == pre_info['profile']:
        return True
    if __salt__['cmd.retcode']('net user {0} /profilepath:{1}'.format(
            name, profile)) != 0:
        return False

    post_info = info(name)
    if post_info['profile'] != pre_info['profile']:
        return post_info['profile'] == profile

    return False

def chfullname(name, fullname):
    '''
    Change the full name of the user

    CLI Example:

    .. code-block:: bash

        salt '*' user.chfullname user 'First Last'
    '''
    pre_info = info(name)

    if not pre_info:
        return False

    if fullname == pre_info['fullname']:
        return True
    if __salt__['cmd.retcode']('net user {0} /fullname:"{1}"'.format(
            name, fullname)) != 0:
        return False

    post_info = info(name)
    if post_info['fullname'] != pre_info['fullname']:
        return post_info['fullname'] == fullname

    return False

def chgroups(name, groups, append=False):
    '''
    Change the groups this user belongs to, add append to append the specified
    groups

    CLI Example:

    .. code-block:: bash

        salt '*' user.chgroups foo wheel,root True
    '''
    if isinstance(groups, string_types):
        groups = groups.split(',')

    groups = [x.strip(' *') for x in groups]
    ugrps = set(list_groups(name))
    if ugrps == set(groups):
        return True

    if not append:
        for group in ugrps:
            if group not in groups:
                __salt__['cmd.retcode'](
                        'net localgroup {0} {1} /delete'.format(group, name))

    for group in groups:
        if group in ugrps:
            continue
        __salt__['cmd.retcode'](
                'net localgroup {0} {1} /add'.format(group, name))
    agrps = set(list_groups(name))
    return len(ugrps - agrps) == 0

def info(name):
    '''
    Return user information

    CLI Example:

    .. code-block:: bash

        salt '*' user.info root
    '''
    ret = {}
    items = {}
    for line in __salt__['cmd.run']('net user {0}'.format(name)).splitlines():
        if 'name could not be found' in line:
            return {}
        if 'successfully' not in line:
            comps = line.split('    ', 1)
            if not len(comps) > 1:
                continue
            items[comps[0].strip()] = comps[1].strip()
    grouplist = []
    groups = items['Local Group Memberships'].split('  ')
    for group in groups:
        if not group:
            continue
        grouplist.append(group.strip(' *'))

    ret['fullname'] = items['Full Name']
    ret['name'] = items['User name']
    ret['comment'] = items['Comment']
    ret['active'] = items['Account active']
    ret['logonscript'] = items['Logon script']
    ret['profile'] = items['User profile']
    if not ret['profile']:
        ret['profile'] = _get_userprofile_from_registry(name)
    ret['home'] = items['Home directory']
    ret['groups'] = grouplist
    ret['gid'] = ''

    return ret

def _get_userprofile_from_registry(user):
    '''
    In case net user doesn't return the userprofile
    we can get it from the registry
    '''
    sid = __salt__['cmd.run']('wmic useraccount where name="{0}" get sid'.format(user)).splitlines()[2]
    sid = sid.strip()
    profile_dir = __salt__['reg.read_key'](
        'HKEY_LOCAL_MACHINE', 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\{0}'.format(sid),
        'ProfileImagePath'
    )
    log.debug('user {0} with sid={2} profile is located at "{1}"'.format(user, profile_dir, sid))
    return profile_dir

def list_groups(name):
    '''
    Return a list of groups the named user belongs to

    CLI Example:

    .. code-block:: bash

        salt '*' user.list_groups foo
    '''
    ugrp = set()
    try:
        user = info(name)['groups']
    except KeyError:
        return False
    for group in user:
        ugrp.add(group.strip(' *'))

    return sorted(list(ugrp))

def getent(refresh=False):
    '''
    Return the list of all info for all users

    CLI Example:

    .. code-block:: bash

        salt '*' user.getent
    '''
    if 'user.getent' in __context__ and not refresh:
        return __context__['user.getent']

    ret = []
    users = []
    startusers = False
    lines = __salt__['cmd.run']('net user').splitlines()
    for line in lines:
        if '----------' in line:
            startusers = True
            continue
        if startusers:
            if 'successfully' not in line:
                comps = line.split()
                users += comps
                ##if not len(comps) > 1:
                #   continue
                #items[comps[0].strip()] = comps[1].strip()
    #return users
    for user in users:
        stuff = {}
        user_info = __salt__['user.info'](user)
        uid = __salt__['file.user_to_uid'](user_info['name'])

        stuff['gid'] = ''
        stuff['groups'] = user_info['groups']
        stuff['home'] = user_info['home']
        stuff['name'] = user_info['name']
        stuff['passwd'] = ''
        stuff['shell'] = ''
        stuff['uid'] = uid

        ret.append(stuff)

    __context__['user.getent'] = ret
    return ret

def list_users():
    '''
    Return a list of users on Windows
    '''
    res = 0
    users = []
    user_list = []
    dowhile = True
    try:
        while res or dowhile:
            dowhile = False
            (users, _, res) = win32net.NetUserEnum(
                'localhost',
                3,
                win32netcon.FILTER_NORMAL_ACCOUNT,
                res,
                win32netcon.MAX_PREFERRED_LENGTH
            )
            for user in users:
                user_list.append(user['name'])
                log.debug('User: {0}'.format(str(user)))
        return user_list
    except win32net.error:
        pass
<commit_msg>Simplify `user.list_users` on Windows<commit_after># -*- coding: utf-8 -*-
'''
Manage Windows users with the net user command

NOTE: This currently only works with local user accounts, not domain accounts
'''

# Import salt libs
import salt.utils
from salt._compat import string_types
import logging

log = logging.getLogger(__name__)

try:
    import win32net
    import win32netcon
    HAS_WIN32NET_MODS = True
except ImportError:
    HAS_WIN32NET_MODS = False

# Define the module's virtual name
__virtualname__ = 'user'

def __virtual__():
    '''
    Set the user module if the kernel is Windows
    '''
    if HAS_WIN32NET_MODS is True and salt.utils.is_windows():
        return __virtualname__
    return False

def add(name,
        # Disable pylint checking on the next options. They exist to match the
        # user modules of other distributions.
        # pylint: disable=W0613
        uid=None,
        gid=None,
        groups=None,
        home=False,
        shell=None,
        unique=False,
        system=False,
        fullname=False,
        roomnumber=False,
        workphone=False,
        homephone=False,
        createhome=False
        # pylint: enable=W0613
        ):
    '''
    Add a user to the minion

    CLI Example:

    .. code-block:: bash

        salt '*' user.add name password
    '''
    ret = __salt__['cmd.run_all']('net user {0} /add'.format(name))
    if groups:
        chgroups(name, groups)
    if fullname:
        chfullname(name, fullname)
    return ret['retcode'] == 0

def delete(name,
           # Disable pylint checking on the next options. They exist to match
           # the user modules of other distributions.
           # pylint: disable=W0613
           purge=False,
           force=False
           # pylint: enable=W0613
           ):
    '''
    Remove a user from the minion
    NOTE: purge and force have not been implemented on Windows yet

    CLI Example:

    .. code-block:: bash

        salt '*' user.delete name
    '''
    ret = __salt__['cmd.run_all']('net user {0} /delete'.format(name))
    return ret['retcode'] == 0

def setpassword(name, password):
    '''
    Set a user's password

    CLI Example:

    .. code-block:: bash

        salt '*' user.setpassword name password
    '''
    ret = __salt__['cmd.run_all'](
        'net user {0} {1}'.format(name, password), output_loglevel='quiet'
    )
    return ret['retcode'] == 0

def addgroup(name, group):
    '''
    Add user to a group

    CLI Example:

    .. code-block:: bash

        salt '*' user.addgroup username groupname
    '''
    user = info(name)
    if not user:
        return False
    if group in user['groups']:
        return True
    ret = __salt__['cmd.run_all'](
        'net localgroup {0} {1} /add'.format(group, name)
    )
    return ret['retcode'] == 0

def removegroup(name, group):
    '''
    Remove user from a group

    CLI Example:

    .. code-block:: bash

        salt '*' user.removegroup username groupname
    '''
    user = info(name)

    if not user:
        return False

    if group not in user['groups']:
        return True

    ret = __salt__['cmd.run_all'](
        'net localgroup {0} {1} /delete'.format(group, name)
    )
    return ret['retcode'] == 0

def chhome(name, home):
    '''
    Change the home directory of the user

    CLI Example:

    .. code-block:: bash

        salt '*' user.chhome foo \\\\fileserver\\home\\foo
    '''
    pre_info = info(name)

    if not pre_info:
        return False

    if home == pre_info['home']:
        return True

    if __salt__['cmd.retcode']('net user {0} /homedir:{1}'.format(
            name, home)) != 0:
        return False

    post_info = info(name)
    if post_info['home'] != pre_info['home']:
        return post_info['home'] == home

    return False

def chprofile(name, profile):
    '''
    Change the profile directory of the user

    CLI Example:

    .. code-block:: bash

        salt '*' user.chprofile foo \\\\fileserver\\profiles\\foo
    '''
    pre_info = info(name)

    if not pre_info:
        return False

    if profile == pre_info['profile']:
        return True
    if __salt__['cmd.retcode']('net user {0} /profilepath:{1}'.format(
            name, profile)) != 0:
        return False

    post_info = info(name)
    if post_info['profile'] != pre_info['profile']:
        return post_info['profile'] == profile

    return False

def chfullname(name, fullname):
    '''
    Change the full name of the user

    CLI Example:

    .. code-block:: bash

        salt '*' user.chfullname user 'First Last'
    '''
    pre_info = info(name)

    if not pre_info:
        return False

    if fullname == pre_info['fullname']:
        return True
    if __salt__['cmd.retcode']('net user {0} /fullname:"{1}"'.format(
            name, fullname)) != 0:
        return False

    post_info = info(name)
    if post_info['fullname'] != pre_info['fullname']:
        return post_info['fullname'] == fullname

    return False

def chgroups(name, groups, append=False):
    '''
    Change the groups this user belongs to, add append to append the specified
    groups

    CLI Example:

    .. code-block:: bash

        salt '*' user.chgroups foo wheel,root True
    '''
    if isinstance(groups, string_types):
        groups = groups.split(',')

    groups = [x.strip(' *') for x in groups]
    ugrps = set(list_groups(name))
    if ugrps == set(groups):
        return True

    if not append:
        for group in ugrps:
            if group not in groups:
                __salt__['cmd.retcode'](
                        'net localgroup {0} {1} /delete'.format(group, name))

    for group in groups:
        if group in ugrps:
            continue
        __salt__['cmd.retcode'](
                'net localgroup {0} {1} /add'.format(group, name))
    agrps = set(list_groups(name))
    return len(ugrps - agrps) == 0

def info(name):
    '''
    Return user information

    CLI Example:

    .. code-block:: bash

        salt '*' user.info root
    '''
    ret = {}
    items = {}
    for line in __salt__['cmd.run']('net user {0}'.format(name)).splitlines():
        if 'name could not be found' in line:
            return {}
        if 'successfully' not in line:
            comps = line.split('    ', 1)
            if not len(comps) > 1:
                continue
            items[comps[0].strip()] = comps[1].strip()
    grouplist = []
    groups = items['Local Group Memberships'].split('  ')
    for group in groups:
        if not group:
            continue
        grouplist.append(group.strip(' *'))

    ret['fullname'] = items['Full Name']
    ret['name'] = items['User name']
    ret['comment'] = items['Comment']
    ret['active'] = items['Account active']
    ret['logonscript'] = items['Logon script']
    ret['profile'] = items['User profile']
    if not ret['profile']:
        ret['profile'] = _get_userprofile_from_registry(name)
    ret['home'] = items['Home directory']
    ret['groups'] = grouplist
    ret['gid'] = ''

    return ret

def _get_userprofile_from_registry(user):
    '''
    In case net user doesn't return the userprofile
    we can get it from the registry
    '''
    sid = __salt__['cmd.run']('wmic useraccount where name="{0}" get sid'.format(user)).splitlines()[2]
    sid = sid.strip()
    profile_dir = __salt__['reg.read_key'](
        'HKEY_LOCAL_MACHINE', 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\{0}'.format(sid),
        'ProfileImagePath'
    )
    log.debug('user {0} with sid={2} profile is located at "{1}"'.format(user, profile_dir, sid))
    return profile_dir

def list_groups(name):
    '''
    Return a list of groups the named user belongs to

    CLI Example:

    .. code-block:: bash

        salt '*' user.list_groups foo
    '''
    ugrp = set()
    try:
        user = info(name)['groups']
    except KeyError:
        return False
    for group in user:
        ugrp.add(group.strip(' *'))

    return sorted(list(ugrp))

def getent(refresh=False):
    '''
    Return the list of all info for all users

    CLI Example:

    .. code-block:: bash

        salt '*' user.getent
    '''
    if 'user.getent' in __context__ and not refresh:
        return __context__['user.getent']

    ret = []
    users = []
    startusers = False
    lines = __salt__['cmd.run']('net user').splitlines()
    for line in lines:
        if '----------' in line:
            startusers = True
            continue
        if startusers:
            if 'successfully' not in line:
                comps = line.split()
                users += comps
                ##if not len(comps) > 1:
                #   continue
                #items[comps[0].strip()] = comps[1].strip()
    #return users
    for user in users:
        stuff = {}
        user_info = __salt__['user.info'](user)
        uid = __salt__['file.user_to_uid'](user_info['name'])

        stuff['gid'] = ''
        stuff['groups'] = user_info['groups']
        stuff['home'] = user_info['home']
        stuff['name'] = user_info['name']
        stuff['passwd'] = ''
        stuff['shell'] = ''
        stuff['uid'] = uid

        ret.append(stuff)

    __context__['user.getent'] = ret
    return ret

def list_users():
    '''
    Return a list of users on Windows
    '''
    res = 0
    users = []
    user_list = []
    dowhile = True
    try:
        while res or dowhile:
            dowhile = False
            (users, _, res) = win32net.NetUserEnum(
                None,
                0,
                win32netcon.FILTER_NORMAL_ACCOUNT,
                res,
                win32netcon.MAX_PREFERRED_LENGTH
            )
            for user in users:
                user_list.append(user['name'])
        return user_list
    except win32net.error:
        pass
<|endoftext|>


<commit_before>from db_handler import DbHandler
from configurator import Configurator

import time
import os
import queue
import threading
import sys
import requests
import bs4
import re
import praw
import argparse
from PIL import Image

configurator = Configurator()

class Scraper:
    """A class for scraping links on reddit, utilizes DbHandler.py,
    and configurator.py"""

    def __init__(self):
        self.db = DbHandler()
        self.r = praw.Reddit(user_agent="PrawWallpaperDownloader 1.0.0 by /u/Pusillus")

        self.succeeded = 0
        self.failed = 0
        self.skipped = 0
        self.n_posts = 0
        self.albums = 0

        self.notify = False

        self.posts = []
        self.que = queue.Queue()
        self.downloaded_images = []
        self.failed_list = []
        self.callbacks = []
        self.skipped_list = []
        self.deleted_images = []

        self.config = configurator.get_config()
        self.args = self.parse_arguments()

    def parse_arguments(self):
        """Parse arguments from commandline"""
        parser = argparse.ArgumentParser()
        parser.add_argument("-s", "--subreddit",
                            help="specify subreddit to scrape",
                            default=self.config['Sub'])
        parser.add_argument("-l", "--limit",
                            help="set amount of posts to sift through "
                                 "(default " + self.config['Limit'] + ")",
                            default=int(self.config['Limit']), type=int)
        parser.add_argument("--log",
                            help="save a log of wallpapers downloaded/skipped/failed",
                            action="store_true", default=False)
        parser.add_argument("-re", "--redownload",
                            help="attempt to download all the links in the database",
                            action="store_true", default=False)
        parser.add_argument("-v", "--verbose", help="increase output detail",
                            action="store_true",
                            default=False)
        parser.add_argument('-nc', "--noclean", help="Skip cleaning off small images (Cleaning: " + self.config['Clean'] + ")",
                            action="store_true", default= not self.config.getboolean('Clean'))
        parser.add_argument('-ns', '--nosort', help="Skip sorting out previously downloaded images (Sorting: {})".format(self.config['sort']),
                            action="store_true", default= not self.config.getboolean('Sort'))
        parser.add_argument('-na', '--noalbum', help='Skip imgur albums',
                            action='store_true', default= not self.config.getboolean('Albums'))
        parser.add_argument('-t', '--threads', help='Amount of threads for downloading images',
                            default=int(self.config['Threads']), type=int)
        parser.add_argument('-con', '--configure', help="Change settings",
                            action='store_true', default=False)
        args = parser.parse_args()
        return args

    def get_posts(self, subreddit):
        """Get and sort posts from reddit"""
        albums = []  # Array to hold all the album elements for later.
        print('Contacting reddit, please hold...')
        for submission in subreddit.get_hot(limit=self.args.limit):
            url = submission.url
            # Check for author
            if not submission.author:
                author = '[User Deleted]'
            else:
                author = str(submission.author)

            if url.endswith(".jpg"):
                context = {"url": url,
                           "title": submission.title,
                           "author": author,
                           "parent_id": None}
                self.posts.append(context)

            # Imgur support
            elif ("imgur.com" in url) and ("/a/" not in url):
                if url.endswith("/new"):
                    url = url.rsplit("/", 1)[0]
                id = url.rsplit("/", 1)[1].rsplit(".", 1)[0]
                link = "http://i.imgur.com/" + id + ".jpg"
                context = {"url": link,
                           "title": submission.title,
                           "author": author,
                           "parent_id": None}
                self.posts.append(context)
            # Album support
            elif ("imgur.com" in url) and ("/a/" in url):
                album_context = {"url"  : url,
                                 "title": submission.title,
                                 "author": author}
                albums.append(album_context)

        # Extract all image links from the imgur albums
        if not self.args.noalbum:
            self.handle_albums(albums)
        # Save amount of valid imagages
        self.n_posts = len(self.posts)
        # Sort out previously downloaded images
        if not self.args.nosort:
            if self.config["MaxAge"].lower().strip() == "none":
                self.posts, self.skipped_list = self.db.sort_links(self.posts)
            else:
                self.posts, self.skipped_list = self.db.sort_links(self.posts, age_limit=self.config["MaxAge"])
            self.print_skipped()

    def handle_albums(self, albums):
        """Extract all links from a list of imgur albums"""
        albums = self.db.sort_albums(albums)
        n_albums = len(albums)

        for _id, album in enumerate(albums):
            print("\rHandling album: {}/{}".format(_id+1,n_albums), end='')
            # Download imgur album
            res = requests.get(album["url"])
            try:
                res.raise_for_status()
            except Exception as exc:
                self.handle_error(exc, album)
                continue

            # Parse through the html fetching all link elements
            soup = bs4.BeautifulSoup(res.text, 'html.parser')
            link_elements = soup.select('a.zoom')

            # Insert link to get id
            album['length'] = len(link_elements)
            album_id = self.db.insert_album(album)

            if len(link_elements) > 0:
                for a_id, ele in enumerate(link_elements):
                    # Put the data in context for later
                    context = {"url"  : "http:" + ele.get('href'),
                               "title": album["title"],
                               "parent_id": album_id,
                               "id"   : a_id,
                               "author": album["author"]}
                    self.posts.append(context)
            self.albums += 1
        print() #Add missing newline from printing album nr

    def handle_error(self, err, post):
        """Handles error stats and prints a message if verbose is enabled"""
        self.callbacks.append(err)
        self.failed += 1
        self.failed_list.append(post)
        if self.args.verbose:
            # \033[F should return cursor to last line
            # But this is not guranteed for all consoles
            # Maybe look into curse library
            print('\nAn album error occured: ' + str(err), end='\033[F')

    def print_skipped(self):
        """Print posts in skipped_list to console"""
        if self.args.verbose:
            print('\n', 'Skipped posts'.center(40, '='))
            for post in self.skipped_list:
                try:
                    print(post["title"] + " has already been downloaded... skipping")
                except UnicodeEncodeError:
                    print(post["url"] + " has already been downloaded... skipping")
            print('End list'.center(40, '='), '\n')

    def grab_image(self, download_folder):
        while True:
            try:
                submission = self.que.get(block=False)
            except queue.Empty:
                return

            # Try to download image
            try:
                response = requests.get(submission["url"], timeout=10)
                response.raise_for_status()
            except Exception as exc:
                self.handle_error(exc, submission)

            # Try to determine file format from headers fall back to trying to
            # determine it from url if content-type is missing.
            # Most modern operating systems will open the file regardless
            # of format suffix
            try:
                type_header = response.headers['Content-Type'].split('/')
                if type_header[0] == 'image':
                    content_type = type_header[1]
                else:
                    # Sometimes the content-type is incorrect
                    # try to guess it from URL
                    if submission["url"].endswith('.png'):
                        content_type = "png"
                    else:
                        content_type = "jpg"
            except KeyError and IndexError:
                # Missing content-type header, guess from link
                if submission["url"].endswith('.png'):
                    content_type = "png"
                else:
                    content_type = "jpg"

            # content-headers describe .jpg images with jpeg
            if  content_type == 'jpeg':
                image_format = '.jpg'
            else:
                image_format = '.' + content_type

            # If there's an id key in the submission it's from an album and
            # should be suffixed with it's position within that album
            if 'id' in submission:
                file_path = os.path.join(download_folder,
                                         re.sub(r'[\\/:*?"<>|]',
                                                '',
                                                submission["title"][:25
                                                ]) + '_' + str(submission['id']+1) + image_format)
            else:
                file_path = os.path.join(download_folder,
                                         re.sub(r'[\\/:*?"<>|]',
                                                '',
                                                submission["title"][:25]) + image_format)
            # Try to save the image to disk
            try:
                with open(file_path, 'wb') as image:
                    for chunk in response.iter_content(4096):
                        image.write(chunk)
                self.succeeded += 1
                self.downloaded_images.append(file_path)
            except Exception as exc:
                self.handle_error(exc, submission)

    def update_screen(self):
        while self.notify:
            handled_images = self.succeeded + self.failed
            print("Downloading images {}/{}".format(handled_images,len(self.posts)),
                  flush=True, end='\r')
            time.sleep(0.5)

    def download_images(self):
        """Create folders and try to download/save the image links
         in self.posts, assumes all links are image links"""
        # Stop if there's not posts to download
        if len(self.posts) < 1:
            print("No new images to download.")
            return

        # Make folders
        os.makedirs("Downloads", exist_ok=True)
        download_folder = os.path.join("Downloads", self.args.subreddit)
        os.makedirs(download_folder, exist_ok=True)

        for post in self.posts:
            self.que.put(post)

        threads = []
        print("Starting {} threads".format(self.args.threads))
        for n in range(self.args.threads):
            thread = threading.Thread(target=self.grab_image,
                                      args=(download_folder, ))
            thread.start()
            threads.append(thread)

        self.notify = True
        threading.Thread(target=self.update_screen).start()
        for thread in threads:
            try:
                thread.join()
            except KeyboardInterrupt:
                # Don't know how to handle this, ideas?
                pass
        self.notify = False

    def print_stats(self):
        """Print download stats to console"""
        print()
        self.skipped = len(self.skipped_list)
        new_images = self.succeeded-len(self.deleted_images)
        print('Albums: {}\nImages downloaded: {}/{} \nSkipped: {}\n'
              'Failed: {}\nDeleted: {}\n'
              'New images: {}'.format(self.albums,
                                      self.succeeded,
                                      self.n_posts,
                                      self.skipped,
                                      self.failed,
                                      len(self.deleted_images),
   				                      new_images))

    def save_posts(self):
        """Save posts currently in self.posts to database"""
        for post in self.posts:
            self.db.insert_link(post)
        self.db.save_changes()

    def save_log(self):
        """Build log file"""
        with open("log.txt", 'w', encoding="utf-8") as log:
            # Introduction
            log.write("Log for " + time.strftime("%d-%m-%Y %H:%M") + "\n")
            log.write("Albums: {}\nSucceeded: {}\nSkipped: {}\n"
                      "Deleted: {}\nFailed: {}\n\n".format(self.albums,
                                                           self.succeeded,
                                                           self.skipped,
                                                           len(self.deleted_images),
                                                           self.failed))

            # Failed list
            if len(self.failed_list) > 0:
                log.write("Begin failed list".center(40, '=') + '\n')
                for post in self.failed_list:
                    try:
                        log.write("{}\n{}\n"
                                 "\n".format(post["title"],
                                             post["url"]))
                    except UnicodeEncodeError:
                        pass
                log.write("End failed list".center(40, '=') + '\n'*2)

            # Callbacks
            if len(self.callbacks) > 0:
                log.write("Begin callbacks".center(40, '=') + '\n')
                for callback in self.callbacks:
                    log.write(str(callback))
                    log.write('\n'*2)
                log.write('End callbacks'.center(40, '=') + '\n'*2)

            # Skipped list
            if len(self.skipped_list) > 0:
                log.write("Begin skipped list".center(40, '=') + '\n')
                for post in self.skipped_list:
                    try:
                        log.write("{}\n{}\n"
                                 "\n".format(post["title"],
                                             post["url"]))
                    except UnicodeEncodeError:
                        pass
                log.write("End skipped list".center(40, '=') + '\n'*2)

            # Deleted list
            if len(self.deleted_images) > 0:
                log.write('Begin deleted list'.center(40, '=') + '\n'*2)
                for image in self.deleted_images:
                    try:
                        log.write("{} deleted due to size\n\n".format(image))
                    except UnicodeEncodeError:
                        pass
                log.write('End deleted list'.center(50, '=') + '\n'*2)

    def clean_up(self):
        """Examines all downloaded images, deleting duds"""
        print('\nCleaning up')
        for image_path in self.downloaded_images:
            try:
                image = Image.open(image_path)
            except OSError:
                continue
            if image.size[0] < int(self.config['MinWidth'])\
                    or image.size[1] < int(self.config['MinHeight']):
                image.close()
                try:
                    os.remove(image_path)
                    self.deleted_images.append(image_path)
                except PermissionError:
                    print('\nCan\'t delete ' + image_path + ' image is currently in use')
            else:
                image.close()

    def re_download(self):
        """Attempts to re-download all links in the database"""
        self.posts = self.db.get_posts()
        self.n_posts = len(self.posts)
        self.download_images()
        if len(self.downloaded_images) > 0 and not self.args.noclean:
            self.clean_up()
        self.print_stats()
        if self.args.log:
            self.save_log()

    def run(self):
        """Run the scraper"""
        try:
            print('Getting posts from: ' + self.args.subreddit)
            self.get_posts(self.r.get_subreddit(self.args.subreddit))
        except praw.errors.InvalidSubreddit:
            sys.exit("It appears like you mis typed the subreddit name")
        except praw.errors.Forbidden:
            sys.exit("Access to subreddit denied")
        except praw.errors.NotFound:
            sys.exit("Subreddit not found")

        self.download_images()
        self.save_posts()
        if len(self.downloaded_images) > 0 and not self.args.noclean:
            self.clean_up()
        self.print_stats()
        if self.args.log:
            self.save_log()
<commit_msg>Implement PyCLIBar<commit_after>from db_handler import DbHandler
from configurator import Configurator

from PyCLIBar.CLIBar import CLIBar

import time
import os
import queue
import threading
import sys
import requests
import bs4
import re
import praw
import argparse
from PIL import Image

configurator = Configurator()

class Scraper:
    """A class for scraping links on reddit, utilizes DbHandler.py,
    and configurator.py"""

    def __init__(self):
        self.db = DbHandler()
        self.r = praw.Reddit(user_agent="PrawWallpaperDownloader 1.0.0 by /u/Pusillus")

        self.succeeded = 0
        self.failed = 0
        self.skipped = 0
        self.n_posts = 0
        self.albums = 0

        self.notify = False

        self.posts = []
        self.que = queue.Queue()
        self.downloaded_images = []
        self.failed_list = []
        self.callbacks = []
        self.skipped_list = []
        self.deleted_images = []

        self.config = configurator.get_config()
        self.args = self.parse_arguments()

    def parse_arguments(self):
        """Parse arguments from commandline"""
        parser = argparse.ArgumentParser()
        parser.add_argument("-s", "--subreddit",
                            help="specify subreddit to scrape",
                            default=self.config['Sub'])
        parser.add_argument("-l", "--limit",
                            help="set amount of posts to sift through "
                                 "(default " + self.config['Limit'] + ")",
                            default=int(self.config['Limit']), type=int)
        parser.add_argument("--log",
                            help="save a log of wallpapers downloaded/skipped/failed",
                            action="store_true", default=False)
        parser.add_argument("-re", "--redownload",
                            help="attempt to download all the links in the database",
                            action="store_true", default=False)
        parser.add_argument("-v", "--verbose", help="increase output detail",
                            action="store_true",
                            default=False)
        parser.add_argument('-nc', "--noclean", help="Skip cleaning off small images (Cleaning: " + self.config['Clean'] + ")",
                            action="store_true", default= not self.config.getboolean('Clean'))
        parser.add_argument('-ns', '--nosort', help="Skip sorting out previously downloaded images (Sorting: {})".format(self.config['sort']),
                            action="store_true", default= not self.config.getboolean('Sort'))
        parser.add_argument('-na', '--noalbum', help='Skip imgur albums',
                            action='store_true', default= not self.config.getboolean('Albums'))
        parser.add_argument('-t', '--threads', help='Amount of threads for downloading images',
                            default=int(self.config['Threads']), type=int)
        parser.add_argument('-con', '--configure', help="Change settings",
                            action='store_true', default=False)
        args = parser.parse_args()
        return args

    def get_posts(self, subreddit):
        """Get and sort posts from reddit"""
        albums = []  # Array to hold all the album elements for later.
        print('Contacting reddit, please hold...')
        for submission in subreddit.get_hot(limit=self.args.limit):
            url = submission.url
            # Check for author
            if not submission.author:
                author = '[User Deleted]'
            else:
                author = str(submission.author)

            if url.endswith(".jpg"):
                context = {"url": url,
                           "title": submission.title,
                           "author": author,
                           "parent_id": None}
                self.posts.append(context)

            # Imgur support
            elif ("imgur.com" in url) and ("/a/" not in url):
                if url.endswith("/new"):
                    url = url.rsplit("/", 1)[0]
                id = url.rsplit("/", 1)[1].rsplit(".", 1)[0]
                link = "http://i.imgur.com/" + id + ".jpg"
                context = {"url": link,
                           "title": submission.title,
                           "author": author,
                           "parent_id": None}
                self.posts.append(context)
            # Album support
            elif ("imgur.com" in url) and ("/a/" in url):
                album_context = {"url"  : url,
                                 "title": submission.title,
                                 "author": author}
                albums.append(album_context)

        # Extract all image links from the imgur albums
        if not self.args.noalbum:
            self.handle_albums(albums)
        # Save amount of valid imagages
        self.n_posts = len(self.posts)
        # Sort out previously downloaded images
        if not self.args.nosort:
            if self.config["MaxAge"].lower().strip() == "none":
                self.posts, self.skipped_list = self.db.sort_links(self.posts)
            else:
                self.posts, self.skipped_list = self.db.sort_links(self.posts, age_limit=self.config["MaxAge"])
            self.print_skipped()

    def handle_albums(self, albums):
        """Extract all links from a list of imgur albums"""
        albums = self.db.sort_albums(albums)
        n_albums = len(albums)

        for _id, album in enumerate(albums):
            print("\rHandling album: {}/{}".format(_id+1,n_albums), end='')
            # Download imgur album
            res = requests.get(album["url"])
            try:
                res.raise_for_status()
            except Exception as exc:
                self.handle_error(exc, album)
                continue

            # Parse through the html fetching all link elements
            soup = bs4.BeautifulSoup(res.text, 'html.parser')
            link_elements = soup.select('a.zoom')

            # Insert link to get id
            album['length'] = len(link_elements)
            album_id = self.db.insert_album(album)

            if len(link_elements) > 0:
                for a_id, ele in enumerate(link_elements):
                    # Put the data in context for later
                    context = {"url"  : "http:" + ele.get('href'),
                               "title": album["title"],
                               "parent_id": album_id,
                               "id"   : a_id,
                               "author": album["author"]}
                    self.posts.append(context)
            self.albums += 1
        print() #Add missing newline from printing album nr

    def handle_error(self, err, post):
        """Handles error stats and prints a message if verbose is enabled"""
        self.callbacks.append(err)
        self.failed += 1
        self.failed_list.append(post)
        if self.args.verbose:
            # \033[F should return cursor to last line
            # But this is not guranteed for all consoles
            # Maybe look into curse library
            print('\nAn album error occured: ' + str(err), end='\033[F')

    def print_skipped(self):
        """Print posts in skipped_list to console"""
        if self.args.verbose:
            print('\n', 'Skipped posts'.center(40, '='))
            for post in self.skipped_list:
                try:
                    print(post["title"] + " has already been downloaded... skipping")
                except UnicodeEncodeError:
                    print(post["url"] + " has already been downloaded... skipping")
            print('End list'.center(40, '='), '\n')

    def grab_image(self, download_folder, bar):
        while True:
            try:
                submission = self.que.get(block=False)
            except queue.Empty:
                return

            # Try to download image
            try:
                response = requests.get(submission["url"], timeout=10)
                response.raise_for_status()
            except Exception as exc:
                self.handle_error(exc, submission)

            # Try to determine file format from headers fall back to trying to
            # determine it from url if content-type is missing.
            # Most modern operating systems will open the file regardless
            # of format suffix
            try:
                type_header = response.headers['Content-Type'].split('/')
                if type_header[0] == 'image':
                    content_type = type_header[1]
                else:
                    # Sometimes the content-type is incorrect
                    # try to guess it from URL
                    if submission["url"].endswith('.png'):
                        content_type = "png"
                    else:
                        content_type = "jpg"
            except KeyError and IndexError:
                # Missing content-type header, guess from link
                if submission["url"].endswith('.png'):
                    content_type = "png"
                else:
                    content_type = "jpg"

            # content-headers describe .jpg images with jpeg
            if  content_type == 'jpeg':
                image_format = '.jpg'
            else:
                image_format = '.' + content_type

            # If there's an id key in the submission it's from an album and
            # should be suffixed with it's position within that album
            if 'id' in submission:
                file_path = os.path.join(download_folder,
                                         re.sub(r'[\\/:*?"<>|]',
                                                '',
                                                submission["title"][:25
                                                ]) + '_' + str(submission['id']+1) + image_format)
            else:
                file_path = os.path.join(download_folder,
                                         re.sub(r'[\\/:*?"<>|]',
                                                '',
                                                submission["title"][:25]) + image_format)
            # Try to save the image to disk
            try:
                with open(file_path, 'wb') as image:
                    for chunk in response.iter_content(4096):
                        image.write(chunk)
                self.succeeded += 1
                self.downloaded_images.append(file_path)
                bar.step()
            except Exception as exc:
                self.handle_error(exc, submission)

    def update_screen(self, bar):
        while self.notify:
            print("{}".format(bar.get_progress_bar()),
                  flush=True, end='\r')
            time.sleep(0.5)

    def download_images(self):
        """Create folders and try to download/save the image links
         in self.posts, assumes all links are image links"""
        # Stop if there's not posts to download
        if len(self.posts) < 1:
            sys.exit("No new images to download.")

        # Make folders
        os.makedirs("Downloads", exist_ok=True)
        download_folder = os.path.join("Downloads", self.args.subreddit)
        os.makedirs(download_folder, exist_ok=True)

        for post in self.posts:
            self.que.put(post)

        # Create progress bar
        bar = CLIBar(_max=len(self.posts))

        threads = []
        print("Starting {} threads".format(self.args.threads))
        for n in range(self.args.threads):
            thread = threading.Thread(target=self.grab_image,
                                      args=(download_folder, bar))
            thread.start()
            threads.append(thread)

        print("Downloading images")
        bar.start()

        self.notify = True
        threading.Thread(target=self.update_screen,
                         args=(bar, )).start()
        for thread in threads:
            try:
                thread.join()
            except KeyboardInterrupt:
                # Don't know how to handle this, ideas?
                pass
        self.notify = False

    def print_stats(self):
        """Print download stats to console"""
        print()
        self.skipped = len(self.skipped_list)
        new_images = self.succeeded-len(self.deleted_images)
        print('Albums: {}\nImages downloaded: {}/{} \nSkipped: {}\n'
              'Failed: {}\nDeleted: {}\n'
              'New images: {}'.format(self.albums,
                                      self.succeeded,
                                      self.n_posts,
                                      self.skipped,
                                      self.failed,
                                      len(self.deleted_images),
   				                      new_images))

    def save_posts(self):
        """Save posts currently in self.posts to database"""
        for post in self.posts:
            self.db.insert_link(post)
        self.db.save_changes()

    def save_log(self):
        """Build log file"""
        with open("log.txt", 'w', encoding="utf-8") as log:
            # Introduction
            log.write("Log for " + time.strftime("%d-%m-%Y %H:%M") + "\n")
            log.write("Albums: {}\nSucceeded: {}\nSkipped: {}\n"
                      "Deleted: {}\nFailed: {}\n\n".format(self.albums,
                                                           self.succeeded,
                                                           self.skipped,
                                                           len(self.deleted_images),
                                                           self.failed))

            # Failed list
            if len(self.failed_list) > 0:
                log.write("Begin failed list".center(40, '=') + '\n')
                for post in self.failed_list:
                    try:
                        log.write("{}\n{}\n"
                                 "\n".format(post["title"],
                                             post["url"]))
                    except UnicodeEncodeError:
                        pass
                log.write("End failed list".center(40, '=') + '\n'*2)

            # Callbacks
            if len(self.callbacks) > 0:
                log.write("Begin callbacks".center(40, '=') + '\n')
                for callback in self.callbacks:
                    log.write(str(callback))
                    log.write('\n'*2)
                log.write('End callbacks'.center(40, '=') + '\n'*2)

            # Skipped list
            if len(self.skipped_list) > 0:
                log.write("Begin skipped list".center(40, '=') + '\n')
                for post in self.skipped_list:
                    try:
                        log.write("{}\n{}\n"
                                 "\n".format(post["title"],
                                             post["url"]))
                    except UnicodeEncodeError:
                        pass
                log.write("End skipped list".center(40, '=') + '\n'*2)

            # Deleted list
            if len(self.deleted_images) > 0:
                log.write('Begin deleted list'.center(40, '=') + '\n'*2)
                for image in self.deleted_images:
                    try:
                        log.write("{} deleted due to size\n\n".format(image))
                    except UnicodeEncodeError:
                        pass
                log.write('End deleted list'.center(50, '=') + '\n'*2)

    def clean_up(self):
        """Examines all downloaded images, deleting duds"""
        print('\nCleaning up')
        for image_path in self.downloaded_images:
            try:
                image = Image.open(image_path)
            except OSError:
                continue
            if image.size[0] < int(self.config['MinWidth'])\
                    or image.size[1] < int(self.config['MinHeight']):
                image.close()
                try:
                    os.remove(image_path)
                    self.deleted_images.append(image_path)
                except PermissionError:
                    print('\nCan\'t delete ' + image_path + ' image is currently in use')
            else:
                image.close()

    def re_download(self):
        """Attempts to re-download all links in the database"""
        self.posts = self.db.get_posts()
        self.n_posts = len(self.posts)
        self.download_images()
        if len(self.downloaded_images) > 0 and not self.args.noclean:
            self.clean_up()
        self.print_stats()
        if self.args.log:
            self.save_log()

    def run(self):
        """Run the scraper"""
        try:
            print('Getting posts from: ' + self.args.subreddit)
            self.get_posts(self.r.get_subreddit(self.args.subreddit))
        except praw.errors.InvalidSubreddit:
            sys.exit("It appears like you mis typed the subreddit name")
        except praw.errors.Forbidden:
            sys.exit("Access to subreddit denied")
        except praw.errors.NotFound:
            sys.exit("Subreddit not found")

        self.download_images()
        self.save_posts()
        if len(self.downloaded_images) > 0 and not self.args.noclean:
            self.clean_up()
        self.print_stats()
        if self.args.log:
            self.save_log()
<|endoftext|>


<commit_before>"""
This module implements geting content from the Human Protein Reference
Database (HPRD), a curated protein data resource, as INDRA Statements.
In particular, the module supports extracting post-translational
modifications, protein complexes, and (binary) protein-protein interactions
from HPRD.

More information about HPRD can be obtained at
`http://www.hprd.org <http://www.hprd.org>`_ and in these publications:

* Peri, S. et al. (2003). Development of Human Protein Reference Database as an
  initial platform for approaching systems biology in humans. Genome Research.
  13, 2363-2371.
* Prasad, T. S. K. et al. (2009). Human Protein Reference Database - 2009
  Update. Nucleic Acids Research. 37, D767-72.

Data from the final release of HPRD (version 9) can be obtained at the
following URLs:

* http://www.hprd.org/RELEASE9/HPRD_FLAT_FILES_041310.tar.gz (text files)
* http://www.hprd.org/RELEASE9/HPRD_XML_041310.tar.gz (XML)

This module is designed to process the text files obtained from the first
link listed above.
"""
from .processor import HprdProcessor
from .api import process_flat_files
<commit_msg>Fix typo<commit_after>"""
This module implements getting content from the Human Protein Reference
Database (HPRD), a curated protein data resource, as INDRA Statements.
In particular, the module supports extracting post-translational
modifications, protein complexes, and (binary) protein-protein interactions
from HPRD.

More information about HPRD can be obtained at
`http://www.hprd.org <http://www.hprd.org>`_ and in these publications:

* Peri, S. et al. (2003). Development of Human Protein Reference Database as an
  initial platform for approaching systems biology in humans. Genome Research.
  13, 2363-2371.
* Prasad, T. S. K. et al. (2009). Human Protein Reference Database - 2009
  Update. Nucleic Acids Research. 37, D767-72.

Data from the final release of HPRD (version 9) can be obtained at the
following URLs:

* http://www.hprd.org/RELEASE9/HPRD_FLAT_FILES_041310.tar.gz (text files)
* http://www.hprd.org/RELEASE9/HPRD_XML_041310.tar.gz (XML)

This module is designed to process the text files obtained from the first
link listed above.
"""
from .processor import HprdProcessor
from .api import process_flat_files
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
#
# pandas documentation build configuration file, created by
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys
import os
from pandas.compat import u

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
# sys.path.append(os.path.abspath('.'))
sys.path.insert(0, os.path.abspath('../sphinxext'))

sys.path.extend([

    # numpy standard doc extensions
    os.path.join(os.path.dirname(__file__),
                 '..', '../..',
                 'sphinxext')

])

# -- General configuration -----------------------------------------------

# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.  sphinxext.

extensions = ['sphinx.ext.autodoc',
              'sphinx.ext.doctest',
              'sphinx.ext.extlinks',
              'sphinx.ext.todo',
              'numpydoc', # used to parse numpy-style docstrings for autodoc
              'ipython_directive',
              'ipython_console_highlighting',
              'sphinx.ext.intersphinx',
              'sphinx.ext.todo',
              'sphinx.ext.coverage',
              'sphinx.ext.pngmath',
              'sphinx.ext.ifconfig',
              'sphinx.ext.autosummary',
              'matplotlib.sphinxext.only_directives',
              'matplotlib.sphinxext.plot_directive',
              ]

# Add any paths that contain templates here, relative to this directory.
templates_path = ['../_templates']

# The suffix of source filenames.
source_suffix = '.rst'

# The encoding of source files.
source_encoding = 'utf-8'

# The master toctree document.
master_doc = 'index'

# General information about the project.
project = u('pandas')
copyright = u('2008-2014, the pandas development team')

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
import pandas

# version = '%s r%s' % (pandas.__version__, svn_version())
version = '%s' % (pandas.__version__)

# The full version, including alpha/beta/rc tags.
release = version

# JP: added from sphinxdocs
autosummary_generate = True

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
# language = None

# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
# today = ''
# Else, today_fmt is used as the format for a strftime call.
# today_fmt = '%B %d, %Y'

# List of documents that shouldn't be included in the build.
# unused_docs = []

# List of directories, relative to source directory, that shouldn't be searched
# for source files.
exclude_trees = []

# The reST default role (used for this markup: `text`) to use for all documents.
# default_role = None

# If true, '()' will be appended to :func: etc. cross-reference text.
# add_function_parentheses = True

# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
# add_module_names = True

# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
# show_authors = False

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'

# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []

# -- Options for HTML output ---------------------------------------------

# The theme to use for HTML and HTML Help pages.  Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
html_theme = 'nature_with_gtoc'

# The style sheet to use for HTML and HTML Help pages. A file of that name
# must exist either in Sphinx' static/ path, or in one of the custom paths
# given in html_static_path.
# html_style = 'statsmodels.css'

# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
# html_theme_options = {}

# Add any paths that contain custom themes here, relative to this directory.
html_theme_path = ['themes']

# The name for this set of Sphinx documents.  If None, it defaults to
# "<project> v<release> documentation".
# html_title = None

# A shorter title for the navigation bar.  Default is the same as html_title.
# html_short_title = None

# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
# html_logo = None

# The name of an image file (within the static path) to use as favicon of the
# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
# html_favicon = None

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
# html_last_updated_fmt = '%b %d, %Y'

# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
# html_use_smartypants = True

# Custom sidebar templates, maps document names to template names.
# html_sidebars = {}

# Additional templates that should be rendered to pages, maps page names to
# template names.
# html_additional_pages = {}

# If false, no module index is generated.
html_use_modindex = True

# If false, no index is generated.
# html_use_index = True

# If true, the index is split into individual pages for each letter.
# html_split_index = False

# If true, links to the reST sources are added to the pages.
# html_show_sourcelink = True

# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it.  The value of this option must be the
# base URL from which the finished HTML is served.
# html_use_opensearch = ''

# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = ''

# Output file base name for HTML help builder.
htmlhelp_basename = 'pandas'

# -- Options for LaTeX output --------------------------------------------

# The paper size ('letter' or 'a4').
# latex_paper_size = 'letter'

# The font size ('10pt', '11pt' or '12pt').
# latex_font_size = '10pt'

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
    ('index', 'pandas.tex',
     u('pandas: powerful Python data analysis toolkit'),
     u('Wes McKinney\n\& PyData Development Team'), 'manual'),
]

# The name of an image file (relative to this directory) to place at the top of
# the title page.
# latex_logo = None

# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
# latex_use_parts = False

# Additional stuff for the LaTeX preamble.
# latex_preamble = ''

# Documents to append as an appendix to all manuals.
# latex_appendices = []

# If false, no module index is generated.
# latex_use_modindex = True

# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {
    'statsmodels': ('http://statsmodels.sourceforge.net/devel/', None),
    'python': ('http://docs.python.org/', None)
}
import glob
autosummary_generate = glob.glob("*.rst")

# extlinks alias
extlinks = {'issue': ('https://github.com/pydata/pandas/issues/%s',
                      'GH'),
            'wiki': ('https://github.com/pydata/pandas/wiki/%s',
                     'wiki ')}

# remove the docstring of the flags attribute (inherited from numpy ndarray)
# because these give doc build errors (see GH issue 5331)
def remove_flags_docstring(app, what, name, obj, options, lines):
    if what == "attribute" and name.endswith(".flags"):
        del lines[:]

def setup(app):
    app.connect("autodoc-process-docstring", remove_flags_docstring)
<commit_msg>BLD/DOC: add logic to sphinx conf.py to speedup processing<commit_after># -*- coding: utf-8 -*-
#
# pandas documentation build configuration file, created by
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys
import os
import re
from pandas.compat import u

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
# sys.path.append(os.path.abspath('.'))
sys.path.insert(0, os.path.abspath('../sphinxext'))

sys.path.extend([

    # numpy standard doc extensions
    os.path.join(os.path.dirname(__file__),
                 '..', '../..',
                 'sphinxext')

])

# -- General configuration -----------------------------------------------

# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.  sphinxext.

extensions = ['sphinx.ext.autodoc',
              'sphinx.ext.doctest',
              'sphinx.ext.extlinks',
              'sphinx.ext.todo',
              'numpydoc', # used to parse numpy-style docstrings for autodoc
              'ipython_directive',
              'ipython_console_highlighting',
              'sphinx.ext.intersphinx',
              'sphinx.ext.todo',
              'sphinx.ext.coverage',
              'sphinx.ext.pngmath',
              'sphinx.ext.ifconfig',
              'matplotlib.sphinxext.only_directives',
              'matplotlib.sphinxext.plot_directive',
              ]

with open("index.rst") as f:
    lines = f.readlines()

# only include the slow autosummary feature if we're building the API section
# of the docs

# JP: added from sphinxdocs
autosummary_generate = False

if any([re.match("\s*api\s*",l) for l in lines]):
    extensions.append('sphinx.ext.autosummary')
    autosummary_generate = True

ds = []
for f in os.listdir(os.path.dirname(__file__)):
    if (not f.endswith(('.rst'))) or (f.startswith('.')) or os.path.basename(f) == 'index.rst':
        continue

    _f = f.split('.rst')[0]
    if not any([re.match("\s*%s\s*$" % _f,l) for l in lines]):
        ds.append(f)

if ds:
    print("I'm about to DELETE the following:\n%s\n" % list(sorted(ds)))
    sys.stdout.write("WARNING: I'd like to delete those to speed up proccesing (yes/no)? ")
    answer = raw_input()

    if answer.lower().strip() in ('y','yes'):
        for f in ds:
            f = os.path.join(os.path.join(os.path.dirname(__file__),f))
            f= os.path.abspath(f)
            try:
                print("Deleting %s" % f)
                os.unlink(f)
            except:
                print("Error deleting %s" % f)
                pass

# Add any paths that contain templates here, relative to this directory.
templates_path = ['../_templates']

# The suffix of source filenames.
source_suffix = '.rst'

# The encoding of source files.
source_encoding = 'utf-8'

# The master toctree document.
master_doc = 'index'

# General information about the project.
project = u('pandas')
copyright = u('2008-2014, the pandas development team')

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
import pandas

# version = '%s r%s' % (pandas.__version__, svn_version())
version = '%s' % (pandas.__version__)

# The full version, including alpha/beta/rc tags.
release = version

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
# language = None

# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
# today = ''
# Else, today_fmt is used as the format for a strftime call.
# today_fmt = '%B %d, %Y'

# List of documents that shouldn't be included in the build.
# unused_docs = []

# List of directories, relative to source directory, that shouldn't be searched
# for source files.
exclude_trees = []

# The reST default role (used for this markup: `text`) to use for all documents.
# default_role = None

# If true, '()' will be appended to :func: etc. cross-reference text.
# add_function_parentheses = True

# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
# add_module_names = True

# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
# show_authors = False

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'

# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []

# -- Options for HTML output ---------------------------------------------

# The theme to use for HTML and HTML Help pages.  Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
html_theme = 'nature_with_gtoc'

# The style sheet to use for HTML and HTML Help pages. A file of that name
# must exist either in Sphinx' static/ path, or in one of the custom paths
# given in html_static_path.
# html_style = 'statsmodels.css'

# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
# html_theme_options = {}

# Add any paths that contain custom themes here, relative to this directory.
html_theme_path = ['themes']

# The name for this set of Sphinx documents.  If None, it defaults to
# "<project> v<release> documentation".
# html_title = None

# A shorter title for the navigation bar.  Default is the same as html_title.
# html_short_title = None

# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
# html_logo = None

# The name of an image file (within the static path) to use as favicon of the
# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
# html_favicon = None

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
# html_last_updated_fmt = '%b %d, %Y'

# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
# html_use_smartypants = True

# Custom sidebar templates, maps document names to template names.
# html_sidebars = {}

# Additional templates that should be rendered to pages, maps page names to
# template names.
# html_additional_pages = {}

# If false, no module index is generated.
html_use_modindex = True

# If false, no index is generated.
# html_use_index = True

# If true, the index is split into individual pages for each letter.
# html_split_index = False

# If true, links to the reST sources are added to the pages.
# html_show_sourcelink = True

# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it.  The value of this option must be the
# base URL from which the finished HTML is served.
# html_use_opensearch = ''

# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = ''

# Output file base name for HTML help builder.
htmlhelp_basename = 'pandas'

# -- Options for LaTeX output --------------------------------------------

# The paper size ('letter' or 'a4').
# latex_paper_size = 'letter'

# The font size ('10pt', '11pt' or '12pt').
# latex_font_size = '10pt'

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
    ('index', 'pandas.tex',
     u('pandas: powerful Python data analysis toolkit'),
     u('Wes McKinney\n\& PyData Development Team'), 'manual'),
]

# The name of an image file (relative to this directory) to place at the top of
# the title page.
# latex_logo = None

# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
# latex_use_parts = False

# Additional stuff for the LaTeX preamble.
# latex_preamble = ''

# Documents to append as an appendix to all manuals.
# latex_appendices = []

# If false, no module index is generated.
# latex_use_modindex = True

# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {
    'statsmodels': ('http://statsmodels.sourceforge.net/devel/', None),
    'python': ('http://docs.python.org/', None)
}
import glob
autosummary_generate = glob.glob("*.rst")

# extlinks alias
extlinks = {'issue': ('https://github.com/pydata/pandas/issues/%s',
                      'GH'),
            'wiki': ('https://github.com/pydata/pandas/wiki/%s',
                     'wiki ')}

# remove the docstring of the flags attribute (inherited from numpy ndarray)
# because these give doc build errors (see GH issue 5331)
def remove_flags_docstring(app, what, name, obj, options, lines):
    if what == "attribute" and name.endswith(".flags"):
        del lines[:]

def setup(app):
    app.connect("autodoc-process-docstring", remove_flags_docstring)
<|endoftext|>