Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
db7b0027
Commit
db7b0027
authored
Mar 20, 2005
by
Fred Drake
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
PEP 314 implementation (client side):
added support for the provides, requires, and obsoletes metadata fields
parent
54398d6a
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
269 additions
and
25 deletions
+269
-25
Doc/dist/dist.tex
Doc/dist/dist.tex
+76
-0
Doc/whatsnew/whatsnew25.tex
Doc/whatsnew/whatsnew25.tex
+8
-0
Lib/distutils/command/register.py
Lib/distutils/command/register.py
+6
-0
Lib/distutils/core.py
Lib/distutils/core.py
+3
-1
Lib/distutils/dist.py
Lib/distutils/dist.py
+86
-23
Lib/distutils/tests/test_dist.py
Lib/distutils/tests/test_dist.py
+90
-1
No files found.
Doc/dist/dist.tex
View file @
db7b0027
...
...
@@ -631,7 +631,83 @@ is not needed when building compiled extensions: Distutils
will automatically add
\code
{
initmodule
}
to the list of exported symbols.
\section
{
Relationships between Distributions and Packages
}
A distribution may relate to packages in three specific ways:
\begin{enumerate}
\item
It can require packages or modules.
\item
It can provide packages or modules.
\item
It can obsolete packages or modules.
\end{enumerate}
These relationships can be specified using keyword arguments to the
\function
{
distutils.core.setup()
}
function.
Dependencies on other Python modules and packages can be specified by
supplying the
\var
{
requires
}
keyword argument to
\function
{
setup()
}
.
The value must be a list of strings. Each string specifies a package
that is required, and optionally what versions are sufficient.
To specify that any version of a module or package is required, the
string should consist entirely of the module or package name.
Examples include
\code
{
'mymodule'
}
and
\code
{
'xml.parsers.expat'
}
.
If specific versions are required, a sequence of qualifiers can be
supplied in parentheses. Each qualifier may consist of a comparison
operator and a version number. The accepted comparison operators are:
\begin{verbatim}
< > ==
<= >= !=
\end{verbatim}
These can be combined by using multiple qualifiers separated by commas
(and optional whitespace). In this case, all of the qualifiers must
be matched; a logical AND is used to combine the evaluations.
Let's look at a bunch of examples:
\begin{tableii}
{
l|l
}{
code
}{
Requires Expression
}{
Explanation
}
\lineii
{
==1.0
}
{
Only version
\code
{
1.0
}
is compatible
}
\lineii
{
>1.0, !=1.5.1, <2.0
}
{
Any version after
\code
{
1.0
}
and before
\code
{
2.0
}
is compatible, except
\code
{
1.5.1
}}
\end{tableii}
Now that we can specify dependencies, we also need to be able to
specify what we provide that other distributions can require. This is
done using the
\var
{
provides
}
keyword argument to
\function
{
setup()
}
.
The value for this keyword is a list of strings, each of which names a
Python module or package, and optionally identifies the version. If
the version is not specified, it is assumed to match that of the
distribution.
Some examples:
\begin{tableii}
{
l|l
}{
code
}{
Provides Expression
}{
Explanation
}
\lineii
{
mypkg
}
{
Provide
\code
{
mypkg
}
, using the distribution version
}
\lineii
{
mypkg (1.1
}
{
Provide
\code
{
mypkg
}
version 1.1, regardless of the
distribution version
}
\end{tableii}
A package can declare that it obsoletes other packages using the
\var
{
obsoletes
}
keyword argument. The value for this is similar to
that of the
\var
{
requires
}
keyword: a list of strings giving module or
package specifiers. Each specifier consists of a module or package
name optionally followed by one or more version qualifiers. Version
qualifiers are given in parentheses after the module or package name.
The versions identified by the qualifiers are those that are obsoleted
by the distribution being described. If no qualifiers are given, all
versions of the named module or package are understood to be
obsoleted.
\section
{
Installing Scripts
}
So far we have been dealing with pure and non-pure Python modules,
which are usually not run by themselves but imported by scripts.
...
...
Doc/whatsnew/whatsnew25.tex
View file @
db7b0027
...
...
@@ -52,6 +52,14 @@ Raymond Hettinger.}
\end{seealso}
%======================================================================
\section
{
PEP 314: Metadata for Python Software Packages v1.1
}
XXX describe this PEP.
distutils
\function
{
setup()
}
now supports the
\var
{
provides
}
,
\var
{
requires
}
,
\var
{
obsoletes
}
keywords.
%======================================================================
\section
{
Other Language Changes
}
...
...
Lib/distutils/command/register.py
View file @
db7b0027
...
...
@@ -231,7 +231,13 @@ Your selection [default 1]: ''',
'platform'
:
meta
.
get_platforms
(),
'classifiers'
:
meta
.
get_classifiers
(),
'download_url'
:
meta
.
get_download_url
(),
# PEP 314
'provides'
:
meta
.
get_provides
(),
'requires'
:
meta
.
get_requires
(),
'obsoletes'
:
meta
.
get_obsoletes
(),
}
if
data
[
'provides'
]
or
data
[
'requires'
]
or
data
[
'obsoletes'
]:
data
[
'metadata_version'
]
=
'1.1'
return
data
def
post_to_server
(
self
,
data
,
auth
=
None
):
...
...
Lib/distutils/core.py
View file @
db7b0027
...
...
@@ -47,7 +47,9 @@ setup_keywords = ('distclass', 'script_name', 'script_args', 'options',
'name'
,
'version'
,
'author'
,
'author_email'
,
'maintainer'
,
'maintainer_email'
,
'url'
,
'license'
,
'description'
,
'long_description'
,
'keywords'
,
'platforms'
,
'classifiers'
,
'download_url'
,)
'platforms'
,
'classifiers'
,
'download_url'
,
'requires'
,
'provides'
,
'obsoletes'
,
)
# Legal keyword arguments for the Extension constructor
extension_keywords
=
(
'name'
,
'sources'
,
'include_dirs'
,
...
...
Lib/distutils/dist.py
View file @
db7b0027
...
...
@@ -106,6 +106,12 @@ Common commands: (see '--help-commands' for more)
"print the list of classifiers"
),
(
'keywords'
,
None
,
"print the list of keywords"
),
(
'provides'
,
None
,
"print the list of packages/modules provided"
),
(
'requires'
,
None
,
"print the list of packages/modules required"
),
(
'obsoletes'
,
None
,
"print the list of packages/modules made obsolete"
)
]
display_option_names
=
map
(
lambda
x
:
translate_longopt
(
x
[
0
]),
display_options
)
...
...
@@ -210,7 +216,6 @@ Common commands: (see '--help-commands' for more)
# distribution options.
if
attrs
:
# Pull out the set of command options and work on them
# specifically. Note that this order guarantees that aliased
# command options will override any supplied redundantly
...
...
@@ -235,7 +240,9 @@ Common commands: (see '--help-commands' for more)
# Now work on the rest of the attributes. Any attribute that's
# not already defined is invalid!
for
(
key
,
val
)
in
attrs
.
items
():
if
hasattr
(
self
.
metadata
,
key
):
if
hasattr
(
self
.
metadata
,
"set_"
+
key
):
getattr
(
self
.
metadata
,
"set_"
+
key
)(
val
)
elif
hasattr
(
self
.
metadata
,
key
):
setattr
(
self
.
metadata
,
key
,
val
)
elif
hasattr
(
self
,
key
):
setattr
(
self
,
key
,
val
)
...
...
@@ -678,7 +685,8 @@ Common commands: (see '--help-commands' for more)
value
=
getattr
(
self
.
metadata
,
"get_"
+
opt
)()
if
opt
in
[
'keywords'
,
'platforms'
]:
print
string
.
join
(
value
,
','
)
elif
opt
==
'classifiers'
:
elif
opt
in
(
'classifiers'
,
'provides'
,
'requires'
,
'obsoletes'
):
print
string
.
join
(
value
,
'
\
n
'
)
else
:
print
value
...
...
@@ -1024,7 +1032,10 @@ class DistributionMetadata:
"license"
,
"description"
,
"long_description"
,
"keywords"
,
"platforms"
,
"fullname"
,
"contact"
,
"contact_email"
,
"license"
,
"classifiers"
,
"download_url"
)
"download_url"
,
# PEP 314
"provides"
,
"requires"
,
"obsoletes"
,
)
def
__init__
(
self
):
self
.
name
=
None
...
...
@@ -1041,40 +1052,58 @@ class DistributionMetadata:
self
.
platforms
=
None
self
.
classifiers
=
None
self
.
download_url
=
None
# PEP 314
self
.
provides
=
None
self
.
requires
=
None
self
.
obsoletes
=
None
def
write_pkg_info
(
self
,
base_dir
):
"""Write the PKG-INFO file into the release tree.
"""
pkg_info
=
open
(
os
.
path
.
join
(
base_dir
,
'PKG-INFO'
),
'w'
)
pkg_info
.
write
(
'Metadata-Version: 1.0
\
n
'
)
pkg_info
.
write
(
'Name: %s
\
n
'
%
self
.
get_name
()
)
pkg_info
.
write
(
'Version: %s
\
n
'
%
self
.
get_version
()
)
pkg_info
.
write
(
'Summary: %s
\
n
'
%
self
.
get_description
()
)
pkg_info
.
write
(
'Home-page: %s
\
n
'
%
self
.
get_url
()
)
pkg_info
.
write
(
'Author: %s
\
n
'
%
self
.
get_contact
()
)
pkg_info
.
write
(
'Author-email: %s
\
n
'
%
self
.
get_contact_email
()
)
pkg_info
.
write
(
'License: %s
\
n
'
%
self
.
get_license
()
)
self
.
write_pkg_file
(
pkg_info
)
pkg_info
.
close
()
# write_pkg_info ()
def
write_pkg_file
(
self
,
file
):
"""Write the PKG-INFO format data to a file object.
"""
version
=
'1.0'
if
self
.
provides
or
self
.
requires
or
self
.
obsoletes
:
version
=
'1.1'
file
.
write
(
'Metadata-Version: %s
\
n
'
%
version
)
file
.
write
(
'Name: %s
\
n
'
%
self
.
get_name
()
)
file
.
write
(
'Version: %s
\
n
'
%
self
.
get_version
()
)
file
.
write
(
'Summary: %s
\
n
'
%
self
.
get_description
()
)
file
.
write
(
'Home-page: %s
\
n
'
%
self
.
get_url
()
)
file
.
write
(
'Author: %s
\
n
'
%
self
.
get_contact
()
)
file
.
write
(
'Author-email: %s
\
n
'
%
self
.
get_contact_email
()
)
file
.
write
(
'License: %s
\
n
'
%
self
.
get_license
()
)
if
self
.
download_url
:
pkg_info
.
write
(
'Download-URL: %s
\
n
'
%
self
.
download_url
)
file
.
write
(
'Download-URL: %s
\
n
'
%
self
.
download_url
)
long_desc
=
rfc822_escape
(
self
.
get_long_description
()
)
pkg_info
.
write
(
'Description: %s
\
n
'
%
long_desc
)
file
.
write
(
'Description: %s
\
n
'
%
long_desc
)
keywords
=
string
.
join
(
self
.
get_keywords
(),
','
)
if
keywords
:
pkg_info
.
write
(
'Keywords: %s
\
n
'
%
keywords
)
for
platform
in
self
.
get_platforms
():
pkg_info
.
write
(
'Platform: %s
\
n
'
%
platform
)
file
.
write
(
'Keywords: %s
\
n
'
%
keywords
)
for
classifier
in
self
.
get_classifiers
():
pkg_info
.
write
(
'Classifier: %s
\
n
'
%
classifier
)
self
.
_write_list
(
file
,
'Platform'
,
self
.
get_platforms
())
self
.
_write_list
(
file
,
'Classifier'
,
self
.
get_classifiers
()
)
pkg_info
.
close
()
# PEP 314
self
.
_write_list
(
file
,
'Requires'
,
self
.
get_requires
())
self
.
_write_list
(
file
,
'Provides'
,
self
.
get_provides
())
self
.
_write_list
(
file
,
'Obsoletes'
,
self
.
get_obsoletes
())
# write_pkg_info ()
def
_write_list
(
self
,
file
,
name
,
values
):
for
value
in
values
:
file
.
write
(
'%s: %s
\
n
'
%
(
name
,
value
))
# -- Metadata query methods ----------------------------------------
...
...
@@ -1134,6 +1163,40 @@ class DistributionMetadata:
def
get_download_url
(
self
):
return
self
.
download_url
or
"UNKNOWN"
# PEP 314
def
get_requires
(
self
):
return
self
.
requires
or
[]
def
set_requires
(
self
,
value
):
import
distutils.versionpredicate
for
v
in
value
:
distutils
.
versionpredicate
.
VersionPredicate
(
v
)
self
.
requires
=
value
def
get_provides
(
self
):
return
self
.
provides
or
[]
def
set_provides
(
self
,
value
):
value
=
[
v
.
strip
()
for
v
in
value
]
for
v
in
value
:
import
distutils.versionpredicate
ver
=
distutils
.
versionpredicate
.
check_provision
(
v
)
if
ver
:
import
distutils.version
sv
=
distutils
.
version
.
StrictVersion
()
sv
.
parse
(
ver
.
strip
()[
1
:
-
1
])
self
.
provides
=
value
def
get_obsoletes
(
self
):
return
self
.
obsoletes
or
[]
def
set_obsoletes
(
self
,
value
):
import
distutils.versionpredicate
for
v
in
value
:
distutils
.
versionpredicate
.
VersionPredicate
(
v
)
self
.
obsoletes
=
value
# class DistributionMetadata
...
...
Lib/distutils/tests/test_dist.py
View file @
db7b0027
...
...
@@ -4,6 +4,7 @@ import distutils.cmd
import
distutils.dist
import
os
import
shutil
import
StringIO
import
sys
import
tempfile
import
unittest
...
...
@@ -96,5 +97,93 @@ class DistributionTestCase(unittest.TestCase):
os
.
unlink
(
TESTFN
)
class
MetadataTestCase
(
unittest
.
TestCase
):
def
test_simple_metadata
(
self
):
attrs
=
{
"name"
:
"package"
,
"version"
:
"1.0"
}
dist
=
distutils
.
dist
.
Distribution
(
attrs
)
meta
=
self
.
format_metadata
(
dist
)
self
.
assert_
(
"Metadata-Version: 1.0"
in
meta
)
self
.
assert_
(
"provides:"
not
in
meta
.
lower
())
self
.
assert_
(
"requires:"
not
in
meta
.
lower
())
self
.
assert_
(
"obsoletes:"
not
in
meta
.
lower
())
def
test_provides
(
self
):
attrs
=
{
"name"
:
"package"
,
"version"
:
"1.0"
,
"provides"
:
[
"package"
,
"package.sub"
]}
dist
=
distutils
.
dist
.
Distribution
(
attrs
)
self
.
assertEqual
(
dist
.
metadata
.
get_provides
(),
[
"package"
,
"package.sub"
])
self
.
assertEqual
(
dist
.
get_provides
(),
[
"package"
,
"package.sub"
])
meta
=
self
.
format_metadata
(
dist
)
self
.
assert_
(
"Metadata-Version: 1.1"
in
meta
)
self
.
assert_
(
"requires:"
not
in
meta
.
lower
())
self
.
assert_
(
"obsoletes:"
not
in
meta
.
lower
())
def
test_provides_illegal
(
self
):
self
.
assertRaises
(
ValueError
,
distutils
.
dist
.
Distribution
,
{
"name"
:
"package"
,
"version"
:
"1.0"
,
"provides"
:
[
"my.pkg (splat)"
]})
def
test_requires
(
self
):
attrs
=
{
"name"
:
"package"
,
"version"
:
"1.0"
,
"requires"
:
[
"other"
,
"another (==1.0)"
]}
dist
=
distutils
.
dist
.
Distribution
(
attrs
)
self
.
assertEqual
(
dist
.
metadata
.
get_requires
(),
[
"other"
,
"another (==1.0)"
])
self
.
assertEqual
(
dist
.
get_requires
(),
[
"other"
,
"another (==1.0)"
])
meta
=
self
.
format_metadata
(
dist
)
self
.
assert_
(
"Metadata-Version: 1.1"
in
meta
)
self
.
assert_
(
"provides:"
not
in
meta
.
lower
())
self
.
assert_
(
"Requires: other"
in
meta
)
self
.
assert_
(
"Requires: another (==1.0)"
in
meta
)
self
.
assert_
(
"obsoletes:"
not
in
meta
.
lower
())
def
test_requires_illegal
(
self
):
self
.
assertRaises
(
ValueError
,
distutils
.
dist
.
Distribution
,
{
"name"
:
"package"
,
"version"
:
"1.0"
,
"requires"
:
[
"my.pkg (splat)"
]})
def
test_obsoletes
(
self
):
attrs
=
{
"name"
:
"package"
,
"version"
:
"1.0"
,
"obsoletes"
:
[
"other"
,
"another (<1.0)"
]}
dist
=
distutils
.
dist
.
Distribution
(
attrs
)
self
.
assertEqual
(
dist
.
metadata
.
get_obsoletes
(),
[
"other"
,
"another (<1.0)"
])
self
.
assertEqual
(
dist
.
get_obsoletes
(),
[
"other"
,
"another (<1.0)"
])
meta
=
self
.
format_metadata
(
dist
)
self
.
assert_
(
"Metadata-Version: 1.1"
in
meta
)
self
.
assert_
(
"provides:"
not
in
meta
.
lower
())
self
.
assert_
(
"requires:"
not
in
meta
.
lower
())
self
.
assert_
(
"Obsoletes: other"
in
meta
)
self
.
assert_
(
"Obsoletes: another (<1.0)"
in
meta
)
def
test_obsoletes_illegal
(
self
):
self
.
assertRaises
(
ValueError
,
distutils
.
dist
.
Distribution
,
{
"name"
:
"package"
,
"version"
:
"1.0"
,
"obsoletes"
:
[
"my.pkg (splat)"
]})
def
format_metadata
(
self
,
dist
):
sio
=
StringIO
.
StringIO
()
dist
.
metadata
.
write_pkg_file
(
sio
)
return
sio
.
getvalue
()
def
test_suite
():
return
unittest
.
makeSuite
(
DistributionTestCase
)
suite
=
unittest
.
TestSuite
()
suite
.
addTest
(
unittest
.
makeSuite
(
DistributionTestCase
))
suite
.
addTest
(
unittest
.
makeSuite
(
MetadataTestCase
))
return
suite
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