Skip to content
This repository was archived by the owner on Dec 29, 2022. It is now read-only.

Commit

Permalink
Add gflags -> absl.flags migration guidelines.
Browse files Browse the repository at this point in the history
  • Loading branch information
yilei committed Nov 1, 2017
1 parent 278e883 commit 1b1d664
Show file tree
Hide file tree
Showing 3 changed files with 225 additions and 4 deletions.
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
This library has been merged into [Abseil Python Common
Libraries](https://github.com/abseil/abseil-py).
This library has been merged into
[Abseil Python Common Libraries](https://github.com/abseil/abseil-py).

This repository is not maintained and will not be updated. Please use
[Abseil](https://github.com/abseil/abseil-py) instead.
This repository is not maintained and will not be updated.
Please see [the guidelines](absl_migration/migration_guidelines.md)
for migrating to [Abseil](https://github.com/abseil/abseil-py).
134 changes: 134 additions & 0 deletions absl_migration/migrate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#!/usr/bin/env python
"""Helper tool for gflags to absl.flags migration."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
import os
import re


_MIGRATIONS = [
(r'\b(g?flags\.)DEFINE_multistring\b', r'\1DEFINE_multi_string'),
(r'\b(g?flags\.)DEFINE_multi_int\b', r'\1DEFINE_multi_integer'),
(r'\b(g?flags\.)RegisterValidator\b', r'\1register_validator'),
(r'\b(g?flags\.)Validator\b', r'\1validator'),
(r'\b(g?flags\.)RegisterMultiFlagsValidator\b', r'\1register_multi_flags_validator'),
(r'\b(g?flags\.)MultiFlagsValidator\b', r'\1multi_flags_validator'),
(r'\b(g?flags\.)MarkFlagAsRequired\b', r'\1mark_flag_as_required'),
(r'\b(g?flags\.)MarkFlagsAsRequired\b', r'\1mark_flags_as_required'),
(r'\b(g?flags\.)MarkFlagsAsMutualExclusive\b', r'\1mark_flags_as_mutual_exclusive'),
(r'\b(g?flags\.)DECLARE_key_flag\b', r'\1declare_key_flag'),
(r'\b(g?flags\.)ADOPT_module_key_flags\b', r'\1adopt_module_key_flags'),
(r'\b(g?flags\.)DISCLAIM_key_flags\b', r'\1disclaim_key_flags'),
(r'\b(g?flags\.)GetHelpWidth\b', r'\1get_help_width'),
(r'\b(g?flags\.)TextWrap\b', r'\1text_wrap'),
(r'\b(g?flags\.)FlagDictToArgs\b', r'\1flag_dict_to_args'),
(r'\b(g?flags\.)DocToHelp\b', r'\1doc_to_help'),
(r'\b(g?flags\.)FlagsError\b', r'\1Error'),
(r'\b(g?flags\.)IllegalFlagValue\b', r'\1IllegalFlagValueError'),
(r'\bFLAGS\.AppendFlagsIntoFile\b', r'FLAGS.append_flags_into_file'),
(r'\bFLAGS\.AppendFlagValues\b', r'FLAGS.append_flag_values'),
(r'\bFLAGS\.FindModuleDefiningFlag\b', r'FLAGS.find_module_defining_flag'),
(r'\bFLAGS\.FindModuleIdDefiningFlag\b', r'FLAGS.find_module_id_defining_flag'),
(r'\bFLAGS\.FlagsByModuleDict\b', r'FLAGS.flags_by_module_dict'),
(r'\bFLAGS\.FlagsByModuleIdDict\b', r'FLAGS.flags_by_module_id_dict'),
(r'\bFLAGS\.FlagsIntoString\b', r'FLAGS.flags_into_string'),
(r'\bFLAGS\.FlagValuesDict\b', r'FLAGS.flag_values_dict'),
(r'\bFLAGS\.IsGnuGetOpt\b', r'FLAGS.is_gnu_getopt'),
(r'\bFLAGS\.IsParsed\b', r'FLAGS.is_parsed'),
(r'\bFLAGS\.KeyFlagsByModuleDict\b', r'FLAGS.key_flags_by_module_dict'),
(r'\bFLAGS\.MainModuleHelp\b', r'FLAGS.main_module_help'),
(r'\bFLAGS\.MarkAsParsed\b', r'FLAGS.mark_as_parsed'),
(r'\bFLAGS\.ModuleHelp\b', r'FLAGS.module_help'),
(r'\bFLAGS\.ReadFlagsFromFiles\b', r'FLAGS.read_flags_from_files'),
(r'\bFLAGS\.RemoveFlagValues\b', r'FLAGS.remove_flag_values'),
(r'\bFLAGS\.Reset\b', r'FLAGS.unparse_flags'),
(r'\bFLAGS\.SetDefault\b', r'FLAGS.set_default'),
(r'\bFLAGS\.WriteHelpInXMLFormat\b', r'FLAGS.write_help_in_xml_format'),
(r'\bFLAGS\.UseGnuGetOpt\(use_gnu_getopt=', r'FLAGS.set_gnu_getopt(gnu_getopt='),
(r'\bFLAGS\.UseGnuGetOpt\(', r'FLAGS.set_gnu_getopt('),
]


_LEGACY_APIS_RE = re.compile(
r'\b('
r'(g?flags\.DEFINE_multistring)|'
r'(g?flags\.DEFINE_multi_int)|'
r'(g?flags\.RegisterValidator)|'
r'(g?flags\.Validator)|'
r'(g?flags\.RegisterMultiFlagsValidator)|'
r'(g?flags\.MultiFlagsValidator)|'
r'(g?flags\.MarkFlagAsRequired)|'
r'(g?flags\.MarkFlagsAsRequired)|'
r'(g?flags\.MarkFlagsAsMutualExclusive)|'
r'(g?flags\.DECLARE_key_flag)|'
r'(g?flags\.ADOPT_module_key_flags)|'
r'(g?flags\.DISCLAIM_key_flags)|'
r'(g?flags\.GetHelpWidth)|'
r'(g?flags\.TextWrap)|'
r'(g?flags\.FlagDictToArgs)|'
r'(g?flags\.DocToHelp)|'
r'(g?flags\.FlagsError)|'
r'(g?flags\.IllegalFlagValue)|'
r'(FLAGS\.AppendFlagsIntoFile)|'
r'(FLAGS\.AppendFlagValues)|'
r'(FLAGS\.FindModuleDefiningFlag)|'
r'(FLAGS\.FindModuleIdDefiningFlag)|'
r'(FLAGS\.FlagsByModuleDict)|'
r'(FLAGS\.FlagsByModuleIdDict)|'
r'(FLAGS\.FlagsIntoString)|'
r'(FLAGS\.FlagValuesDict)|'
r'(FLAGS\.IsGnuGetOpt)|'
r'(FLAGS\.IsParsed)|'
r'(FLAGS\.KeyFlagsByModuleDict)|'
r'(FLAGS\.MainModuleHelp)|'
r'(FLAGS\.MarkAsParsed)|'
r'(FLAGS\.ModuleHelp)|'
r'(FLAGS\.ReadFlagsFromFiles)|'
r'(FLAGS\.RemoveFlagValues)|'
r'(FLAGS\.Reset)|'
r'(FLAGS\.SetDefault)|'
r'(FLAGS\.WriteHelpInXMLFormat)|'
r'(from\ gflags\ import\ (argument_parser|exceptions|flag|flags_formatting_test|flags_unicode_literals_test|flagvalues|validators))'
r')\b')


def run(root_dir, migrate):
for root, _, filenames in os.walk(root_dir):
for filename in filenames:
if not filename.endswith('.py'):
continue
filepath = os.path.join(root, filename)
with open(filepath) as f:
content = f.read()

if migrate:
new_content = content
for m in _MIGRATIONS:
new_content = re.sub(m[0], m[1], new_content)
if new_content != content:
with open(filepath, 'w') as f:
f.write(new_content)
content = new_content

for index, line in enumerate(content.split('\n')):
if _LEGACY_APIS_RE.search(line):
print('{}:{} {}'.format(filepath, index + 1, line))


def main():
parser = argparse.ArgumentParser(
description='A gflags -> absl.flags migration tool.')
parser.add_argument('--migrate', dest='migrate', action='store_true')
parser.set_defaults(migrate=False)
parser.add_argument('--root_dir', dest='root_dir', required=True)
args = parser.parse_args()

run(args.root_dir, args.migrate)


if __name__ == '__main__':
main()
86 changes: 86 additions & 0 deletions absl_migration/migration_guidelines.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# gflags to absl.flags Migration Guidelines

The [python-gflags](https://github.com/google/python-gflags) library has been merged into [Abseil Python Common Libraries](https://github.com/abseil/abseil-py).
As a result, python-gflags will no longer be maintained.
This document tries to help explain how to migrate from `gflags` to `absl.flags`.

Note if your upstream dependencies have been migrated to `absl.flags`,
we encourage you also migrating to <code>[absl.flags](https://github.com/abseil/abseil-py/tree/master/absl/flags)</code>.
Otherwise there will be two global `FLAGS` objects coexisting in the same process.
Both of them define flags and need to parse command-line args.

## Changes

This section lists the majors changes in absl.flags.

### API Renaming

1. Except the `DEFINE` functions, other method and function names are updated so they conform to PEP8 snake_case style.
1. `DEFINE_multistring` and `DEFINE_multti_int` are renamed to `DEFINE_multi_string` and `DEFINE_multti_integer`, for consistency.
1. Exceptions are renamed so they end with `Error`. Also `FlagsError` renamed to `Error`.
1. All sub-modules have been made private, the public APIs should only be accessed at the package level.

### Behavior Changes

1. Flags now use [GNU-style](https://docs.python.org/3/library/getopt.html#getopt.gnu_getopt) parsing by default. To opt-in to non-GNU style, call `FLAGS.set_gnu_getopt(False)` before parsing flags.
1. Accessing flag values before command-line args are parsed now raises the `UnparsedFlagAccessError`.
1. It is no longer legal to define a flag with a default value type that mismatches the flag type.
1. `FLAGS.set_default` no longer overrides the current value if the flag is set by `FLAGS.name = value`, or specified in the command line.

## Migration Guidelines

We suggest the following steps for migrating from `gflags` to `absl.flags`:

1. Upgrade to the latest python-gflags version, which contains the new API names (see [Appendix](#appendix-renamed-apis)).
1. Update the codebase to use the new APIs.
* You can leverage [migrate.py](migrate.py) to perform the renames and sanity checks. Be aware that it only uses regex matching, which may have false positives or miss some cases.
1. Remove the dependency on [python-gflags](https://pypi.python.org/pypi/python-gflags) and add the dependency on [absl-py](https://pypi.python.org/pypi/absl-py). Then replace `import gflags` with `from absl import flags as gflags`.
1. Once step (3) succeeds, remove the import alias and just use `flags`.

Depending on your project, you can choose to do these at once, or make incremental changes.

## Appendix: Renamed APIs

Here is a list of renamed APIs:

```
DEFINE_multistring -> DEFINE_multi_string
DEFINE_multi_int -> DEFINE_multi_integer
RegisterValidator -> register_validator
Validator -> validator
RegisterMultiFlagsValidator -> register_multi_flags_validator
MultiFlagsValidator -> multi_flags_validator
MarkFlagAsRequired -> mark_flag_as_required
MarkFlagsAsRequired -> mark_flags_as_required
MarkFlagsAsMutualExclusive -> mark_flags_as_mutual_exclusive
DECLARE_key_flag -> declare_key_flag
ADOPT_module_key_flags -> adopt_module_key_flags
DISCLAIM_key_flags -> disclaim_key_flags
GetHelpWidth -> get_help_width
TextWrap -> text_wrap
FlagDictToArgs -> flag_dict_to_args
DocToHelp -> doc_to_help
FlagsError -> Error
IllegalFlagValue -> IllegalFlagValueError
ArgumentParser.Parse -> ArgumentParser.parse
ArgumentParser.Type -> ArgumentParser.flag_type
FLAGS.AppendFlagsIntoFile -> FLAGS.append_flags_into_file
FLAGS.AppendFlagValues -> FLAGS.append_flag_values
FLAGS.FindModuleDefiningFlag -> FLAGS.find_module_defining_flag
FLAGS.FindModuleIdDefiningFlag -> FLAGS.find_module_id_defining_flag
FLAGS.FlagsByModuleDict -> FLAGS.flags_by_module_dict
FLAGS.FlagsByModuleIdDict -> FLAGS.flags_by_module_id_dict
FLAGS.FlagsIntoString -> FLAGS.flags_into_string
FLAGS.FlagValuesDict -> FLAGS.flag_values_dict
FLAGS.IsGnuGetOpt -> FLAGS.is_gnu_getopt
FLAGS.IsParsed -> FLAGS.is_parsed
FLAGS.KeyFlagsByModuleDict -> FLAGS.key_flags_by_module_dict
FLAGS.MainModuleHelp -> FLAGS.main_module_help
FLAGS.MarkAsParsed -> FLAGS.mark_as_parsed
FLAGS.ModuleHelp -> FLAGS.module_help
FLAGS.ReadFlagsFromFiles -> FLAGS.read_flags_from_files
FLAGS.RemoveFlagValues -> FLAGS.remove_flag_values
FLAGS.Reset -> FLAGS.unparse_flags
FLAGS.SetDefault -> FLAGS.set_default
FLAGS.WriteHelpInXMLFormat -> FLAGS.write_help_in_xml_format
```

0 comments on commit 1b1d664

Please sign in to comment.