#!/usr/bin/env python
from setuptools import setup
setup(
  name = 'cs.tagset',
  author = 'Cameron Simpson',
  author_email = 'cs@cskk.id.au',
  version = '20200521.1',
  url = 'https://bitbucket.org/cameron_simpson/css/commits/all',
  description =
    ('Tags and sets of tags with __format__ support and optional ontology '    
 'information.'),
  long_description =
    ('Tags and sets of tags\n'    
 'with __format__ support and optional ontology information.\n'    
 '\n'    
 '*Latest release 20200521.1*:\n'    
 'Fix DISTINFO.install_requires, drop debug import.\n'    
 '\n'    
 'See `cs.fstags` for support for applying these to filesystem objects\n'    
 'such as directories and files.\n'    
 '\n'    
 'See `cs.sqltags` for support for databases of entities with tags,\n'    
 'not directly associated with filesystem objects.\n'    
 'This is suited to both log entries (entities with no "name")\n'    
 'and large collections of named entities;\n'    
 'both accept `Tag`s and can be seached on that basis.\n'    
 '\n'    
 'All of the available complexity is optional:\n'    
 'you can use `Tag`s without bothering with `TagSet`s\n'    
 'or `TagsOntology`s.\n'    
 '\n'    
 'This module contains the following main classes:\n'    
 '* `Tag`: an object with a `.name` and optional `.value` (default `None`)\n'    
 '  and also an optional reference `.ontology`\n'    
 '  for associating semantics with tag values.\n'    
 '  The `.value` (if not `None`) will often be a string,\n'    
 '  but may be any Python object.\n'    
 "  If you're using these via `cs.fstags`,\n"    
 '  the object will need to be JSON transcribeable.\n'    
 '* `TagSet`: a `dict` subclass representing a set of `Tag`s\n'    
 '  to associate with something;\n'    
 '  it also has setlike `.add` and `.discard` methods.\n'    
 '  As such it only supports a single `Tag` for a given tag name,\n'    
 '  but that tag value can of course be a sequence or mapping\n'    
 '  for more elaborate tag values.\n'    
 '* `TagsOntology`:\n'    
 '  a mapping of type names to `TagSet`s defining the type.\n'    
 '  This mapping also contains entries for the metadata\n'    
 '  for specific type values.\n'    
 '\n'    
 "Here's a simple example with some `Tag`s and a `TagSet`.\n"    
 '\n'    
 '    >>> tags = TagSet()\n'    
 '    >>> # add a "bare" Tag named \'blue\' with no value\n'    
 "    >>> tags.add('blue')\n"    
 '    >>> # add a "topic=tagging" Tag\n'    
 "    >>> tags.add('topic','tagging')\n"    
 '    >>> # make a "subtopic" Tag and add it\n'    
 "    >>> subtopic = Tag('subtopic', 'ontologies')\n"    
 '    >>> # Tags have nice repr() and str()\n'    
 '    >>> subtopic\n'    
 "    Tag(name='subtopic',value='ontologies',ontology=None)\n"    
 '    >>> print(subtopic)\n'    
 '    subtopic=ontologies\n'    
 '    >>> # you can add a Tag directly\n'    
 '    >>> tags.add(subtopic)\n'    
 '    >>> # TagSets also have nice repr() and str()\n'    
 '    >>> tags\n'    
 "    TagSet:{'blue': None, 'topic': 'tagging', 'subtopic': 'ontologies'}\n"    
 '    >>> print(tags)\n'    
 '    blue subtopic=ontologies topic=tagging\n'    
 '    >>> # because TagSets are dicts you can format strings with them\n'    
 "    >>> print('topic:{topic} subtopic:{subtopic}'.format_map(tags))\n"    
 '    topic:tagging subtopic:ontologies\n'    
 '    >>> # TagSets have convenient membership tests\n'    
 '    >>> # test for blueness\n'    
 "    >>> 'blue' in tags\n"    
 '    True\n'    
 '    >>> # test for redness\n'    
 "    >>> 'red' in tags\n"    
 '    False\n'    
 '    >>> # test for any "subtopic" tag\n'    
 "    >>> 'subtopic' in tags\n"    
 '    True\n'    
 '    >>> # test for subtopic=ontologies\n'    
 '    >>> subtopic in tags\n'    
 '    True\n'    
 "    >>> subtopic2 = Tag('subtopic', 'libraries')\n"    
 '    >>> # test for subtopic=libraries\n'    
 '    >>> subtopic2 in tags\n'    
 '    False\n'    
 '\n'    
 '## Class `ExtendedNamespace(types.SimpleNamespace)`\n'    
 '\n'    
 'Subclass `SimpleNamespace` with inferred attributes\n'    
 'intended primarily for use in format strings.\n'    
 'As such it also presents attributes as `[]` elements via `__getitem__`.\n'    
 '\n'    
 'Because [:alpha:]* attribute names\n'    
 'are reserved for "public" keys/attributes,\n'    
 "most methods commence with an underscore (`'_'`).\n"    
 '\n'    
 '## Class `KeyValueMetadata(KeyValueMetadata,builtins.tuple)`\n'    
 '\n'    
 'Metadata information about a `(key,value)` pair.\n'    
 '* `ontology`: the reference ontology\n'    
 '* `key_metadata`: the metadata for the `key`,\n'    
 '  the `TagSet` from `ontology[key_metadata.ontkey]`\n'    
 '* `value`: the value\n'    
 '* `value_metadata`: the metadata for the `value`,\n'    
 '  the `TagSet` from `ontology[value_metadata.ontkey]`\n'    
 '\n'    
 '## Class `Tag(Tag,builtins.tuple)`\n'    
 '\n'    
 'A Tag has a `.name` (`str`) and a `.value`\n'    
 'and an optional `.ontology`.\n'    
 '\n'    
 'The `name` must be a dotted identifier.\n'    
 '\n'    
 'Terminology:\n'    
 '* A "bare" `Tag` has a `value` of `None`.\n'    
 '* A "naive" `Tag` has an `ontology` of `None`.\n'    
 '\n'    
 'The constructor for a `Tag` is unusual:\n'    
 '* both the `value` and `ontology` are optional,\n'    
 '  defaulting to `None`\n'    
 '* if `name` is a `str` then we always construct a new `Tag`\n'    
 '  with the suppplied values\n'    
 '* if `name` is not a `str`\n'    
 '  it should be a `Tag`like object to promote;\n'    
 '  it is an error if the `value` parameter is not `None`\n'    
 '  in this case\n'    
 '\n'    
 'The promotion process is as follows:\n'    
 '* if `name` is a `Tag` subinstance\n'    
 '  then if the supplied `ontology` is not `None`\n'    
 '  and is not the ontology associated with `name`\n'    
 '  then a new `Tag` is made,\n'    
 '  otherwise `name` is returned unchanged\n'    
 '* otherwise a new `Tag` is made from `name`\n'    
 '  using its `.value`\n'    
 '  and overriding its `.ontology`\n'    
 '  if the `ontology` parameter is not `None`\n'    
 '\n'    
 '## Class `TagChoice(TagChoice,builtins.tuple)`\n'    
 '\n'    
 'A "tag choice", an apply/reject flag and a `Tag`,\n'    
 'used to apply changes to a `TagSet`\n'    
 'or as a criterion for a tag search.\n'    
 '\n'    
 'Attributes:\n'    
 '* `spec`: the source text from which this choice was parsed,\n'    
 '  possibly `None`\n'    
 '* `choice`: the apply/reject flag\n'    
 '* `tag`: the `Tag` representing the criterion\n'    
 '\n'    
 '## Class `TagsCommandMixin`\n'    
 '\n'    
 'Utility methods for `cs.cmdutils.BaseCommand` classes working with tags.\n'    
 '\n'    
 '## Class `TagSet(builtins.dict,cs.lex.FormatableMixin)`\n'    
 '\n'    
 'A setlike class associating a set of tag names with values.\n'    
 '\n'    
 'This actually subclasses `dict`, so a `TagSet` is a direct\n'    
 'mapping of tag names to values.\n'    
 '\n'    
 '*NOTE*: iteration yields `Tag`s, not dict keys.\n'    
 '\n'    
 'Also note that all the `Tags` from `TagSet`\n'    
 'share its ontology.\n'    
 '\n'    
 '### Method `TagSet.__init__(self, *a, **kw)`\n'    
 '\n'    
 'Initialise the `TagSet`.\n'    
 '\n'    
 '## Class `TagSetNamespace(ExtendedNamespace,types.SimpleNamespace)`\n'    
 '\n'    
 'A formattable nested namespace for a `TagSet`,\n'    
 'subclassing `ExtendedNamespace`.\n'    
 '\n'    
 'Where the node paths of this namespace tree match\n'    
 'the name of a `Tag` from the `TagSet`\n'    
 'that node has the following direct attributes:\n'    
 '\n'    
 '## Class `TagsOntology(cs.obj.SingletonMixin)`\n'    
 '\n'    
 'An ontology for tag names.\n'    
 '\n'    
 'This is based around a mapping of tag names\n'    
 'to ontological information expressed as a `TagSet`.\n'    
 '\n'    
 'A `cs.fstags.FSTags` uses ontologies initialised from `TagFile`s\n'    
 'containing ontology mappings.\n'    
 '\n'    
 '## Class `ValueMetadata(ValueMetadata,builtins.tuple)`\n'    
 '\n'    
 'Metadata information about a value.\n'    
 '* `ontology`: the reference ontology\n'    
 '* `ontkey`: the key within the ontology providing the metadata\n'    
 '* `value`: the value\n'    
 '\n'    
 '## Class '    
 '`ValueMetadataNamespace(TagSetNamespace,ExtendedNamespace,types.SimpleNamespace)`\n'    
 '\n'    
 "A subclass of `TagSetNamespace` for a `Tag`'s metadata.\n"    
 '\n'    
 'The reference `TagSet` is the defining `TagSet`\n'    
 'for the metadata of a particular `Tag` value\n'    
 'as defined by a `ValueMetadata`\n'    
 '(the return value of `Tag.metadata`).\n'    
 '\n'    
 '# Release Log\n'    
 '\n'    
 '\n'    
 '\n'    
 '*Release 20200521.1*:\n'    
 'Fix DISTINFO.install_requires, drop debug import.\n'    
 '\n'    
 '*Release 20200521*:\n'    
 '* New ValueDetail and KeyValueDetail classes for returning ontology '    
 'information; TagInfo.detail now returns a ValueDetail for scalar types, a '    
 'list of ValueDetails for sequence types and a list of KeyValueDetails for '    
 'mapping types; drop various TagInfo mapping/iterable style methods, too '    
 'confusing to use.\n'    
 '* Plumb ontology parameter throughout, always optional.\n'    
 '* Drop TypedTag, Tags now use ontologies for this.\n'    
 '* New TagsCommandMixin to support BaseCommands which manipulate Tags.\n'    
 '* Many improvements and bugfixes.\n'    
 '\n'    
 '*Release 20200318*:\n'    
 '* *Note that the TagsOntology stuff is in flux and totally alpha.*\n'    
 '* Tag.prefix_name factory returning a new tag if prefix is not empty, '    
 'ptherwise self.\n'    
 '* TagSet.update: accept an optional prefix for inserting "foreign" tags with '    
 'a distinguishing name prefix.\n'    
 '* Tag.as_json: turn sets and tuples into lists for encoding.\n'    
 '* Backport for Python < 3.7 (no fromisoformat functions).\n'    
 '* TagSet: drop unused and illplaced .titleify, .episode_title and .title '    
 'methods.\n'    
 '* TagSet: remove "defaults", unused.\n'    
 '* Make TagSet a direct subclass of dict, adjust uses of .update etc.\n'    
 '* New ExtendedNamespace class which is a SimpleNamespace with some inferred '    
 'attributes and a partial mapping API (keys and __getitem__).\n'    
 '* New TagSet.ns() returning the Tags as an ExtendedNamespace, which doubles '    
 'as a mapping for str.format_map; TagSet.format_kwargs is now an alias for '    
 'this.\n'    
 '* New Tag.from_string factory to parse a str into a Tag.\n'    
 '* New TagsOntology and TypedTag classes to provide type and value-detail '    
 'information; very very alpha and subject to change.\n'    
 '\n'    
 '*Release 20200229.1*:\n'    
 'Initial release: pull TagSet, Tag, TagChoice from cs.fstags for independent '    
 'use.'),
  classifiers = ['Programming Language :: Python', 'Programming Language :: Python :: 3', 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'Operating System :: OS Independent', 'Topic :: Software Development :: Libraries :: Python Modules', 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)'],
  install_requires = ['cs.edit', 'cs.lex', 'cs.logutils', 'cs.obj', 'cs.pfx', 'cs.py3', 'icontract'],
  keywords = ['python3'],
  license = 'GNU General Public License v3 or later (GPLv3+)',
  long_description_content_type = 'text/markdown',
  package_dir = {'': 'lib/python'},
  py_modules = ['cs.tagset'],
)
