def version_setup_hook(config): """Creates a Python module called version.py which contains these variables: * ``__version__`` (the release version) * ``__svn_revision__`` (the SVN revision info as returned by the ``svnversion`` command) * ``__svn_full_info__`` (as returned by the ``svn info`` command) * ``__setup_datetime__`` (the date and time that setup.py was last run). * ``__vdate__`` (the release date) These variables can be imported in the package's ``__init__.py`` for degugging purposes. The version.py module will *only* be created in a package that imports from the version module in its ``__init__.py``. It should be noted that this is generally preferable to writing these variables directly into ``__init__.py``, since this provides more control and is less likely to unexpectedly break things in ``__init__.py``. Config Usage:: [global] setup-hooks = stsci.distutils.hooks.version_setup_hook You should write exactly this in your package's ``__init__.py``:: from .version import * """ if is_display_option(ignore=['--version']): return name = config['metadata'].get('name') version = config['metadata'].get('version', '0.0.0') vdate = config['metadata'].get('vdate', 'unspecified') package_dir = config.get('files', {}).get('packages_root', '') packages = config.get('files', {}).get('packages', '') packages = split_multiline(packages) _version_hook(__name__ + '.version_setup_hook', package_dir, packages, name, version, vdate)
def tag_svn_revision(config): """ A setup_hook to add the SVN revision of the current working copy path to the package version string, but only if the version ends in .dev. For example, ``mypackage-1.0.dev`` becomes ``mypackage-1.0.dev1234``. This is in accordance with the version string format standardized by PEP 386. This should be used as a replacement for the ``tag_svn_revision`` option to the egg_info command. This hook is more compatible with packaging/distutils2, which does not include any VCS support. This hook is also more flexible in that it turns the revision number on/off depending on the presence of ``.dev`` in the version string, so that it's not automatically added to the version in final releases. This hook does require the ``svnversion`` command to be available in order to work. It does not examine the working copy metadata directly. Config Usage:: [global] setup_hooks = stsci.distutils.hooks.tag_svn_revision You should write exactly this in your package's ``__init__.py``:: from .version import * """ if 'metadata' in config and 'version' in config['metadata']: metadata = config['metadata'] version = metadata['version'] # Don't add an svn revision unless the version ends with .dev if not version.endswith('.dev'): return # First try to get the revision by checking for it in an existing # .version module package_dir = config.get('files', {}).get('packages_root', '') packages = config.get('files', {}).get('packages', '') packages = split_multiline(packages) rev = None for package in packages: version_py = package_uses_version_py(package_dir, package) if not version_py: continue try: mod = __import__(package + '.version', fromlist='__svn_revision__') except ImportError: mod = None if mod is not None and hasattr(mod, '__svn_revision__'): rev = mod.__svn_revision__ break # Cleanup for modname in list(sys.modules): if modname == package or modname.startswith(package + '.'): del sys.modules[modname] if rev is None: # A .version module didn't exist or was incomplete; try calling # svnversion directly rev = get_svn_version() if not rev: return if ':' in rev: rev, _ = rev.split(':', 1) while rev and rev[-1] not in string.digits: rev = rev[:-1] try: rev = int(rev) except (ValueError, TypeError): return metadata['version'] ='%s%d' % (version, rev)
def _load_commands(self, commands): commands = split_multiline(commands) if isinstance(commands, str): commands = [commands] for command in commands: set_command(command.strip())
def _load_compilers(self, compilers): compilers = split_multiline(compilers) if isinstance(compilers, str): compilers = [compilers] for compiler in compilers: set_compiler(compiler.strip())
def parse_config_files(self, filenames=None): if filenames is None: filenames = self.find_config_files() logger.debug("Distribution.parse_config_files():") parser = RawConfigParser() for filename in filenames: logger.debug(" reading %s", filename) parser.read(filename, encoding='utf-8') if os.path.split(filename)[-1] == 'setup.cfg': self._read_setup_cfg(parser, filename) for section in parser.sections(): if section == 'global': if parser.has_option('global', 'compilers'): self._load_compilers(parser.get('global', 'compilers')) if parser.has_option('global', 'commands'): self._load_commands(parser.get('global', 'commands')) options = parser.options(section) opt_dict = self.dist.get_option_dict(section) for opt in options: if opt == '__name__': continue val = parser.get(section, opt) opt = opt.replace('-', '_') if opt == 'sub_commands': val = split_multiline(val) if isinstance(val, str): val = [val] # Hooks use a suffix system to prevent being overriden # by a config file processed later (i.e. a hook set in # the user config file cannot be replaced by a hook # set in a project config file, unless they have the # same suffix). if (opt.startswith("pre_hook.") or opt.startswith("post_hook.")): hook_type, alias = opt.split(".") hook_dict = opt_dict.setdefault( hook_type, (filename, {}))[1] hook_dict[alias] = val else: opt_dict[opt] = filename, val # Make the RawConfigParser forget everything (so we retain # the original filenames that options come from) parser.__init__() # If there was a "global" section in the config file, use it # to set Distribution options. if 'global' in self.dist.command_options: for opt, (src, val) in self.dist.command_options['global'].items(): alias = self.dist.negative_opt.get(opt) try: if alias: setattr(self.dist, alias, not strtobool(val)) elif opt == 'dry_run': # FIXME ugh! setattr(self.dist, opt, strtobool(val)) else: setattr(self.dist, opt, val) except ValueError as msg: raise PackagingOptionError(msg)
def _read_setup_cfg(self, parser, cfg_filename): cfg_directory = os.path.dirname(os.path.abspath(cfg_filename)) content = {} for section in parser.sections(): content[section] = dict(parser.items(section)) # global setup hooks are called first if 'global' in content: if 'setup_hooks' in content['global']: setup_hooks = split_multiline(content['global']['setup_hooks']) # add project directory to sys.path, to allow hooks to be # distributed with the project sys.path.insert(0, cfg_directory) try: for line in setup_hooks: try: hook = resolve_name(line) except ImportError as e: logger.warning('cannot find setup hook: %s', e.args[0]) else: self.setup_hooks.append(hook) self.run_hooks(content) finally: sys.path.pop(0) metadata = self.dist.metadata # setting the metadata values if 'metadata' in content: for key, value in content['metadata'].items(): key = key.replace('_', '-') if metadata.is_multi_field(key): value = split_multiline(value) if key == 'project-url': value = [(label.strip(), url.strip()) for label, url in [v.split(',') for v in value]] if key == 'description-file': if 'description' in content['metadata']: msg = ("description and description-file' are " "mutually exclusive") raise PackagingOptionError(msg) filenames = value.split() # concatenate all files value = [] for filename in filenames: # will raise if file not found with open(filename) as description_file: value.append(description_file.read().strip()) # add filename as a required file if filename not in metadata.requires_files: metadata.requires_files.append(filename) value = '\n'.join(value).strip() key = 'description' if metadata.is_metadata_field(key): metadata[key] = self._convert_metadata(key, value) if 'files' in content: files = content['files'] self.dist.package_dir = files.pop('packages_root', None) files = dict((key, split_multiline(value)) for key, value in files.items()) self.dist.packages = [] packages = files.get('packages', []) if isinstance(packages, str): packages = [packages] for package in packages: if ':' in package: dir_, package = package.split(':') self.dist.package_dir[package] = dir_ self.dist.packages.append(package) self.dist.py_modules = files.get('modules', []) if isinstance(self.dist.py_modules, str): self.dist.py_modules = [self.dist.py_modules] self.dist.scripts = files.get('scripts', []) if isinstance(self.dist.scripts, str): self.dist.scripts = [self.dist.scripts] self.dist.package_data = {} # bookkeeping for the loop below firstline = True prev = None for line in files.get('package_data', []): if '=' in line: # package name -- file globs or specs key, value = line.split('=') prev = self.dist.package_data[key.strip()] = value.split() elif firstline: # invalid continuation on the first line raise PackagingOptionError( 'malformed package_data first line: %r (misses "=")' % line) else: # continuation, add to last seen package name prev.extend(line.split()) firstline = False self.dist.data_files = [] for data in files.get('data_files', []): data = data.split('=') if len(data) != 2: continue key, value = data values = [v.strip() for v in value.split(',')] self.dist.data_files.append((key, values)) # manifest template self.dist.extra_files = files.get('extra_files', []) resources = [] for rule in files.get('resources', []): glob, destination = rule.split('=', 1) rich_glob = glob.strip().split(' ', 1) if len(rich_glob) == 2: prefix, suffix = rich_glob else: assert len(rich_glob) == 1 prefix = '' suffix = glob if destination == '<exclude>': destination = None resources.append( (prefix.strip(), suffix.strip(), destination.strip())) self.dist.data_files = get_resources_dests( cfg_directory, resources) ext_modules = self.dist.ext_modules for section_key in content: # no str.partition in 2.4 :( labels = section_key.split(':') if len(labels) == 2 and labels[0] == 'extension': values_dct = content[section_key] if 'name' in values_dct: raise PackagingOptionError( 'extension name should be given as [extension: name], ' 'not as key') name = labels[1].strip() _check_name(name, self.dist.packages) ext_modules.append(Extension( name, _pop_values(values_dct, 'sources'), _pop_values(values_dct, 'include_dirs'), _pop_values(values_dct, 'define_macros'), _pop_values(values_dct, 'undef_macros'), _pop_values(values_dct, 'library_dirs'), _pop_values(values_dct, 'libraries'), _pop_values(values_dct, 'runtime_library_dirs'), _pop_values(values_dct, 'extra_objects'), _pop_values(values_dct, 'extra_compile_args'), _pop_values(values_dct, 'extra_link_args'), _pop_values(values_dct, 'export_symbols'), _pop_values(values_dct, 'swig_opts'), _pop_values(values_dct, 'depends'), values_dct.pop('language', None), values_dct.pop('optional', None), **values_dct))
def tag_svn_revision(config): """ A setup_hook to add the SVN revision of the current working copy path to the package version string, but only if the version ends in .dev. For example, ``mypackage-1.0.dev`` becomes ``mypackage-1.0.dev1234``. This is in accordance with the version string format standardized by PEP 386. This should be used as a replacement for the ``tag_svn_revision`` option to the egg_info command. This hook is more compatible with packaging/distutils2, which does not include any VCS support. This hook is also more flexible in that it turns the revision number on/off depending on the presence of ``.dev`` in the version string, so that it's not automatically added to the version in final releases. This hook does require the ``svnversion`` command to be available in order to work. It does not examine the working copy metadata directly. Config Usage:: [global] setup_hooks = stsci.distutils.hooks.tag_svn_revision You should write exactly this in your package's ``__init__.py``:: from .version import * """ if 'metadata' in config and 'version' in config['metadata']: metadata = config['metadata'] version = metadata['version'] # Don't add an svn revision unless the version ends with .dev if not version.endswith('.dev'): return # First try to get the revision by checking for it in an existing # .version module package_dir = config.get('files', {}).get('packages_root', '') packages = config.get('files', {}).get('packages', '') packages = split_multiline(packages) rev = None for package in packages: version_py = package_uses_version_py(package_dir, package) if not version_py: continue try: mod = __import__(package + '.version', fromlist='__svn_revision__') except ImportError: mod = None if mod is not None and hasattr(mod, '__svn_revision__'): rev = mod.__svn_revision__ break # Cleanup for modname in list(sys.modules): if modname == package or modname.startswith(package + '.'): del sys.modules[modname] if rev is None: # A .version module didn't exist or was incomplete; try calling # svnversion directly rev = get_svn_version() if not rev: return if ':' in rev: rev, _ = rev.split(':', 1) while rev and rev[-1] not in string.digits: rev = rev[:-1] try: rev = int(rev) except (ValueError, TypeError): return metadata['version'] = '%s%d' % (version, rev)