Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
groupe-calcul
spip2pelican
Commits
dc0f2367
Commit
dc0f2367
authored
Jun 20, 2018
by
Matthieu Boileau
Browse files
Show rubriques as a tree
parent
9d7c674b
Changes
2
Hide whitespace changes
Inline
Side-by-side
requirements.txt
View file @
dc0f2367
anytree
ruamel.yaml
bs4
colorlog
spip2pelican.py
View file @
dc0f2367
...
...
@@ -5,6 +5,8 @@ Convert spip YAML content to markdown following
https://github.com/nhoizey/spip2markdown/blob/master/spip2markdown_options.php
"""
from
anytree
import
Node
,
RenderTree
import
argparse
from
ruamel.yaml
import
YAML
import
bs4
from
colorlog
import
ColoredFormatter
...
...
@@ -373,6 +375,49 @@ summary: {self.summary}
return
self
.
skip_reason
class
Tree
(
dict
):
"""
Simple Tree data structure from http://schinckel.net/2016/01/15/tree-data-as-a-nested-list
Stores data in the form:
{
"a": {
"b": {},
"c": {},
},
"d": {
"e": {},
},
}
And can be nested to any depth.
"""
def
__missing__
(
self
,
key
):
value
=
self
[
key
]
=
type
(
self
)()
return
value
def
insert
(
self
,
node
,
ancestors
):
"""Insert the supplied node, creating all ancestors as required.
This expects a list (possibly empty) containing the ancestors,
and a value for the node.
"""
if
not
ancestors
:
self
[
node
]
else
:
self
[
ancestors
[
0
]].
insert
(
node
,
ancestors
[
1
:])
def
label
(
self
,
labels
,
sort_key
=
lambda
x
:
x
[
0
]):
"""Return a nested 2-tuple with just the supplied labels.
Realistically, the labels could be any type of object.
"""
return
sorted
([
(
labels
.
get
(
key
),
value
.
label
(
labels
,
sort_key
)
)
for
key
,
value
in
self
.
items
()
],
key
=
sort_key
)
class
Website
:
"""Define a website from Spip data"""
...
...
@@ -445,7 +490,7 @@ class Website:
"""Return category from id_rubrique"""
while
id_rubrique
not
in
self
.
categories
:
try
:
id_rubrique
=
parents
[
id_rubrique
]
id_rubrique
=
self
.
parents
[
id_rubrique
]
except
KeyError
:
id_rubrique
=
-
1
...
...
@@ -455,10 +500,63 @@ class Website:
with
open
(
self
.
rubriques_filename
,
mode
=
'r'
)
as
yml_file
:
rubriques
=
yaml
.
load
(
yml_file
.
read
())
parents
=
{
rubrique
[
'id_rubrique'
]:
rubrique
[
'id_parent'
]
for
rubrique
in
rubriques
}
self
.
parents
=
{
rubrique
[
'id_rubrique'
]:
rubrique
[
'id_parent'
]
for
rubrique
in
rubriques
}
self
.
labels
=
{
rubrique
[
'id_rubrique'
]:
rubrique
[
'titre'
]
for
rubrique
in
rubriques
}
self
.
category_index
=
{
rubrique
[
'id_rubrique'
]:
get_category
(
rubrique
[
'id_rubrique'
])
for
rubrique
in
rubriques
}
def
print_rubrique_tree
(
self
):
"""Print the rubrique structure as a tree using anytree"""
def
get_label
(
node_id
):
"""Render node label from node id"""
return
f
"
{
node_id
}
:
{
self
.
labels
[
node_id
]
}
"
def
walk
(
node
,
parent
=
None
):
"""
A recursive function to walk a Tree object in order to build an anytree.Node tree
node: a Tree object
parent: a Tree object
"""
if
len
(
node
):
# node is a real Tree, not a leaf
name
=
list
(
node
.
keys
())[
0
]
nodes
[
name
]
=
Node
(
name
,
parent
=
parent
)
children
=
list
(
node
.
values
())[
0
]
for
k
,
v
in
children
.
items
():
walk
({
k
:
v
},
nodes
[
name
])
data
=
[]
# a list of Tree nodes
tree
=
Tree
()
# a Tree object to store rubrique structure as a nested dict
self
.
labels
[
0
]
=
"root"
# Root node label
# Build ancestors list
for
node_id
in
self
.
parents
:
node
=
{}
label
=
get_label
(
node_id
)
node
[
'node'
]
=
label
node
[
'label'
]
=
self
.
labels
[
node_id
]
node
[
'ancestors'
]
=
[]
current_id
=
node_id
while
current_id
!=
0
:
# Insert node if it is not the tree root
current_id
=
self
.
parents
[
current_id
]
label
=
get_label
(
current_id
)
node
[
'ancestors'
].
insert
(
0
,
label
)
data
.
append
(
node
)
for
node
in
data
:
tree
.
insert
(
node
[
'node'
],
node
[
'ancestors'
])
# Create a dictionary of anytree.Node objects
nodes
=
{
get_label
(
0
):
Node
(
get_label
(
0
))}
walk
(
tree
)
# Render the anytree object like the bash "tree" command would do
for
pre
,
fill
,
node
in
RenderTree
(
nodes
[
'0: root'
]):
print
(
f
"
{
pre
}{
node
.
name
}
"
)
def
_build_doc_index
(
self
):
"""Build the index dictionary: {id_doc: file_path}"""
...
...
@@ -489,6 +587,7 @@ class Website:
"""
def
add_articles
(
filename
,
spip_type
):
"""Add article or rubrique to website.articles and website.article_index"""
# Load original article file as a list
with
open
(
filename
,
mode
=
'r'
)
as
yml_file
:
spip_articles
=
yaml
.
load
(
yml_file
)
...
...
@@ -532,8 +631,20 @@ class Website:
logger
.
debug
(
"See ouput.log"
)
if
__name__
==
'__main__'
:
def
parse_cl_args
():
"""Parse command line arguments"""
parser
=
argparse
.
ArgumentParser
(
description
=
"Convert Spip website as YAML data to Pelican format"
)
parser
.
add_argument
(
'-r'
,
'--rubriques'
,
action
=
'store_true'
,
help
=
"Show Spip rubriques structure as a tree"
)
parser
.
add_argument
(
'-c'
,
'--convert'
,
action
=
'store_true'
,
default
=
True
,
help
=
"Convert to Pelican"
)
return
parser
.
parse_args
()
if
__name__
==
'__main__'
:
args
=
parse_cl_args
()
website
=
Website
()
website
.
read_spip
()
website
.
export_to_pelican
()
if
args
.
rubriques
:
# Show only Spip rubrique structure
website
.
print_rubrique_tree
()
else
:
website
.
export_to_pelican
()
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