Skip to content
This repository was archived by the owner on Dec 29, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
```