Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
news
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Sartika Aritonang
news
Commits
baec43d6
Commit
baec43d6
authored
May 29, 2020
by
Sartika Aritonang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Upload New File
parent
0652c760
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
656 additions
and
0 deletions
+656
-0
config.py
stbi/Lib/site-packages/setuptools/config.py
+656
-0
No files found.
stbi/Lib/site-packages/setuptools/config.py
0 → 100644
View file @
baec43d6
from
__future__
import
absolute_import
,
unicode_literals
import
io
import
os
import
sys
import
warnings
import
functools
from
collections
import
defaultdict
from
functools
import
partial
from
functools
import
wraps
from
importlib
import
import_module
from
distutils.errors
import
DistutilsOptionError
,
DistutilsFileError
from
setuptools.extern.packaging.version
import
LegacyVersion
,
parse
from
setuptools.extern.six
import
string_types
,
PY3
__metaclass__
=
type
def
read_configuration
(
filepath
,
find_others
=
False
,
ignore_option_errors
=
False
):
"""Read given configuration file and returns options from it as a dict.
:param str|unicode filepath: Path to configuration file
to get options from.
:param bool find_others: Whether to search for other configuration files
which could be on in various places.
:param bool ignore_option_errors: Whether to silently ignore
options, values of which could not be resolved (e.g. due to exceptions
in directives such as file:, attr:, etc.).
If False exceptions are propagated as expected.
:rtype: dict
"""
from
setuptools.dist
import
Distribution
,
_Distribution
filepath
=
os
.
path
.
abspath
(
filepath
)
if
not
os
.
path
.
isfile
(
filepath
):
raise
DistutilsFileError
(
'Configuration file
%
s does not exist.'
%
filepath
)
current_directory
=
os
.
getcwd
()
os
.
chdir
(
os
.
path
.
dirname
(
filepath
))
try
:
dist
=
Distribution
()
filenames
=
dist
.
find_config_files
()
if
find_others
else
[]
if
filepath
not
in
filenames
:
filenames
.
append
(
filepath
)
_Distribution
.
parse_config_files
(
dist
,
filenames
=
filenames
)
handlers
=
parse_configuration
(
dist
,
dist
.
command_options
,
ignore_option_errors
=
ignore_option_errors
)
finally
:
os
.
chdir
(
current_directory
)
return
configuration_to_dict
(
handlers
)
def
_get_option
(
target_obj
,
key
):
"""
Given a target object and option key, get that option from
the target object, either through a get_{key} method or
from an attribute directly.
"""
getter_name
=
'get_{key}'
.
format
(
**
locals
())
by_attribute
=
functools
.
partial
(
getattr
,
target_obj
,
key
)
getter
=
getattr
(
target_obj
,
getter_name
,
by_attribute
)
return
getter
()
def
configuration_to_dict
(
handlers
):
"""Returns configuration data gathered by given handlers as a dict.
:param list[ConfigHandler] handlers: Handlers list,
usually from parse_configuration()
:rtype: dict
"""
config_dict
=
defaultdict
(
dict
)
for
handler
in
handlers
:
for
option
in
handler
.
set_options
:
value
=
_get_option
(
handler
.
target_obj
,
option
)
config_dict
[
handler
.
section_prefix
][
option
]
=
value
return
config_dict
def
parse_configuration
(
distribution
,
command_options
,
ignore_option_errors
=
False
):
"""Performs additional parsing of configuration options
for a distribution.
Returns a list of used option handlers.
:param Distribution distribution:
:param dict command_options:
:param bool ignore_option_errors: Whether to silently ignore
options, values of which could not be resolved (e.g. due to exceptions
in directives such as file:, attr:, etc.).
If False exceptions are propagated as expected.
:rtype: list
"""
options
=
ConfigOptionsHandler
(
distribution
,
command_options
,
ignore_option_errors
)
options
.
parse
()
meta
=
ConfigMetadataHandler
(
distribution
.
metadata
,
command_options
,
ignore_option_errors
,
distribution
.
package_dir
)
meta
.
parse
()
return
meta
,
options
class
ConfigHandler
:
"""Handles metadata supplied in configuration files."""
section_prefix
=
None
"""Prefix for config sections handled by this handler.
Must be provided by class heirs.
"""
aliases
=
{}
"""Options aliases.
For compatibility with various packages. E.g.: d2to1 and pbr.
Note: `-` in keys is replaced with `_` by config parser.
"""
def
__init__
(
self
,
target_obj
,
options
,
ignore_option_errors
=
False
):
sections
=
{}
section_prefix
=
self
.
section_prefix
for
section_name
,
section_options
in
options
.
items
():
if
not
section_name
.
startswith
(
section_prefix
):
continue
section_name
=
section_name
.
replace
(
section_prefix
,
''
)
.
strip
(
'.'
)
sections
[
section_name
]
=
section_options
self
.
ignore_option_errors
=
ignore_option_errors
self
.
target_obj
=
target_obj
self
.
sections
=
sections
self
.
set_options
=
[]
@property
def
parsers
(
self
):
"""Metadata item name to parser function mapping."""
raise
NotImplementedError
(
'
%
s must provide .parsers property'
%
self
.
__class__
.
__name__
)
def
__setitem__
(
self
,
option_name
,
value
):
unknown
=
tuple
()
target_obj
=
self
.
target_obj
# Translate alias into real name.
option_name
=
self
.
aliases
.
get
(
option_name
,
option_name
)
current_value
=
getattr
(
target_obj
,
option_name
,
unknown
)
if
current_value
is
unknown
:
raise
KeyError
(
option_name
)
if
current_value
:
# Already inhabited. Skipping.
return
skip_option
=
False
parser
=
self
.
parsers
.
get
(
option_name
)
if
parser
:
try
:
value
=
parser
(
value
)
except
Exception
:
skip_option
=
True
if
not
self
.
ignore_option_errors
:
raise
if
skip_option
:
return
setter
=
getattr
(
target_obj
,
'set_
%
s'
%
option_name
,
None
)
if
setter
is
None
:
setattr
(
target_obj
,
option_name
,
value
)
else
:
setter
(
value
)
self
.
set_options
.
append
(
option_name
)
@classmethod
def
_parse_list
(
cls
,
value
,
separator
=
','
):
"""Represents value as a list.
Value is split either by separator (defaults to comma) or by lines.
:param value:
:param separator: List items separator character.
:rtype: list
"""
if
isinstance
(
value
,
list
):
# _get_parser_compound case
return
value
if
'
\n
'
in
value
:
value
=
value
.
splitlines
()
else
:
value
=
value
.
split
(
separator
)
return
[
chunk
.
strip
()
for
chunk
in
value
if
chunk
.
strip
()]
@classmethod
def
_parse_dict
(
cls
,
value
):
"""Represents value as a dict.
:param value:
:rtype: dict
"""
separator
=
'='
result
=
{}
for
line
in
cls
.
_parse_list
(
value
):
key
,
sep
,
val
=
line
.
partition
(
separator
)
if
sep
!=
separator
:
raise
DistutilsOptionError
(
'Unable to parse option value to dict:
%
s'
%
value
)
result
[
key
.
strip
()]
=
val
.
strip
()
return
result
@classmethod
def
_parse_bool
(
cls
,
value
):
"""Represents value as boolean.
:param value:
:rtype: bool
"""
value
=
value
.
lower
()
return
value
in
(
'1'
,
'true'
,
'yes'
)
@classmethod
def
_exclude_files_parser
(
cls
,
key
):
"""Returns a parser function to make sure field inputs
are not files.
Parses a value after getting the key so error messages are
more informative.
:param key:
:rtype: callable
"""
def
parser
(
value
):
exclude_directive
=
'file:'
if
value
.
startswith
(
exclude_directive
):
raise
ValueError
(
'Only strings are accepted for the {0} field, '
'files are not accepted'
.
format
(
key
))
return
value
return
parser
@classmethod
def
_parse_file
(
cls
,
value
):
"""Represents value as a string, allowing including text
from nearest files using `file:` directive.
Directive is sandboxed and won't reach anything outside
directory with setup.py.
Examples:
file: README.rst, CHANGELOG.md, src/file.txt
:param str value:
:rtype: str
"""
include_directive
=
'file:'
if
not
isinstance
(
value
,
string_types
):
return
value
if
not
value
.
startswith
(
include_directive
):
return
value
spec
=
value
[
len
(
include_directive
):]
filepaths
=
(
os
.
path
.
abspath
(
path
.
strip
())
for
path
in
spec
.
split
(
','
))
return
'
\n
'
.
join
(
cls
.
_read_file
(
path
)
for
path
in
filepaths
if
(
cls
.
_assert_local
(
path
)
or
True
)
and
os
.
path
.
isfile
(
path
)
)
@staticmethod
def
_assert_local
(
filepath
):
if
not
filepath
.
startswith
(
os
.
getcwd
()):
raise
DistutilsOptionError
(
'`file:` directive can not access
%
s'
%
filepath
)
@staticmethod
def
_read_file
(
filepath
):
with
io
.
open
(
filepath
,
encoding
=
'utf-8'
)
as
f
:
return
f
.
read
()
@classmethod
def
_parse_attr
(
cls
,
value
,
package_dir
=
None
):
"""Represents value as a module attribute.
Examples:
attr: package.attr
attr: package.module.attr
:param str value:
:rtype: str
"""
attr_directive
=
'attr:'
if
not
value
.
startswith
(
attr_directive
):
return
value
attrs_path
=
value
.
replace
(
attr_directive
,
''
)
.
strip
()
.
split
(
'.'
)
attr_name
=
attrs_path
.
pop
()
module_name
=
'.'
.
join
(
attrs_path
)
module_name
=
module_name
or
'__init__'
parent_path
=
os
.
getcwd
()
if
package_dir
:
if
attrs_path
[
0
]
in
package_dir
:
# A custom path was specified for the module we want to import
custom_path
=
package_dir
[
attrs_path
[
0
]]
parts
=
custom_path
.
rsplit
(
'/'
,
1
)
if
len
(
parts
)
>
1
:
parent_path
=
os
.
path
.
join
(
os
.
getcwd
(),
parts
[
0
])
module_name
=
parts
[
1
]
else
:
module_name
=
custom_path
elif
''
in
package_dir
:
# A custom parent directory was specified for all root modules
parent_path
=
os
.
path
.
join
(
os
.
getcwd
(),
package_dir
[
''
])
sys
.
path
.
insert
(
0
,
parent_path
)
try
:
module
=
import_module
(
module_name
)
value
=
getattr
(
module
,
attr_name
)
finally
:
sys
.
path
=
sys
.
path
[
1
:]
return
value
@classmethod
def
_get_parser_compound
(
cls
,
*
parse_methods
):
"""Returns parser function to represents value as a list.
Parses a value applying given methods one after another.
:param parse_methods:
:rtype: callable
"""
def
parse
(
value
):
parsed
=
value
for
method
in
parse_methods
:
parsed
=
method
(
parsed
)
return
parsed
return
parse
@classmethod
def
_parse_section_to_dict
(
cls
,
section_options
,
values_parser
=
None
):
"""Parses section options into a dictionary.
Optionally applies a given parser to values.
:param dict section_options:
:param callable values_parser:
:rtype: dict
"""
value
=
{}
values_parser
=
values_parser
or
(
lambda
val
:
val
)
for
key
,
(
_
,
val
)
in
section_options
.
items
():
value
[
key
]
=
values_parser
(
val
)
return
value
def
parse_section
(
self
,
section_options
):
"""Parses configuration file section.
:param dict section_options:
"""
for
(
name
,
(
_
,
value
))
in
section_options
.
items
():
try
:
self
[
name
]
=
value
except
KeyError
:
pass
# Keep silent for a new option may appear anytime.
def
parse
(
self
):
"""Parses configuration file items from one
or more related sections.
"""
for
section_name
,
section_options
in
self
.
sections
.
items
():
method_postfix
=
''
if
section_name
:
# [section.option] variant
method_postfix
=
'_
%
s'
%
section_name
section_parser_method
=
getattr
(
self
,
# Dots in section names are translated into dunderscores.
(
'parse_section
%
s'
%
method_postfix
)
.
replace
(
'.'
,
'__'
),
None
)
if
section_parser_method
is
None
:
raise
DistutilsOptionError
(
'Unsupported distribution option section: [
%
s.
%
s]'
%
(
self
.
section_prefix
,
section_name
))
section_parser_method
(
section_options
)
def
_deprecated_config_handler
(
self
,
func
,
msg
,
warning_class
):
""" this function will wrap around parameters that are deprecated
:param msg: deprecation message
:param warning_class: class of warning exception to be raised
:param func: function to be wrapped around
"""
@wraps
(
func
)
def
config_handler
(
*
args
,
**
kwargs
):
warnings
.
warn
(
msg
,
warning_class
)
return
func
(
*
args
,
**
kwargs
)
return
config_handler
class
ConfigMetadataHandler
(
ConfigHandler
):
section_prefix
=
'metadata'
aliases
=
{
'home_page'
:
'url'
,
'summary'
:
'description'
,
'classifier'
:
'classifiers'
,
'platform'
:
'platforms'
,
}
strict_mode
=
False
"""We need to keep it loose, to be partially compatible with
`pbr` and `d2to1` packages which also uses `metadata` section.
"""
def
__init__
(
self
,
target_obj
,
options
,
ignore_option_errors
=
False
,
package_dir
=
None
):
super
(
ConfigMetadataHandler
,
self
)
.
__init__
(
target_obj
,
options
,
ignore_option_errors
)
self
.
package_dir
=
package_dir
@property
def
parsers
(
self
):
"""Metadata item name to parser function mapping."""
parse_list
=
self
.
_parse_list
parse_file
=
self
.
_parse_file
parse_dict
=
self
.
_parse_dict
exclude_files_parser
=
self
.
_exclude_files_parser
return
{
'platforms'
:
parse_list
,
'keywords'
:
parse_list
,
'provides'
:
parse_list
,
'requires'
:
self
.
_deprecated_config_handler
(
parse_list
,
"The requires parameter is deprecated, please use "
"install_requires for runtime dependencies."
,
DeprecationWarning
),
'obsoletes'
:
parse_list
,
'classifiers'
:
self
.
_get_parser_compound
(
parse_file
,
parse_list
),
'license'
:
exclude_files_parser
(
'license'
),
'description'
:
parse_file
,
'long_description'
:
parse_file
,
'version'
:
self
.
_parse_version
,
'project_urls'
:
parse_dict
,
}
def
_parse_version
(
self
,
value
):
"""Parses `version` option value.
:param value:
:rtype: str
"""
version
=
self
.
_parse_file
(
value
)
if
version
!=
value
:
version
=
version
.
strip
()
# Be strict about versions loaded from file because it's easy to
# accidentally include newlines and other unintended content
if
isinstance
(
parse
(
version
),
LegacyVersion
):
tmpl
=
(
'Version loaded from {value} does not '
'comply with PEP 440: {version}'
)
raise
DistutilsOptionError
(
tmpl
.
format
(
**
locals
()))
return
version
version
=
self
.
_parse_attr
(
value
,
self
.
package_dir
)
if
callable
(
version
):
version
=
version
()
if
not
isinstance
(
version
,
string_types
):
if
hasattr
(
version
,
'__iter__'
):
version
=
'.'
.
join
(
map
(
str
,
version
))
else
:
version
=
'
%
s'
%
version
return
version
class
ConfigOptionsHandler
(
ConfigHandler
):
section_prefix
=
'options'
@property
def
parsers
(
self
):
"""Metadata item name to parser function mapping."""
parse_list
=
self
.
_parse_list
parse_list_semicolon
=
partial
(
self
.
_parse_list
,
separator
=
';'
)
parse_bool
=
self
.
_parse_bool
parse_dict
=
self
.
_parse_dict
return
{
'zip_safe'
:
parse_bool
,
'use_2to3'
:
parse_bool
,
'include_package_data'
:
parse_bool
,
'package_dir'
:
parse_dict
,
'use_2to3_fixers'
:
parse_list
,
'use_2to3_exclude_fixers'
:
parse_list
,
'convert_2to3_doctests'
:
parse_list
,
'scripts'
:
parse_list
,
'eager_resources'
:
parse_list
,
'dependency_links'
:
parse_list
,
'namespace_packages'
:
parse_list
,
'install_requires'
:
parse_list_semicolon
,
'setup_requires'
:
parse_list_semicolon
,
'tests_require'
:
parse_list_semicolon
,
'packages'
:
self
.
_parse_packages
,
'entry_points'
:
self
.
_parse_file
,
'py_modules'
:
parse_list
,
}
def
_parse_packages
(
self
,
value
):
"""Parses `packages` option value.
:param value:
:rtype: list
"""
find_directives
=
[
'find:'
,
'find_namespace:'
]
trimmed_value
=
value
.
strip
()
if
trimmed_value
not
in
find_directives
:
return
self
.
_parse_list
(
value
)
findns
=
trimmed_value
==
find_directives
[
1
]
if
findns
and
not
PY3
:
raise
DistutilsOptionError
(
'find_namespace: directive is unsupported on Python < 3.3'
)
# Read function arguments from a dedicated section.
find_kwargs
=
self
.
parse_section_packages__find
(
self
.
sections
.
get
(
'packages.find'
,
{}))
if
findns
:
from
setuptools
import
find_namespace_packages
as
find_packages
else
:
from
setuptools
import
find_packages
return
find_packages
(
**
find_kwargs
)
def
parse_section_packages__find
(
self
,
section_options
):
"""Parses `packages.find` configuration file section.
To be used in conjunction with _parse_packages().
:param dict section_options:
"""
section_data
=
self
.
_parse_section_to_dict
(
section_options
,
self
.
_parse_list
)
valid_keys
=
[
'where'
,
'include'
,
'exclude'
]
find_kwargs
=
dict
(
[(
k
,
v
)
for
k
,
v
in
section_data
.
items
()
if
k
in
valid_keys
and
v
])
where
=
find_kwargs
.
get
(
'where'
)
if
where
is
not
None
:
find_kwargs
[
'where'
]
=
where
[
0
]
# cast list to single val
return
find_kwargs
def
parse_section_entry_points
(
self
,
section_options
):
"""Parses `entry_points` configuration file section.
:param dict section_options:
"""
parsed
=
self
.
_parse_section_to_dict
(
section_options
,
self
.
_parse_list
)
self
[
'entry_points'
]
=
parsed
def
_parse_package_data
(
self
,
section_options
):
parsed
=
self
.
_parse_section_to_dict
(
section_options
,
self
.
_parse_list
)
root
=
parsed
.
get
(
'*'
)
if
root
:
parsed
[
''
]
=
root
del
parsed
[
'*'
]
return
parsed
def
parse_section_package_data
(
self
,
section_options
):
"""Parses `package_data` configuration file section.
:param dict section_options:
"""
self
[
'package_data'
]
=
self
.
_parse_package_data
(
section_options
)
def
parse_section_exclude_package_data
(
self
,
section_options
):
"""Parses `exclude_package_data` configuration file section.
:param dict section_options:
"""
self
[
'exclude_package_data'
]
=
self
.
_parse_package_data
(
section_options
)
def
parse_section_extras_require
(
self
,
section_options
):
"""Parses `extras_require` configuration file section.
:param dict section_options:
"""
parse_list
=
partial
(
self
.
_parse_list
,
separator
=
';'
)
self
[
'extras_require'
]
=
self
.
_parse_section_to_dict
(
section_options
,
parse_list
)
def
parse_section_data_files
(
self
,
section_options
):
"""Parses `data_files` configuration file section.
:param dict section_options:
"""
parsed
=
self
.
_parse_section_to_dict
(
section_options
,
self
.
_parse_list
)
self
[
'data_files'
]
=
[(
k
,
v
)
for
k
,
v
in
parsed
.
items
()]
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment